支付,金币权限
This commit is contained in:
parent
0fc752832e
commit
7df5a8e04d
@ -46,13 +46,8 @@ red-circle:
|
|||||||
gateway-base-url: ${LIKEI_PAYERMAX_GATEWAY_BASE_URL}
|
gateway-base-url: ${LIKEI_PAYERMAX_GATEWAY_BASE_URL}
|
||||||
enable-real-time-exchange-rate: ${LIKEI_PAYERMAX_ENABLE_REAL_TIME_EXCHANGE_RATE}
|
enable-real-time-exchange-rate: ${LIKEI_PAYERMAX_ENABLE_REAL_TIME_EXCHANGE_RATE}
|
||||||
|
|
||||||
mifa-pay:
|
factory-config:
|
||||||
mer-account: ${LIKEI_MIFA_PAY_MER_ACCOUNT}
|
cache-ttl-seconds: ${LIKEI_PAY_FACTORY_CONFIG_CACHE_TTL_SECONDS:300}
|
||||||
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}
|
|
||||||
|
|
||||||
airwallex:
|
airwallex:
|
||||||
client-id: ${LIKEI_AIRWALLEX_CLIENT_ID}
|
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.PageResult;
|
||||||
import com.red.circle.framework.dto.ResultResponse;
|
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.SysPayFactoryCmd;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryQryCmd;
|
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.model.dto.SysPayFactoryDTO;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -36,4 +38,11 @@ public interface PayFactoryClientApi {
|
|||||||
|
|
||||||
@PostMapping("/updateSysPayChannel")
|
@PostMapping("/updateSysPayChannel")
|
||||||
ResultResponse<Void> updateSysPayChannel(@RequestBody SysPayFactoryCmd param);
|
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;
|
||||||
|
}
|
||||||
@ -41,4 +41,9 @@ public class DeductGoldCmd extends CommonCommand {
|
|||||||
*/
|
*/
|
||||||
private Long operationUserId;
|
private Long operationUserId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证跟踪id.
|
||||||
|
*/
|
||||||
|
private String trackId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,6 +44,12 @@ public class UserGoldRunningWaterBackQryCmd extends Command {
|
|||||||
*/
|
*/
|
||||||
private Boolean queryBackOperationUser;
|
private Boolean queryBackOperationUser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后台操作用户ID.
|
||||||
|
*/
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long backOperationUser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 跟踪id.
|
* 跟踪id.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -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.console.infra.annotations.OpsOperationReqLog;
|
||||||
import com.red.circle.framework.dto.PageResult;
|
import com.red.circle.framework.dto.PageResult;
|
||||||
import com.red.circle.framework.web.controller.BaseController;
|
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.SysPayFactoryCmd;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryQryCmd;
|
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.model.dto.SysPayFactoryDTO;
|
||||||
import com.red.circle.tool.core.date.TimestampUtils;
|
import com.red.circle.tool.core.date.TimestampUtils;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -70,4 +72,23 @@ public class SysPayFactoryController extends BaseController {
|
|||||||
sysPayFactoryService.updateSysPayChannel(param);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ 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.UserGoldRunningWaterCO;
|
||||||
import com.red.circle.console.app.dto.clienobject.user.UserGoldRunningWaterClsTmpCO;
|
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.app.service.app.user.UserWalletService;
|
||||||
import com.red.circle.console.infra.annotations.OpsOperationReqLog;
|
import com.red.circle.console.infra.annotations.OpsOperationReqLog;
|
||||||
import com.red.circle.framework.web.controller.BaseController;
|
import com.red.circle.framework.web.controller.BaseController;
|
||||||
@ -32,6 +33,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
public class UserWalletRestController extends BaseController {
|
public class UserWalletRestController extends BaseController {
|
||||||
|
|
||||||
private final UserWalletService userWalletService;
|
private final UserWalletService userWalletService;
|
||||||
|
private final GmGoldOperationService gmGoldOperationService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流水列表(使用cls代替).
|
* 流水列表(使用cls代替).
|
||||||
@ -54,14 +56,14 @@ public class UserWalletRestController extends BaseController {
|
|||||||
@PostMapping("/send-gold")
|
@PostMapping("/send-gold")
|
||||||
public void sendGold(@RequestBody @Validated SendGoldCmd param) {
|
public void sendGold(@RequestBody @Validated SendGoldCmd param) {
|
||||||
param.setOperationUserId(param.getReqUserId());
|
param.setOperationUserId(param.getReqUserId());
|
||||||
userWalletService.sendGold(param);
|
gmGoldOperationService.submitSendGold(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
@OpsOperationReqLog("扣除金币")
|
@OpsOperationReqLog("扣除金币")
|
||||||
@PostMapping("/deduct-gold")
|
@PostMapping("/deduct-gold")
|
||||||
public void deductCandy(@RequestBody @Validated DeductGoldCmd param) {
|
public void deductCandy(@RequestBody @Validated DeductGoldCmd param) {
|
||||||
param.setOperationUserId(param.getReqUserId());
|
param.setOperationUserId(param.getReqUserId());
|
||||||
userWalletService.deductGold(param);
|
gmGoldOperationService.submitDeductGold(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
@OpsOperationReqLog("发送钻石")
|
@OpsOperationReqLog("发送钻石")
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,9 +2,13 @@ package com.red.circle.console.app.command.admin.query;
|
|||||||
|
|
||||||
import com.red.circle.console.app.convertor.MenuAppConvertor;
|
import com.red.circle.console.app.convertor.MenuAppConvertor;
|
||||||
import com.red.circle.console.app.dto.clienobject.admin.MenuTreeCO;
|
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.MenuService;
|
||||||
|
import com.red.circle.console.infra.database.rds.service.admin.UserService;
|
||||||
import com.red.circle.framework.core.dto.CommonCommand;
|
import com.red.circle.framework.core.dto.CommonCommand;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -17,12 +21,41 @@ import org.springframework.stereotype.Component;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class AccountMenuQryExe {
|
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 MenuService menuService;
|
||||||
|
private final UserService userService;
|
||||||
private final MenuAppConvertor menuAppConvertor;
|
private final MenuAppConvertor menuAppConvertor;
|
||||||
|
|
||||||
public List<MenuTreeCO> execute(CommonCommand cmd) {
|
public List<MenuTreeCO> execute(CommonCommand cmd) {
|
||||||
return menuAppConvertor.toListMenuTreeCO(
|
Integer reqUserId = cmd.requiredReqUserId().intValue();
|
||||||
menuService.listUserPermMenu(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.core.asserts.ResponseAssert;
|
||||||
import com.red.circle.framework.dto.PageResult;
|
import com.red.circle.framework.dto.PageResult;
|
||||||
import com.red.circle.order.inner.endpoint.PayFactoryClient;
|
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.SysPayFactoryCmd;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryQryCmd;
|
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.model.dto.SysPayFactoryDTO;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -50,4 +52,14 @@ public class SysPayFactoryServiceImpl implements SysPayFactoryService {
|
|||||||
public Map<String, SysPayFactoryDTO> mapByCodes(Set<String> codes) {
|
public Map<String, SysPayFactoryDTO> mapByCodes(Set<String> codes) {
|
||||||
return ResponseAssert.requiredSuccess(payFactoryClient.mapByCodes(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(
|
userProfileClient.mapByUserIds(
|
||||||
runningWaters.stream().map(UserGoldRunningWaterHistoryDTO::getUserId)
|
runningWaters.stream().map(UserGoldRunningWaterHistoryDTO::getUserId)
|
||||||
.collect(Collectors.toSet())));
|
.collect(Collectors.toSet())));
|
||||||
/*
|
Map<Long, String> opsUserNicknameMap = userService.mapBackUserNickname(
|
||||||
Map<Long, User> userMap = userService.mapBackUser(
|
runningWaters.stream().map(UserGoldRunningWaterHistoryDTO::getBackOperationUser)
|
||||||
runningWaters.stream().map(UserGoldRunningWaterTmpDTO::getBackOperationUser)
|
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.collect(Collectors.toSet()));*/
|
.collect(Collectors.toSet()));
|
||||||
|
|
||||||
return runningWaters.stream()
|
return runningWaters.stream()
|
||||||
.map(runningWater -> {
|
.map(runningWater -> {
|
||||||
@ -113,12 +112,9 @@ public class UserWalletServiceImpl implements UserWalletService {
|
|||||||
|
|
||||||
return new UserGoldRunningWaterCO()
|
return new UserGoldRunningWaterCO()
|
||||||
.setUserProfile(userProfileMap.get(runningWater.getUserId()))
|
.setUserProfile(userProfileMap.get(runningWater.getUserId()))
|
||||||
.setRunningWater(walletAppConvertor.toUserGoldRunningWaterDTO(runningWater));
|
.setRunningWater(walletAppConvertor.toUserGoldRunningWaterDTO(runningWater))
|
||||||
/*.backOperationName(Optional.ofNullable(runningWater.getBackOperationUser())
|
.setBackOperationName(Optional.ofNullable(runningWater.getBackOperationUser())
|
||||||
.map(backUid -> Optional.of(userMap.get(backUid))
|
.map(opsUserNicknameMap::get).orElse(""));
|
||||||
.map(User::getNickname)
|
|
||||||
.orElse(""))
|
|
||||||
.orElse(""))*/
|
|
||||||
})
|
})
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
@ -269,7 +265,7 @@ public class UserWalletServiceImpl implements UserWalletService {
|
|||||||
.opsExpenditure()
|
.opsExpenditure()
|
||||||
.userId(userProfile.getId())
|
.userId(userProfile.getId())
|
||||||
.sysOrigin(userProfile.getOriginSys())
|
.sysOrigin(userProfile.getOriginSys())
|
||||||
.eventId("BACK-" + param.getOperationUserId())
|
.eventId(StringUtils.isBlankOrElse(param.getTrackId(), "BACK-" + param.getOperationUserId()))
|
||||||
.amount(param.getQuantity())
|
.amount(param.getQuantity())
|
||||||
.origin(GoldOrigin.DEDUCT_COINS)
|
.origin(GoldOrigin.DEDUCT_COINS)
|
||||||
.remark(param.getRemarks())
|
.remark(param.getRemarks())
|
||||||
|
|||||||
@ -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;
|
package com.red.circle.console.app.service.app.sys.pay;
|
||||||
|
|
||||||
import com.red.circle.framework.dto.PageResult;
|
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.SysPayFactoryCmd;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryQryCmd;
|
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.model.dto.SysPayFactoryDTO;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -42,4 +44,8 @@ public interface SysPayFactoryService {
|
|||||||
* 获取渠道映射信息.
|
* 获取渠道映射信息.
|
||||||
*/
|
*/
|
||||||
Map<String, SysPayFactoryDTO> mapByCodes(Set<String> codes);
|
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,5 +1,7 @@
|
|||||||
package com.red.circle.console.infra.database.rds.entity.admin;
|
package com.red.circle.console.infra.database.rds.entity.admin;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
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.MenuTypeEnum;
|
||||||
import com.red.circle.console.infra.database.rds.enums.StatusEnum;
|
import com.red.circle.console.infra.database.rds.enums.StatusEnum;
|
||||||
@ -29,6 +31,7 @@ public class Menu extends TimestampBaseEntity {
|
|||||||
/**
|
/**
|
||||||
* 记录id.
|
* 记录id.
|
||||||
*/
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
protected Integer id;
|
protected Integer id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
package com.red.circle.console.infra.database.rds.entity.admin;
|
package com.red.circle.console.infra.database.rds.entity.admin;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import java.io.Serial;
|
import java.io.Serial;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@ -26,6 +28,7 @@ public class MenuResource implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* 记录id.
|
* 记录id.
|
||||||
*/
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
protected Integer id;
|
protected Integer id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
package com.red.circle.console.infra.database.rds.entity.admin;
|
package com.red.circle.console.infra.database.rds.entity.admin;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
|
import com.red.circle.framework.mybatis.entity.TimestampBaseEntity;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -24,6 +26,7 @@ public class Role extends TimestampBaseEntity {
|
|||||||
/**
|
/**
|
||||||
* 记录id.
|
* 记录id.
|
||||||
*/
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -20,6 +20,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.red.circle.console.infra.database.rds.entity.admin;
|
package com.red.circle.console.infra.database.rds.entity.admin;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -44,6 +46,7 @@ public class RoleMenu implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* 记录id.
|
* 记录id.
|
||||||
*/
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
protected Integer id;
|
protected Integer id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
package com.red.circle.console.infra.database.rds.entity.admin;
|
package com.red.circle.console.infra.database.rds.entity.admin;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -24,6 +26,7 @@ public class RoleResource implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* 记录id.
|
* 记录id.
|
||||||
*/
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
protected Integer id;
|
protected Integer id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -20,6 +20,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.red.circle.console.infra.database.rds.entity.admin;
|
package com.red.circle.console.infra.database.rds.entity.admin;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -44,6 +46,7 @@ public class UserRole implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* 记录id.
|
* 记录id.
|
||||||
*/
|
*/
|
||||||
|
@TableId(value = "id", type = IdType.AUTO)
|
||||||
private Integer id;
|
private Integer 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 {
|
||||||
|
}
|
||||||
@ -3,12 +3,13 @@ package com.red.circle.order.app.command.pay.web;
|
|||||||
import com.red.circle.component.pay.paymax.PayMaxUtils;
|
import com.red.circle.component.pay.paymax.PayMaxUtils;
|
||||||
import com.red.circle.order.app.common.InAppPurchaseCommon;
|
import com.red.circle.order.app.common.InAppPurchaseCommon;
|
||||||
import com.red.circle.order.app.common.MiFaPayMysqlOrderSupport;
|
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.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.InAppPurchaseCollectionReceiptService;
|
||||||
import com.red.circle.order.infra.database.mongo.order.entity.InAppPurchaseDetails;
|
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.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.order.infra.database.rds.service.order.OrderUserPurchasePayService;
|
||||||
import com.red.circle.tool.core.text.StringUtils;
|
import com.red.circle.tool.core.text.StringUtils;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -31,7 +32,7 @@ public class MiFaPayServerNoticeReceivePaymentCmdExe {
|
|||||||
private static final String SUCCESS = "SUCCESS";
|
private static final String SUCCESS = "SUCCESS";
|
||||||
private static final String FAIL = "FAIL";
|
private static final String FAIL = "FAIL";
|
||||||
|
|
||||||
private final MiFaPayProperties miFaPayProperties;
|
private final MiFaPayConfigService miFaPayConfigService;
|
||||||
private final InAppPurchaseCommon inAppPurchaseCommon;
|
private final InAppPurchaseCommon inAppPurchaseCommon;
|
||||||
private final InAppPurchaseCollectionReceiptService inAppPurchaseCollectionReceiptService;
|
private final InAppPurchaseCollectionReceiptService inAppPurchaseCollectionReceiptService;
|
||||||
private final OrderUserPurchasePayNoticeService orderUserPurchasePayNoticeService;
|
private final OrderUserPurchasePayNoticeService orderUserPurchasePayNoticeService;
|
||||||
@ -60,23 +61,6 @@ public class MiFaPayServerNoticeReceivePaymentCmdExe {
|
|||||||
return FAIL;
|
return FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证签名(对data字段验签)
|
|
||||||
if (StringUtils.isBlank(notice.getSign()) || StringUtils.isBlank(notice.getData())) {
|
|
||||||
log.error("MiFaPay回调签名或data为空");
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean validSign = PayMaxUtils.validSignRsa(
|
|
||||||
notice.getData(),
|
|
||||||
notice.getSign(),
|
|
||||||
miFaPayProperties.getPlatformRsaPublicKey()
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!validSign) {
|
|
||||||
log.error("MiFaPay回调验签失败: sign={}, data={}", notice.getSign(), notice.getData());
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
MiFaPayReceivePaymentNotice.MiFaPayNoticeData noticeData = notice.getNoticeData();
|
MiFaPayReceivePaymentNotice.MiFaPayNoticeData noticeData = notice.getNoticeData();
|
||||||
|
|
||||||
OrderUserPurchasePay mysqlOrder = getMysqlOrder(noticeData.getOrderId());
|
OrderUserPurchasePay mysqlOrder = getMysqlOrder(noticeData.getOrderId());
|
||||||
@ -84,6 +68,26 @@ public class MiFaPayServerNoticeReceivePaymentCmdExe {
|
|||||||
log.error("MiFaPay回调未找到MySQL订单: orderId={}", noticeData.getOrderId());
|
log.error("MiFaPay回调未找到MySQL订单: orderId={}", noticeData.getOrderId());
|
||||||
return FAIL;
|
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(),
|
||||||
|
config.getPlatformRsaPublicKey()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!validSign) {
|
||||||
|
log.error("MiFaPay回调验签失败: sign={}, data={}", notice.getSign(), notice.getData());
|
||||||
|
return FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
return handleMysqlOrder(notice, noticeData, mysqlOrder);
|
return handleMysqlOrder(notice, noticeData, mysqlOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -117,7 +117,8 @@ public class PayWebApplicationCommodityV2QueryExe {
|
|||||||
private List<PayApplicationCommodity> getPayApplicationCommodities(
|
private List<PayApplicationCommodity> getPayApplicationCommodities(
|
||||||
PayWebApplicationCommodityCmd cmd) {
|
PayWebApplicationCommodityCmd cmd) {
|
||||||
|
|
||||||
if (Objects.equals(cmd.requireReqSysOriginChildEnum(), SysOriginPlatformEnum.YOLO)) {
|
if (Objects.equals(cmd.requireReqSysOriginChildEnum(), SysOriginPlatformEnum.YOLO)
|
||||||
|
|| StringUtils.isNotBlank(cmd.getRegionId())) {
|
||||||
|
|
||||||
ResponseAssert
|
ResponseAssert
|
||||||
.isTrue(CommonErrorCode.NOT_SUPPORTED_REGION, StringUtils.isNotBlank(cmd.getRegionId()));
|
.isTrue(CommonErrorCode.NOT_SUPPORTED_REGION, StringUtils.isNotBlank(cmd.getRegionId()));
|
||||||
|
|||||||
@ -66,7 +66,7 @@ public class MiFaPayWebPayPlaceAnOrderStrategy implements PayWebPlaceAnOrderStra
|
|||||||
|
|
||||||
private MiFaPayResponseCO requestApi(PayPlaceAnOrderDetailsV2 details, MiFaPayPlaceAnOrderParam param) {
|
private MiFaPayResponseCO requestApi(PayPlaceAnOrderDetailsV2 details, MiFaPayPlaceAnOrderParam param) {
|
||||||
try {
|
try {
|
||||||
return miFaPayService.placeAnOrder(param);
|
return miFaPayService.placeAnOrder(param, details.getSysOrigin());
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
log.error("MiFaPay订单创建请求失败:details={}、requestParam={}",
|
log.error("MiFaPay订单创建请求失败:details={}、requestParam={}",
|
||||||
@ -105,7 +105,7 @@ public class MiFaPayWebPayPlaceAnOrderStrategy implements PayWebPlaceAnOrderStra
|
|||||||
.payType(details.getFactoryChannel())
|
.payType(details.getFactoryChannel())
|
||||||
.userIp(details.getRequestIp())
|
.userIp(details.getRequestIp())
|
||||||
.returnUrl(details.getSuccessRedirectUrl())
|
.returnUrl(details.getSuccessRedirectUrl())
|
||||||
.notifyUrl(miFaPayService.getNotifyUrl())
|
.notifyUrl(miFaPayService.getNotifyUrl(details.getSysOrigin()))
|
||||||
.language("en")
|
.language("en")
|
||||||
.email(memberInfo.getEmail())
|
.email(memberInfo.getEmail())
|
||||||
.countryCode(replaceCountryCode(details.getCountryCode()))
|
.countryCode(replaceCountryCode(details.getCountryCode()))
|
||||||
|
|||||||
@ -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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,17 +3,15 @@ package com.red.circle.order.app.service;
|
|||||||
import com.red.circle.component.pay.paymax.PayMaxUtils;
|
import com.red.circle.component.pay.paymax.PayMaxUtils;
|
||||||
import com.red.circle.order.app.common.MiFaPayPlaceAnOrderParam;
|
import com.red.circle.order.app.common.MiFaPayPlaceAnOrderParam;
|
||||||
import com.red.circle.order.app.dto.clientobject.MiFaPayResponseCO;
|
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.http.RcHttpClient;
|
||||||
import com.red.circle.tool.core.json.JacksonUtils;
|
import com.red.circle.tool.core.json.JacksonUtils;
|
||||||
import com.red.circle.tool.core.text.StringUtils;
|
import com.red.circle.tool.core.text.StringUtils;
|
||||||
|
import java.util.Objects;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MiFaPay支付服务
|
* MiFaPay支付服务
|
||||||
*
|
*
|
||||||
@ -23,133 +21,124 @@ import java.util.Objects;
|
|||||||
@Service
|
@Service
|
||||||
public class MiFaPayService {
|
public class MiFaPayService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下单接口路径
|
* 下单接口路径
|
||||||
*/
|
*/
|
||||||
private static final String PLACE_ORDER_PATH = "/paygateway/mbpay/order/en_v2";
|
private static final String PLACE_ORDER_PATH = "/paygateway/mbpay/order/en_v2";
|
||||||
|
|
||||||
private final String active;
|
private final String active;
|
||||||
private final MiFaPayProperties miFaPayProperties;
|
private final MiFaPayConfigService miFaPayConfigService;
|
||||||
private final RcHttpClient rcHttpClient = RcHttpClient.builder().build();
|
private final RcHttpClient rcHttpClient = RcHttpClient.builder().build();
|
||||||
|
|
||||||
public MiFaPayService(@Value("${spring.profiles.active:dev}") String active,
|
public MiFaPayService(@Value("${spring.profiles.active:dev}") String active,
|
||||||
MiFaPayProperties miFaPayProperties) {
|
MiFaPayConfigService miFaPayConfigService) {
|
||||||
this.active = active;
|
this.active = active;
|
||||||
this.miFaPayProperties = miFaPayProperties;
|
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) {
|
private String merAccount;
|
||||||
validateRequiredConfig();
|
|
||||||
|
|
||||||
// 设置商户编号
|
|
||||||
param.setMerNo(miFaPayProperties.getMerNo());
|
|
||||||
|
|
||||||
String url = miFaPayProperties.getGatewayBaseUrl() + PLACE_ORDER_PATH;
|
|
||||||
|
|
||||||
// 将param转为JSON字符串作为data
|
|
||||||
String dataJson = JacksonUtils.toJson(param);
|
|
||||||
|
|
||||||
// 对data进行签名
|
|
||||||
String sign = PayMaxUtils.signRsa(dataJson, miFaPayProperties.getRsaPrivateKey());
|
|
||||||
|
|
||||||
// 构建请求体: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
|
private String sign;
|
||||||
public static class MiFaPayRequest {
|
|
||||||
/**
|
|
||||||
* 商户标识
|
|
||||||
*/
|
|
||||||
private String merAccount;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 签名
|
* 主请求参数(JSON字符串)
|
||||||
*/
|
*/
|
||||||
private String sign;
|
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.PayCountryChannel;
|
||||||
import com.red.circle.order.infra.database.rds.entity.pay.PayCountryChannelDetails;
|
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.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.infra.database.rds.query.SysPayChannelQry;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayApplicationCommodityCmd;
|
import com.red.circle.order.inner.model.cmd.SysPayApplicationCommodityCmd;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayChannelCmd;
|
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.SysPayChannelQryCmd;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayCountryAddCmd;
|
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.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.cmd.SysPayFactoryCmd;
|
||||||
import com.red.circle.order.inner.model.dto.CountryCodeDTO;
|
import com.red.circle.order.inner.model.dto.CountryCodeDTO;
|
||||||
import com.red.circle.order.inner.model.dto.PayCountryDTO;
|
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.SysPayCountryChannelDTO;
|
||||||
import com.red.circle.order.inner.model.dto.SysPayCountryChannelDetailsDTO;
|
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.SysPayFactoryAssociatedChannelsDTO;
|
||||||
|
import com.red.circle.order.inner.model.dto.SysPayFactoryConfigDTO;
|
||||||
import com.red.circle.order.inner.model.dto.SysPayFactoryDTO;
|
import com.red.circle.order.inner.model.dto.SysPayFactoryDTO;
|
||||||
import com.red.circle.other.inner.model.dto.sys.SysCountryCodeDTO;
|
import com.red.circle.other.inner.model.dto.sys.SysCountryCodeDTO;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -58,6 +61,10 @@ public interface WebPayInnerConvertor {
|
|||||||
|
|
||||||
PayFactory toPayFactory(SysPayFactoryCmd cmd);
|
PayFactory toPayFactory(SysPayFactoryCmd cmd);
|
||||||
|
|
||||||
|
PayFactoryConfig toPayFactoryConfig(SysPayFactoryConfigCmd cmd);
|
||||||
|
|
||||||
|
SysPayFactoryConfigDTO toSysPayFactoryConfigDTO(PayFactoryConfig config);
|
||||||
|
|
||||||
Map<String, SysPayChannelDTO> toMapSysPayChannelDTO(Map<String, PayChannel> map);
|
Map<String, SysPayChannelDTO> toMapSysPayChannelDTO(Map<String, PayChannel> map);
|
||||||
|
|
||||||
SysPayFactoryAssociatedChannelsDTO toSysPayFactoryAssociatedChannelsDTO(
|
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.PageResult;
|
||||||
import com.red.circle.framework.dto.ResultResponse;
|
import com.red.circle.framework.dto.ResultResponse;
|
||||||
import com.red.circle.order.inner.endpoint.api.PayFactoryClientApi;
|
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.SysPayFactoryCmd;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryQryCmd;
|
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.model.dto.SysPayFactoryDTO;
|
||||||
import com.red.circle.order.inner.service.PayFactoryClientService;
|
import com.red.circle.order.inner.service.PayFactoryClientService;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -56,4 +58,15 @@ public class PayFactoryClientEndpoint implements PayFactoryClientApi {
|
|||||||
payFactoryClientService.updateSysPayChannel(param);
|
payFactoryClientService.updateSysPayChannel(param);
|
||||||
return ResultResponse.success();
|
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.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.SysPayFactoryCmd;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryQryCmd;
|
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.model.dto.SysPayFactoryDTO;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -25,4 +27,8 @@ public interface PayFactoryClientService {
|
|||||||
void addSysPayChannel(SysPayFactoryCmd param);
|
void addSysPayChannel(SysPayFactoryCmd param);
|
||||||
|
|
||||||
void updateSysPayChannel(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;
|
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.framework.dto.PageResult;
|
||||||
|
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.infra.database.rds.service.pay.PayFactoryService;
|
||||||
import com.red.circle.order.inner.convertor.WebPayInnerConvertor;
|
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.SysPayFactoryCmd;
|
||||||
import com.red.circle.order.inner.model.cmd.SysPayFactoryQryCmd;
|
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.model.dto.SysPayFactoryDTO;
|
||||||
import com.red.circle.order.inner.service.PayFactoryClientService;
|
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.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -23,6 +33,7 @@ import org.springframework.stereotype.Service;
|
|||||||
public class PayFactoryClientServiceImpl implements PayFactoryClientService {
|
public class PayFactoryClientServiceImpl implements PayFactoryClientService {
|
||||||
|
|
||||||
private final PayFactoryService payFactoryService;
|
private final PayFactoryService payFactoryService;
|
||||||
|
private final PayFactoryConfigService payFactoryConfigService;
|
||||||
private final WebPayInnerConvertor webPayInnerConvertor;
|
private final WebPayInnerConvertor webPayInnerConvertor;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -57,4 +68,69 @@ public class PayFactoryClientServiceImpl implements PayFactoryClientService {
|
|||||||
public void updateSysPayChannel(SysPayFactoryCmd param) {
|
public void updateSysPayChannel(SysPayFactoryCmd param) {
|
||||||
payFactoryService.updateSysPayChannel(webPayInnerConvertor.toPayFactory(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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -150,6 +150,8 @@ public class TmpGoldWalletServiceImpl implements TmpGoldWalletService {
|
|||||||
.eq(Objects.nonNull(cmd.getId()), WalletGoldAssetRecord::getId, cmd.getId())
|
.eq(Objects.nonNull(cmd.getId()), WalletGoldAssetRecord::getId, cmd.getId())
|
||||||
.eq(Objects.nonNull(cmd.getQueryBackOperationUser()), WalletGoldAssetRecord::getOpUserType,
|
.eq(Objects.nonNull(cmd.getQueryBackOperationUser()), WalletGoldAssetRecord::getOpUserType,
|
||||||
cmd.getQueryBackOperationUser())
|
cmd.getQueryBackOperationUser())
|
||||||
|
.eq(Objects.nonNull(cmd.getBackOperationUser()), WalletGoldAssetRecord::getCreateUser,
|
||||||
|
cmd.getBackOperationUser())
|
||||||
.eq(Objects.nonNull(cmd.getType()), WalletGoldAssetRecord::getType, cmd.getType())
|
.eq(Objects.nonNull(cmd.getType()), WalletGoldAssetRecord::getType, cmd.getType())
|
||||||
.eq(Objects.nonNull(cmd.getUserId()), WalletGoldAssetRecord::getUserId, cmd.getUserId())
|
.eq(Objects.nonNull(cmd.getUserId()), WalletGoldAssetRecord::getUserId, cmd.getUserId())
|
||||||
.eq(StringUtils.isNotBlank(cmd.getTrackId()), WalletGoldAssetRecord::getEventId,
|
.eq(StringUtils.isNotBlank(cmd.getTrackId()), WalletGoldAssetRecord::getEventId,
|
||||||
@ -189,6 +191,8 @@ public class TmpGoldWalletServiceImpl implements TmpGoldWalletService {
|
|||||||
.map(Objects::toString)
|
.map(Objects::toString)
|
||||||
.orElse(""))
|
.orElse(""))
|
||||||
.setRemark(remarkValue.get(Objects.toString(assetRecord.getId())))
|
.setRemark(remarkValue.get(Objects.toString(assetRecord.getId())))
|
||||||
|
.setBackOperationUser(Objects.equals(assetRecord.getOpUserType(), 1)
|
||||||
|
? assetRecord.getCreateUser() : null)
|
||||||
.setCreateTime(assetRecord.getCreateTime().getTime())
|
.setCreateTime(assetRecord.getCreateTime().getTime())
|
||||||
.setUpdateTime(assetRecord.getUpdateTime().getTime())
|
.setUpdateTime(assetRecord.getUpdateTime().getTime())
|
||||||
).toList();
|
).toList();
|
||||||
@ -390,6 +394,7 @@ public class TmpGoldWalletServiceImpl implements TmpGoldWalletService {
|
|||||||
toQuery("sysOrigin", getQuerySysOrigin(cmd)),
|
toQuery("sysOrigin", getQuerySysOrigin(cmd)),
|
||||||
toQuery("id", cmd.getId()),
|
toQuery("id", cmd.getId()),
|
||||||
toQuery("opUserType", DataTypeUtils.toInteger(cmd.getQueryBackOperationUser())),
|
toQuery("opUserType", DataTypeUtils.toInteger(cmd.getQueryBackOperationUser())),
|
||||||
|
toQuery("createUser", cmd.getBackOperationUser()),
|
||||||
toQuery("type", cmd.getType()),
|
toQuery("type", cmd.getType()),
|
||||||
toQuery("userId", cmd.getUserId()),
|
toQuery("userId", cmd.getUserId()),
|
||||||
toQuery("eventId", cmd.getTrackId()),
|
toQuery("eventId", cmd.getTrackId()),
|
||||||
|
|||||||
@ -165,6 +165,8 @@ public class WalletGoldClientServiceImpl implements WalletGoldClientService {
|
|||||||
.eq(Objects.nonNull(cmd.getId()), WalletGoldAssetRecord::getId, cmd.getId())
|
.eq(Objects.nonNull(cmd.getId()), WalletGoldAssetRecord::getId, cmd.getId())
|
||||||
.eq(Objects.nonNull(cmd.getQueryBackOperationUser()), WalletGoldAssetRecord::getOpUserType,
|
.eq(Objects.nonNull(cmd.getQueryBackOperationUser()), WalletGoldAssetRecord::getOpUserType,
|
||||||
cmd.getQueryBackOperationUser())
|
cmd.getQueryBackOperationUser())
|
||||||
|
.eq(Objects.nonNull(cmd.getBackOperationUser()), WalletGoldAssetRecord::getCreateUser,
|
||||||
|
cmd.getBackOperationUser())
|
||||||
.eq(Objects.nonNull(cmd.getType()), WalletGoldAssetRecord::getType, cmd.getType())
|
.eq(Objects.nonNull(cmd.getType()), WalletGoldAssetRecord::getType, cmd.getType())
|
||||||
.eq(Objects.nonNull(cmd.getUserId()), WalletGoldAssetRecord::getUserId, cmd.getUserId())
|
.eq(Objects.nonNull(cmd.getUserId()), WalletGoldAssetRecord::getUserId, cmd.getUserId())
|
||||||
.eq(StringUtils.isNotBlank(cmd.getTrackId()), WalletGoldAssetRecord::getEventId,
|
.eq(StringUtils.isNotBlank(cmd.getTrackId()), WalletGoldAssetRecord::getEventId,
|
||||||
@ -204,6 +206,8 @@ public class WalletGoldClientServiceImpl implements WalletGoldClientService {
|
|||||||
.setStatus(Optional.ofNullable(statusMap.get(assetRecord.getId()))
|
.setStatus(Optional.ofNullable(statusMap.get(assetRecord.getId()))
|
||||||
.map(Objects::toString).orElse(""))
|
.map(Objects::toString).orElse(""))
|
||||||
.setRemark(remarkValue.get(Objects.toString(assetRecord.getId())))
|
.setRemark(remarkValue.get(Objects.toString(assetRecord.getId())))
|
||||||
|
.setBackOperationUser(Objects.equals(assetRecord.getOpUserType(), 1)
|
||||||
|
? assetRecord.getCreateUser() : null)
|
||||||
.setCreateTime(assetRecord.getCreateTime().getTime())
|
.setCreateTime(assetRecord.getCreateTime().getTime())
|
||||||
.setUpdateTime(assetRecord.getUpdateTime().getTime())
|
.setUpdateTime(assetRecord.getUpdateTime().getTime())
|
||||||
).toList();
|
).toList();
|
||||||
@ -300,6 +304,7 @@ public class WalletGoldClientServiceImpl implements WalletGoldClientService {
|
|||||||
toQuery("sysOrigin", querySysOrigin(cmd)),
|
toQuery("sysOrigin", querySysOrigin(cmd)),
|
||||||
toQuery("id", cmd.getId()),
|
toQuery("id", cmd.getId()),
|
||||||
toQuery("opUserType", DataTypeUtils.toInteger(cmd.getQueryBackOperationUser())),
|
toQuery("opUserType", DataTypeUtils.toInteger(cmd.getQueryBackOperationUser())),
|
||||||
|
toQuery("createUser", cmd.getBackOperationUser()),
|
||||||
toQuery("type", cmd.getType()),
|
toQuery("type", cmd.getType()),
|
||||||
toQuery("userId", cmd.getUserId()),
|
toQuery("userId", cmd.getUserId()),
|
||||||
toQuery("eventId", cmd.getTrackId()),
|
toQuery("eventId", cmd.getTrackId()),
|
||||||
|
|||||||
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