支付,金币权限
This commit is contained in:
parent
0fc752832e
commit
7df5a8e04d
@ -46,13 +46,8 @@ red-circle:
|
||||
gateway-base-url: ${LIKEI_PAYERMAX_GATEWAY_BASE_URL}
|
||||
enable-real-time-exchange-rate: ${LIKEI_PAYERMAX_ENABLE_REAL_TIME_EXCHANGE_RATE}
|
||||
|
||||
mifa-pay:
|
||||
mer-account: ${LIKEI_MIFA_PAY_MER_ACCOUNT}
|
||||
mer-no: ${LIKEI_MIFA_PAY_MER_NO}
|
||||
gateway-base-url: ${LIKEI_MIFA_PAY_GATEWAY_BASE_URL}
|
||||
rsa-private-key: ${LIKEI_MIFA_PAY_RSA_PRIVATE_KEY}
|
||||
platform-rsa-public-key: ${LIKEI_MIFA_PAY_PLATFORM_RSA_PUBLIC_KEY}
|
||||
notify-url: ${LIKEI_MIFA_PAY_NOTIFY_URL:https://jvapi.haiyihy.com/play-server-notice/mifa_pay/receive_payment}
|
||||
factory-config:
|
||||
cache-ttl-seconds: ${LIKEI_PAY_FACTORY_CONFIG_CACHE_TTL_SECONDS:300}
|
||||
|
||||
airwallex:
|
||||
client-id: ${LIKEI_AIRWALLEX_CLIENT_ID}
|
||||
|
||||
@ -2,8 +2,10 @@ package com.red.circle.order.inner.endpoint.api;
|
||||
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryConfigCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryQryCmd;
|
||||
import com.red.circle.order.inner.model.dto.SysPayFactoryConfigDTO;
|
||||
import com.red.circle.order.inner.model.dto.SysPayFactoryDTO;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -36,4 +38,11 @@ public interface PayFactoryClientApi {
|
||||
|
||||
@PostMapping("/updateSysPayChannel")
|
||||
ResultResponse<Void> updateSysPayChannel(@RequestBody SysPayFactoryCmd param);
|
||||
|
||||
@PostMapping("/getFactoryConfig")
|
||||
ResultResponse<SysPayFactoryConfigDTO> getFactoryConfig(
|
||||
@RequestBody SysPayFactoryConfigCmd param);
|
||||
|
||||
@PostMapping("/saveOrUpdateFactoryConfig")
|
||||
ResultResponse<Void> saveOrUpdateFactoryConfig(@RequestBody SysPayFactoryConfigCmd param);
|
||||
}
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
package com.red.circle.order.inner.model.cmd;
|
||||
|
||||
import com.red.circle.framework.core.dto.CommonCommand;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import java.io.Serial;
|
||||
import java.sql.Timestamp;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 支付厂商运行配置.
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class SysPayFactoryConfigCmd extends CommonCommand {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long id;
|
||||
|
||||
@NotBlank
|
||||
private String factoryCode;
|
||||
|
||||
private String env;
|
||||
|
||||
private String sysOrigin;
|
||||
|
||||
private String merAccount;
|
||||
|
||||
private String merNo;
|
||||
|
||||
private String gatewayBaseUrl;
|
||||
|
||||
private String rsaPrivateKey;
|
||||
|
||||
private String platformRsaPublicKey;
|
||||
|
||||
private String notifyUrl;
|
||||
|
||||
private Boolean enabled;
|
||||
|
||||
private Timestamp createTime;
|
||||
|
||||
private Timestamp updateTime;
|
||||
|
||||
private Long createUser;
|
||||
|
||||
private Long updateUser;
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package com.red.circle.order.inner.model.dto;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import java.sql.Timestamp;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 支付厂商运行配置.
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class SysPayFactoryConfigDTO extends Convert {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
private String factoryCode;
|
||||
|
||||
private String env;
|
||||
|
||||
private String sysOrigin;
|
||||
|
||||
private String merAccount;
|
||||
|
||||
private String merNo;
|
||||
|
||||
private String gatewayBaseUrl;
|
||||
|
||||
private String rsaPrivateKey;
|
||||
|
||||
private String platformRsaPublicKey;
|
||||
|
||||
private String notifyUrl;
|
||||
|
||||
private Boolean enabled;
|
||||
|
||||
private Timestamp createTime;
|
||||
|
||||
private Timestamp updateTime;
|
||||
|
||||
private Long createUser;
|
||||
|
||||
private Long updateUser;
|
||||
}
|
||||
@ -36,9 +36,14 @@ public class DeductGoldCmd extends CommonCommand {
|
||||
*/
|
||||
private String remarks;
|
||||
|
||||
/**
|
||||
* 后台操作用户id.
|
||||
*/
|
||||
private Long operationUserId;
|
||||
|
||||
}
|
||||
/**
|
||||
* 后台操作用户id.
|
||||
*/
|
||||
private Long operationUserId;
|
||||
|
||||
/**
|
||||
* 验证跟踪id.
|
||||
*/
|
||||
private String trackId;
|
||||
|
||||
}
|
||||
|
||||
@ -39,15 +39,21 @@ public class UserGoldRunningWaterBackQryCmd extends Command {
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 后台操作用户.
|
||||
*/
|
||||
private Boolean queryBackOperationUser;
|
||||
|
||||
/**
|
||||
* 跟踪id.
|
||||
*/
|
||||
private String trackId;
|
||||
/**
|
||||
* 后台操作用户.
|
||||
*/
|
||||
private Boolean queryBackOperationUser;
|
||||
|
||||
/**
|
||||
* 后台操作用户ID.
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long backOperationUser;
|
||||
|
||||
/**
|
||||
* 跟踪id.
|
||||
*/
|
||||
private String trackId;
|
||||
|
||||
/**
|
||||
* 类型0.收入 1.消耗.
|
||||
|
||||
@ -5,8 +5,10 @@ import com.red.circle.console.app.service.app.sys.pay.SysPayFactoryService;
|
||||
import com.red.circle.console.infra.annotations.OpsOperationReqLog;
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.framework.web.controller.BaseController;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryConfigCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryQryCmd;
|
||||
import com.red.circle.order.inner.model.dto.SysPayFactoryConfigDTO;
|
||||
import com.red.circle.order.inner.model.dto.SysPayFactoryDTO;
|
||||
import com.red.circle.tool.core.date.TimestampUtils;
|
||||
import java.util.List;
|
||||
@ -70,4 +72,23 @@ public class SysPayFactoryController extends BaseController {
|
||||
sysPayFactoryService.updateSysPayChannel(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* 厂商运行配置.
|
||||
*/
|
||||
@GetMapping("/config")
|
||||
public SysPayFactoryConfigDTO getFactoryConfig(SysPayFactoryConfigCmd param) {
|
||||
return sysPayFactoryService.getFactoryConfig(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存厂商运行配置.
|
||||
*/
|
||||
@OpsOperationReqLog("保存-支付厂商运行配置")
|
||||
@PostMapping("/config/save")
|
||||
public void saveOrUpdateFactoryConfig(@RequestBody @Validated SysPayFactoryConfigCmd param) {
|
||||
param.setUpdateUser(param.getReqUserId());
|
||||
param.setUpdateTime(TimestampUtils.now());
|
||||
sysPayFactoryService.saveOrUpdateFactoryConfig(param);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
package com.red.circle.console.adapter.app.user;
|
||||
|
||||
|
||||
import com.red.circle.console.app.dto.clienobject.user.UserGoldRunningWaterCO;
|
||||
import com.red.circle.console.app.dto.clienobject.user.UserGoldRunningWaterClsTmpCO;
|
||||
import com.red.circle.console.app.service.app.user.UserWalletService;
|
||||
import com.red.circle.console.infra.annotations.OpsOperationReqLog;
|
||||
import com.red.circle.framework.web.controller.BaseController;
|
||||
import com.red.circle.console.app.dto.clienobject.user.UserGoldRunningWaterCO;
|
||||
import com.red.circle.console.app.dto.clienobject.user.UserGoldRunningWaterClsTmpCO;
|
||||
import com.red.circle.console.app.service.gm.GmGoldOperationService;
|
||||
import com.red.circle.console.app.service.app.user.UserWalletService;
|
||||
import com.red.circle.console.infra.annotations.OpsOperationReqLog;
|
||||
import com.red.circle.framework.web.controller.BaseController;
|
||||
import com.red.circle.wallet.inner.model.cmd.DeductGoldCmd;
|
||||
import com.red.circle.wallet.inner.model.cmd.DiamondCmd;
|
||||
import com.red.circle.wallet.inner.model.cmd.SendGoldCmd;
|
||||
@ -29,9 +30,10 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/user-wallet")
|
||||
public class UserWalletRestController extends BaseController {
|
||||
|
||||
private final UserWalletService userWalletService;
|
||||
public class UserWalletRestController extends BaseController {
|
||||
|
||||
private final UserWalletService userWalletService;
|
||||
private final GmGoldOperationService gmGoldOperationService;
|
||||
|
||||
/**
|
||||
* 流水列表(使用cls代替).
|
||||
@ -50,19 +52,19 @@ public class UserWalletRestController extends BaseController {
|
||||
return userWalletService.getGoldRunningWaterCls(query);
|
||||
}
|
||||
|
||||
@OpsOperationReqLog("发送金币")
|
||||
@PostMapping("/send-gold")
|
||||
public void sendGold(@RequestBody @Validated SendGoldCmd param) {
|
||||
param.setOperationUserId(param.getReqUserId());
|
||||
userWalletService.sendGold(param);
|
||||
}
|
||||
|
||||
@OpsOperationReqLog("扣除金币")
|
||||
@PostMapping("/deduct-gold")
|
||||
public void deductCandy(@RequestBody @Validated DeductGoldCmd param) {
|
||||
param.setOperationUserId(param.getReqUserId());
|
||||
userWalletService.deductGold(param);
|
||||
}
|
||||
@OpsOperationReqLog("发送金币")
|
||||
@PostMapping("/send-gold")
|
||||
public void sendGold(@RequestBody @Validated SendGoldCmd param) {
|
||||
param.setOperationUserId(param.getReqUserId());
|
||||
gmGoldOperationService.submitSendGold(param);
|
||||
}
|
||||
|
||||
@OpsOperationReqLog("扣除金币")
|
||||
@PostMapping("/deduct-gold")
|
||||
public void deductCandy(@RequestBody @Validated DeductGoldCmd param) {
|
||||
param.setOperationUserId(param.getReqUserId());
|
||||
gmGoldOperationService.submitDeductGold(param);
|
||||
}
|
||||
|
||||
@OpsOperationReqLog("发送钻石")
|
||||
@PostMapping("/send-diamond")
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
package com.red.circle.console.adapter.gm;
|
||||
|
||||
import com.red.circle.console.app.dto.clienobject.gm.GmGoldOperationCO;
|
||||
import com.red.circle.console.app.dto.cmd.gm.GmGoldOperationCmd;
|
||||
import com.red.circle.console.app.dto.cmd.gm.GmGoldOperationPageQryCmd;
|
||||
import com.red.circle.console.app.dto.cmd.gm.GmGoldOperationReviewCmd;
|
||||
import com.red.circle.console.app.service.gm.GmGoldOperationService;
|
||||
import com.red.circle.console.infra.annotations.OpsOperationReqLog;
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.framework.web.controller.BaseController;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* GM金币操作.
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/gm/gold-operation")
|
||||
public class GmGoldOperationRestController extends BaseController {
|
||||
|
||||
private final GmGoldOperationService gmGoldOperationService;
|
||||
|
||||
@OpsOperationReqLog("GM金币操作申请")
|
||||
@PostMapping
|
||||
public GmGoldOperationCO submit(@RequestBody @Validated GmGoldOperationCmd cmd) {
|
||||
return gmGoldOperationService.submit(cmd);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
public PageResult<GmGoldOperationCO> page(GmGoldOperationPageQryCmd cmd) {
|
||||
return gmGoldOperationService.page(cmd);
|
||||
}
|
||||
|
||||
@OpsOperationReqLog("GM金币操作审核")
|
||||
@PostMapping("/review")
|
||||
public GmGoldOperationCO review(@RequestBody @Validated GmGoldOperationReviewCmd cmd) {
|
||||
return gmGoldOperationService.review(cmd);
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,16 @@
|
||||
package com.red.circle.console.app.command.admin.query;
|
||||
|
||||
import com.red.circle.console.app.convertor.MenuAppConvertor;
|
||||
import com.red.circle.console.app.dto.clienobject.admin.MenuTreeCO;
|
||||
import com.red.circle.console.infra.database.rds.service.admin.MenuService;
|
||||
import com.red.circle.framework.core.dto.CommonCommand;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.red.circle.console.app.convertor.MenuAppConvertor;
|
||||
import com.red.circle.console.app.dto.clienobject.admin.MenuTreeCO;
|
||||
import com.red.circle.console.infra.database.rds.entity.admin.User;
|
||||
import com.red.circle.console.infra.database.rds.service.admin.MenuService;
|
||||
import com.red.circle.console.infra.database.rds.service.admin.UserService;
|
||||
import com.red.circle.framework.core.dto.CommonCommand;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 账号菜单查询.
|
||||
@ -15,14 +19,43 @@ import org.springframework.stereotype.Component;
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class AccountMenuQryExe {
|
||||
|
||||
private final MenuService menuService;
|
||||
private final MenuAppConvertor menuAppConvertor;
|
||||
|
||||
public List<MenuTreeCO> execute(CommonCommand cmd) {
|
||||
return menuAppConvertor.toListMenuTreeCO(
|
||||
menuService.listUserPermMenu(cmd.requiredReqUserId().intValue()));
|
||||
}
|
||||
|
||||
}
|
||||
public class AccountMenuQryExe {
|
||||
|
||||
private static final String YUMI_ADMIN = "yumiadmin";
|
||||
private static final String GM_OPERATION = "GmOperation";
|
||||
private static final String GM_GOLD_OPERATION_REVIEW = "GmGoldOperationReview";
|
||||
|
||||
private final MenuService menuService;
|
||||
private final UserService userService;
|
||||
private final MenuAppConvertor menuAppConvertor;
|
||||
|
||||
public List<MenuTreeCO> execute(CommonCommand cmd) {
|
||||
Integer reqUserId = cmd.requiredReqUserId().intValue();
|
||||
List<MenuTreeCO> menus = menuAppConvertor.toListMenuTreeCO(menuService.listUserPermMenu(reqUserId));
|
||||
User user = userService.getById(reqUserId);
|
||||
if (Objects.nonNull(user) && YUMI_ADMIN.equalsIgnoreCase(user.getLoginName())) {
|
||||
return menus;
|
||||
}
|
||||
removeReviewMenu(menus);
|
||||
return menus;
|
||||
}
|
||||
|
||||
private void removeReviewMenu(List<MenuTreeCO> menus) {
|
||||
if (menus == null) {
|
||||
return;
|
||||
}
|
||||
Iterator<MenuTreeCO> iterator = menus.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
MenuTreeCO menu = iterator.next();
|
||||
removeReviewMenu(menu.getChildrens());
|
||||
if (GM_GOLD_OPERATION_REVIEW.equals(menu.getAlias())
|
||||
|| (GM_OPERATION.equals(menu.getAlias()) && isEmpty(menu.getChildrens()))) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEmpty(List<?> values) {
|
||||
return values == null || values.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,8 +3,10 @@ package com.red.circle.console.app.service.app.sys.pay;
|
||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.order.inner.endpoint.PayFactoryClient;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryConfigCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryQryCmd;
|
||||
import com.red.circle.order.inner.model.dto.SysPayFactoryConfigDTO;
|
||||
import com.red.circle.order.inner.model.dto.SysPayFactoryDTO;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -50,4 +52,14 @@ public class SysPayFactoryServiceImpl implements SysPayFactoryService {
|
||||
public Map<String, SysPayFactoryDTO> mapByCodes(Set<String> codes) {
|
||||
return ResponseAssert.requiredSuccess(payFactoryClient.mapByCodes(codes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SysPayFactoryConfigDTO getFactoryConfig(SysPayFactoryConfigCmd param) {
|
||||
return ResponseAssert.requiredSuccess(payFactoryClient.getFactoryConfig(param));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveOrUpdateFactoryConfig(SysPayFactoryConfigCmd param) {
|
||||
ResponseAssert.requiredSuccess(payFactoryClient.saveOrUpdateFactoryConfig(param));
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,11 +95,10 @@ public class UserWalletServiceImpl implements UserWalletService {
|
||||
userProfileClient.mapByUserIds(
|
||||
runningWaters.stream().map(UserGoldRunningWaterHistoryDTO::getUserId)
|
||||
.collect(Collectors.toSet())));
|
||||
/*
|
||||
Map<Long, User> userMap = userService.mapBackUser(
|
||||
runningWaters.stream().map(UserGoldRunningWaterTmpDTO::getBackOperationUser)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet()));*/
|
||||
Map<Long, String> opsUserNicknameMap = userService.mapBackUserNickname(
|
||||
runningWaters.stream().map(UserGoldRunningWaterHistoryDTO::getBackOperationUser)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet()));
|
||||
|
||||
return runningWaters.stream()
|
||||
.map(runningWater -> {
|
||||
@ -111,15 +110,12 @@ public class UserWalletServiceImpl implements UserWalletService {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new UserGoldRunningWaterCO()
|
||||
.setUserProfile(userProfileMap.get(runningWater.getUserId()))
|
||||
.setRunningWater(walletAppConvertor.toUserGoldRunningWaterDTO(runningWater));
|
||||
/*.backOperationName(Optional.ofNullable(runningWater.getBackOperationUser())
|
||||
.map(backUid -> Optional.of(userMap.get(backUid))
|
||||
.map(User::getNickname)
|
||||
.orElse(""))
|
||||
.orElse(""))*/
|
||||
})
|
||||
return new UserGoldRunningWaterCO()
|
||||
.setUserProfile(userProfileMap.get(runningWater.getUserId()))
|
||||
.setRunningWater(walletAppConvertor.toUserGoldRunningWaterDTO(runningWater))
|
||||
.setBackOperationName(Optional.ofNullable(runningWater.getBackOperationUser())
|
||||
.map(opsUserNicknameMap::get).orElse(""));
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
@ -266,12 +262,12 @@ public class UserWalletServiceImpl implements UserWalletService {
|
||||
ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, userProfile);
|
||||
|
||||
walletGoldClient.changeBalance(GoldReceiptCmd.builder()
|
||||
.opsExpenditure()
|
||||
.userId(userProfile.getId())
|
||||
.sysOrigin(userProfile.getOriginSys())
|
||||
.eventId("BACK-" + param.getOperationUserId())
|
||||
.amount(param.getQuantity())
|
||||
.origin(GoldOrigin.DEDUCT_COINS)
|
||||
.opsExpenditure()
|
||||
.userId(userProfile.getId())
|
||||
.sysOrigin(userProfile.getOriginSys())
|
||||
.eventId(StringUtils.isBlankOrElse(param.getTrackId(), "BACK-" + param.getOperationUserId()))
|
||||
.amount(param.getQuantity())
|
||||
.origin(GoldOrigin.DEDUCT_COINS)
|
||||
.remark(param.getRemarks())
|
||||
.closeDelayAsset()
|
||||
.opUserId(param.getOperationUserId())
|
||||
|
||||
@ -0,0 +1,316 @@
|
||||
package com.red.circle.console.app.service.gm;
|
||||
|
||||
import com.red.circle.console.app.dto.clienobject.gm.GmGoldOperationCO;
|
||||
import com.red.circle.console.app.dto.cmd.gm.GmGoldOperationCmd;
|
||||
import com.red.circle.console.app.dto.cmd.gm.GmGoldOperationPageQryCmd;
|
||||
import com.red.circle.console.app.dto.cmd.gm.GmGoldOperationReviewCmd;
|
||||
import com.red.circle.console.app.service.app.user.UserWalletService;
|
||||
import com.red.circle.console.infra.database.rds.entity.admin.User;
|
||||
import com.red.circle.console.infra.database.rds.entity.app.gm.GmGoldOperationRecord;
|
||||
import com.red.circle.console.infra.database.rds.service.admin.UserService;
|
||||
import com.red.circle.console.infra.database.rds.service.app.gm.GmGoldOperationRecordService;
|
||||
import com.red.circle.console.inner.error.ConsoleErrorCode;
|
||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||
import com.red.circle.framework.core.response.CommonErrorCode;
|
||||
import com.red.circle.framework.core.response.ResponseErrorCode;
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.other.inner.endpoint.user.user.UserProfileClient;
|
||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||
import com.red.circle.tool.core.collection.CollectionUtils;
|
||||
import com.red.circle.tool.core.sequence.IdWorkerUtils;
|
||||
import com.red.circle.wallet.inner.error.WalletErrorCode;
|
||||
import com.red.circle.wallet.inner.model.cmd.DeductGoldCmd;
|
||||
import com.red.circle.wallet.inner.model.cmd.SendGoldCmd;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* GM金币操作.
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class GmGoldOperationServiceImpl implements GmGoldOperationService {
|
||||
|
||||
private static final int OPERATION_INCOME = 0;
|
||||
private static final int OPERATION_EXPENDITURE = 1;
|
||||
private static final String STATUS_PENDING = "PENDING";
|
||||
private static final String STATUS_APPROVED = "APPROVED";
|
||||
private static final String STATUS_REJECTED = "REJECTED";
|
||||
private static final String YUMI_ADMIN = "yumiadmin";
|
||||
|
||||
private final GmGoldOperationRecordService recordService;
|
||||
private final UserWalletService userWalletService;
|
||||
private final UserProfileClient userProfileClient;
|
||||
private final UserService userService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public GmGoldOperationCO submit(GmGoldOperationCmd cmd) {
|
||||
validateSubmit(cmd);
|
||||
|
||||
Long applicantId = cmd.getReqUserId();
|
||||
User applicant = getAdminUser(applicantId);
|
||||
UserProfileDTO userProfile = getUserProfile(cmd.getUserId());
|
||||
|
||||
GmGoldOperationRecord record = buildRecord(cmd, applicant, userProfile);
|
||||
recordService.save(record);
|
||||
|
||||
if (isYumiAdmin(applicant)) {
|
||||
approveAndExecute(record, applicant, "yumiadmin direct execution");
|
||||
}
|
||||
|
||||
return toCO(record, userProfile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GmGoldOperationCO submitSendGold(SendGoldCmd cmd) {
|
||||
GmGoldOperationCmd operationCmd = new GmGoldOperationCmd();
|
||||
operationCmd.setReqUserId(cmd.getReqUserId());
|
||||
operationCmd.setUserId(cmd.getUserId());
|
||||
operationCmd.setOperationType(OPERATION_INCOME);
|
||||
operationCmd.setQuantity(cmd.getQuantity());
|
||||
operationCmd.setReasonType(cmd.getType());
|
||||
operationCmd.setUsdQuantity(cmd.getUsdQuantity());
|
||||
operationCmd.setRemarks(cmd.getRemarks());
|
||||
return submit(operationCmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GmGoldOperationCO submitDeductGold(DeductGoldCmd cmd) {
|
||||
GmGoldOperationCmd operationCmd = new GmGoldOperationCmd();
|
||||
operationCmd.setReqUserId(cmd.getReqUserId());
|
||||
operationCmd.setUserId(cmd.getUserId());
|
||||
operationCmd.setOperationType(OPERATION_EXPENDITURE);
|
||||
operationCmd.setQuantity(cmd.getQuantity());
|
||||
operationCmd.setReasonType(4);
|
||||
operationCmd.setRemarks(cmd.getRemarks());
|
||||
return submit(operationCmd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<GmGoldOperationCO> page(GmGoldOperationPageQryCmd cmd) {
|
||||
PageResult<GmGoldOperationRecord> page = recordService.query()
|
||||
.eq(Objects.nonNull(cmd.getUserId()), GmGoldOperationRecord::getUserId, cmd.getUserId())
|
||||
.eq(Objects.nonNull(cmd.getApplicantId()), GmGoldOperationRecord::getApplicantId,
|
||||
cmd.getApplicantId())
|
||||
.eq(Objects.nonNull(cmd.getOperationType()), GmGoldOperationRecord::getOperationType,
|
||||
cmd.getOperationType())
|
||||
.eq(Objects.nonNull(cmd.getStatus()), GmGoldOperationRecord::getStatus, cmd.getStatus())
|
||||
.ge(Objects.nonNull(cmd.getStartTime()), GmGoldOperationRecord::getCreateTime,
|
||||
toTimestamp(cmd.getStartTime()))
|
||||
.le(Objects.nonNull(cmd.getEndTime()), GmGoldOperationRecord::getCreateTime,
|
||||
toTimestamp(cmd.getEndTime()))
|
||||
.orderByDesc(GmGoldOperationRecord::getId)
|
||||
.page(cmd.getPageQuery());
|
||||
|
||||
Map<Long, UserProfileDTO> userProfileMap = mapUserProfiles(page.getRecords());
|
||||
return page.convert(record -> toCO(record, userProfileMap.get(record.getUserId())));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public GmGoldOperationCO review(GmGoldOperationReviewCmd cmd) {
|
||||
Long reviewerId = cmd.getReqUserId();
|
||||
User reviewer = getAdminUser(reviewerId);
|
||||
ResponseAssert.isTrue(ConsoleErrorCode.ACCOUNT_NOT_PERMISSIONS, isYumiAdmin(reviewer));
|
||||
|
||||
GmGoldOperationRecord record = recordService.getById(cmd.getId());
|
||||
ResponseAssert.notNull(ConsoleErrorCode.NOT_FOUND_RECORD, record);
|
||||
ResponseAssert.isTrue(ConsoleErrorCode.PROCESSED, STATUS_PENDING.equals(record.getStatus()));
|
||||
|
||||
if (Boolean.TRUE.equals(cmd.getApproved())) {
|
||||
approveAndExecute(record, reviewer, cmd.getReviewRemark());
|
||||
} else {
|
||||
record.setStatus(STATUS_REJECTED);
|
||||
record.setReviewerId(reviewer.getId().longValue());
|
||||
record.setReviewerName(resolveAdminName(reviewer));
|
||||
record.setReviewRemark(cmd.getReviewRemark());
|
||||
record.setReviewTime(now());
|
||||
recordService.updateSelectiveById(record);
|
||||
}
|
||||
|
||||
return toCO(record, getUserProfile(record.getUserId()));
|
||||
}
|
||||
|
||||
private void validateSubmit(GmGoldOperationCmd cmd) {
|
||||
ResponseAssert.notNull(ResponseErrorCode.REQUEST_PARAMETER_ERROR, cmd.getReqUserId());
|
||||
ResponseAssert.notNull(ResponseErrorCode.REQUEST_PARAMETER_ERROR, cmd.getUserId(),
|
||||
cmd.getOperationType(), cmd.getQuantity(), cmd.getReasonType());
|
||||
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
||||
Objects.equals(cmd.getOperationType(), OPERATION_INCOME)
|
||||
|| Objects.equals(cmd.getOperationType(), OPERATION_EXPENDITURE));
|
||||
ResponseAssert.isTrue(WalletErrorCode.REQUIRED_GT_ZERO,
|
||||
cmd.getQuantity().compareTo(BigDecimal.ZERO) > 0);
|
||||
ResponseAssert.notBlank(ResponseErrorCode.REQUEST_PARAMETER_ERROR, cmd.getRemarks());
|
||||
}
|
||||
|
||||
private GmGoldOperationRecord buildRecord(GmGoldOperationCmd cmd, User applicant,
|
||||
UserProfileDTO userProfile) {
|
||||
Long id = IdWorkerUtils.getId();
|
||||
return new GmGoldOperationRecord()
|
||||
.setId(id)
|
||||
.setUserId(userProfile.getId())
|
||||
.setSysOrigin(userProfile.getOriginSys())
|
||||
.setOperationType(cmd.getOperationType())
|
||||
.setQuantity(cmd.getQuantity())
|
||||
.setReasonType(cmd.getReasonType())
|
||||
.setUsdQuantity(cmd.getUsdQuantity())
|
||||
.setRemarks(cmd.getRemarks())
|
||||
.setStatus(STATUS_PENDING)
|
||||
.setApplicantId(applicant.getId().longValue())
|
||||
.setApplicantName(resolveAdminName(applicant))
|
||||
.setTrackId("GM-GOLD-" + id);
|
||||
}
|
||||
|
||||
private void approveAndExecute(GmGoldOperationRecord record, User reviewer, String reviewRemark) {
|
||||
executeWallet(record);
|
||||
record.setStatus(STATUS_APPROVED);
|
||||
record.setReviewerId(reviewer.getId().longValue());
|
||||
record.setReviewerName(resolveAdminName(reviewer));
|
||||
record.setReviewRemark(reviewRemark);
|
||||
record.setReviewTime(now());
|
||||
record.setExecutedTime(now());
|
||||
recordService.updateSelectiveById(record);
|
||||
}
|
||||
|
||||
private void executeWallet(GmGoldOperationRecord record) {
|
||||
if (Objects.equals(record.getOperationType(), OPERATION_INCOME)) {
|
||||
SendGoldCmd cmd = new SendGoldCmd();
|
||||
cmd.setUserId(record.getUserId());
|
||||
cmd.setQuantity(record.getQuantity());
|
||||
cmd.setType(record.getReasonType());
|
||||
cmd.setUsdQuantity(record.getUsdQuantity());
|
||||
cmd.setRemarks(record.getRemarks());
|
||||
cmd.setTrackId(record.getTrackId());
|
||||
cmd.setReqUserId(record.getApplicantId());
|
||||
cmd.setOperationUserId(record.getApplicantId());
|
||||
userWalletService.sendGold(cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
DeductGoldCmd cmd = new DeductGoldCmd();
|
||||
cmd.setUserId(record.getUserId());
|
||||
cmd.setQuantity(record.getQuantity());
|
||||
cmd.setRemarks(record.getRemarks());
|
||||
cmd.setTrackId(record.getTrackId());
|
||||
cmd.setReqUserId(record.getApplicantId());
|
||||
cmd.setOperationUserId(record.getApplicantId());
|
||||
userWalletService.deductGold(cmd);
|
||||
}
|
||||
|
||||
private User getAdminUser(Long userId) {
|
||||
User user = userService.getById(Math.toIntExact(userId));
|
||||
ResponseAssert.notNull(ConsoleErrorCode.USER_NOT_FOUND, user);
|
||||
return user;
|
||||
}
|
||||
|
||||
private UserProfileDTO getUserProfile(Long userId) {
|
||||
UserProfileDTO userProfile = ResponseAssert.requiredSuccess(userProfileClient.getByUserId(userId));
|
||||
ResponseAssert.notNull(ConsoleErrorCode.USER_NOT_FOUND, userProfile);
|
||||
return userProfile;
|
||||
}
|
||||
|
||||
private boolean isYumiAdmin(User user) {
|
||||
return Objects.nonNull(user) && YUMI_ADMIN.equalsIgnoreCase(user.getLoginName());
|
||||
}
|
||||
|
||||
private String resolveAdminName(User user) {
|
||||
if (Objects.isNull(user)) {
|
||||
return null;
|
||||
}
|
||||
if (Objects.nonNull(user.getNickname()) && !user.getNickname().isBlank()) {
|
||||
return user.getNickname();
|
||||
}
|
||||
return user.getLoginName();
|
||||
}
|
||||
|
||||
private Map<Long, UserProfileDTO> mapUserProfiles(Collection<GmGoldOperationRecord> records) {
|
||||
if (CollectionUtils.isEmpty(records)) {
|
||||
return Map.of();
|
||||
}
|
||||
Set<Long> userIds = records.stream()
|
||||
.map(GmGoldOperationRecord::getUserId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
if (CollectionUtils.isEmpty(userIds)) {
|
||||
return Map.of();
|
||||
}
|
||||
return ResponseAssert.requiredSuccess(userProfileClient.mapByUserIds(userIds));
|
||||
}
|
||||
|
||||
private GmGoldOperationCO toCO(GmGoldOperationRecord record, UserProfileDTO userProfile) {
|
||||
GmGoldOperationCO co = new GmGoldOperationCO();
|
||||
co.setId(record.getId());
|
||||
co.setUserId(record.getUserId());
|
||||
co.setSysOrigin(record.getSysOrigin());
|
||||
co.setOperationType(record.getOperationType());
|
||||
co.setOperationName(operationName(record.getOperationType()));
|
||||
co.setQuantity(record.getQuantity());
|
||||
co.setReasonType(record.getReasonType());
|
||||
co.setReasonName(reasonName(record.getOperationType(), record.getReasonType()));
|
||||
co.setUsdQuantity(record.getUsdQuantity());
|
||||
co.setRemarks(record.getRemarks());
|
||||
co.setStatus(record.getStatus());
|
||||
co.setStatusName(statusName(record.getStatus()));
|
||||
co.setApplicantId(record.getApplicantId());
|
||||
co.setApplicantName(record.getApplicantName());
|
||||
co.setReviewerId(record.getReviewerId());
|
||||
co.setReviewerName(record.getReviewerName());
|
||||
co.setReviewRemark(record.getReviewRemark());
|
||||
co.setTrackId(record.getTrackId());
|
||||
co.setReviewTime(record.getReviewTime());
|
||||
co.setExecutedTime(record.getExecutedTime());
|
||||
co.setCreateTime(record.getCreateTime());
|
||||
co.setUpdateTime(record.getUpdateTime());
|
||||
co.setUserProfile(userProfile);
|
||||
return co;
|
||||
}
|
||||
|
||||
private String operationName(Integer operationType) {
|
||||
return Objects.equals(operationType, OPERATION_INCOME) ? "增加金币" : "扣除金币";
|
||||
}
|
||||
|
||||
private String statusName(String status) {
|
||||
return switch (status) {
|
||||
case STATUS_APPROVED -> "已通过";
|
||||
case STATUS_REJECTED -> "已拒绝";
|
||||
default -> "待审核";
|
||||
};
|
||||
}
|
||||
|
||||
private String reasonName(Integer operationType, Integer reasonType) {
|
||||
if (Objects.equals(operationType, OPERATION_INCOME)) {
|
||||
return switch (reasonType) {
|
||||
case 1 -> "奖励";
|
||||
case 2 -> "内部";
|
||||
case 3 -> "工资";
|
||||
case 4 -> "充值";
|
||||
case 5 -> "其他";
|
||||
default -> "未知";
|
||||
};
|
||||
}
|
||||
return switch (reasonType) {
|
||||
case 1 -> "违规";
|
||||
case 2 -> "多发";
|
||||
case 3 -> "操作错误";
|
||||
case 4 -> "其他";
|
||||
default -> "未知";
|
||||
};
|
||||
}
|
||||
|
||||
private Timestamp toTimestamp(Long value) {
|
||||
return Objects.isNull(value) ? null : new Timestamp(value);
|
||||
}
|
||||
|
||||
private Timestamp now() {
|
||||
return new Timestamp(System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
package com.red.circle.console.app.dto.clienobject.gm;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.red.circle.framework.dto.ClientObject;
|
||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||
import java.io.Serial;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Timestamp;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* GM金币操作申请.
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class GmGoldOperationCO extends ClientObject {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long userId;
|
||||
|
||||
private String sysOrigin;
|
||||
|
||||
private Integer operationType;
|
||||
|
||||
private String operationName;
|
||||
|
||||
private BigDecimal quantity;
|
||||
|
||||
private Integer reasonType;
|
||||
|
||||
private String reasonName;
|
||||
|
||||
private BigDecimal usdQuantity;
|
||||
|
||||
private String remarks;
|
||||
|
||||
private String status;
|
||||
|
||||
private String statusName;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long applicantId;
|
||||
|
||||
private String applicantName;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long reviewerId;
|
||||
|
||||
private String reviewerName;
|
||||
|
||||
private String reviewRemark;
|
||||
|
||||
private String trackId;
|
||||
|
||||
private Timestamp reviewTime;
|
||||
|
||||
private Timestamp executedTime;
|
||||
|
||||
private Timestamp createTime;
|
||||
|
||||
private Timestamp updateTime;
|
||||
|
||||
private UserProfileDTO userProfile;
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package com.red.circle.console.app.dto.cmd.gm;
|
||||
|
||||
import com.red.circle.framework.core.dto.CommonCommand;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.io.Serial;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* GM金币操作申请.
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class GmGoldOperationCmd extends CommonCommand {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* APP用户ID.
|
||||
*/
|
||||
@NotNull
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 操作类型: 0 增加, 1 扣除.
|
||||
*/
|
||||
@NotNull
|
||||
private Integer operationType;
|
||||
|
||||
/**
|
||||
* 金币数量.
|
||||
*/
|
||||
@NotNull
|
||||
private BigDecimal quantity;
|
||||
|
||||
/**
|
||||
* 原因类型.
|
||||
*/
|
||||
@NotNull
|
||||
private Integer reasonType;
|
||||
|
||||
/**
|
||||
* 工资/充值折算USD金额.
|
||||
*/
|
||||
private BigDecimal usdQuantity;
|
||||
|
||||
/**
|
||||
* 备注.
|
||||
*/
|
||||
private String remarks;
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.red.circle.console.app.dto.cmd.gm;
|
||||
|
||||
import com.red.circle.framework.core.dto.PageCommand;
|
||||
import java.io.Serial;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* GM金币操作申请分页查询.
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class GmGoldOperationPageQryCmd extends PageCommand {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long userId;
|
||||
|
||||
private Long applicantId;
|
||||
|
||||
private Integer operationType;
|
||||
|
||||
private String status;
|
||||
|
||||
private Long startTime;
|
||||
|
||||
private Long endTime;
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package com.red.circle.console.app.dto.cmd.gm;
|
||||
|
||||
import com.red.circle.framework.core.dto.CommonCommand;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.io.Serial;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* GM金币操作审核.
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class GmGoldOperationReviewCmd extends CommonCommand {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@NotNull
|
||||
private Long id;
|
||||
|
||||
@NotNull
|
||||
private Boolean approved;
|
||||
|
||||
private String reviewRemark;
|
||||
}
|
||||
@ -1,8 +1,10 @@
|
||||
package com.red.circle.console.app.service.app.sys.pay;
|
||||
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryConfigCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryQryCmd;
|
||||
import com.red.circle.order.inner.model.dto.SysPayFactoryConfigDTO;
|
||||
import com.red.circle.order.inner.model.dto.SysPayFactoryDTO;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -42,4 +44,8 @@ public interface SysPayFactoryService {
|
||||
* 获取渠道映射信息.
|
||||
*/
|
||||
Map<String, SysPayFactoryDTO> mapByCodes(Set<String> codes);
|
||||
|
||||
SysPayFactoryConfigDTO getFactoryConfig(SysPayFactoryConfigCmd param);
|
||||
|
||||
void saveOrUpdateFactoryConfig(SysPayFactoryConfigCmd param);
|
||||
}
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
package com.red.circle.console.app.service.gm;
|
||||
|
||||
import com.red.circle.console.app.dto.clienobject.gm.GmGoldOperationCO;
|
||||
import com.red.circle.console.app.dto.cmd.gm.GmGoldOperationCmd;
|
||||
import com.red.circle.console.app.dto.cmd.gm.GmGoldOperationPageQryCmd;
|
||||
import com.red.circle.console.app.dto.cmd.gm.GmGoldOperationReviewCmd;
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.wallet.inner.model.cmd.DeductGoldCmd;
|
||||
import com.red.circle.wallet.inner.model.cmd.SendGoldCmd;
|
||||
|
||||
/**
|
||||
* GM金币操作.
|
||||
*/
|
||||
public interface GmGoldOperationService {
|
||||
|
||||
GmGoldOperationCO submit(GmGoldOperationCmd cmd);
|
||||
|
||||
GmGoldOperationCO submitSendGold(SendGoldCmd cmd);
|
||||
|
||||
GmGoldOperationCO submitDeductGold(DeductGoldCmd cmd);
|
||||
|
||||
PageResult<GmGoldOperationCO> page(GmGoldOperationPageQryCmd cmd);
|
||||
|
||||
GmGoldOperationCO review(GmGoldOperationReviewCmd cmd);
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
package com.red.circle.console.infra.database.rds.dao.app.gm;
|
||||
|
||||
import com.red.circle.console.infra.database.rds.entity.app.gm.GmGoldOperationRecord;
|
||||
import com.red.circle.framework.mybatis.dao.BaseDAO;
|
||||
|
||||
/**
|
||||
* GM金币操作申请记录 DAO.
|
||||
*/
|
||||
public interface GmGoldOperationRecordDAO extends BaseDAO<GmGoldOperationRecord> {
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
package com.red.circle.console.infra.database.rds.entity.admin;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.red.circle.console.infra.database.rds.enums.MenuTypeEnum;
|
||||
import com.red.circle.console.infra.database.rds.enums.StatusEnum;
|
||||
import com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
|
||||
@ -26,10 +28,11 @@ public class Menu extends TimestampBaseEntity {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 记录id.
|
||||
*/
|
||||
protected Integer id;
|
||||
/**
|
||||
* 记录id.
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
protected Integer id;
|
||||
|
||||
/**
|
||||
* 父菜单ID,一级菜单为0
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package com.red.circle.console.infra.database.rds.entity.admin;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
@ -23,10 +25,11 @@ public class MenuResource implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 记录id.
|
||||
*/
|
||||
protected Integer id;
|
||||
/**
|
||||
* 记录id.
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
protected Integer id;
|
||||
|
||||
/**
|
||||
* 菜单ID
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package com.red.circle.console.infra.database.rds.entity.admin;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -21,10 +23,11 @@ public class Role extends TimestampBaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 记录id.
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 记录id.
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
* 角色名称
|
||||
|
||||
@ -20,7 +20,9 @@
|
||||
*/
|
||||
package com.red.circle.console.infra.database.rds.entity.admin;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -41,10 +43,11 @@ public class RoleMenu implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 记录id.
|
||||
*/
|
||||
protected Integer id;
|
||||
/**
|
||||
* 记录id.
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
protected Integer id;
|
||||
|
||||
/**
|
||||
* 角色ID
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package com.red.circle.console.infra.database.rds.entity.admin;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -21,10 +23,11 @@ public class RoleResource implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 记录id.
|
||||
*/
|
||||
protected Integer id;
|
||||
/**
|
||||
* 记录id.
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
protected Integer id;
|
||||
|
||||
/**
|
||||
* 角色ID
|
||||
|
||||
@ -20,7 +20,9 @@
|
||||
*/
|
||||
package com.red.circle.console.infra.database.rds.entity.admin;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@ -41,10 +43,11 @@ public class UserRole implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 记录id.
|
||||
*/
|
||||
private Integer id;
|
||||
/**
|
||||
* 记录id.
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
|
||||
@ -0,0 +1,77 @@
|
||||
package com.red.circle.console.infra.database.rds.entity.app.gm;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
|
||||
import java.io.Serial;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Timestamp;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* GM金币操作申请记录.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@TableName("gm_gold_operation_record")
|
||||
public class GmGoldOperationRecord extends TimestampBaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id", type = IdType.INPUT)
|
||||
private Long id;
|
||||
|
||||
@TableField("user_id")
|
||||
private Long userId;
|
||||
|
||||
@TableField("sys_origin")
|
||||
private String sysOrigin;
|
||||
|
||||
@TableField("operation_type")
|
||||
private Integer operationType;
|
||||
|
||||
@TableField("quantity")
|
||||
private BigDecimal quantity;
|
||||
|
||||
@TableField("reason_type")
|
||||
private Integer reasonType;
|
||||
|
||||
@TableField("usd_quantity")
|
||||
private BigDecimal usdQuantity;
|
||||
|
||||
@TableField("remarks")
|
||||
private String remarks;
|
||||
|
||||
@TableField("status")
|
||||
private String status;
|
||||
|
||||
@TableField("applicant_id")
|
||||
private Long applicantId;
|
||||
|
||||
@TableField("applicant_name")
|
||||
private String applicantName;
|
||||
|
||||
@TableField("reviewer_id")
|
||||
private Long reviewerId;
|
||||
|
||||
@TableField("reviewer_name")
|
||||
private String reviewerName;
|
||||
|
||||
@TableField("review_remark")
|
||||
private String reviewRemark;
|
||||
|
||||
@TableField("track_id")
|
||||
private String trackId;
|
||||
|
||||
@TableField("review_time")
|
||||
private Timestamp reviewTime;
|
||||
|
||||
@TableField("executed_time")
|
||||
private Timestamp executedTime;
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
package com.red.circle.console.infra.database.rds.service.app.gm;
|
||||
|
||||
import com.red.circle.console.infra.database.rds.entity.app.gm.GmGoldOperationRecord;
|
||||
import com.red.circle.framework.mybatis.service.BaseService;
|
||||
|
||||
/**
|
||||
* GM金币操作申请记录服务.
|
||||
*/
|
||||
public interface GmGoldOperationRecordService extends BaseService<GmGoldOperationRecord> {
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.red.circle.console.infra.database.rds.service.app.gm.impl;
|
||||
|
||||
import com.red.circle.console.infra.database.rds.dao.app.gm.GmGoldOperationRecordDAO;
|
||||
import com.red.circle.console.infra.database.rds.entity.app.gm.GmGoldOperationRecord;
|
||||
import com.red.circle.console.infra.database.rds.service.app.gm.GmGoldOperationRecordService;
|
||||
import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* GM金币操作申请记录服务实现.
|
||||
*/
|
||||
@Service
|
||||
public class GmGoldOperationRecordServiceImpl extends
|
||||
BaseServiceImpl<GmGoldOperationRecordDAO, GmGoldOperationRecord>
|
||||
implements GmGoldOperationRecordService {
|
||||
}
|
||||
@ -1,19 +1,20 @@
|
||||
package com.red.circle.order.app.command.pay.web;
|
||||
|
||||
import com.red.circle.component.pay.paymax.PayMaxUtils;
|
||||
import com.red.circle.order.app.common.InAppPurchaseCommon;
|
||||
import com.red.circle.order.app.common.MiFaPayMysqlOrderSupport;
|
||||
import com.red.circle.order.domain.order.MiFaPayReceivePaymentNotice;
|
||||
import com.red.circle.order.infra.config.MiFaPayProperties;
|
||||
import com.red.circle.order.infra.database.mongo.order.InAppPurchaseCollectionReceiptService;
|
||||
import com.red.circle.order.infra.database.mongo.order.entity.InAppPurchaseDetails;
|
||||
import com.red.circle.order.infra.database.rds.service.order.OrderUserPurchasePayNoticeService;
|
||||
import com.red.circle.order.infra.database.rds.entity.order.OrderUserPurchasePay;
|
||||
import com.red.circle.order.infra.database.rds.service.order.OrderUserPurchasePayService;
|
||||
import com.red.circle.tool.core.text.StringUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.red.circle.component.pay.paymax.PayMaxUtils;
|
||||
import com.red.circle.order.app.common.InAppPurchaseCommon;
|
||||
import com.red.circle.order.app.common.MiFaPayMysqlOrderSupport;
|
||||
import com.red.circle.order.app.service.MiFaPayConfig;
|
||||
import com.red.circle.order.app.service.MiFaPayConfigService;
|
||||
import com.red.circle.order.domain.order.MiFaPayReceivePaymentNotice;
|
||||
import com.red.circle.order.infra.database.mongo.order.InAppPurchaseCollectionReceiptService;
|
||||
import com.red.circle.order.infra.database.mongo.order.entity.InAppPurchaseDetails;
|
||||
import com.red.circle.order.infra.database.rds.entity.order.OrderUserPurchasePay;
|
||||
import com.red.circle.order.infra.database.rds.service.order.OrderUserPurchasePayNoticeService;
|
||||
import com.red.circle.order.infra.database.rds.service.order.OrderUserPurchasePayService;
|
||||
import com.red.circle.tool.core.text.StringUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Objects;
|
||||
@ -30,12 +31,12 @@ public class MiFaPayServerNoticeReceivePaymentCmdExe {
|
||||
|
||||
private static final String SUCCESS = "SUCCESS";
|
||||
private static final String FAIL = "FAIL";
|
||||
|
||||
private final MiFaPayProperties miFaPayProperties;
|
||||
private final InAppPurchaseCommon inAppPurchaseCommon;
|
||||
private final InAppPurchaseCollectionReceiptService inAppPurchaseCollectionReceiptService;
|
||||
private final OrderUserPurchasePayNoticeService orderUserPurchasePayNoticeService;
|
||||
private final OrderUserPurchasePayService orderUserPurchasePayService;
|
||||
|
||||
private final MiFaPayConfigService miFaPayConfigService;
|
||||
private final InAppPurchaseCommon inAppPurchaseCommon;
|
||||
private final InAppPurchaseCollectionReceiptService inAppPurchaseCollectionReceiptService;
|
||||
private final OrderUserPurchasePayNoticeService orderUserPurchasePayNoticeService;
|
||||
private final OrderUserPurchasePayService orderUserPurchasePayService;
|
||||
|
||||
/**
|
||||
* 处理MiFaPay支付回调
|
||||
@ -60,16 +61,26 @@ public class MiFaPayServerNoticeReceivePaymentCmdExe {
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
MiFaPayReceivePaymentNotice.MiFaPayNoticeData noticeData = notice.getNoticeData();
|
||||
|
||||
OrderUserPurchasePay mysqlOrder = getMysqlOrder(noticeData.getOrderId());
|
||||
if (Objects.isNull(mysqlOrder)) {
|
||||
log.error("MiFaPay回调未找到MySQL订单: orderId={}", noticeData.getOrderId());
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
// 验证签名(对data字段验签)
|
||||
if (StringUtils.isBlank(notice.getSign()) || StringUtils.isBlank(notice.getData())) {
|
||||
log.error("MiFaPay回调签名或data为空");
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
MiFaPayConfig config = miFaPayConfigService.getConfig(
|
||||
mysqlOrder.getFactoryCode(), mysqlOrder.getEvn(), mysqlOrder.getSysOrigin());
|
||||
boolean validSign = PayMaxUtils.validSignRsa(
|
||||
notice.getData(),
|
||||
notice.getSign(),
|
||||
miFaPayProperties.getPlatformRsaPublicKey()
|
||||
config.getPlatformRsaPublicKey()
|
||||
);
|
||||
|
||||
if (!validSign) {
|
||||
@ -77,74 +88,67 @@ public class MiFaPayServerNoticeReceivePaymentCmdExe {
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
MiFaPayReceivePaymentNotice.MiFaPayNoticeData noticeData = notice.getNoticeData();
|
||||
|
||||
OrderUserPurchasePay mysqlOrder = getMysqlOrder(noticeData.getOrderId());
|
||||
if (Objects.isNull(mysqlOrder)) {
|
||||
log.error("MiFaPay回调未找到MySQL订单: orderId={}", noticeData.getOrderId());
|
||||
return FAIL;
|
||||
}
|
||||
return handleMysqlOrder(notice, noticeData, mysqlOrder);
|
||||
}
|
||||
|
||||
private String handleMysqlOrder(MiFaPayReceivePaymentNotice notice,
|
||||
MiFaPayReceivePaymentNotice.MiFaPayNoticeData noticeData,
|
||||
OrderUserPurchasePay mysqlOrder) {
|
||||
orderUserPurchasePayNoticeService.addNotice(
|
||||
mysqlOrder.getId(),
|
||||
notice.getSign(),
|
||||
"mifapay-" + noticeData.getOrderStatus(),
|
||||
notice,
|
||||
mysqlOrder.getUpdateUser()
|
||||
);
|
||||
|
||||
if (!Objects.equals(mysqlOrder.getPayStatus(), MiFaPayMysqlOrderSupport.PAY_STATUS_PREPAYMENT)) {
|
||||
log.warn("MiFaPay订单已处理(MySQL): orderId={}, status={}",
|
||||
mysqlOrder.getId(), mysqlOrder.getPayStatus());
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
InAppPurchaseDetails order = MiFaPayMysqlOrderSupport.toInAppPurchaseDetails(mysqlOrder);
|
||||
|
||||
if (noticeData.isSuccess()) {
|
||||
if (order.receiptTypeEqReceipt()) {
|
||||
inAppPurchaseCommon.inAppPurchaseReceipt(order,
|
||||
() -> orderUserPurchasePayService.updateSuccess(mysqlOrder.getId()));
|
||||
log.info("MiFaPay收款单处理成功(MySQL): orderId={}", mysqlOrder.getId());
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
if (order.receiptTypeEqPayment()) {
|
||||
inAppPurchaseCommon.inAppPurchasePayment(order,
|
||||
() -> orderUserPurchasePayService.updateSuccess(mysqlOrder.getId()));
|
||||
log.info("MiFaPay付款单处理成功(MySQL): orderId={}", mysqlOrder.getId());
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
log.error("MiFaPay订单类型错误(MySQL): orderId={}", mysqlOrder.getId());
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if (noticeData.isFailed()) {
|
||||
if (order.receiptTypeEqReceipt() && StringUtils.isNotBlank(mysqlOrder.getReferenceId())) {
|
||||
inAppPurchaseCollectionReceiptService.updateStatusSuccessFail(
|
||||
mysqlOrder.getReferenceId());
|
||||
}
|
||||
orderUserPurchasePayService.updateFail(
|
||||
mysqlOrder.getId(),
|
||||
String.format("MiFaPay支付失败: %s", noticeData.getOrderStatus())
|
||||
);
|
||||
log.info("MiFaPay支付失败处理完成(MySQL): orderId={}", mysqlOrder.getId());
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
log.error("MiFaPay未知订单状态(MySQL): orderId={}, status={}",
|
||||
mysqlOrder.getId(), noticeData.getOrderStatus());
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
private OrderUserPurchasePay getMysqlOrder(String orderId) {
|
||||
Long mysqlOrderId = MiFaPayMysqlOrderSupport.parseOrderId(orderId);
|
||||
return mysqlOrderId == null ? null : orderUserPurchasePayService.getById(mysqlOrderId);
|
||||
}
|
||||
}
|
||||
return handleMysqlOrder(notice, noticeData, mysqlOrder);
|
||||
}
|
||||
|
||||
private String handleMysqlOrder(MiFaPayReceivePaymentNotice notice,
|
||||
MiFaPayReceivePaymentNotice.MiFaPayNoticeData noticeData,
|
||||
OrderUserPurchasePay mysqlOrder) {
|
||||
orderUserPurchasePayNoticeService.addNotice(
|
||||
mysqlOrder.getId(),
|
||||
notice.getSign(),
|
||||
"mifapay-" + noticeData.getOrderStatus(),
|
||||
notice,
|
||||
mysqlOrder.getUpdateUser()
|
||||
);
|
||||
|
||||
if (!Objects.equals(mysqlOrder.getPayStatus(), MiFaPayMysqlOrderSupport.PAY_STATUS_PREPAYMENT)) {
|
||||
log.warn("MiFaPay订单已处理(MySQL): orderId={}, status={}",
|
||||
mysqlOrder.getId(), mysqlOrder.getPayStatus());
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
InAppPurchaseDetails order = MiFaPayMysqlOrderSupport.toInAppPurchaseDetails(mysqlOrder);
|
||||
|
||||
if (noticeData.isSuccess()) {
|
||||
if (order.receiptTypeEqReceipt()) {
|
||||
inAppPurchaseCommon.inAppPurchaseReceipt(order,
|
||||
() -> orderUserPurchasePayService.updateSuccess(mysqlOrder.getId()));
|
||||
log.info("MiFaPay收款单处理成功(MySQL): orderId={}", mysqlOrder.getId());
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
if (order.receiptTypeEqPayment()) {
|
||||
inAppPurchaseCommon.inAppPurchasePayment(order,
|
||||
() -> orderUserPurchasePayService.updateSuccess(mysqlOrder.getId()));
|
||||
log.info("MiFaPay付款单处理成功(MySQL): orderId={}", mysqlOrder.getId());
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
log.error("MiFaPay订单类型错误(MySQL): orderId={}", mysqlOrder.getId());
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if (noticeData.isFailed()) {
|
||||
if (order.receiptTypeEqReceipt() && StringUtils.isNotBlank(mysqlOrder.getReferenceId())) {
|
||||
inAppPurchaseCollectionReceiptService.updateStatusSuccessFail(
|
||||
mysqlOrder.getReferenceId());
|
||||
}
|
||||
orderUserPurchasePayService.updateFail(
|
||||
mysqlOrder.getId(),
|
||||
String.format("MiFaPay支付失败: %s", noticeData.getOrderStatus())
|
||||
);
|
||||
log.info("MiFaPay支付失败处理完成(MySQL): orderId={}", mysqlOrder.getId());
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
log.error("MiFaPay未知订单状态(MySQL): orderId={}, status={}",
|
||||
mysqlOrder.getId(), noticeData.getOrderStatus());
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
private OrderUserPurchasePay getMysqlOrder(String orderId) {
|
||||
Long mysqlOrderId = MiFaPayMysqlOrderSupport.parseOrderId(orderId);
|
||||
return mysqlOrderId == null ? null : orderUserPurchasePayService.getById(mysqlOrderId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,7 +117,8 @@ public class PayWebApplicationCommodityV2QueryExe {
|
||||
private List<PayApplicationCommodity> getPayApplicationCommodities(
|
||||
PayWebApplicationCommodityCmd cmd) {
|
||||
|
||||
if (Objects.equals(cmd.requireReqSysOriginChildEnum(), SysOriginPlatformEnum.YOLO)) {
|
||||
if (Objects.equals(cmd.requireReqSysOriginChildEnum(), SysOriginPlatformEnum.YOLO)
|
||||
|| StringUtils.isNotBlank(cmd.getRegionId())) {
|
||||
|
||||
ResponseAssert
|
||||
.isTrue(CommonErrorCode.NOT_SUPPORTED_REGION, StringUtils.isNotBlank(cmd.getRegionId()));
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package com.red.circle.order.app.command.pay.web.strategy;
|
||||
|
||||
import com.red.circle.component.pay.paymax.service.PlaceAnOrderParam;
|
||||
import com.red.circle.common.business.core.util.CountryCodeAliasUtils;
|
||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||
package com.red.circle.order.app.command.pay.web.strategy;
|
||||
|
||||
import com.red.circle.component.pay.paymax.service.PlaceAnOrderParam;
|
||||
import com.red.circle.common.business.core.util.CountryCodeAliasUtils;
|
||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||
import com.red.circle.framework.core.response.ResponseErrorCode;
|
||||
import com.red.circle.order.app.common.MiFaPayPlaceAnOrderParam;
|
||||
import com.red.circle.order.app.dto.clientobject.MiFaPayResponseCO;
|
||||
@ -66,10 +66,10 @@ public class MiFaPayWebPayPlaceAnOrderStrategy implements PayWebPlaceAnOrderStra
|
||||
|
||||
private MiFaPayResponseCO requestApi(PayPlaceAnOrderDetailsV2 details, MiFaPayPlaceAnOrderParam param) {
|
||||
try {
|
||||
return miFaPayService.placeAnOrder(param);
|
||||
return miFaPayService.placeAnOrder(param, details.getSysOrigin());
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
log.error("MiFaPay订单创建请求失败:details={}、requestParam={}",
|
||||
log.error("MiFaPay订单创建请求失败:details={}、requestParam={}",
|
||||
JacksonUtils.toJson(details), JacksonUtils.toJson(param));
|
||||
}
|
||||
return null;
|
||||
@ -102,13 +102,13 @@ public class MiFaPayWebPayPlaceAnOrderStrategy implements PayWebPlaceAnOrderStra
|
||||
.amount(amountInCents)
|
||||
.currency(details.getCurrency())
|
||||
.payWay(extractPayWay(details.getChannelCode()))
|
||||
.payType(details.getFactoryChannel())
|
||||
.userIp(details.getRequestIp())
|
||||
.returnUrl(details.getSuccessRedirectUrl())
|
||||
.notifyUrl(miFaPayService.getNotifyUrl())
|
||||
.language("en")
|
||||
.email(memberInfo.getEmail())
|
||||
.countryCode(replaceCountryCode(details.getCountryCode()))
|
||||
.payType(details.getFactoryChannel())
|
||||
.userIp(details.getRequestIp())
|
||||
.returnUrl(details.getSuccessRedirectUrl())
|
||||
.notifyUrl(miFaPayService.getNotifyUrl(details.getSysOrigin()))
|
||||
.language("en")
|
||||
.email(memberInfo.getEmail())
|
||||
.countryCode(replaceCountryCode(details.getCountryCode()))
|
||||
.firstName(memberInfo.getFirstName())
|
||||
.lastName(memberInfo.getLastName())
|
||||
.phone(memberInfo.getPhone())
|
||||
@ -126,9 +126,9 @@ public class MiFaPayWebPayPlaceAnOrderStrategy implements PayWebPlaceAnOrderStra
|
||||
return underscoreIndex > 0 ? channelCode.substring(0, underscoreIndex) : channelCode;
|
||||
}
|
||||
|
||||
private static String replaceCountryCode(String countryCode) {
|
||||
return CountryCodeAliasUtils.normalizeSaudiCode(countryCode);
|
||||
}
|
||||
private static String replaceCountryCode(String countryCode) {
|
||||
return CountryCodeAliasUtils.normalizeSaudiCode(countryCode);
|
||||
}
|
||||
|
||||
|
||||
private String getPlaceAnOrderPaymentDetailParam(PayPlaceAnOrderDetailsV2 details) {
|
||||
@ -139,7 +139,7 @@ public class MiFaPayWebPayPlaceAnOrderStrategy implements PayWebPlaceAnOrderStra
|
||||
if (StringUtils.isBlank(details.getFactoryChannel())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
PlaceAnOrderPaymentDetail paymentDetail = new PlaceAnOrderPaymentDetail();
|
||||
paymentDetail.setPaymentType(details.getFactoryChannel());
|
||||
if (paymentDetail.getPaymentType().equals("PROMPTPAY")) {
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
package com.red.circle.order.app.service;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* MiFaPay 运行配置.
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class MiFaPayConfig {
|
||||
|
||||
private String factoryCode;
|
||||
|
||||
private String env;
|
||||
|
||||
private String sysOrigin;
|
||||
|
||||
private String merAccount;
|
||||
|
||||
private String merNo;
|
||||
|
||||
private String gatewayBaseUrl;
|
||||
|
||||
private String rsaPrivateKey;
|
||||
|
||||
private String platformRsaPublicKey;
|
||||
|
||||
private String notifyUrl;
|
||||
}
|
||||
@ -0,0 +1,107 @@
|
||||
package com.red.circle.order.app.service;
|
||||
|
||||
import com.red.circle.framework.web.props.EnvProperties;
|
||||
import com.red.circle.order.app.common.MiFaPayMysqlOrderSupport;
|
||||
import com.red.circle.order.app.command.pay.web.strategy.PayEnv;
|
||||
import com.red.circle.order.infra.config.PayFactoryConfigProperties;
|
||||
import com.red.circle.order.infra.database.rds.entity.pay.PayFactoryConfig;
|
||||
import com.red.circle.order.infra.database.rds.service.pay.PayFactoryConfigService;
|
||||
import com.red.circle.tool.core.text.StringUtils;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* MiFaPay DB 配置读取服务.
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class MiFaPayConfigService {
|
||||
|
||||
private final EnvProperties envProperties;
|
||||
private final PayFactoryConfigProperties properties;
|
||||
private final PayFactoryConfigService payFactoryConfigService;
|
||||
private final ConcurrentMap<String, CacheItem> cache = new ConcurrentHashMap<>();
|
||||
|
||||
public MiFaPayConfig getConfig(String sysOrigin) {
|
||||
return getConfig(MiFaPayMysqlOrderSupport.FACTORY_CODE, currentEnv(), sysOrigin);
|
||||
}
|
||||
|
||||
public MiFaPayConfig getConfig(String env, String sysOrigin) {
|
||||
return getConfig(MiFaPayMysqlOrderSupport.FACTORY_CODE, env, sysOrigin);
|
||||
}
|
||||
|
||||
public MiFaPayConfig getConfig(String factoryCode, String env, String sysOrigin) {
|
||||
String normalizedFactoryCode = StringUtils.isBlank(factoryCode)
|
||||
? MiFaPayMysqlOrderSupport.FACTORY_CODE : factoryCode.trim();
|
||||
String normalizedEnv = StringUtils.isBlank(env) ? currentEnv() : env.trim();
|
||||
String normalizedOrigin = normalize(sysOrigin);
|
||||
String cacheKey = normalizedFactoryCode + "|" + normalizedEnv + "|" + normalizedOrigin;
|
||||
long now = System.currentTimeMillis();
|
||||
CacheItem cached = cache.get(cacheKey);
|
||||
if (cached != null && cached.expireAt > now) {
|
||||
return cached.config;
|
||||
}
|
||||
MiFaPayConfig config = loadConfig(normalizedFactoryCode, normalizedEnv, normalizedOrigin);
|
||||
cache.put(cacheKey, new CacheItem(config, now + cacheTtlMillis()));
|
||||
return config;
|
||||
}
|
||||
|
||||
public String currentEnv() {
|
||||
return envProperties.isProd() ? PayEnv.PROD.name() : PayEnv.TEST.name();
|
||||
}
|
||||
|
||||
private MiFaPayConfig loadConfig(String factoryCode, String env, String sysOrigin) {
|
||||
PayFactoryConfig config = payFactoryConfigService.getEnabledByScope(
|
||||
factoryCode, env, sysOrigin);
|
||||
if (config == null) {
|
||||
throw new IllegalStateException(
|
||||
"MiFaPay config missing: factoryCode=" + factoryCode
|
||||
+ ", env=" + env + ", sysOrigin=" + sysOrigin);
|
||||
}
|
||||
MiFaPayConfig runtimeConfig = new MiFaPayConfig()
|
||||
.setFactoryCode(config.getFactoryCode())
|
||||
.setEnv(config.getEnv())
|
||||
.setSysOrigin(config.getSysOrigin())
|
||||
.setMerAccount(config.getMerAccount())
|
||||
.setMerNo(config.getMerNo())
|
||||
.setGatewayBaseUrl(config.getGatewayBaseUrl())
|
||||
.setRsaPrivateKey(config.getRsaPrivateKey())
|
||||
.setPlatformRsaPublicKey(config.getPlatformRsaPublicKey())
|
||||
.setNotifyUrl(config.getNotifyUrl());
|
||||
validate(runtimeConfig);
|
||||
return runtimeConfig;
|
||||
}
|
||||
|
||||
private long cacheTtlMillis() {
|
||||
Long seconds = properties.getCacheTtlSeconds();
|
||||
if (seconds == null || seconds <= 0) {
|
||||
return TimeUnit.MINUTES.toMillis(5);
|
||||
}
|
||||
return TimeUnit.SECONDS.toMillis(seconds);
|
||||
}
|
||||
|
||||
private void validate(MiFaPayConfig config) {
|
||||
validateRequiredValue("merAccount", config.getMerAccount());
|
||||
validateRequiredValue("merNo", config.getMerNo());
|
||||
validateRequiredValue("gatewayBaseUrl", config.getGatewayBaseUrl());
|
||||
validateRequiredValue("rsaPrivateKey", config.getRsaPrivateKey());
|
||||
validateRequiredValue("platformRsaPublicKey", config.getPlatformRsaPublicKey());
|
||||
validateRequiredValue("notifyUrl", config.getNotifyUrl());
|
||||
}
|
||||
|
||||
private void validateRequiredValue(String fieldName, String value) {
|
||||
if (StringUtils.isBlank(value)) {
|
||||
throw new IllegalStateException("MiFaPay config missing: " + fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
private String normalize(String value) {
|
||||
return StringUtils.isBlank(value) ? "" : value.trim();
|
||||
}
|
||||
|
||||
private record CacheItem(MiFaPayConfig config, long expireAt) {
|
||||
}
|
||||
}
|
||||
@ -1,18 +1,16 @@
|
||||
package com.red.circle.order.app.service;
|
||||
|
||||
import com.red.circle.component.pay.paymax.PayMaxUtils;
|
||||
import com.red.circle.order.app.common.MiFaPayPlaceAnOrderParam;
|
||||
import com.red.circle.order.app.dto.clientobject.MiFaPayResponseCO;
|
||||
import com.red.circle.order.infra.config.MiFaPayProperties;
|
||||
import com.red.circle.tool.core.http.RcHttpClient;
|
||||
import com.red.circle.tool.core.json.JacksonUtils;
|
||||
import com.red.circle.tool.core.text.StringUtils;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.red.circle.component.pay.paymax.PayMaxUtils;
|
||||
import com.red.circle.order.app.common.MiFaPayPlaceAnOrderParam;
|
||||
import com.red.circle.order.app.dto.clientobject.MiFaPayResponseCO;
|
||||
import com.red.circle.tool.core.http.RcHttpClient;
|
||||
import com.red.circle.tool.core.json.JacksonUtils;
|
||||
import com.red.circle.tool.core.text.StringUtils;
|
||||
import java.util.Objects;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* MiFaPay支付服务
|
||||
@ -21,135 +19,126 @@ import java.util.Objects;
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class MiFaPayService {
|
||||
|
||||
/**
|
||||
* 下单接口路径
|
||||
*/
|
||||
private static final String PLACE_ORDER_PATH = "/paygateway/mbpay/order/en_v2";
|
||||
public class MiFaPayService {
|
||||
|
||||
private final String active;
|
||||
private final MiFaPayProperties miFaPayProperties;
|
||||
private final RcHttpClient rcHttpClient = RcHttpClient.builder().build();
|
||||
/**
|
||||
* 下单接口路径
|
||||
*/
|
||||
private static final String PLACE_ORDER_PATH = "/paygateway/mbpay/order/en_v2";
|
||||
|
||||
public MiFaPayService(@Value("${spring.profiles.active:dev}") String active,
|
||||
MiFaPayProperties miFaPayProperties) {
|
||||
this.active = active;
|
||||
this.miFaPayProperties = miFaPayProperties;
|
||||
private final String active;
|
||||
private final MiFaPayConfigService miFaPayConfigService;
|
||||
private final RcHttpClient rcHttpClient = RcHttpClient.builder().build();
|
||||
|
||||
public MiFaPayService(@Value("${spring.profiles.active:dev}") String active,
|
||||
MiFaPayConfigService miFaPayConfigService) {
|
||||
this.active = active;
|
||||
this.miFaPayConfigService = miFaPayConfigService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起支付下单
|
||||
*
|
||||
* @param param 下单参数
|
||||
* @return 支付响应
|
||||
*/
|
||||
public MiFaPayResponseCO placeAnOrder(MiFaPayPlaceAnOrderParam param, String sysOrigin) {
|
||||
MiFaPayConfig config = miFaPayConfigService.getConfig(sysOrigin);
|
||||
|
||||
// 设置商户编号
|
||||
param.setMerNo(config.getMerNo());
|
||||
|
||||
String url = config.getGatewayBaseUrl() + PLACE_ORDER_PATH;
|
||||
|
||||
// 将param转为JSON字符串作为data
|
||||
String dataJson = JacksonUtils.toJson(param);
|
||||
|
||||
// 对data进行签名
|
||||
String sign = PayMaxUtils.signRsa(dataJson, config.getRsaPrivateKey());
|
||||
|
||||
// 构建请求体:merAccount + sign + data
|
||||
MiFaPayRequest request = new MiFaPayRequest();
|
||||
request.setMerAccount(config.getMerAccount());
|
||||
request.setSign(sign);
|
||||
request.setData(dataJson);
|
||||
|
||||
String body = JacksonUtils.toJson(request);
|
||||
|
||||
// 非生产环境打印日志
|
||||
if (!Objects.equals(active, "prod")) {
|
||||
log.warn("MiFaPay Request URL: {}\nBody:{}", url, body);
|
||||
}
|
||||
|
||||
MiFaPayResponseCO response = rcHttpClient.post()
|
||||
.uri(url)
|
||||
.contentType("application/json")
|
||||
.bodyValue(body)
|
||||
.retrieve()
|
||||
.bodyToEntity(MiFaPayResponseCO.class)
|
||||
.block();
|
||||
|
||||
// 非生产环境打印响应日志
|
||||
if (!Objects.equals(active, "prod")) {
|
||||
log.warn("MiFaPay Response: {}", JacksonUtils.toJson(response));
|
||||
}
|
||||
|
||||
verifySuccessfulResponse(response, config);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public String getNotifyUrl(String sysOrigin) {
|
||||
return miFaPayConfigService.getConfig(sysOrigin).getNotifyUrl();
|
||||
}
|
||||
|
||||
private void verifySuccessfulResponse(MiFaPayResponseCO response, MiFaPayConfig config) {
|
||||
if (response == null || !response.isSuccess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
validateRequiredValue("response.data", response.getData());
|
||||
validateRequiredValue("response.sign", response.getSign());
|
||||
|
||||
if (StringUtils.isNotBlank(response.getMerAccount())
|
||||
&& !Objects.equals(response.getMerAccount(), config.getMerAccount())) {
|
||||
throw new IllegalStateException("MiFaPay response merAccount mismatch");
|
||||
}
|
||||
|
||||
boolean validSign = PayMaxUtils.validSignRsa(
|
||||
response.getData(),
|
||||
response.getSign(),
|
||||
config.getPlatformRsaPublicKey()
|
||||
);
|
||||
if (!validSign) {
|
||||
throw new IllegalStateException("MiFaPay response signature verification failed");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateRequiredValue(String fieldName, String value) {
|
||||
if (StringUtils.isBlank(value)) {
|
||||
throw new IllegalStateException("MiFaPay config missing: " + fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MiFaPay请求体结构
|
||||
*/
|
||||
@Data
|
||||
public static class MiFaPayRequest {
|
||||
|
||||
/**
|
||||
* 发起支付下单
|
||||
*
|
||||
* @param param 下单参数
|
||||
* @return 支付响应
|
||||
* 商户标识
|
||||
*/
|
||||
public MiFaPayResponseCO placeAnOrder(MiFaPayPlaceAnOrderParam param) {
|
||||
validateRequiredConfig();
|
||||
|
||||
// 设置商户编号
|
||||
param.setMerNo(miFaPayProperties.getMerNo());
|
||||
private String merAccount;
|
||||
|
||||
String url = miFaPayProperties.getGatewayBaseUrl() + PLACE_ORDER_PATH;
|
||||
|
||||
// 将param转为JSON字符串作为data
|
||||
String dataJson = JacksonUtils.toJson(param);
|
||||
|
||||
// 对data进行签名
|
||||
String sign = PayMaxUtils.signRsa(dataJson, miFaPayProperties.getRsaPrivateKey());
|
||||
/**
|
||||
* 签名
|
||||
*/
|
||||
private String sign;
|
||||
|
||||
// 构建请求体:merAccount + sign + data
|
||||
MiFaPayRequest request = new MiFaPayRequest();
|
||||
request.setMerAccount(miFaPayProperties.getMerAccount());
|
||||
request.setSign(sign);
|
||||
request.setData(dataJson);
|
||||
|
||||
String body = JacksonUtils.toJson(request);
|
||||
|
||||
// 非生产环境打印日志
|
||||
if (!Objects.equals(active, "prod")) {
|
||||
log.warn("MiFaPay Request URL: {}\nBody:{}", url, body);
|
||||
}
|
||||
|
||||
MiFaPayResponseCO response = rcHttpClient.post()
|
||||
.uri(url)
|
||||
.contentType("application/json")
|
||||
.bodyValue(body)
|
||||
.retrieve()
|
||||
.bodyToEntity(MiFaPayResponseCO.class)
|
||||
.block();
|
||||
|
||||
// 非生产环境打印响应日志
|
||||
if (!Objects.equals(active, "prod")) {
|
||||
log.warn("MiFaPay Response: {}", JacksonUtils.toJson(response));
|
||||
}
|
||||
|
||||
verifySuccessfulResponse(response);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public String getNotifyUrl() {
|
||||
validateRequiredValue("notifyUrl", miFaPayProperties.getNotifyUrl());
|
||||
return miFaPayProperties.getNotifyUrl();
|
||||
}
|
||||
|
||||
private void verifySuccessfulResponse(MiFaPayResponseCO response) {
|
||||
if (response == null || !response.isSuccess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
validateRequiredValue("response.data", response.getData());
|
||||
validateRequiredValue("response.sign", response.getSign());
|
||||
|
||||
if (StringUtils.isNotBlank(response.getMerAccount())
|
||||
&& !Objects.equals(response.getMerAccount(), miFaPayProperties.getMerAccount())) {
|
||||
throw new IllegalStateException("MiFaPay response merAccount mismatch");
|
||||
}
|
||||
|
||||
boolean validSign = PayMaxUtils.validSignRsa(
|
||||
response.getData(),
|
||||
response.getSign(),
|
||||
miFaPayProperties.getPlatformRsaPublicKey()
|
||||
);
|
||||
if (!validSign) {
|
||||
throw new IllegalStateException("MiFaPay response signature verification failed");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateRequiredConfig() {
|
||||
validateRequiredValue("merAccount", miFaPayProperties.getMerAccount());
|
||||
validateRequiredValue("merNo", miFaPayProperties.getMerNo());
|
||||
validateRequiredValue("gatewayBaseUrl", miFaPayProperties.getGatewayBaseUrl());
|
||||
validateRequiredValue("rsaPrivateKey", miFaPayProperties.getRsaPrivateKey());
|
||||
validateRequiredValue("platformRsaPublicKey", miFaPayProperties.getPlatformRsaPublicKey());
|
||||
validateRequiredValue("notifyUrl", miFaPayProperties.getNotifyUrl());
|
||||
}
|
||||
|
||||
private void validateRequiredValue(String fieldName, String value) {
|
||||
if (StringUtils.isBlank(value)) {
|
||||
throw new IllegalStateException("MiFaPay config missing: " + fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MiFaPay请求体结构
|
||||
*/
|
||||
@Data
|
||||
public static class MiFaPayRequest {
|
||||
/**
|
||||
* 商户标识
|
||||
*/
|
||||
private String merAccount;
|
||||
|
||||
/**
|
||||
* 签名
|
||||
*/
|
||||
private String sign;
|
||||
|
||||
/**
|
||||
* 主请求参数(JSON字符串)
|
||||
*/
|
||||
private String data;
|
||||
}
|
||||
/**
|
||||
* 主请求参数(JSON字符串)
|
||||
*/
|
||||
private String data;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,48 +0,0 @@
|
||||
package com.red.circle.order.infra.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* MiFaPay配置属性
|
||||
*
|
||||
* @author system
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "red-circle.pay.mifa-pay")
|
||||
@RefreshScope
|
||||
public class MiFaPayProperties {
|
||||
|
||||
/**
|
||||
* 商户标识(平台分配)
|
||||
*/
|
||||
private String merAccount;
|
||||
|
||||
/**
|
||||
* 商户号
|
||||
*/
|
||||
private String merNo;
|
||||
|
||||
/**
|
||||
* 网关基础URL
|
||||
*/
|
||||
private String gatewayBaseUrl;
|
||||
|
||||
/**
|
||||
* 商户私钥(用于签名)
|
||||
*/
|
||||
private String rsaPrivateKey;
|
||||
|
||||
/**
|
||||
* 平台公钥(用于验签)
|
||||
*/
|
||||
private String platformRsaPublicKey;
|
||||
|
||||
/**
|
||||
* 支付结果异步通知地址
|
||||
*/
|
||||
private String notifyUrl;
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.red.circle.order.infra.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 支付厂商运行配置.
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "red-circle.pay.factory-config")
|
||||
public class PayFactoryConfigProperties {
|
||||
|
||||
/**
|
||||
* order 运行时读取配置的本地缓存 TTL.
|
||||
*/
|
||||
private Long cacheTtlSeconds = 300L;
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package com.red.circle.order.infra.database.rds.dao.pay;
|
||||
|
||||
import com.red.circle.framework.mybatis.dao.BaseDAO;
|
||||
import com.red.circle.order.infra.database.rds.entity.pay.PayFactoryConfig;
|
||||
|
||||
/**
|
||||
* 支付厂商运行配置 Mapper.
|
||||
*/
|
||||
public interface PayFactoryConfigDAO extends BaseDAO<PayFactoryConfig> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package com.red.circle.order.infra.database.rds.entity.pay;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
|
||||
import java.io.Serial;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 支付厂商运行配置.
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
@TableName("sys_pay_factory_config")
|
||||
public class PayFactoryConfig extends TimestampBaseEntity {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId("id")
|
||||
private Long id;
|
||||
|
||||
@TableField("factory_code")
|
||||
private String factoryCode;
|
||||
|
||||
@TableField("env")
|
||||
private String env;
|
||||
|
||||
@TableField("sys_origin")
|
||||
private String sysOrigin;
|
||||
|
||||
@TableField("mer_account")
|
||||
private String merAccount;
|
||||
|
||||
@TableField("mer_no")
|
||||
private String merNo;
|
||||
|
||||
@TableField("gateway_base_url")
|
||||
private String gatewayBaseUrl;
|
||||
|
||||
@TableField("rsa_private_key")
|
||||
private String rsaPrivateKey;
|
||||
|
||||
@TableField("platform_rsa_public_key")
|
||||
private String platformRsaPublicKey;
|
||||
|
||||
@TableField("notify_url")
|
||||
private String notifyUrl;
|
||||
|
||||
@TableField("enabled")
|
||||
private Boolean enabled;
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package com.red.circle.order.infra.database.rds.service.pay;
|
||||
|
||||
import com.red.circle.framework.mybatis.service.BaseService;
|
||||
import com.red.circle.order.infra.database.rds.entity.pay.PayFactoryConfig;
|
||||
|
||||
/**
|
||||
* 支付厂商运行配置.
|
||||
*/
|
||||
public interface PayFactoryConfigService extends BaseService<PayFactoryConfig> {
|
||||
|
||||
PayFactoryConfig getByScope(String factoryCode, String env, String sysOrigin);
|
||||
|
||||
PayFactoryConfig getEnabledByScope(String factoryCode, String env, String sysOrigin);
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
package com.red.circle.order.infra.database.rds.service.pay.impl;
|
||||
|
||||
import com.red.circle.framework.mybatis.constant.PageConstant;
|
||||
import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
|
||||
import com.red.circle.order.infra.database.rds.dao.pay.PayFactoryConfigDAO;
|
||||
import com.red.circle.order.infra.database.rds.entity.pay.PayFactoryConfig;
|
||||
import com.red.circle.order.infra.database.rds.service.pay.PayFactoryConfigService;
|
||||
import com.red.circle.tool.core.text.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 支付厂商运行配置.
|
||||
*/
|
||||
@Service
|
||||
public class PayFactoryConfigServiceImpl extends
|
||||
BaseServiceImpl<PayFactoryConfigDAO, PayFactoryConfig> implements PayFactoryConfigService {
|
||||
|
||||
@Override
|
||||
public PayFactoryConfig getByScope(String factoryCode, String env, String sysOrigin) {
|
||||
return getByScope(factoryCode, env, sysOrigin, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PayFactoryConfig getEnabledByScope(String factoryCode, String env, String sysOrigin) {
|
||||
PayFactoryConfig exact = getByScope(factoryCode, env, sysOrigin, Boolean.TRUE);
|
||||
if (exact != null) {
|
||||
return exact;
|
||||
}
|
||||
PayFactoryConfig envDefault = getByScope(factoryCode, env, "", Boolean.TRUE);
|
||||
if (envDefault != null) {
|
||||
return envDefault;
|
||||
}
|
||||
PayFactoryConfig originDefault = getByScope(factoryCode, "", sysOrigin, Boolean.TRUE);
|
||||
if (originDefault != null) {
|
||||
return originDefault;
|
||||
}
|
||||
return getByScope(factoryCode, "", "", Boolean.TRUE);
|
||||
}
|
||||
|
||||
private PayFactoryConfig getByScope(String factoryCode, String env, String sysOrigin,
|
||||
Boolean enabled) {
|
||||
return query()
|
||||
.eq(PayFactoryConfig::getFactoryCode, normalize(factoryCode))
|
||||
.eq(PayFactoryConfig::getEnv, normalize(env))
|
||||
.eq(PayFactoryConfig::getSysOrigin, normalize(sysOrigin))
|
||||
.eq(enabled != null, PayFactoryConfig::getEnabled, enabled)
|
||||
.last(PageConstant.LIMIT_ONE)
|
||||
.getOne();
|
||||
}
|
||||
|
||||
private String normalize(String value) {
|
||||
return StringUtils.isBlank(value) ? "" : value.trim();
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,7 @@ import com.red.circle.order.infra.database.rds.entity.pay.PayCountry;
|
||||
import com.red.circle.order.infra.database.rds.entity.pay.PayCountryChannel;
|
||||
import com.red.circle.order.infra.database.rds.entity.pay.PayCountryChannelDetails;
|
||||
import com.red.circle.order.infra.database.rds.entity.pay.PayFactory;
|
||||
import com.red.circle.order.infra.database.rds.entity.pay.PayFactoryConfig;
|
||||
import com.red.circle.order.infra.database.rds.query.SysPayChannelQry;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayApplicationCommodityCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayChannelCmd;
|
||||
@ -17,6 +18,7 @@ import com.red.circle.order.inner.model.cmd.SysPayChannelFactoryCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayChannelQryCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayCountryAddCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayCountryChannelDetailsCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryConfigCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryCmd;
|
||||
import com.red.circle.order.inner.model.dto.CountryCodeDTO;
|
||||
import com.red.circle.order.inner.model.dto.PayCountryDTO;
|
||||
@ -26,6 +28,7 @@ import com.red.circle.order.inner.model.dto.SysPayChannelDTO;
|
||||
import com.red.circle.order.inner.model.dto.SysPayCountryChannelDTO;
|
||||
import com.red.circle.order.inner.model.dto.SysPayCountryChannelDetailsDTO;
|
||||
import com.red.circle.order.inner.model.dto.SysPayFactoryAssociatedChannelsDTO;
|
||||
import com.red.circle.order.inner.model.dto.SysPayFactoryConfigDTO;
|
||||
import com.red.circle.order.inner.model.dto.SysPayFactoryDTO;
|
||||
import com.red.circle.other.inner.model.dto.sys.SysCountryCodeDTO;
|
||||
import java.util.List;
|
||||
@ -58,6 +61,10 @@ public interface WebPayInnerConvertor {
|
||||
|
||||
PayFactory toPayFactory(SysPayFactoryCmd cmd);
|
||||
|
||||
PayFactoryConfig toPayFactoryConfig(SysPayFactoryConfigCmd cmd);
|
||||
|
||||
SysPayFactoryConfigDTO toSysPayFactoryConfigDTO(PayFactoryConfig config);
|
||||
|
||||
Map<String, SysPayChannelDTO> toMapSysPayChannelDTO(Map<String, PayChannel> map);
|
||||
|
||||
SysPayFactoryAssociatedChannelsDTO toSysPayFactoryAssociatedChannelsDTO(
|
||||
|
||||
@ -3,8 +3,10 @@ package com.red.circle.order.inner.endpoint;
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.framework.dto.ResultResponse;
|
||||
import com.red.circle.order.inner.endpoint.api.PayFactoryClientApi;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryConfigCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryQryCmd;
|
||||
import com.red.circle.order.inner.model.dto.SysPayFactoryConfigDTO;
|
||||
import com.red.circle.order.inner.model.dto.SysPayFactoryDTO;
|
||||
import com.red.circle.order.inner.service.PayFactoryClientService;
|
||||
import java.util.List;
|
||||
@ -56,4 +58,15 @@ public class PayFactoryClientEndpoint implements PayFactoryClientApi {
|
||||
payFactoryClientService.updateSysPayChannel(param);
|
||||
return ResultResponse.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultResponse<SysPayFactoryConfigDTO> getFactoryConfig(SysPayFactoryConfigCmd param) {
|
||||
return ResultResponse.success(payFactoryClientService.getFactoryConfig(param));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultResponse<Void> saveOrUpdateFactoryConfig(SysPayFactoryConfigCmd param) {
|
||||
payFactoryClientService.saveOrUpdateFactoryConfig(param);
|
||||
return ResultResponse.success();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,8 +2,10 @@ package com.red.circle.order.inner.service;
|
||||
|
||||
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryConfigCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryQryCmd;
|
||||
import com.red.circle.order.inner.model.dto.SysPayFactoryConfigDTO;
|
||||
import com.red.circle.order.inner.model.dto.SysPayFactoryDTO;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -25,4 +27,8 @@ public interface PayFactoryClientService {
|
||||
void addSysPayChannel(SysPayFactoryCmd param);
|
||||
|
||||
void updateSysPayChannel(SysPayFactoryCmd param);
|
||||
|
||||
SysPayFactoryConfigDTO getFactoryConfig(SysPayFactoryConfigCmd param);
|
||||
|
||||
void saveOrUpdateFactoryConfig(SysPayFactoryConfigCmd param);
|
||||
}
|
||||
|
||||
@ -1,14 +1,24 @@
|
||||
package com.red.circle.order.inner.service.impl;
|
||||
|
||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||
import com.red.circle.framework.core.response.ResponseErrorCode;
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
import com.red.circle.order.infra.database.rds.service.pay.PayFactoryService;
|
||||
import com.red.circle.order.inner.convertor.WebPayInnerConvertor;
|
||||
import com.red.circle.order.infra.database.rds.entity.pay.PayFactoryConfig;
|
||||
import com.red.circle.order.infra.database.rds.service.pay.PayFactoryConfigService;
|
||||
import com.red.circle.order.infra.database.rds.service.pay.PayFactoryService;
|
||||
import com.red.circle.order.inner.convertor.WebPayInnerConvertor;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryConfigCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryCmd;
|
||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryQryCmd;
|
||||
import com.red.circle.order.inner.model.dto.SysPayFactoryConfigDTO;
|
||||
import com.red.circle.order.inner.model.dto.SysPayFactoryDTO;
|
||||
import com.red.circle.order.inner.service.PayFactoryClientService;
|
||||
import com.red.circle.tool.core.date.TimestampUtils;
|
||||
import com.red.circle.tool.core.sequence.IdWorkerUtils;
|
||||
import com.red.circle.tool.core.text.StringUtils;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -22,8 +32,9 @@ import org.springframework.stereotype.Service;
|
||||
@RequiredArgsConstructor
|
||||
public class PayFactoryClientServiceImpl implements PayFactoryClientService {
|
||||
|
||||
private final PayFactoryService payFactoryService;
|
||||
private final WebPayInnerConvertor webPayInnerConvertor;
|
||||
private final PayFactoryService payFactoryService;
|
||||
private final PayFactoryConfigService payFactoryConfigService;
|
||||
private final WebPayInnerConvertor webPayInnerConvertor;
|
||||
|
||||
@Override
|
||||
public Map<String, SysPayFactoryDTO> mapByCodes(Set<String> codes) {
|
||||
@ -57,4 +68,69 @@ public class PayFactoryClientServiceImpl implements PayFactoryClientService {
|
||||
public void updateSysPayChannel(SysPayFactoryCmd param) {
|
||||
payFactoryService.updateSysPayChannel(webPayInnerConvertor.toPayFactory(param));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SysPayFactoryConfigDTO getFactoryConfig(SysPayFactoryConfigCmd param) {
|
||||
normalize(param);
|
||||
PayFactoryConfig config = payFactoryConfigService.getByScope(
|
||||
param.getFactoryCode(), param.getEnv(), param.getSysOrigin());
|
||||
return webPayInnerConvertor.toSysPayFactoryConfigDTO(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveOrUpdateFactoryConfig(SysPayFactoryConfigCmd param) {
|
||||
normalize(param);
|
||||
validate(param);
|
||||
|
||||
PayFactoryConfig existing = findExisting(param);
|
||||
PayFactoryConfig entity = webPayInnerConvertor.toPayFactoryConfig(param);
|
||||
if (existing != null) {
|
||||
entity.setId(existing.getId());
|
||||
entity.setCreateTime(existing.getCreateTime());
|
||||
entity.setCreateUser(existing.getCreateUser());
|
||||
entity.setUpdateTime(Objects.requireNonNullElse(param.getUpdateTime(), TimestampUtils.now()));
|
||||
payFactoryConfigService.updateSelectiveById(entity);
|
||||
return;
|
||||
}
|
||||
|
||||
entity.setId(Objects.requireNonNullElseGet(param.getId(), IdWorkerUtils::getId));
|
||||
entity.setCreateTime(Objects.requireNonNullElse(param.getCreateTime(), TimestampUtils.now()));
|
||||
entity.setUpdateTime(param.getUpdateTime());
|
||||
payFactoryConfigService.save(entity);
|
||||
}
|
||||
|
||||
private PayFactoryConfig findExisting(SysPayFactoryConfigCmd param) {
|
||||
if (param.getId() != null) {
|
||||
PayFactoryConfig byId = payFactoryConfigService.getById(param.getId());
|
||||
if (byId != null) {
|
||||
return byId;
|
||||
}
|
||||
}
|
||||
return payFactoryConfigService.getByScope(
|
||||
param.getFactoryCode(), param.getEnv(), param.getSysOrigin());
|
||||
}
|
||||
|
||||
private void normalize(SysPayFactoryConfigCmd param) {
|
||||
param.setFactoryCode(normalize(param.getFactoryCode()));
|
||||
param.setEnv(normalize(param.getEnv()));
|
||||
param.setSysOrigin(normalize(param.getSysOrigin()));
|
||||
if (param.getEnabled() == null) {
|
||||
param.setEnabled(Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
private String normalize(String value) {
|
||||
return StringUtils.isBlank(value) ? "" : value.trim();
|
||||
}
|
||||
|
||||
private void validate(SysPayFactoryConfigCmd param) {
|
||||
ResponseAssert.notBlank(ResponseErrorCode.REQUEST_PARAMETER_ERROR, param.getFactoryCode());
|
||||
ResponseAssert.notBlank(ResponseErrorCode.REQUEST_PARAMETER_ERROR, param.getMerAccount());
|
||||
ResponseAssert.notBlank(ResponseErrorCode.REQUEST_PARAMETER_ERROR, param.getMerNo());
|
||||
ResponseAssert.notBlank(ResponseErrorCode.REQUEST_PARAMETER_ERROR, param.getGatewayBaseUrl());
|
||||
ResponseAssert.notBlank(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
|
||||
param.getPlatformRsaPublicKey());
|
||||
ResponseAssert.notBlank(ResponseErrorCode.REQUEST_PARAMETER_ERROR, param.getNotifyUrl());
|
||||
ResponseAssert.notBlank(ResponseErrorCode.REQUEST_PARAMETER_ERROR, param.getRsaPrivateKey());
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,12 +146,14 @@ public class TmpGoldWalletServiceImpl implements TmpGoldWalletService {
|
||||
|
||||
List<WalletGoldAssetRecord> assetRecords = queryChain
|
||||
.ge(WalletGoldAssetRecord::getCreateTime, cmd.getStartTime())
|
||||
.le(WalletGoldAssetRecord::getCreateTime, cmd.getEndTime())
|
||||
.eq(Objects.nonNull(cmd.getId()), WalletGoldAssetRecord::getId, cmd.getId())
|
||||
.eq(Objects.nonNull(cmd.getQueryBackOperationUser()), WalletGoldAssetRecord::getOpUserType,
|
||||
cmd.getQueryBackOperationUser())
|
||||
.eq(Objects.nonNull(cmd.getType()), WalletGoldAssetRecord::getType, cmd.getType())
|
||||
.eq(Objects.nonNull(cmd.getUserId()), WalletGoldAssetRecord::getUserId, cmd.getUserId())
|
||||
.le(WalletGoldAssetRecord::getCreateTime, cmd.getEndTime())
|
||||
.eq(Objects.nonNull(cmd.getId()), WalletGoldAssetRecord::getId, cmd.getId())
|
||||
.eq(Objects.nonNull(cmd.getQueryBackOperationUser()), WalletGoldAssetRecord::getOpUserType,
|
||||
cmd.getQueryBackOperationUser())
|
||||
.eq(Objects.nonNull(cmd.getBackOperationUser()), WalletGoldAssetRecord::getCreateUser,
|
||||
cmd.getBackOperationUser())
|
||||
.eq(Objects.nonNull(cmd.getType()), WalletGoldAssetRecord::getType, cmd.getType())
|
||||
.eq(Objects.nonNull(cmd.getUserId()), WalletGoldAssetRecord::getUserId, cmd.getUserId())
|
||||
.eq(StringUtils.isNotBlank(cmd.getTrackId()), WalletGoldAssetRecord::getEventId,
|
||||
cmd.getTrackId())
|
||||
.eq(StringUtils.isNotBlank(cmd.getOrigin()), WalletGoldAssetRecord::getEventType,
|
||||
@ -185,13 +187,15 @@ public class TmpGoldWalletServiceImpl implements TmpGoldWalletService {
|
||||
.setType(assetRecord.getType())
|
||||
.setOrigin(assetRecord.getEventType())
|
||||
.setOriginName(assetRecord.getEventDesc())
|
||||
.setStatus(Optional.ofNullable(statusMap.get(assetRecord.getId()))
|
||||
.map(Objects::toString)
|
||||
.orElse(""))
|
||||
.setRemark(remarkValue.get(Objects.toString(assetRecord.getId())))
|
||||
.setCreateTime(assetRecord.getCreateTime().getTime())
|
||||
.setUpdateTime(assetRecord.getUpdateTime().getTime())
|
||||
).toList();
|
||||
.setStatus(Optional.ofNullable(statusMap.get(assetRecord.getId()))
|
||||
.map(Objects::toString)
|
||||
.orElse(""))
|
||||
.setRemark(remarkValue.get(Objects.toString(assetRecord.getId())))
|
||||
.setBackOperationUser(Objects.equals(assetRecord.getOpUserType(), 1)
|
||||
? assetRecord.getCreateUser() : null)
|
||||
.setCreateTime(assetRecord.getCreateTime().getTime())
|
||||
.setUpdateTime(assetRecord.getUpdateTime().getTime())
|
||||
).toList();
|
||||
|
||||
}
|
||||
|
||||
@ -388,10 +392,11 @@ public class TmpGoldWalletServiceImpl implements TmpGoldWalletService {
|
||||
private String getQueryString(UserGoldRunningWaterBackQryCmd cmd) {
|
||||
List<String> query = Stream.of(
|
||||
toQuery("sysOrigin", getQuerySysOrigin(cmd)),
|
||||
toQuery("id", cmd.getId()),
|
||||
toQuery("opUserType", DataTypeUtils.toInteger(cmd.getQueryBackOperationUser())),
|
||||
toQuery("type", cmd.getType()),
|
||||
toQuery("userId", cmd.getUserId()),
|
||||
toQuery("id", cmd.getId()),
|
||||
toQuery("opUserType", DataTypeUtils.toInteger(cmd.getQueryBackOperationUser())),
|
||||
toQuery("createUser", cmd.getBackOperationUser()),
|
||||
toQuery("type", cmd.getType()),
|
||||
toQuery("userId", cmd.getUserId()),
|
||||
toQuery("eventId", cmd.getTrackId()),
|
||||
toQuery("eventType", getOrigin(cmd.getOrigin())))
|
||||
.filter(StringUtils::isNotBlank).toList();
|
||||
|
||||
@ -161,12 +161,14 @@ public class WalletGoldClientServiceImpl implements WalletGoldClientService {
|
||||
|
||||
List<WalletGoldAssetRecord> assetRecords = queryChain
|
||||
.ge(WalletGoldAssetRecord::getCreateTime, cmd.getStartTime())
|
||||
.le(WalletGoldAssetRecord::getCreateTime, cmd.getEndTime())
|
||||
.eq(Objects.nonNull(cmd.getId()), WalletGoldAssetRecord::getId, cmd.getId())
|
||||
.eq(Objects.nonNull(cmd.getQueryBackOperationUser()), WalletGoldAssetRecord::getOpUserType,
|
||||
cmd.getQueryBackOperationUser())
|
||||
.eq(Objects.nonNull(cmd.getType()), WalletGoldAssetRecord::getType, cmd.getType())
|
||||
.eq(Objects.nonNull(cmd.getUserId()), WalletGoldAssetRecord::getUserId, cmd.getUserId())
|
||||
.le(WalletGoldAssetRecord::getCreateTime, cmd.getEndTime())
|
||||
.eq(Objects.nonNull(cmd.getId()), WalletGoldAssetRecord::getId, cmd.getId())
|
||||
.eq(Objects.nonNull(cmd.getQueryBackOperationUser()), WalletGoldAssetRecord::getOpUserType,
|
||||
cmd.getQueryBackOperationUser())
|
||||
.eq(Objects.nonNull(cmd.getBackOperationUser()), WalletGoldAssetRecord::getCreateUser,
|
||||
cmd.getBackOperationUser())
|
||||
.eq(Objects.nonNull(cmd.getType()), WalletGoldAssetRecord::getType, cmd.getType())
|
||||
.eq(Objects.nonNull(cmd.getUserId()), WalletGoldAssetRecord::getUserId, cmd.getUserId())
|
||||
.eq(StringUtils.isNotBlank(cmd.getTrackId()), WalletGoldAssetRecord::getEventId,
|
||||
cmd.getTrackId())
|
||||
.eq(StringUtils.isNotBlank(cmd.getOrigin()), WalletGoldAssetRecord::getEventType,
|
||||
@ -201,12 +203,14 @@ public class WalletGoldClientServiceImpl implements WalletGoldClientService {
|
||||
.setType(assetRecord.getType())
|
||||
.setOrigin(assetRecord.getEventType())
|
||||
.setOriginName(assetRecord.getEventDesc())
|
||||
.setStatus(Optional.ofNullable(statusMap.get(assetRecord.getId()))
|
||||
.map(Objects::toString).orElse(""))
|
||||
.setRemark(remarkValue.get(Objects.toString(assetRecord.getId())))
|
||||
.setCreateTime(assetRecord.getCreateTime().getTime())
|
||||
.setUpdateTime(assetRecord.getUpdateTime().getTime())
|
||||
).toList();
|
||||
.setStatus(Optional.ofNullable(statusMap.get(assetRecord.getId()))
|
||||
.map(Objects::toString).orElse(""))
|
||||
.setRemark(remarkValue.get(Objects.toString(assetRecord.getId())))
|
||||
.setBackOperationUser(Objects.equals(assetRecord.getOpUserType(), 1)
|
||||
? assetRecord.getCreateUser() : null)
|
||||
.setCreateTime(assetRecord.getCreateTime().getTime())
|
||||
.setUpdateTime(assetRecord.getUpdateTime().getTime())
|
||||
).toList();
|
||||
return walletInnerConvertor.toListUserGoldRunningWaterHistoryDTO(co);
|
||||
}
|
||||
|
||||
@ -298,10 +302,11 @@ public class WalletGoldClientServiceImpl implements WalletGoldClientService {
|
||||
private String getQueryString(UserGoldRunningWaterBackQryCmd cmd) {
|
||||
List<String> query = Stream.of(
|
||||
toQuery("sysOrigin", querySysOrigin(cmd)),
|
||||
toQuery("id", cmd.getId()),
|
||||
toQuery("opUserType", DataTypeUtils.toInteger(cmd.getQueryBackOperationUser())),
|
||||
toQuery("type", cmd.getType()),
|
||||
toQuery("userId", cmd.getUserId()),
|
||||
toQuery("id", cmd.getId()),
|
||||
toQuery("opUserType", DataTypeUtils.toInteger(cmd.getQueryBackOperationUser())),
|
||||
toQuery("createUser", cmd.getBackOperationUser()),
|
||||
toQuery("type", cmd.getType()),
|
||||
toQuery("userId", cmd.getUserId()),
|
||||
toQuery("eventId", cmd.getTrackId()),
|
||||
toQuery("eventType", getOrigin(cmd.getOrigin()))
|
||||
)
|
||||
|
||||
13005
sql/20260430_mifapay_full_payment_country_channels.sql
Normal file
13005
sql/20260430_mifapay_full_payment_country_channels.sql
Normal file
File diff suppressed because it is too large
Load Diff
5146
sql/20260430_mifapay_full_payment_country_channels_manifest.json
Normal file
5146
sql/20260430_mifapay_full_payment_country_channels_manifest.json
Normal file
File diff suppressed because it is too large
Load Diff
108
sql/20260430_mifapay_v2_region_gold_tiers.sql
Normal file
108
sql/20260430_mifapay_v2_region_gold_tiers.sql
Normal file
@ -0,0 +1,108 @@
|
||||
-- MiFaPay V2 region commodity tiers.
|
||||
-- Region: LIKEI Middle East, sys_region_config._id = 2046145518364221441.
|
||||
|
||||
START TRANSACTION;
|
||||
|
||||
SET @application_id := 2048200000000000701;
|
||||
SET @region_id := '2046145518364221441';
|
||||
SET @type := 'GOLD';
|
||||
|
||||
SET @unexpected_existing_ids := (
|
||||
SELECT COUNT(*)
|
||||
FROM `sys_pay_application_commodity`
|
||||
WHERE `id` IN (
|
||||
2048200000000000801,
|
||||
2048200000000000802,
|
||||
2048200000000000803,
|
||||
2048200000000000804,
|
||||
2048200000000000805,
|
||||
2048200000000000806
|
||||
)
|
||||
AND (`application_id` <> @application_id OR `type` <> @type)
|
||||
);
|
||||
|
||||
SET @abort_sql := IF(
|
||||
@unexpected_existing_ids = 0,
|
||||
'DO 0',
|
||||
'SIGNAL SQLSTATE ''45000'' SET MESSAGE_TEXT = ''MiFaPay commodity id collision'''
|
||||
);
|
||||
PREPARE stmt FROM @abort_sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
INSERT INTO `sys_pay_application` (
|
||||
`id`,
|
||||
`app_name`,
|
||||
`app_code`,
|
||||
`android_link`,
|
||||
`ios_link`,
|
||||
`create_time`,
|
||||
`update_time`,
|
||||
`create_user`,
|
||||
`update_user`
|
||||
) VALUES (
|
||||
@application_id,
|
||||
'LIKEI',
|
||||
'LIKEI',
|
||||
'',
|
||||
'',
|
||||
CURRENT_TIMESTAMP,
|
||||
CURRENT_TIMESTAMP,
|
||||
NULL,
|
||||
NULL
|
||||
) ON DUPLICATE KEY UPDATE
|
||||
`app_name` = VALUES(`app_name`),
|
||||
`app_code` = VALUES(`app_code`),
|
||||
`android_link` = VALUES(`android_link`),
|
||||
`ios_link` = VALUES(`ios_link`),
|
||||
`update_time` = CURRENT_TIMESTAMP,
|
||||
`update_user` = VALUES(`update_user`);
|
||||
|
||||
DELETE FROM `sys_pay_application_commodity`
|
||||
WHERE `application_id` = @application_id
|
||||
AND `region_id` = @region_id
|
||||
AND `type` = @type
|
||||
AND `amount_usd` IN (1.00, 5.00, 10.00, 25.00, 50.00, 100.00)
|
||||
AND `id` NOT IN (
|
||||
2048200000000000801,
|
||||
2048200000000000802,
|
||||
2048200000000000803,
|
||||
2048200000000000804,
|
||||
2048200000000000805,
|
||||
2048200000000000806
|
||||
);
|
||||
|
||||
INSERT INTO `sys_pay_application_commodity` (
|
||||
`id`,
|
||||
`application_id`,
|
||||
`pay_country_id`,
|
||||
`region_id`,
|
||||
`type`,
|
||||
`content`,
|
||||
`award_content`,
|
||||
`amount_usd`,
|
||||
`is_shelf`,
|
||||
`create_time`,
|
||||
`update_time`,
|
||||
`create_user`,
|
||||
`update_user`
|
||||
) VALUES
|
||||
(2048200000000000801, @application_id, NULL, @region_id, @type, '80000', '0', 1.00, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL),
|
||||
(2048200000000000802, @application_id, NULL, @region_id, @type, '400000', '0', 5.00, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL),
|
||||
(2048200000000000803, @application_id, NULL, @region_id, @type, '800000', '0', 10.00, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL),
|
||||
(2048200000000000804, @application_id, NULL, @region_id, @type, '2000000', '0', 25.00, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL),
|
||||
(2048200000000000805, @application_id, NULL, @region_id, @type, '4000000', '0', 50.00, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL),
|
||||
(2048200000000000806, @application_id, NULL, @region_id, @type, '8000000', '0', 100.00, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, NULL)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`application_id` = VALUES(`application_id`),
|
||||
`pay_country_id` = VALUES(`pay_country_id`),
|
||||
`region_id` = VALUES(`region_id`),
|
||||
`type` = VALUES(`type`),
|
||||
`content` = VALUES(`content`),
|
||||
`award_content` = VALUES(`award_content`),
|
||||
`amount_usd` = VALUES(`amount_usd`),
|
||||
`is_shelf` = VALUES(`is_shelf`),
|
||||
`update_time` = CURRENT_TIMESTAMP,
|
||||
`update_user` = VALUES(`update_user`);
|
||||
|
||||
COMMIT;
|
||||
24
sql/20260430_sys_pay_factory_config.sql
Normal file
24
sql/20260430_sys_pay_factory_config.sql
Normal file
@ -0,0 +1,24 @@
|
||||
CREATE TABLE IF NOT EXISTS `sys_pay_factory_config`
|
||||
(
|
||||
`id` BIGINT NOT NULL COMMENT '主键',
|
||||
`factory_code` VARCHAR(64) NOT NULL COMMENT '支付厂商code',
|
||||
`env` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '运行环境,PROD/TEST,空表示通用',
|
||||
`sys_origin` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '来源系统,空表示通用',
|
||||
`mer_account` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '商户标识',
|
||||
`mer_no` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '商户编号',
|
||||
`gateway_base_url` VARCHAR(512) NOT NULL DEFAULT '' COMMENT '网关基础地址',
|
||||
`rsa_private_key` TEXT COMMENT '商户RSA私钥',
|
||||
`platform_rsa_public_key` TEXT COMMENT '平台RSA公钥',
|
||||
`notify_url` VARCHAR(512) NOT NULL DEFAULT '' COMMENT '回调地址',
|
||||
`enabled` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
|
||||
`create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
|
||||
`update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
|
||||
`create_user` BIGINT DEFAULT NULL COMMENT '创建人',
|
||||
`update_user` BIGINT DEFAULT NULL COMMENT '更新人',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_factory_env_origin` (`factory_code`, `env`, `sys_origin`),
|
||||
KEY `idx_factory_enabled` (`factory_code`, `enabled`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE = utf8mb4_unicode_ci
|
||||
COMMENT ='支付厂商运行配置';
|
||||
Loading…
x
Reference in New Issue
Block a user