分销后台相关接口 现金充值 记录明细
This commit is contained in:
@@ -2,28 +2,23 @@ package com.czg.controller.admin;
|
|||||||
|
|
||||||
import com.czg.annotation.SaAdminCheckPermission;
|
import com.czg.annotation.SaAdminCheckPermission;
|
||||||
import com.czg.annotation.SaCheckMainShop;
|
import com.czg.annotation.SaCheckMainShop;
|
||||||
import com.czg.constant.TableValueConstant;
|
|
||||||
import com.czg.market.dto.MkDistributionConfigDTO;
|
import com.czg.market.dto.MkDistributionConfigDTO;
|
||||||
import com.czg.market.dto.MkEnableConfigDTO;
|
import com.czg.market.service.MkDistributionAmountFlowService;
|
||||||
import com.czg.market.dto.MkRedemptionConfigDTO;
|
|
||||||
import com.czg.market.service.MkDistributionConfigService;
|
import com.czg.market.service.MkDistributionConfigService;
|
||||||
import com.czg.market.service.MkEnableConfigService;
|
import com.czg.market.vo.*;
|
||||||
import com.czg.market.service.MkRedemptionConfigService;
|
import com.czg.order.dto.MkDistributionPayDTO;
|
||||||
import com.czg.market.vo.MkDistributionConfigVO;
|
|
||||||
import com.czg.market.vo.MkEnableConfigVO;
|
|
||||||
import com.czg.market.vo.MkRedemptionCodeVO;
|
|
||||||
import com.czg.market.vo.MkRedemptionConfigVO;
|
|
||||||
import com.czg.resp.CzgResult;
|
import com.czg.resp.CzgResult;
|
||||||
import com.czg.sa.StpKit;
|
import com.czg.sa.StpKit;
|
||||||
|
import com.czg.utils.AssertUtil;
|
||||||
import com.czg.validator.group.UpdateGroup;
|
import com.czg.validator.group.UpdateGroup;
|
||||||
import com.mybatisflex.core.paginate.Page;
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import jakarta.validation.groups.Default;
|
import jakarta.validation.groups.Default;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 分销相关
|
* 分销相关
|
||||||
@@ -34,6 +29,8 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
public class DistributionController {
|
public class DistributionController {
|
||||||
@Resource
|
@Resource
|
||||||
private MkDistributionConfigService configService;
|
private MkDistributionConfigService configService;
|
||||||
|
@Resource
|
||||||
|
private MkDistributionAmountFlowService distributionAmountFlowService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 配置信息详情
|
* 配置信息详情
|
||||||
@@ -41,7 +38,7 @@ public class DistributionController {
|
|||||||
@SaAdminCheckPermission(value = "distribution:detail", name = "分销配置")
|
@SaAdminCheckPermission(value = "distribution:detail", name = "分销配置")
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public CzgResult<MkDistributionConfigVO> detail() {
|
public CzgResult<MkDistributionConfigVO> detail() {
|
||||||
return CzgResult.success(configService.detail(StpKit.USER.getMainShopId()));
|
return CzgResult.success(configService.detail(StpKit.USER.getShopId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,5 +54,29 @@ public class DistributionController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 现金充值
|
||||||
|
* @param payParam 充值信息
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
@PostMapping("/cashPay")
|
||||||
|
public CzgResult<Boolean> cashPayOrder(@Validated @RequestBody MkDistributionPayDTO payParam) {
|
||||||
|
AssertUtil.isNull(payParam.getShopId(), "店铺id不能为空");
|
||||||
|
AssertUtil.isNull(payParam.getAmount(), "充值金额不能为空");
|
||||||
|
AssertUtil.isTrue(payParam.getAmount().compareTo(BigDecimal.ZERO) == 0, "金额不为0");
|
||||||
|
return CzgResult.success(configService.cashPayOrder(StpKit.USER.getLoginIdAsLong(), payParam));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 金额记录
|
||||||
|
* @param type manual_recharge充值 self_recharge自助充值 refund退款 manual_sub手动扣减 sub统扣减
|
||||||
|
* @param key 搜索
|
||||||
|
*/
|
||||||
|
@GetMapping("/flow")
|
||||||
|
public CzgResult<Map<String, Object>> flow(@RequestParam(required = false) String type, @RequestParam(required = false) String key) {
|
||||||
|
return CzgResult.success(distributionAmountFlowService.pageInfo(StpKit.USER.getShopId(), type, key));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.czg.controller.user;
|
||||||
|
|
||||||
|
import com.czg.order.dto.MkDistributionPayDTO;
|
||||||
|
import com.czg.market.service.MkDistributionConfigService;
|
||||||
|
import com.czg.resp.CzgResult;
|
||||||
|
import com.czg.sa.StpKit;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 分销相关
|
||||||
|
* @author Administrator
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/user/distribution")
|
||||||
|
public class UDistributionController {
|
||||||
|
@Resource
|
||||||
|
private MkDistributionConfigService configService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分销员购买
|
||||||
|
*/
|
||||||
|
@PostMapping("/pay")
|
||||||
|
public CzgResult<Map<String, Object>> pay(@Validated @RequestBody MkDistributionPayDTO payDTO) {
|
||||||
|
return CzgResult.success(configService.pay(StpKit.USER.getLoginIdAsLong(), payDTO));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package com.czg.controller;
|
||||||
|
|
||||||
|
import com.czg.annotation.Debounce;
|
||||||
|
import com.czg.order.dto.MkDistributionPayDTO;
|
||||||
|
import com.czg.resp.CzgResult;
|
||||||
|
import com.czg.service.order.service.DistributionPayService;
|
||||||
|
import com.czg.system.service.SysParamsService;
|
||||||
|
import com.czg.utils.ServletUtil;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.apache.dubbo.config.annotation.DubboReference;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付
|
||||||
|
*
|
||||||
|
* @author ww
|
||||||
|
* @description
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/pay/distribution")
|
||||||
|
public class DistributionPayController {
|
||||||
|
@Resource
|
||||||
|
private DistributionPayService payService;
|
||||||
|
@DubboReference
|
||||||
|
private SysParamsService paramsService;
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/cashPay")
|
||||||
|
@Debounce(value = "#payParam.checkOrderPay.orderId")
|
||||||
|
public CzgResult<Object> cashPayOrder(@RequestHeader Long shopId, @Validated @RequestBody MkDistributionPayDTO payParam) {
|
||||||
|
payParam.setShopId(shopId);
|
||||||
|
return payService.cashPayOrder(payParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 小程序支付
|
||||||
|
* payType 必填 支付方式,aliPay 支付宝,wechatPay 微信
|
||||||
|
* openId 必填
|
||||||
|
*/
|
||||||
|
@PostMapping("/ltPayOrder")
|
||||||
|
@Debounce(value = "#payParam.checkOrderPay.orderId")
|
||||||
|
public CzgResult<Map<String, Object>> ltPayOrder(@RequestHeader Long shopId, HttpServletRequest request, @Validated @RequestBody MkDistributionPayDTO payParam) {
|
||||||
|
payParam.setShopId(shopId);
|
||||||
|
return payService.ltPayOrder(ServletUtil.getClientIP(request), payParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正扫
|
||||||
|
*/
|
||||||
|
@PostMapping("/scanPay")
|
||||||
|
@Debounce(value = "#payParam.checkOrderPay.orderId")
|
||||||
|
public CzgResult<Map<String, Object>> scanPayOrder(@RequestHeader Long shopId, HttpServletRequest request, @Validated @RequestBody MkDistributionPayDTO payParam) {
|
||||||
|
payParam.setShopId(shopId);
|
||||||
|
return payService.scanPayOrder(ServletUtil.getClientIP(request), payParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 反扫
|
||||||
|
* authCode 必填 扫描码
|
||||||
|
*/
|
||||||
|
@PostMapping("/microPay")
|
||||||
|
@Debounce(value = "#payParam.checkOrderPay.orderId")
|
||||||
|
public CzgResult<Map<String, Object>> microPayOrder(@RequestHeader Long shopId, @Validated @RequestBody MkDistributionPayDTO payParam) {
|
||||||
|
payParam.setShopId(shopId);
|
||||||
|
return payService.microPayOrder(payParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package com.czg.controller;
|
|||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.thread.ThreadUtil;
|
import cn.hutool.core.thread.ThreadUtil;
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.czg.CzgPayUtils;
|
import com.czg.CzgPayUtils;
|
||||||
import com.czg.entity.CzgBaseRespParams;
|
import com.czg.entity.CzgBaseRespParams;
|
||||||
@@ -14,7 +15,9 @@ import jakarta.annotation.Resource;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 回调
|
* 回调
|
||||||
@@ -37,6 +40,13 @@ public class NotifyController {
|
|||||||
private ShopTableOrderStatisticService shopTableOrderStatisticService;
|
private ShopTableOrderStatisticService shopTableOrderStatisticService;
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("testOpen")
|
||||||
|
public Map<String, String> test1(String code) throws Exception {
|
||||||
|
// return WxService.v3Pay("oeQYq5LzW-kSxJL9TR4s_UmOmNLE", new BigDecimal("0.01"), "测试", "testZs" + RandomUtil.randomNumbers(20), "test");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@RequestMapping("/payCallBack")
|
@RequestMapping("/payCallBack")
|
||||||
public String notifyCallBack(@RequestBody CzgBaseRespParams respParams) {
|
public String notifyCallBack(@RequestBody CzgBaseRespParams respParams) {
|
||||||
JSONObject czg = CzgPayUtils.getCzg(respParams);
|
JSONObject czg = CzgPayUtils.getCzg(respParams);
|
||||||
|
|||||||
@@ -330,4 +330,9 @@ public class ShopInfo implements Serializable {
|
|||||||
@Column(ignore = true)
|
@Column(ignore = true)
|
||||||
private Integer tableClearTime;
|
private Integer tableClearTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 运营端余额
|
||||||
|
*/
|
||||||
|
private BigDecimal amount;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.czg.account.entity.ShopInfo;
|
|||||||
import com.mybatisflex.core.paginate.Page;
|
import com.mybatisflex.core.paginate.Page;
|
||||||
import com.mybatisflex.core.service.IService;
|
import com.mybatisflex.core.service.IService;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,4 +34,6 @@ public interface ShopInfoService extends IService<ShopInfo> {
|
|||||||
Long getMainIdByShopId(Long shopId);
|
Long getMainIdByShopId(Long shopId);
|
||||||
|
|
||||||
List<ShopInfo> getByMainIdOrList(Long mainShopId, List<Long> shopIdList, String shopName);
|
List<ShopInfo> getByMainIdOrList(Long mainShopId, List<Long> shopIdList, String shopName);
|
||||||
|
|
||||||
|
BigDecimal updateAmount(Long id, BigDecimal amount);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
|
||||||
|
package com.czg.market.dto;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import com.alibaba.fastjson2.annotation.JSONField;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
import java.io.Serial;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分销运营余额扣减记录 实体类。
|
||||||
|
*
|
||||||
|
* @author ww
|
||||||
|
* @since 2025-10-27
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class MkDistributionAmountFlowDTO implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* recharge充值 refund退款 sub扣减
|
||||||
|
*/
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主店id
|
||||||
|
*/
|
||||||
|
private Long mainShopId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 店铺id
|
||||||
|
*/
|
||||||
|
private Long shopId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变动后金额
|
||||||
|
*/
|
||||||
|
private BigDecimal amount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变动金额
|
||||||
|
*/
|
||||||
|
private BigDecimal changeAmount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关联id
|
||||||
|
*/
|
||||||
|
private Long sourceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作人账号
|
||||||
|
*/
|
||||||
|
private String opAccount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package com.czg.market.entity;
|
||||||
|
|
||||||
|
import com.mybatisflex.annotation.Column;
|
||||||
|
import com.mybatisflex.annotation.Id;
|
||||||
|
import com.mybatisflex.annotation.KeyType;
|
||||||
|
import com.mybatisflex.annotation.Table;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分销运营余额扣减记录 实体类。
|
||||||
|
*
|
||||||
|
* @author ww
|
||||||
|
* @since 2025-10-27
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Table("mk_distribution_amount_flow")
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class MkDistributionAmountFlow implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Id(keyType = KeyType.Auto)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* manual_recharge充值 self_recharge自助充值 refund退款 manual_sub手动扣减 sub统扣减
|
||||||
|
*/
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主店id
|
||||||
|
*/
|
||||||
|
private Long mainShopId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 店铺id
|
||||||
|
*/
|
||||||
|
private Long shopId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变动后金额
|
||||||
|
*/
|
||||||
|
private BigDecimal amount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变动金额
|
||||||
|
*/
|
||||||
|
private BigDecimal changeAmount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关联id
|
||||||
|
*/
|
||||||
|
private Long sourceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 备注
|
||||||
|
*/
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作人账号
|
||||||
|
*/
|
||||||
|
private String opAccount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
@Column(onInsertValue = "now()")
|
||||||
|
private LocalDateTime createTime;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -97,5 +97,6 @@ public class MkDistributionConfig implements Serializable {
|
|||||||
* 主店id
|
* 主店id
|
||||||
*/
|
*/
|
||||||
private Long mainShopId;
|
private Long mainShopId;
|
||||||
|
private Long shopId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,11 +39,7 @@ public class MkDistributionLevelConfig implements Serializable {
|
|||||||
*/
|
*/
|
||||||
private Long distributionConfigId;
|
private Long distributionConfigId;
|
||||||
|
|
||||||
/**
|
private Long shopId;
|
||||||
* 主店id
|
|
||||||
*/
|
|
||||||
private Long mainShopId;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 名称
|
* 名称
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.czg.market.service;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.service.IService;
|
||||||
|
import com.czg.market.entity.MkDistributionAmountFlow;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分销运营余额扣减记录 服务层。
|
||||||
|
*
|
||||||
|
* @author ww
|
||||||
|
* @since 2025-10-27
|
||||||
|
*/
|
||||||
|
public interface MkDistributionAmountFlowService extends IService<MkDistributionAmountFlow> {
|
||||||
|
|
||||||
|
Map<String, Object> pageInfo(Long shopId, String type, String key);
|
||||||
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
package com.czg.market.service;
|
package com.czg.market.service;
|
||||||
|
|
||||||
import com.czg.market.dto.MkDistributionConfigDTO;
|
import com.czg.market.dto.MkDistributionConfigDTO;
|
||||||
|
import com.czg.order.dto.MkDistributionPayDTO;
|
||||||
import com.czg.market.vo.MkDistributionConfigVO;
|
import com.czg.market.vo.MkDistributionConfigVO;
|
||||||
import com.czg.market.vo.MkRedemptionConfigVO;
|
|
||||||
import com.mybatisflex.core.service.IService;
|
import com.mybatisflex.core.service.IService;
|
||||||
import com.czg.market.entity.MkDistributionConfig;
|
import com.czg.market.entity.MkDistributionConfig;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分销配置 服务层。
|
* 分销配置 服务层。
|
||||||
*
|
*
|
||||||
@@ -16,4 +18,8 @@ public interface MkDistributionConfigService extends IService<MkDistributionConf
|
|||||||
MkDistributionConfigVO detail(Long mainShopId);
|
MkDistributionConfigVO detail(Long mainShopId);
|
||||||
|
|
||||||
Boolean edit(Long shopId, MkDistributionConfigDTO dto);
|
Boolean edit(Long shopId, MkDistributionConfigDTO dto);
|
||||||
|
|
||||||
|
Map<String, Object> pay(long userId, MkDistributionPayDTO payDTO);
|
||||||
|
|
||||||
|
Boolean cashPayOrder(long adminId, MkDistributionPayDTO payParam);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.czg.market.vo;
|
||||||
|
|
||||||
|
import com.czg.market.entity.MkDistributionAmountFlow;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Administrator
|
||||||
|
*/
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class MkDistributionAmountFlowVO extends MkDistributionAmountFlow implements Serializable {
|
||||||
|
private String orderNo;
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
package com.czg.order.dto;
|
||||||
|
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分销配置 实体类。
|
||||||
|
*
|
||||||
|
* @author ww
|
||||||
|
* @since 2025-10-25
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Accessors(chain = true)
|
||||||
|
public class MkDistributionPayDTO implements Serializable {
|
||||||
|
private Long shopId;
|
||||||
|
private String platformType;
|
||||||
|
private Long userId;
|
||||||
|
private String payType;
|
||||||
|
private String returnUrl;
|
||||||
|
private String buyerRemark;
|
||||||
|
private BigDecimal amount;
|
||||||
|
private String remark;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.czg.system.service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信支付相关
|
||||||
|
* @author Administrator
|
||||||
|
*/
|
||||||
|
public interface WxService {
|
||||||
|
String getPhone(String code);
|
||||||
|
|
||||||
|
String getOpenId(String code);
|
||||||
|
|
||||||
|
Map<String, String> v3Pay(String openId, BigDecimal amount, String desc, String tradeNo, String type);
|
||||||
|
}
|
||||||
@@ -23,6 +23,41 @@ public interface TableValueConstant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface DistributionConfig {
|
||||||
|
@Getter
|
||||||
|
enum OpenType {
|
||||||
|
PAY("PAY", "支付购买"),
|
||||||
|
COST("COST", "消费增积分");
|
||||||
|
private final String code;
|
||||||
|
private final String msg;
|
||||||
|
|
||||||
|
OpenType(String code, String msg) {
|
||||||
|
this.code = code;
|
||||||
|
this.msg = msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DistributionAmountFlow {
|
||||||
|
@Getter
|
||||||
|
enum Type {
|
||||||
|
MANUAL_RECHARGE("manual_recharge", "手动充值"),
|
||||||
|
SUB("sub", "系统扣减"),
|
||||||
|
MANUAL_SUB("manual_sub", "手动扣减"),
|
||||||
|
SELF_RECHARGE("self_recharge", "自助充值");
|
||||||
|
private final String code;
|
||||||
|
private final String msg;
|
||||||
|
|
||||||
|
Type(String code, String msg) {
|
||||||
|
this.code = code;
|
||||||
|
this.msg = msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
interface EnableConfig {
|
interface EnableConfig {
|
||||||
@Getter
|
@Getter
|
||||||
enum Type {
|
enum Type {
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ import org.springframework.cache.annotation.Cacheable;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -445,4 +446,17 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
|
|||||||
|
|
||||||
return list(queryWrapper);
|
return list(queryWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BigDecimal updateAmount(Long id, BigDecimal amount) {
|
||||||
|
ShopInfo shopInfo = getShopInfo(id);
|
||||||
|
if (shopInfo.getAmount() == null) {
|
||||||
|
shopInfo.setAmount(BigDecimal.ZERO);
|
||||||
|
}
|
||||||
|
shopInfo.setAmount(shopInfo.getAmount().add(amount));
|
||||||
|
updateById(shopInfo);
|
||||||
|
return shopInfo.getAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.czg.service.market.mapper;
|
||||||
|
|
||||||
|
import com.mybatisflex.core.BaseMapper;
|
||||||
|
import com.czg.market.entity.MkDistributionAmountFlow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分销运营余额扣减记录 映射层。
|
||||||
|
*
|
||||||
|
* @author ww
|
||||||
|
* @since 2025-10-27
|
||||||
|
*/
|
||||||
|
public interface MkDistributionAmountFlowMapper extends BaseMapper<MkDistributionAmountFlow> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package com.czg.service.market.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.czg.account.entity.ShopUser;
|
||||||
|
import com.czg.account.entity.UserInfo;
|
||||||
|
import com.czg.constant.TableValueConstant;
|
||||||
|
import com.czg.market.vo.MkDistributionAmountFlowVO;
|
||||||
|
import com.czg.order.entity.OrderInfo;
|
||||||
|
import com.czg.utils.MyQueryWrapper;
|
||||||
|
import com.czg.utils.PageUtil;
|
||||||
|
import com.mybatisflex.core.paginate.Page;
|
||||||
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
|
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||||
|
import com.czg.market.entity.MkDistributionAmountFlow;
|
||||||
|
import com.czg.market.service.MkDistributionAmountFlowService;
|
||||||
|
import com.czg.service.market.mapper.MkDistributionAmountFlowMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分销运营余额扣减记录 服务层实现。
|
||||||
|
*
|
||||||
|
* @author ww
|
||||||
|
* @since 2025-10-27
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class MkDistributionAmountFlowServiceImpl extends ServiceImpl<MkDistributionAmountFlowMapper, MkDistributionAmountFlow> implements MkDistributionAmountFlowService{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> pageInfo(Long shopId, String type, String key) {
|
||||||
|
QueryWrapper queryWrapper = new MyQueryWrapper()
|
||||||
|
.selectAll(MkDistributionAmountFlow.class)
|
||||||
|
.leftJoin(OrderInfo.class).on(OrderInfo::getId, MkDistributionAmountFlow::getSourceId)
|
||||||
|
.leftJoin(ShopUser.class).on(ShopUser::getId, OrderInfo::getUserId)
|
||||||
|
.eq(MkDistributionAmountFlow::getShopId, shopId)
|
||||||
|
.select(OrderInfo::getOrderNo);
|
||||||
|
if (StrUtil.isNotBlank(type)) {
|
||||||
|
queryWrapper.eq(MkDistributionAmountFlow::getType, type);
|
||||||
|
}
|
||||||
|
if (StrUtil.isNotBlank(key)) {
|
||||||
|
queryWrapper.and(and -> {
|
||||||
|
and.or(or -> {
|
||||||
|
or.like(OrderInfo::getOrderNo, key);
|
||||||
|
});
|
||||||
|
and.or(or -> {
|
||||||
|
or.like(ShopUser::getNickName, key);
|
||||||
|
});
|
||||||
|
and.or(or -> {
|
||||||
|
or.like(ShopUser::getPhone, key);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Page<MkDistributionAmountFlowVO> pageInfo = pageAs(PageUtil.buildPage(), queryWrapper, MkDistributionAmountFlowVO.class);
|
||||||
|
Map<String, Object> map = BeanUtil.beanToMap(pageInfo);
|
||||||
|
map.put("totalRecharge", getOne(new QueryWrapper().eq(MkDistributionAmountFlow::getShopId, shopId)
|
||||||
|
.in(MkDistributionAmountFlow::getType, TableValueConstant.DistributionAmountFlow.Type.MANUAL_RECHARGE.getCode(), TableValueConstant.DistributionAmountFlow.Type.SELF_RECHARGE.getCode())
|
||||||
|
.select("sum(change_amount)")));
|
||||||
|
map.put("totalSub", getOne(new QueryWrapper().eq(MkDistributionAmountFlow::getShopId, shopId)
|
||||||
|
.in(MkDistributionAmountFlow::getType, TableValueConstant.DistributionAmountFlow.Type.SUB.getCode(), TableValueConstant.DistributionAmountFlow.Type.MANUAL_SUB.getCode())
|
||||||
|
.select("sum(change_amount)")));
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
QueryWrapper queryWrapper = new MyQueryWrapper()
|
||||||
|
.selectAll(MkDistributionAmountFlow.class)
|
||||||
|
.leftJoin(OrderInfo.class).on(OrderInfo::getId, MkDistributionAmountFlow::getSourceId)
|
||||||
|
.leftJoin(ShopUser.class).on(ShopUser::getId, OrderInfo::getUserId)
|
||||||
|
.select(OrderInfo::getOrderNo);
|
||||||
|
queryWrapper.and(and -> {
|
||||||
|
|
||||||
|
});
|
||||||
|
System.out.println(queryWrapper.toSQL());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,38 @@
|
|||||||
package com.czg.service.market.service.impl;
|
package com.czg.service.market.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import com.czg.account.entity.ShopInfo;
|
||||||
|
import com.czg.account.service.ShopInfoService;
|
||||||
|
import com.czg.constant.TableValueConstant;
|
||||||
|
import com.czg.exception.CzgException;
|
||||||
import com.czg.market.dto.MkDistributionConfigDTO;
|
import com.czg.market.dto.MkDistributionConfigDTO;
|
||||||
|
import com.czg.market.entity.MkDistributionAmountFlow;
|
||||||
|
import com.czg.market.service.MkDistributionAmountFlowService;
|
||||||
|
import com.czg.order.dto.MkDistributionPayDTO;
|
||||||
import com.czg.market.entity.MkDistributionLevelConfig;
|
import com.czg.market.entity.MkDistributionLevelConfig;
|
||||||
import com.czg.market.service.MkDistributionLevelConfigService;
|
import com.czg.market.service.MkDistributionLevelConfigService;
|
||||||
import com.czg.market.vo.MkDistributionConfigVO;
|
import com.czg.market.vo.MkDistributionConfigVO;
|
||||||
|
import com.czg.order.entity.OrderPayment;
|
||||||
|
import com.czg.order.service.OrderPaymentService;
|
||||||
|
import com.czg.sa.StpKit;
|
||||||
|
import com.czg.system.service.WxService;
|
||||||
|
import com.czg.utils.AssertUtil;
|
||||||
import com.mybatisflex.core.query.QueryWrapper;
|
import com.mybatisflex.core.query.QueryWrapper;
|
||||||
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||||
import com.czg.market.entity.MkDistributionConfig;
|
import com.czg.market.entity.MkDistributionConfig;
|
||||||
import com.czg.market.service.MkDistributionConfigService;
|
import com.czg.market.service.MkDistributionConfigService;
|
||||||
import com.czg.service.market.mapper.MkDistributionConfigMapper;
|
import com.czg.service.market.mapper.MkDistributionConfigMapper;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
import org.apache.dubbo.config.annotation.DubboReference;
|
||||||
|
import org.springframework.cache.annotation.CacheConfig;
|
||||||
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分销配置 服务层实现。
|
* 分销配置 服务层实现。
|
||||||
*
|
*
|
||||||
@@ -20,18 +40,30 @@ import org.springframework.stereotype.Service;
|
|||||||
* @since 2025-10-25
|
* @since 2025-10-25
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
|
@CacheConfig(cacheNames = "distributionConfig")
|
||||||
public class MkDistributionConfigServiceImpl extends ServiceImpl<MkDistributionConfigMapper, MkDistributionConfig> implements MkDistributionConfigService{
|
public class MkDistributionConfigServiceImpl extends ServiceImpl<MkDistributionConfigMapper, MkDistributionConfig> implements MkDistributionConfigService{
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private MkDistributionLevelConfigService levelConfigService;
|
private MkDistributionLevelConfigService levelConfigService;
|
||||||
|
@Resource
|
||||||
|
private MkDistributionAmountFlowService distributionAmountFlowService;
|
||||||
|
|
||||||
|
@DubboReference
|
||||||
|
private OrderPaymentService orderPaymentService;
|
||||||
|
@DubboReference
|
||||||
|
private ShopInfoService shopInfoService;
|
||||||
|
@DubboReference
|
||||||
|
private WxService wxService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MkDistributionConfigVO detail(Long mainShopId) {
|
@Cacheable(key = "#shopId")
|
||||||
MkDistributionConfig config = getOne(new QueryWrapper().eq(MkDistributionConfig::getMainShopId, mainShopId));
|
public MkDistributionConfigVO detail(Long shopId) {
|
||||||
|
Long mainIdByShopId = shopInfoService.getMainIdByShopId(shopId);
|
||||||
|
MkDistributionConfig config = getOne(new QueryWrapper().eq(MkDistributionConfig::getShopId, shopId));
|
||||||
if (config == null) {
|
if (config == null) {
|
||||||
config = new MkDistributionConfig().setMainShopId(mainShopId);
|
config = new MkDistributionConfig().setMainShopId(shopId).setMainShopId(mainIdByShopId);
|
||||||
save(config);
|
save(config);
|
||||||
config = getOne(new QueryWrapper().eq(MkDistributionConfig::getMainShopId, mainShopId));
|
config = getOne(new QueryWrapper().eq(MkDistributionConfig::getShopId, shopId));
|
||||||
}
|
}
|
||||||
|
|
||||||
MkDistributionConfigVO configVO = BeanUtil.copyProperties(config, MkDistributionConfigVO.class);
|
MkDistributionConfigVO configVO = BeanUtil.copyProperties(config, MkDistributionConfigVO.class);
|
||||||
@@ -40,14 +72,46 @@ public class MkDistributionConfigServiceImpl extends ServiceImpl<MkDistributionC
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@CacheEvict(key = "#shopId")
|
||||||
public Boolean edit(Long shopId, MkDistributionConfigDTO dto) {
|
public Boolean edit(Long shopId, MkDistributionConfigDTO dto) {
|
||||||
MkDistributionConfig config = getOne(new QueryWrapper().eq(MkDistributionConfig::getMainShopId, shopId));
|
MkDistributionConfig config = getOne(new QueryWrapper().eq(MkDistributionConfig::getShopId, shopId));
|
||||||
BeanUtil.copyProperties(dto, config);
|
BeanUtil.copyProperties(dto, config);
|
||||||
|
|
||||||
if (dto.getLevelConfigList() != null) {
|
if (dto.getLevelConfigList() != null) {
|
||||||
levelConfigService.updateByShopId(dto.getLevelConfigList(), config.getMainShopId(), config.getId());
|
levelConfigService.updateByShopId(dto.getLevelConfigList(), config.getShopId(), config.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
return updateById(config);
|
return updateById(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> pay(long userId, MkDistributionPayDTO payDTO) {
|
||||||
|
MkDistributionConfigVO detail = detail(payDTO.getShopId());
|
||||||
|
AssertUtil.isTrue(detail.getIsEnable() != 1, "分销未开启");
|
||||||
|
if (!TableValueConstant.DistributionConfig.OpenType.PAY.getCode().equals(detail.getOpenType())) {
|
||||||
|
throw new CzgException("当前未开启购买分销配置");
|
||||||
|
}
|
||||||
|
|
||||||
|
OrderPayment orderPayment = new OrderPayment().setShopId(payDTO.getShopId()).setSourceId(userId)
|
||||||
|
.setPayType("distribution").setOrderNo(payDTO.getPlatformType() + IdUtil.getSnowflakeNextId()).setAmount(detail.getPayAmount());
|
||||||
|
orderPaymentService.save(orderPayment);
|
||||||
|
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean cashPayOrder(long adminId, MkDistributionPayDTO payParam) {
|
||||||
|
ShopInfo shopInfo = shopInfoService.getById(payParam.getShopId());
|
||||||
|
AssertUtil.isNull(shopInfo, "店铺不存在");
|
||||||
|
BigDecimal amount = shopInfoService.updateAmount(shopInfo.getId(), payParam.getAmount());
|
||||||
|
Long mainShopId = shopInfoService.getMainIdByShopId(shopInfo.getId());
|
||||||
|
shopInfoService.updateAmount(shopInfo.getId(), payParam.getAmount());
|
||||||
|
|
||||||
|
distributionAmountFlowService.save(new MkDistributionAmountFlow()
|
||||||
|
.setType(payParam.getAmount().compareTo(BigDecimal.ZERO) < 0 ? TableValueConstant.DistributionAmountFlow.Type.MANUAL_SUB.getCode() :
|
||||||
|
TableValueConstant.DistributionAmountFlow.Type.MANUAL_RECHARGE.getCode())
|
||||||
|
.setMainShopId(mainShopId).setShopId(shopInfo.getId()).setAmount(amount).setChangeAmount(payParam.getAmount())
|
||||||
|
.setRemark(payParam.getRemark()).setOpAccount(StpKit.USER.getAccount()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import java.util.List;
|
|||||||
public class MkDistributionLevelConfigServiceImpl extends ServiceImpl<MkDistributionLevelConfigMapper, MkDistributionLevelConfig> implements MkDistributionLevelConfigService{
|
public class MkDistributionLevelConfigServiceImpl extends ServiceImpl<MkDistributionLevelConfigMapper, MkDistributionLevelConfig> implements MkDistributionLevelConfigService{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateByShopId(List<MkDistributionLevelConfigDTO> levelConfigList, Long mainShopId, Long id) {
|
public void updateByShopId(List<MkDistributionLevelConfigDTO> levelConfigList, Long shopId, Long id) {
|
||||||
if (levelConfigList.isEmpty()) {
|
if (levelConfigList.isEmpty()) {
|
||||||
remove(new QueryWrapper().eq(MkDistributionLevelConfig::getDistributionConfigId, id));
|
remove(new QueryWrapper().eq(MkDistributionLevelConfig::getDistributionConfigId, id));
|
||||||
return;
|
return;
|
||||||
@@ -30,7 +30,7 @@ public class MkDistributionLevelConfigServiceImpl extends ServiceImpl<MkDistribu
|
|||||||
levelConfigList.forEach(item -> {
|
levelConfigList.forEach(item -> {
|
||||||
MkDistributionLevelConfig config = BeanUtil.copyProperties(item, MkDistributionLevelConfig.class);
|
MkDistributionLevelConfig config = BeanUtil.copyProperties(item, MkDistributionLevelConfig.class);
|
||||||
config.setDistributionConfigId(id);
|
config.setDistributionConfigId(id);
|
||||||
config.setMainShopId(mainShopId);
|
config.setShopId(shopId);
|
||||||
saveOrUpdate(config);
|
saveOrUpdate(config);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper
|
||||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.czg.service.market.mapper.MkDistributionAmountFlowMapper">
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.czg.service.order.service;
|
||||||
|
|
||||||
|
import com.czg.order.dto.MkDistributionPayDTO;
|
||||||
|
import com.czg.resp.CzgResult;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付
|
||||||
|
*
|
||||||
|
* @author ww
|
||||||
|
*/
|
||||||
|
public interface DistributionPayService {
|
||||||
|
/**
|
||||||
|
* 现金支付
|
||||||
|
*/
|
||||||
|
CzgResult<Object> cashPayOrder(MkDistributionPayDTO payParam);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 小程序支付
|
||||||
|
*/
|
||||||
|
CzgResult<Map<String, Object>> ltPayOrder(String clintIp, MkDistributionPayDTO payParam);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PC扫码支付
|
||||||
|
*/
|
||||||
|
CzgResult<Map<String, Object>> scanPayOrder(String clintIp, MkDistributionPayDTO payParam);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 反扫
|
||||||
|
*/
|
||||||
|
CzgResult<Map<String, Object>> microPayOrder(MkDistributionPayDTO payParam);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
package com.czg.service.order.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import com.czg.account.entity.ShopUser;
|
||||||
|
import com.czg.account.entity.UserInfo;
|
||||||
|
import com.czg.account.service.ShopInfoService;
|
||||||
|
import com.czg.account.service.ShopUserService;
|
||||||
|
import com.czg.account.service.UserInfoService;
|
||||||
|
import com.czg.constant.TableValueConstant;
|
||||||
|
import com.czg.entity.req.CzgLtPayReq;
|
||||||
|
import com.czg.exception.CzgException;
|
||||||
|
import com.czg.market.service.MkDistributionConfigService;
|
||||||
|
import com.czg.market.vo.MkDistributionConfigVO;
|
||||||
|
import com.czg.order.dto.MkDistributionPayDTO;
|
||||||
|
import com.czg.order.entity.OrderInfo;
|
||||||
|
import com.czg.order.entity.OrderPayment;
|
||||||
|
import com.czg.order.enums.PayEnums;
|
||||||
|
import com.czg.order.service.OrderPaymentService;
|
||||||
|
import com.czg.resp.CzgResult;
|
||||||
|
import com.czg.service.order.service.DistributionPayService;
|
||||||
|
import com.czg.service.order.service.PayService;
|
||||||
|
import com.czg.system.service.WxService;
|
||||||
|
import com.czg.utils.AssertUtil;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
import org.apache.dubbo.config.annotation.DubboReference;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Administrator
|
||||||
|
*/
|
||||||
|
public class DistributionPayServiceImpl implements DistributionPayService {
|
||||||
|
private final BigDecimal MONEY_RATE = new BigDecimal("100");
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private OrderPaymentService orderPaymentService;
|
||||||
|
@Resource
|
||||||
|
private MkDistributionConfigService configService;
|
||||||
|
@Resource
|
||||||
|
private WxService wxService;
|
||||||
|
@Resource
|
||||||
|
private PayServiceImpl payService;
|
||||||
|
|
||||||
|
@DubboReference
|
||||||
|
private ShopInfoService shopInfoService;
|
||||||
|
@DubboReference
|
||||||
|
private ShopUserService shopUserService;
|
||||||
|
@DubboReference
|
||||||
|
private UserInfoService userInfoService;
|
||||||
|
|
||||||
|
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@Data
|
||||||
|
private static class InitInfo {
|
||||||
|
public OrderPayment payment;
|
||||||
|
public MkDistributionConfigVO config;
|
||||||
|
public ShopUser shopUser;
|
||||||
|
private String openId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private InitInfo initPayment(Long userId, MkDistributionPayDTO payParam) {
|
||||||
|
Long mainShopId = shopInfoService.getMainIdByShopId(payParam.getShopId());
|
||||||
|
MkDistributionConfigVO detail = configService.detail(payParam.getShopId());
|
||||||
|
AssertUtil.isTrue(detail.getIsEnable() != 1, "分销未开启");
|
||||||
|
if (!TableValueConstant.DistributionConfig.OpenType.PAY.getCode().equals(detail.getOpenType())) {
|
||||||
|
throw new CzgException("当前未开启购买分销配置");
|
||||||
|
}
|
||||||
|
|
||||||
|
OrderPayment orderPayment = new OrderPayment().setShopId(mainShopId).setSourceId(userId)
|
||||||
|
.setPayType("distribution").setOrderNo(payParam.getPlatformType() + IdUtil.getSnowflakeNextId()).setAmount(detail.getPayAmount());
|
||||||
|
orderPaymentService.save(orderPayment);
|
||||||
|
|
||||||
|
ShopUser shopUserInfo = shopUserService.getShopUserInfo(payParam.getShopId(), userId);
|
||||||
|
UserInfo userInfo = userInfoService.getById(userId);
|
||||||
|
return new InitInfo().setConfig(detail).setPayment(orderPayment).setShopUser(shopUserInfo)
|
||||||
|
.setOpenId("aliPay".equals(payParam.getPayType()) ? userInfo.getAlipayOpenId() : userInfo.getWechatOpenId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CzgResult<Object> cashPayOrder(MkDistributionPayDTO payParam) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CzgResult<Map<String, Object>> ltPayOrder(String clintIp, MkDistributionPayDTO payParam) {
|
||||||
|
InitInfo initInfo = initPayment(payParam.getUserId(), payParam);
|
||||||
|
return payService.ltPay(payParam.getShopId(), payParam.getPayType(), new CzgLtPayReq(initInfo.payment.getOrderNo(), initInfo.payment.getAmount().multiply(MONEY_RATE).longValue(),
|
||||||
|
payParam.getPayType(), "分销员开通", initInfo.getOpenId(), clintIp, payParam.getReturnUrl(), payParam.getBuyerRemark(), ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CzgResult<Map<String, Object>> scanPayOrder(String clintIp, MkDistributionPayDTO payParam) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CzgResult<Map<String, Object>> microPayOrder(MkDistributionPayDTO payParam) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -862,7 +862,7 @@ public class PayServiceImpl implements PayService {
|
|||||||
return execPayResult(jsPayRespCzgResult);
|
return execPayResult(jsPayRespCzgResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CzgResult<Map<String, Object>> ltPay(@NonNull Long shopId, String payType, CzgLtPayReq bizData) {
|
public CzgResult<Map<String, Object>> ltPay(@NonNull Long shopId, String payType, CzgLtPayReq bizData) {
|
||||||
ShopMerchant shopMerchant = getMerchant(shopId);
|
ShopMerchant shopMerchant = getMerchant(shopId);
|
||||||
bizData.setSubAppid("aliPay".equals(payType) ? shopMerchant.getAlipaySmallAppid() : shopMerchant.getWechatSmallAppid());
|
bizData.setSubAppid("aliPay".equals(payType) ? shopMerchant.getAlipaySmallAppid() : shopMerchant.getWechatSmallAppid());
|
||||||
AssertUtil.isBlank(bizData.getSubAppid(), "暂不可用,请联系商家配置" + ("aliPay".equals(payType) ? "支付宝" : "微信") + "小程序");
|
AssertUtil.isBlank(bizData.getSubAppid(), "暂不可用,请联系商家配置" + ("aliPay".equals(payType) ? "支付宝" : "微信") + "小程序");
|
||||||
|
|||||||
@@ -0,0 +1,633 @@
|
|||||||
|
package com.czg.service.Impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpUtil;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.czg.exception.CzgException;
|
||||||
|
import com.czg.service.RedisService;
|
||||||
|
import com.czg.system.service.SysParamsService;
|
||||||
|
import com.czg.system.service.WxService;
|
||||||
|
import com.ijpay.core.IJPayHttpResponse;
|
||||||
|
import com.ijpay.core.enums.RequestMethodEnum;
|
||||||
|
import com.ijpay.core.enums.SignType;
|
||||||
|
import com.ijpay.core.kit.AesUtil;
|
||||||
|
import com.ijpay.core.kit.PayKit;
|
||||||
|
import com.ijpay.core.kit.RsaKit;
|
||||||
|
import com.ijpay.core.kit.WxPayKit;
|
||||||
|
import com.ijpay.wxpay.WxPayApi;
|
||||||
|
import com.ijpay.wxpay.enums.WxDomainEnum;
|
||||||
|
import com.ijpay.wxpay.enums.v3.BasePayApiEnum;
|
||||||
|
import com.ijpay.wxpay.enums.v3.OtherApiEnum;
|
||||||
|
import com.ijpay.wxpay.enums.v3.ProfitSharingApiEnum;
|
||||||
|
import com.ijpay.wxpay.model.ReceiverModel;
|
||||||
|
import com.ijpay.wxpay.model.v3.*;
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.dubbo.config.annotation.DubboReference;
|
||||||
|
import org.apache.dubbo.config.annotation.DubboService;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.PrivateKey;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 微信支付service
|
||||||
|
* @author Administrator
|
||||||
|
*/
|
||||||
|
@DubboService
|
||||||
|
@Slf4j
|
||||||
|
public class WxServiceImpl implements WxService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisService autoRedisService;
|
||||||
|
@DubboReference
|
||||||
|
private SysParamsService paramsService;
|
||||||
|
private static RedisService redisService;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
// 小程序id
|
||||||
|
appId = paramsService.getSysParamValue("shop_wx_appid");
|
||||||
|
// 小程序secrete
|
||||||
|
appSecret = paramsService.getSysParamValue("shop_wx_secrete");
|
||||||
|
certPath = "";
|
||||||
|
// 微信支付公钥
|
||||||
|
pubKey = paramsService.getSysParamValue("wx_pub_key");
|
||||||
|
// api支付证书私钥
|
||||||
|
apiCertKey = paramsService.getSysParamValue("wx_apiclient_key");
|
||||||
|
// api支付证书公钥
|
||||||
|
apiCert = paramsService.getSysParamValue("wx_apiclient_cert");
|
||||||
|
try {
|
||||||
|
privateKey = RsaKit.loadPrivateKey(apiCertKey);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("微信加载api证书失败");
|
||||||
|
}
|
||||||
|
// 平台证书
|
||||||
|
platformCertPath = "";
|
||||||
|
// 平台证书编号
|
||||||
|
platformCertNo = "";
|
||||||
|
// 商户号
|
||||||
|
mchId = paramsService.getSysParamValue("wx_mch_id");
|
||||||
|
// v3密钥
|
||||||
|
apiV3Key = paramsService.getSysParamValue("wx_v3_key");
|
||||||
|
apiV2Key = "";
|
||||||
|
// 回调地址
|
||||||
|
notifyUrl = paramsService.getSysParamValue("native_notify_url") + "/wx/pay";
|
||||||
|
refundNotifyUrl = "";
|
||||||
|
transferNotifyUrl = paramsService.getSysParamValue("native_notify_url") + "/wx/transfer";
|
||||||
|
redisService = this.autoRedisService;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static copies for use in static methods
|
||||||
|
private static String appId;
|
||||||
|
private static String appSecret;
|
||||||
|
private static String certPath;
|
||||||
|
private static String pubKey;
|
||||||
|
private static String apiCertKey;
|
||||||
|
private static PrivateKey privateKey;
|
||||||
|
private static String apiCert;
|
||||||
|
private static String platformCertPath;
|
||||||
|
private static String platformCertNo;
|
||||||
|
private static String mchId;
|
||||||
|
private static String apiV3Key;
|
||||||
|
private static String apiV2Key;
|
||||||
|
private static String notifyUrl;
|
||||||
|
private static String refundNotifyUrl;
|
||||||
|
private static String transferNotifyUrl;
|
||||||
|
|
||||||
|
private static String getAccessToken(boolean refresh) {
|
||||||
|
Object token = redisService.get("access_token");
|
||||||
|
if (!refresh && token instanceof String) {
|
||||||
|
return (String) token;
|
||||||
|
}
|
||||||
|
|
||||||
|
String response = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/token",
|
||||||
|
Map.of("grant_type", "client_credential", "appid", appId, "secret", appSecret)
|
||||||
|
);
|
||||||
|
|
||||||
|
log.info("获取access_token响应: {}", response);
|
||||||
|
JSONObject jsonObject = JSONObject.parseObject(response);
|
||||||
|
String accessToken = jsonObject.getString("access_token");
|
||||||
|
if (accessToken == null) {
|
||||||
|
throw new RuntimeException("获取access_token失败");
|
||||||
|
}
|
||||||
|
Long expiresIn = jsonObject.getLong("expires_in");
|
||||||
|
if (expiresIn == null) {
|
||||||
|
expiresIn = 7200L;
|
||||||
|
}
|
||||||
|
redisService.set("access_token", accessToken, expiresIn - 200);
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPhone(String code) {
|
||||||
|
String requestBody = JSONObject.toJSONString(Map.of("code", code));
|
||||||
|
String response = HttpUtil.post("https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + getAccessToken(false), requestBody);
|
||||||
|
log.info("获取手机号响应: {}", response);
|
||||||
|
JSONObject jsonObject = JSONObject.parseObject(response);
|
||||||
|
Integer errCode = jsonObject.getInteger("errcode");
|
||||||
|
|
||||||
|
if (Integer.valueOf(0).equals(errCode)) {
|
||||||
|
return jsonObject.getJSONObject("phone_info").getString("phoneNumber");
|
||||||
|
} else if (Integer.valueOf(40001).equals(errCode)) {
|
||||||
|
getAccessToken(true);
|
||||||
|
}
|
||||||
|
throw new RuntimeException("获取手机号失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getOpenId(String code) {
|
||||||
|
String response = HttpUtil.get("https://api.weixin.qq.com/sns/jscode2session",
|
||||||
|
Map.of("appid", appId, "secret", appSecret, "js_code", code, "grant_type", "authorization_code")
|
||||||
|
);
|
||||||
|
log.info("获取openId响应: {}", response);
|
||||||
|
JSONObject jsonObject = JSONObject.parseObject(response);
|
||||||
|
String openId = jsonObject.getString("openid");
|
||||||
|
if (openId != null && !openId.isBlank()) {
|
||||||
|
return openId;
|
||||||
|
}
|
||||||
|
throw new RuntimeException("获取openId失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用微信支付平台证书公钥加密敏感信息(OAEP)
|
||||||
|
*/
|
||||||
|
private static String encryptByPlatformCert(String content) {
|
||||||
|
try (var certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(platformCertPath)) {
|
||||||
|
if (certStream == null) {
|
||||||
|
throw new RuntimeException("未找到微信支付平台证书文件: " + platformCertPath);
|
||||||
|
}
|
||||||
|
X509Certificate certificate = PayKit.getCertificate(certStream);
|
||||||
|
if (certificate == null) throw new RuntimeException("读取证书失败");
|
||||||
|
return PayKit.rsaEncryptOAEP(content, certificate);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSerialNumberFromPem(String certContent) {
|
||||||
|
try {
|
||||||
|
// 去掉 PEM 头尾并清理空格换行
|
||||||
|
String pem = certContent
|
||||||
|
.replace("-----BEGIN CERTIFICATE-----", "")
|
||||||
|
.replace("-----END CERTIFICATE-----", "")
|
||||||
|
.replaceAll("\\s+", "");
|
||||||
|
|
||||||
|
// Base64 解码
|
||||||
|
byte[] certBytes = Base64.getDecoder().decode(pem);
|
||||||
|
|
||||||
|
try (ByteArrayInputStream bis = new ByteArrayInputStream(certBytes)) {
|
||||||
|
X509Certificate certificate = PayKit.getCertificate(bis);
|
||||||
|
|
||||||
|
if (certificate != null) {
|
||||||
|
String serialNo = certificate.getSerialNumber()
|
||||||
|
.toString(16)
|
||||||
|
.toUpperCase(Locale.getDefault());
|
||||||
|
|
||||||
|
System.out.println("证书序列号:" + serialNo);
|
||||||
|
|
||||||
|
return serialNo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("无效的证书", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
// // 文件路径(支持绝对路径或相对路径)
|
||||||
|
// String filePath = "D:/certs/apiclient_cert.pem";
|
||||||
|
// try (var certStream = new FileInputStream("E:\\workspace\\cashier_server1\\cash-api\\order-server\\src\\main\\resources\\cert.pem")) {
|
||||||
|
// X509Certificate certificate = PayKit.getCertificate(certStream);
|
||||||
|
// if (certificate != null) {
|
||||||
|
// String serialNo = certificate.getSerialNumber().toString(16).toUpperCase(Locale.getDefault());
|
||||||
|
// boolean isValid = PayKit.checkCertificateIsValid(certificate, mchId, -2);
|
||||||
|
// log.info("证书是否可用 {} 证书有效期为 {}", isValid, certificate.getNotAfter());
|
||||||
|
// log.info("证书序列号: {}", serialNo);
|
||||||
|
// }
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// log.error("读取证书失败", e);
|
||||||
|
// }
|
||||||
|
|
||||||
|
getSerialNumberFromPem("-----BEGIN CERTIFICATE-----\n" +
|
||||||
|
"MIIEJDCCAwygAwIBAgIUctkT9cVeYPVI02uqwzEw2Xg/QLQwDQYJKoZIhvcNAQEL\n" +
|
||||||
|
"BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT\n" +
|
||||||
|
"FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg\n" +
|
||||||
|
"Q0EwHhcNMjUxMDI1MDI0NzU3WhcNMzAxMDI0MDI0NzU3WjB+MRMwEQYDVQQDDAox\n" +
|
||||||
|
"NzMwMDkxMjAzMRswGQYDVQQKDBLlvq7kv6HllYbmiLfns7vnu58xKjAoBgNVBAsM\n" +
|
||||||
|
"IemZleilv+i2heaOjOafnOenkeaKgOaciemZkOWFrOWPuDELMAkGA1UEBhMCQ04x\n" +
|
||||||
|
"ETAPBgNVBAcMCFNoZW5aaGVuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\n" +
|
||||||
|
"AQEAqCcrDNKTGCBk2euqL6ENu2akxEdmlQQjlf8AVKdGA4nPp0GkWF+WQxFFxAHo\n" +
|
||||||
|
"jOLSeOUoxqQ5Nr9wa14Nfv3m6R4UIo+JeG0TkNyzum4GRokwoK70vQa8IXZW9vmM\n" +
|
||||||
|
"lVce/2mxb8sxcnVfAABPfo2A7L14PKPMvAPF4HgJOi5tnMco1sVlg4uwxejoMl7q\n" +
|
||||||
|
"CiE6lozFW2IRaZZrtmBJMW3oSxCGuLtaWmkXDyj4tLzAJspDxNMQHCVNzYodPREA\n" +
|
||||||
|
"OP9Z1Wy2v0xIseoxGnxgefE7LpF5jCZiGLkiOg1Xa79tpX02zZ22A8JvTfPWhKJJ\n" +
|
||||||
|
"nYV0r3PZi/32IU0bBmURYjuh5QIDAQABo4G5MIG2MAkGA1UdEwQCMAAwCwYDVR0P\n" +
|
||||||
|
"BAQDAgP4MIGbBgNVHR8EgZMwgZAwgY2ggYqggYeGgYRodHRwOi8vZXZjYS5pdHJ1\n" +
|
||||||
|
"cy5jb20uY24vcHVibGljL2l0cnVzY3JsP0NBPTFCRDQyMjBFNTBEQkMwNEIwNkFE\n" +
|
||||||
|
"Mzk3NTQ5ODQ2QzAxQzNFOEVCRDImc2c9SEFDQzQ3MUI2NTQyMkUxMkIyN0E5RDMz\n" +
|
||||||
|
"QTg3QUQxQ0RGNTkyNkUxNDAzNzEwDQYJKoZIhvcNAQELBQADggEBAKLBRR+E8hrK\n" +
|
||||||
|
"hQB+T0GIqQBgkFaCiakylUbw+jdEdQxJD8gO14tHSOTkqOMf5cZONnZiff2rIn+Y\n" +
|
||||||
|
"kFjR/lO//v5PsTIsby+siwnoc4MOz9tJ5qNUlleuXi3i/Fb1kU9nW6HC8GJdjZxG\n" +
|
||||||
|
"YqE3UyS23SG5VnrNeBplLHWS3ttmzduNKbl+180R5SoMIyCT35k0EStcZPlVrXnt\n" +
|
||||||
|
"MqJftxS2Jl1lDHer62tOTgKRGZFfS6z0DOD97mJfyRJ5agUnJTD0L1LCb3lefNRV\n" +
|
||||||
|
"KgmAkkE7q9cRRIKf8SifdvFDaGhFFi1ezXI/vorSh3PnpMqd8SCc81/IhWmm09RA\n" +
|
||||||
|
"RLdEZXoPSmM=\n" +
|
||||||
|
"-----END CERTIFICATE-----\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getSerialNumber() {
|
||||||
|
try (var certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(certPath)) {
|
||||||
|
X509Certificate certificate = PayKit.getCertificate(certStream);
|
||||||
|
if (certificate != null) {
|
||||||
|
String serialNo = certificate.getSerialNumber().toString(16).toUpperCase(Locale.getDefault());
|
||||||
|
boolean isValid = PayKit.checkCertificateIsValid(certificate, mchId, -2);
|
||||||
|
log.info("证书是否可用 {} 证书有效期为 {}", isValid, certificate.getNotAfter());
|
||||||
|
log.info("证书序列号: {}", serialNo);
|
||||||
|
return serialNo;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("读取证书失败", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getPlatSerialNumber() {
|
||||||
|
try (var certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(platformCertNo)) {
|
||||||
|
X509Certificate certificate = PayKit.getCertificate(certStream);
|
||||||
|
if (certificate != null) {
|
||||||
|
String serialNo = certificate.getSerialNumber().toString(16).toUpperCase(Locale.getDefault());
|
||||||
|
boolean isValid = PayKit.checkCertificateIsValid(certificate, mchId, -2);
|
||||||
|
log.info("平台证书是否可用 {} 证书有效期为 {}", isValid, certificate.getNotAfter());
|
||||||
|
log.info("平台证书序列号: {}", serialNo);
|
||||||
|
return serialNo;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("读取平台证书失败", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JSONObject verifySignature(HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
log.info("开始校验签名并解密");
|
||||||
|
String timestamp = request.getHeader("Wechatpay-Timestamp");
|
||||||
|
String nonce = request.getHeader("Wechatpay-Nonce");
|
||||||
|
String serialNo = request.getHeader("Wechatpay-Serial");
|
||||||
|
String signature = request.getHeader("Wechatpay-Signature");
|
||||||
|
String result = request.getReader().lines().reduce((a, b) -> a + b).orElse("");
|
||||||
|
String resp = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp, apiV3Key, platformCertPath);
|
||||||
|
log.info("解密明文{}", resp);
|
||||||
|
return JSONObject.parseObject(resp);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void getPlatCert() throws Exception {
|
||||||
|
String response = WxPayApi.v3(
|
||||||
|
RequestMethodEnum.GET,
|
||||||
|
WxDomainEnum.CHINA.toString(),
|
||||||
|
OtherApiEnum.GET_CERTIFICATES.toString(),
|
||||||
|
mchId,
|
||||||
|
getSerialNumber(),
|
||||||
|
null,
|
||||||
|
apiCertKey,
|
||||||
|
""
|
||||||
|
).getBody();
|
||||||
|
|
||||||
|
JSONObject jsonObject = JSONObject.parseObject(response);
|
||||||
|
var dataArray = jsonObject.getJSONArray("data");
|
||||||
|
var encryptObject = dataArray.getJSONObject(0);
|
||||||
|
var encryptCertificate = encryptObject.getJSONObject("encrypt_certificate");
|
||||||
|
String associatedData = encryptCertificate.getString("associated_data");
|
||||||
|
String cipherText = encryptCertificate.getString("ciphertext");
|
||||||
|
String nonce = encryptCertificate.getString("nonce");
|
||||||
|
AesUtil aesUtil = new AesUtil(apiV3Key.getBytes(StandardCharsets.UTF_8));
|
||||||
|
String publicKey = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), cipherText);
|
||||||
|
log.info(publicKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> v3Pay(String openId, BigDecimal amount, String desc, String tradeNo, String type) {
|
||||||
|
if (desc == null) desc = "订单支付";
|
||||||
|
UnifiedOrderModel model = new UnifiedOrderModel();
|
||||||
|
model.setAppid(appId);
|
||||||
|
model.setMchid(mchId);
|
||||||
|
model.setDescription(desc);
|
||||||
|
model.setOut_trade_no(tradeNo);
|
||||||
|
int total = amount.setScale(2, RoundingMode.UP).multiply(new BigDecimal(100)).intValueExact();
|
||||||
|
model.setAmount(new Amount(total, "CNY"));
|
||||||
|
model.setNotify_url(notifyUrl + "/" + type);
|
||||||
|
model.setPayer(new Payer(openId, null, null));
|
||||||
|
|
||||||
|
String payInfo = JSONObject.toJSONString(model);
|
||||||
|
log.info("统一下单参数: {}", payInfo);
|
||||||
|
|
||||||
|
IJPayHttpResponse resp = null;
|
||||||
|
try {
|
||||||
|
resp = WxPayApi.v3(
|
||||||
|
RequestMethodEnum.POST,
|
||||||
|
WxDomainEnum.CHINA.toString(),
|
||||||
|
BasePayApiEnum.JS_API_PAY.toString(),
|
||||||
|
mchId,
|
||||||
|
getSerialNumberFromPem(apiCert),
|
||||||
|
null,
|
||||||
|
privateKey,
|
||||||
|
payInfo
|
||||||
|
);
|
||||||
|
log.info("统一下单响应: {}", resp);
|
||||||
|
String body = resp.getBody();
|
||||||
|
JSONObject jsonObject = JSONObject.parseObject(body);
|
||||||
|
String prepayId = jsonObject.getString("prepay_id");
|
||||||
|
if (StrUtil.isBlank(prepayId)) {
|
||||||
|
throw new RuntimeException(jsonObject.getString("message"));
|
||||||
|
}
|
||||||
|
return WxPayKit.jsApiCreateSign(appId, prepayId, privateKey);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, String> v2Pay(String openId, BigDecimal amount, String desc, String tradeNo) {
|
||||||
|
Map<String, String> payModel = com.ijpay.wxpay.model.UnifiedOrderModel.builder()
|
||||||
|
.appid(appId)
|
||||||
|
.mch_id(mchId)
|
||||||
|
.body(desc)
|
||||||
|
.out_trade_no(tradeNo)
|
||||||
|
.total_fee(amount.setScale(2, RoundingMode.UP).multiply(new BigDecimal(100)).intValueExact() + "")
|
||||||
|
.fee_type("CNY")
|
||||||
|
.notify_url(notifyUrl)
|
||||||
|
.openid(openId)
|
||||||
|
.trade_type("JSAPI")
|
||||||
|
.build()
|
||||||
|
.createSign(apiV2Key, SignType.MD5);
|
||||||
|
|
||||||
|
log.info("统一下单参数: {}", payModel);
|
||||||
|
String resp = WxPayApi.pushOrder(false, payModel);
|
||||||
|
log.info("统一下单响应: {}", resp);
|
||||||
|
|
||||||
|
Map<String, String> resultMap = WxPayKit.xmlToMap(resp);
|
||||||
|
String returnCode = resultMap.get("return_code");
|
||||||
|
String returnMsg = resultMap.get("return_msg");
|
||||||
|
if (!WxPayKit.codeIsOk(returnCode)) {
|
||||||
|
throw new CzgException(returnMsg);
|
||||||
|
}
|
||||||
|
String resultCode = resultMap.get("result_code");
|
||||||
|
if (!WxPayKit.codeIsOk(resultCode)) {
|
||||||
|
throw new CzgException(returnMsg);
|
||||||
|
}
|
||||||
|
String prepayId = resultMap.get("prepay_id");
|
||||||
|
return WxPayKit.prepayIdCreateSign(prepayId, appId, appSecret, SignType.MD5);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String refund(String tradeNo, String refundTradeNo, BigDecimal amount) {
|
||||||
|
int finalAmount = amount.multiply(new BigDecimal(100)).intValueExact();
|
||||||
|
RefundModel model = new RefundModel();
|
||||||
|
model.setOut_trade_no(tradeNo);
|
||||||
|
model.setOut_refund_no(refundTradeNo);
|
||||||
|
model.setAmount(new RefundAmount(finalAmount, "CNY", finalAmount));
|
||||||
|
model.setNotify_url(refundNotifyUrl);
|
||||||
|
|
||||||
|
String info = JSONObject.toJSONString(model);
|
||||||
|
log.info("统一退款参数: {}", info);
|
||||||
|
IJPayHttpResponse response;
|
||||||
|
try {
|
||||||
|
response = WxPayApi.v3(
|
||||||
|
RequestMethodEnum.POST,
|
||||||
|
WxDomainEnum.CHINA.toString(),
|
||||||
|
BasePayApiEnum.REFUND.toString(),
|
||||||
|
mchId,
|
||||||
|
getSerialNumber(),
|
||||||
|
getSerialNumber(),
|
||||||
|
apiCertKey,
|
||||||
|
info
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
log.info("统一退款响应 {}", response);
|
||||||
|
String body = response.getBody();
|
||||||
|
JSONObject jsonObject = JSONObject.parseObject(body);
|
||||||
|
if ("ABNORMAL".equals(jsonObject.getString("status")) || response.getStatus() != 200) {
|
||||||
|
throw new CzgException("退款异常," + jsonObject.getString("message"));
|
||||||
|
}
|
||||||
|
return jsonObject.getString("refund_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String genCode(int shopId, int id, String path) {
|
||||||
|
Map<String, Object> params = Map.of(
|
||||||
|
"scene", "id=" + id + "&shopId=" + shopId,
|
||||||
|
"page", path,
|
||||||
|
"width", 430
|
||||||
|
);
|
||||||
|
var response = HttpRequest.post("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + getAccessToken(false))
|
||||||
|
.body(JSONObject.toJSONString(params))
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
byte[] bodyBytes = response.bodyBytes();
|
||||||
|
String str = new String(bodyBytes);
|
||||||
|
if (str.contains("errmsg")) {
|
||||||
|
JSONObject json = JSONObject.parseObject(str);
|
||||||
|
throw new CzgException(json.getString("errmsg"));
|
||||||
|
}
|
||||||
|
return "data:image/png;base64," + Base64.getEncoder().encodeToString(bodyBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String addProfitSharingUser(AddReceivers params) throws Exception {
|
||||||
|
getPlatCert();
|
||||||
|
params.setAppid(appId);
|
||||||
|
if (params.getName() != null && !params.getName().isBlank()) {
|
||||||
|
params.setName(encryptByPlatformCert(params.getName()));
|
||||||
|
} else {
|
||||||
|
params.setName(null);
|
||||||
|
}
|
||||||
|
log.info("添加分账方参数: {}", JSONObject.toJSONString(params));
|
||||||
|
var response = WxPayApi.v3(
|
||||||
|
RequestMethodEnum.POST,
|
||||||
|
WxDomainEnum.CHINA.toString(),
|
||||||
|
ProfitSharingApiEnum.PROFIT_SHARING_RECEIVERS_ADD.toString(),
|
||||||
|
mchId,
|
||||||
|
getSerialNumber(),
|
||||||
|
platformCertNo,
|
||||||
|
apiCertKey,
|
||||||
|
JSONObject.toJSONString(params)
|
||||||
|
);
|
||||||
|
log.info("添加分账方响应 {}", response.getBody());
|
||||||
|
JSONObject resp = JSONObject.parseObject(response.getBody());
|
||||||
|
if (resp.containsKey("code")) {
|
||||||
|
throw new CzgException("分账添加失败" + resp.getString("message"));
|
||||||
|
}
|
||||||
|
return resp.getString("account");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JSONObject getMchConfig(String mchIdParam) throws Exception {
|
||||||
|
var response = WxPayApi.v3(
|
||||||
|
RequestMethodEnum.GET,
|
||||||
|
WxDomainEnum.CHINA.toString(),
|
||||||
|
String.format(ProfitSharingApiEnum.PROFIT_SHARING_MERCHANT_CONFIGS.toString(), mchIdParam),
|
||||||
|
mchId,
|
||||||
|
getSerialNumber(),
|
||||||
|
getSerialNumber(),
|
||||||
|
apiCertKey,
|
||||||
|
""
|
||||||
|
);
|
||||||
|
log.info("查询分账响应 {}", response.getBody());
|
||||||
|
JSONObject resp = JSONObject.parseObject(response.getBody());
|
||||||
|
if (resp.containsKey("code")) {
|
||||||
|
throw new CzgException("分账查询失败" + resp.getString("message"));
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取可分账金额
|
||||||
|
*/
|
||||||
|
public static BigDecimal getRemainAmount(String transactionId) {
|
||||||
|
IJPayHttpResponse response;
|
||||||
|
try {
|
||||||
|
response = WxPayApi.v3(
|
||||||
|
RequestMethodEnum.GET,
|
||||||
|
WxDomainEnum.CHINA.toString(),
|
||||||
|
String.format(ProfitSharingApiEnum.PROFIT_SHARING_UNFREEZE_QUERY.toString(), transactionId),
|
||||||
|
mchId,
|
||||||
|
getSerialNumber(),
|
||||||
|
getSerialNumber(),
|
||||||
|
apiCertKey,
|
||||||
|
""
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
log.info("查询可分账响应 {}", response.getBody());
|
||||||
|
JSONObject resp = JSONObject.parseObject(response.getBody());
|
||||||
|
if (resp.containsKey("code")) {
|
||||||
|
throw new CzgException("分账查询失败" + resp.getString("message"));
|
||||||
|
}
|
||||||
|
return resp.getBigDecimal("unsplit_amount");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void profitSharing(String transactionId, ReceiverModel... receivers) {
|
||||||
|
for (ReceiverModel r : receivers) {
|
||||||
|
if (r.getName() != null && !r.getName().isBlank()) {
|
||||||
|
r.setName(encryptByPlatformCert(r.getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String tradeNo = IdUtil.simpleUUID();
|
||||||
|
ProfitSharingModel model = new ProfitSharingModel();
|
||||||
|
model.setAppid(appId);
|
||||||
|
model.setTransaction_id(transactionId);
|
||||||
|
model.setReceivers(List.of(receivers));
|
||||||
|
model.setUnfreeze_unsplit(true);
|
||||||
|
model.setOut_order_no(tradeNo);
|
||||||
|
|
||||||
|
String params = JSONObject.toJSONString(model);
|
||||||
|
log.info("分账参数: {}", params);
|
||||||
|
IJPayHttpResponse response;
|
||||||
|
try {
|
||||||
|
response = WxPayApi.v3(
|
||||||
|
RequestMethodEnum.POST,
|
||||||
|
WxDomainEnum.CHINA.toString(),
|
||||||
|
ProfitSharingApiEnum.PROFIT_SHARING_ORDERS.toString(),
|
||||||
|
mchId,
|
||||||
|
getSerialNumber(),
|
||||||
|
platformCertNo,
|
||||||
|
apiCertKey,
|
||||||
|
params
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
log.info("分账响应 {}", response.getBody());
|
||||||
|
JSONObject resp = JSONObject.parseObject(response.getBody());
|
||||||
|
if (resp.containsKey("code")) {
|
||||||
|
throw new CzgException("分账失败" + resp.getString("message") + ", 响应: " + resp.toJSONString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void unFreezeSharing(String transactionId, String orderNo) {
|
||||||
|
com.ijpay.wxpay.model.ProfitSharingModel paramsModel = new com.ijpay.wxpay.model.ProfitSharingModel();
|
||||||
|
paramsModel.setTransaction_id(transactionId);
|
||||||
|
paramsModel.setOut_order_no(orderNo);
|
||||||
|
paramsModel.setDescription("分账解冻");
|
||||||
|
String params = JSONObject.toJSONString(paramsModel);
|
||||||
|
log.info("分账解冻参数: {}", params);
|
||||||
|
IJPayHttpResponse response;
|
||||||
|
try {
|
||||||
|
response = WxPayApi.v3(
|
||||||
|
RequestMethodEnum.POST,
|
||||||
|
WxDomainEnum.CHINA.toString(),
|
||||||
|
ProfitSharingApiEnum.PROFIT_SHARING_UNFREEZE.toString(),
|
||||||
|
mchId,
|
||||||
|
getSerialNumber(),
|
||||||
|
platformCertNo,
|
||||||
|
apiCertKey,
|
||||||
|
params
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
log.info("分账解冻响应 {}", response.getBody());
|
||||||
|
JSONObject resp = JSONObject.parseObject(response.getBody());
|
||||||
|
if (resp.containsKey("code")) {
|
||||||
|
throw new CzgException("分账解冻失败" + resp.getString("message") + ", 响应: " + resp.toJSONString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JSONObject transferBalance(String openId, String name, BigDecimal amount, String remarkTxt, String billNoTxt) {
|
||||||
|
String remark = remarkTxt == null ? "佣金" : remarkTxt;
|
||||||
|
String billNo = billNoTxt == null ? IdUtil.simpleUUID() : billNoTxt;
|
||||||
|
Map<String, Object> params = Map.of(
|
||||||
|
"appid", appId,
|
||||||
|
"out_bill_no", billNo,
|
||||||
|
"transfer_scene_id", "1005",
|
||||||
|
"openid", openId,
|
||||||
|
"user_name", encryptByPlatformCert(name),
|
||||||
|
"transfer_amount", amount.multiply(BigDecimal.valueOf(100)).intValue(),
|
||||||
|
"transfer_remark", remark,
|
||||||
|
"notify_url", transferNotifyUrl,
|
||||||
|
"transfer_scene_report_infos", new Object[]{
|
||||||
|
Map.of("info_type", "岗位类型", "info_content", "加盟商"),
|
||||||
|
Map.of("info_type", "报酬说明", "info_content", "测试")
|
||||||
|
}
|
||||||
|
);
|
||||||
|
log.info("转账到零钱参数: {}", JSONObject.toJSONString(params));
|
||||||
|
IJPayHttpResponse response = null;
|
||||||
|
try {
|
||||||
|
response = WxPayApi.v3(
|
||||||
|
RequestMethodEnum.POST,
|
||||||
|
WxDomainEnum.CHINA.toString(),
|
||||||
|
"/v3/fund-app/mch-transfer/transfer-bills",
|
||||||
|
mchId,
|
||||||
|
getSerialNumber(),
|
||||||
|
platformCertNo,
|
||||||
|
apiCertKey,
|
||||||
|
JSONObject.toJSONString(params)
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
log.info("转账到零钱响应 {}", response.getBody());
|
||||||
|
JSONObject resp = JSONObject.parseObject(response.getBody());
|
||||||
|
if (resp.containsKey("code")) {
|
||||||
|
throw new CzgException("转账到零钱失败" + resp.getString("message") + ", 响应: " + resp.toJSONString());
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,554 +0,0 @@
|
|||||||
//package com.czg.service;
|
|
||||||
//
|
|
||||||
//import cn.hutool.core.util.IdUtil;
|
|
||||||
//import cn.hutool.core.util.StrUtil;
|
|
||||||
//import cn.hutool.http.HttpRequest;
|
|
||||||
//import cn.hutool.http.HttpUtil;
|
|
||||||
//import com.alibaba.fastjson.JSONObject;
|
|
||||||
//import com.czg.exception.CzgException;
|
|
||||||
//import com.ijpay.core.IJPayHttpResponse;
|
|
||||||
//import com.ijpay.core.enums.RequestMethodEnum;
|
|
||||||
//import com.ijpay.core.enums.SignType;
|
|
||||||
//import com.ijpay.core.kit.AesUtil;
|
|
||||||
//import com.ijpay.core.kit.PayKit;
|
|
||||||
//import com.ijpay.core.kit.RsaKit;
|
|
||||||
//import com.ijpay.core.kit.WxPayKit;
|
|
||||||
//import com.ijpay.wxpay.WxPayApi;
|
|
||||||
//import com.ijpay.wxpay.enums.WxDomainEnum;
|
|
||||||
//import com.ijpay.wxpay.enums.v3.BasePayApiEnum;
|
|
||||||
//import com.ijpay.wxpay.enums.v3.OtherApiEnum;
|
|
||||||
//import com.ijpay.wxpay.enums.v3.ProfitSharingApiEnum;
|
|
||||||
//import com.ijpay.wxpay.enums.v3.TransferApiEnum;
|
|
||||||
//import com.ijpay.wxpay.model.ReceiverModel;
|
|
||||||
//import com.ijpay.wxpay.model.v3.*;
|
|
||||||
//import jakarta.annotation.PostConstruct;
|
|
||||||
//import jakarta.annotation.Resource;
|
|
||||||
//import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
//import lombok.extern.slf4j.Slf4j;
|
|
||||||
//import org.springframework.beans.factory.annotation.Value;
|
|
||||||
//import org.springframework.stereotype.Component;
|
|
||||||
//
|
|
||||||
//import java.math.BigDecimal;
|
|
||||||
//import java.math.RoundingMode;
|
|
||||||
//import java.nio.charset.StandardCharsets;
|
|
||||||
//import java.security.cert.X509Certificate;
|
|
||||||
//import java.util.Base64;
|
|
||||||
//import java.util.List;
|
|
||||||
//import java.util.Locale;
|
|
||||||
//import java.util.Map;
|
|
||||||
//
|
|
||||||
//@Component
|
|
||||||
//@Slf4j
|
|
||||||
//public class WxService {
|
|
||||||
//
|
|
||||||
// @Value("${wx.appId}")
|
|
||||||
// private String appIdInstance;
|
|
||||||
// @Value("${wx.appSecret}")
|
|
||||||
// private String appSecretInstance;
|
|
||||||
// @Value("${wx.pay.certPath}")
|
|
||||||
// private String certPathInstance;
|
|
||||||
// @Value("${wx.pay.certKeyPath}")
|
|
||||||
// private String certKeyPathInstance;
|
|
||||||
// @Value("${wx.pay.pubKey}")
|
|
||||||
// private String pubKeyInstance;
|
|
||||||
// @Value("${wx.pay.platformCertPath}")
|
|
||||||
// private String platformCertPathInstance;
|
|
||||||
// @Value("${wx.pay.platformCertNo}")
|
|
||||||
// private String platformCertNoInstance;
|
|
||||||
// @Value("${wx.pay.mchId}")
|
|
||||||
// private String mchIdInstance;
|
|
||||||
// @Value("${wx.pay.apiV3Key}")
|
|
||||||
// private String apiV3KeyInstance;
|
|
||||||
// @Value("${wx.pay.apiV2Key}")
|
|
||||||
// private String apiV2KeyInstance;
|
|
||||||
// @Value("${wx.pay.notifyUrl}")
|
|
||||||
// private String notifyUrlInstance;
|
|
||||||
// @Value("${wx.pay.refundNotifyUrl}")
|
|
||||||
// private String refundNotifyUrlInstance;
|
|
||||||
// @Value("${wx.pay.transferNotifyUrl}")
|
|
||||||
// private String transferNotifyUrlInstance;
|
|
||||||
//
|
|
||||||
// @Resource
|
|
||||||
// private RedisService autoRedisService;
|
|
||||||
// private static RedisService redisService;
|
|
||||||
//
|
|
||||||
// @PostConstruct
|
|
||||||
// public void init() {
|
|
||||||
// appId = appIdInstance;
|
|
||||||
// appSecret = appSecretInstance;
|
|
||||||
// certPath = certPathInstance;
|
|
||||||
// pubKey = pubKeyInstance;
|
|
||||||
// certKeyPath = certKeyPathInstance;
|
|
||||||
// platformCertPath = platformCertPathInstance;
|
|
||||||
// platformCertNo = platformCertNoInstance;
|
|
||||||
// mchId = mchIdInstance;
|
|
||||||
// apiV3Key = apiV3KeyInstance;
|
|
||||||
// apiV2Key = apiV2KeyInstance;
|
|
||||||
// notifyUrl = notifyUrlInstance;
|
|
||||||
// refundNotifyUrl = refundNotifyUrlInstance;
|
|
||||||
// transferNotifyUrl = transferNotifyUrlInstance;
|
|
||||||
// redisService = this.autoRedisService;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // static copies for use in static methods
|
|
||||||
// private static String appId;
|
|
||||||
// private static String appSecret;
|
|
||||||
// private static String certPath;
|
|
||||||
// private static String pubKey;
|
|
||||||
// private static String certKeyPath;
|
|
||||||
// private static String platformCertPath;
|
|
||||||
// private static String platformCertNo;
|
|
||||||
// private static String mchId;
|
|
||||||
// private static String apiV3Key;
|
|
||||||
// private static String apiV2Key;
|
|
||||||
// private static String notifyUrl;
|
|
||||||
// private static String refundNotifyUrl;
|
|
||||||
// private static String transferNotifyUrl;
|
|
||||||
//
|
|
||||||
// private static String getAccessToken(boolean refresh) {
|
|
||||||
// Object token = redisService.get("access_token");
|
|
||||||
// if (!refresh && token instanceof String) {
|
|
||||||
// return (String) token;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// String response = HttpUtil.get("https://api.weixin.qq.com/cgi-bin/token",
|
|
||||||
// Map.of("grant_type", "client_credential", "appid", appId, "secret", appSecret)
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// log.info("获取access_token响应: {}", response);
|
|
||||||
// JSONObject jsonObject = JSONObject.parseObject(response);
|
|
||||||
// String accessToken = jsonObject.getString("access_token");
|
|
||||||
// if (accessToken == null) {
|
|
||||||
// throw new RuntimeException("获取access_token失败");
|
|
||||||
// }
|
|
||||||
// Long expiresIn = jsonObject.getLong("expires_in");
|
|
||||||
// if (expiresIn == null) {
|
|
||||||
// expiresIn = 7200L;
|
|
||||||
// }
|
|
||||||
// redisService.set("access_token", accessToken, expiresIn - 200);
|
|
||||||
// return accessToken;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static String getPhone(String code) {
|
|
||||||
// String requestBody = JSONObject.toJSONString(Map.of("code", code));
|
|
||||||
// String response = HttpUtil.post("https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + getAccessToken(false), requestBody);
|
|
||||||
// log.info("获取手机号响应: {}", response);
|
|
||||||
// JSONObject jsonObject = JSONObject.parseObject(response);
|
|
||||||
// Integer errCode = jsonObject.getInteger("errcode");
|
|
||||||
//
|
|
||||||
// if (Integer.valueOf(0).equals(errCode)) {
|
|
||||||
// return jsonObject.getJSONObject("phone_info").getString("phoneNumber");
|
|
||||||
// } else if (Integer.valueOf(40001).equals(errCode)) {
|
|
||||||
// getAccessToken(true);
|
|
||||||
// }
|
|
||||||
// throw new RuntimeException("获取手机号失败");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static String getOpenId(String code) {
|
|
||||||
// String response = HttpUtil.get("https://api.weixin.qq.com/sns/jscode2session",
|
|
||||||
// Map.of("appid", appId, "secret", appSecret, "js_code", code, "grant_type", "authorization_code")
|
|
||||||
// );
|
|
||||||
// log.info("获取openId响应: {}", response);
|
|
||||||
// JSONObject jsonObject = JSONObject.parseObject(response);
|
|
||||||
// String openId = jsonObject.getString("openid");
|
|
||||||
// if (openId != null && !openId.isBlank()) {
|
|
||||||
// return openId;
|
|
||||||
// }
|
|
||||||
// throw new RuntimeException("获取openId失败");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * 使用微信支付平台证书公钥加密敏感信息(OAEP)
|
|
||||||
// */
|
|
||||||
// private static String encryptByPlatformCert(String content) {
|
|
||||||
// try (var certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(platformCertPath)) {
|
|
||||||
// if (certStream == null) {
|
|
||||||
// throw new RuntimeException("未找到微信支付平台证书文件: " + platformCertPath);
|
|
||||||
// }
|
|
||||||
// X509Certificate certificate = PayKit.getCertificate(certStream);
|
|
||||||
// if (certificate == null) throw new RuntimeException("读取证书失败");
|
|
||||||
// return PayKit.rsaEncryptOAEP(content, certificate);
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// throw new RuntimeException(e);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private static String getSerialNumber() {
|
|
||||||
// try (var certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(certPath)) {
|
|
||||||
// X509Certificate certificate = PayKit.getCertificate(certStream);
|
|
||||||
// if (certificate != null) {
|
|
||||||
// String serialNo = certificate.getSerialNumber().toString(16).toUpperCase(Locale.getDefault());
|
|
||||||
// boolean isValid = PayKit.checkCertificateIsValid(certificate, mchId, -2);
|
|
||||||
// log.info("证书是否可用 {} 证书有效期为 {}", isValid, certificate.getNotAfter());
|
|
||||||
// log.info("证书序列号: {}", serialNo);
|
|
||||||
// return serialNo;
|
|
||||||
// }
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// log.error("读取证书失败", e);
|
|
||||||
// }
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private static String getPlatSerialNumber() {
|
|
||||||
// try (var certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(platformCertNo)) {
|
|
||||||
// X509Certificate certificate = PayKit.getCertificate(certStream);
|
|
||||||
// if (certificate != null) {
|
|
||||||
// String serialNo = certificate.getSerialNumber().toString(16).toUpperCase(Locale.getDefault());
|
|
||||||
// boolean isValid = PayKit.checkCertificateIsValid(certificate, mchId, -2);
|
|
||||||
// log.info("平台证书是否可用 {} 证书有效期为 {}", isValid, certificate.getNotAfter());
|
|
||||||
// log.info("平台证书序列号: {}", serialNo);
|
|
||||||
// return serialNo;
|
|
||||||
// }
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// log.error("读取平台证书失败", e);
|
|
||||||
// }
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static JSONObject verifySignature(HttpServletRequest request) {
|
|
||||||
// try {
|
|
||||||
// log.info("开始校验签名并解密");
|
|
||||||
// String timestamp = request.getHeader("Wechatpay-Timestamp");
|
|
||||||
// String nonce = request.getHeader("Wechatpay-Nonce");
|
|
||||||
// String serialNo = request.getHeader("Wechatpay-Serial");
|
|
||||||
// String signature = request.getHeader("Wechatpay-Signature");
|
|
||||||
// String result = request.getReader().lines().reduce((a, b) -> a + b).orElse("");
|
|
||||||
// String resp = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp, apiV3Key, platformCertPath);
|
|
||||||
// log.info("解密明文{}", resp);
|
|
||||||
// return JSONObject.parseObject(resp);
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// throw new RuntimeException(e);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static void getPlatCert() throws Exception {
|
|
||||||
// String response = WxPayApi.v3(
|
|
||||||
// RequestMethodEnum.GET,
|
|
||||||
// WxDomainEnum.CHINA.toString(),
|
|
||||||
// OtherApiEnum.GET_CERTIFICATES.toString(),
|
|
||||||
// mchId,
|
|
||||||
// getSerialNumber(),
|
|
||||||
// null,
|
|
||||||
// certKeyPath,
|
|
||||||
// ""
|
|
||||||
// ).getBody();
|
|
||||||
//
|
|
||||||
// JSONObject jsonObject = JSONObject.parseObject(response);
|
|
||||||
// var dataArray = jsonObject.getJSONArray("data");
|
|
||||||
// var encryptObject = dataArray.getJSONObject(0);
|
|
||||||
// var encryptCertificate = encryptObject.getJSONObject("encrypt_certificate");
|
|
||||||
// String associatedData = encryptCertificate.getString("associated_data");
|
|
||||||
// String cipherText = encryptCertificate.getString("ciphertext");
|
|
||||||
// String nonce = encryptCertificate.getString("nonce");
|
|
||||||
// AesUtil aesUtil = new AesUtil(apiV3Key.getBytes(StandardCharsets.UTF_8));
|
|
||||||
// String publicKey = aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), cipherText);
|
|
||||||
// log.info(publicKey);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static Map<String, String> pay(String openId, BigDecimal amount, String desc, String tradeNo, String type) throws Exception {
|
|
||||||
// if (desc == null) desc = "订单支付";
|
|
||||||
// UnifiedOrderModel model = new UnifiedOrderModel();
|
|
||||||
// model.setAppid(appId);
|
|
||||||
// model.setMchid(mchId);
|
|
||||||
// model.setDescription(desc);
|
|
||||||
// model.setOut_trade_no(tradeNo);
|
|
||||||
// int total = amount.setScale(2, RoundingMode.UP).multiply(new BigDecimal(100)).intValueExact();
|
|
||||||
// model.setAmount(new Amount(total, "CNY"));
|
|
||||||
// model.setNotify_url(notifyUrl + "/" + type);
|
|
||||||
// model.setPayer(new Payer(openId, null, null));
|
|
||||||
//
|
|
||||||
// String payInfo = JSONObject.toJSONString(model);
|
|
||||||
// log.info("统一下单参数: {}", payInfo);
|
|
||||||
//
|
|
||||||
// var resp = WxPayApi.v3(
|
|
||||||
// RequestMethodEnum.POST,
|
|
||||||
// WxDomainEnum.CHINA.toString(),
|
|
||||||
// BasePayApiEnum.JS_API_PAY.toString(),
|
|
||||||
// mchId,
|
|
||||||
// getSerialNumber(),
|
|
||||||
// getSerialNumber(),
|
|
||||||
// certKeyPath,
|
|
||||||
// payInfo
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// log.info("统一下单响应: {}", resp);
|
|
||||||
// String body = resp.getBody();
|
|
||||||
// JSONObject jsonObject = JSONObject.parseObject(body);
|
|
||||||
// String prepayId = jsonObject.getString("prepay_id");
|
|
||||||
// if (StrUtil.isBlank(prepayId)) {
|
|
||||||
// throw new RuntimeException(jsonObject.getString("message"));
|
|
||||||
// }
|
|
||||||
// try {
|
|
||||||
// return WxPayKit.jsApiCreateSign(appId, prepayId, certKeyPath);
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// throw new RuntimeException(e);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static Map<String, String> v2Pay(String openId, BigDecimal amount, String desc, String tradeNo) {
|
|
||||||
// Map<String, String> payModel = com.ijpay.wxpay.model.UnifiedOrderModel.builder()
|
|
||||||
// .appid(appId)
|
|
||||||
// .mch_id(mchId)
|
|
||||||
// .body(desc)
|
|
||||||
// .out_trade_no(tradeNo)
|
|
||||||
// .total_fee(amount.setScale(2, RoundingMode.UP).multiply(new BigDecimal(100)).intValueExact() + "")
|
|
||||||
// .fee_type("CNY")
|
|
||||||
// .notify_url(notifyUrl)
|
|
||||||
// .openid(openId)
|
|
||||||
// .trade_type("JSAPI")
|
|
||||||
// .build()
|
|
||||||
// .createSign(apiV2Key, SignType.MD5);
|
|
||||||
//
|
|
||||||
// log.info("统一下单参数: {}", payModel);
|
|
||||||
// String resp = WxPayApi.pushOrder(false, payModel);
|
|
||||||
// log.info("统一下单响应: {}", resp);
|
|
||||||
//
|
|
||||||
// Map<String, String> resultMap = WxPayKit.xmlToMap(resp);
|
|
||||||
// String returnCode = resultMap.get("return_code");
|
|
||||||
// String returnMsg = resultMap.get("return_msg");
|
|
||||||
// if (!WxPayKit.codeIsOk(returnCode)) {
|
|
||||||
// throw new CzgException(returnMsg);
|
|
||||||
// }
|
|
||||||
// String resultCode = resultMap.get("result_code");
|
|
||||||
// if (!WxPayKit.codeIsOk(resultCode)) {
|
|
||||||
// throw new CzgException(returnMsg);
|
|
||||||
// }
|
|
||||||
// String prepayId = resultMap.get("prepay_id");
|
|
||||||
// return WxPayKit.prepayIdCreateSign(prepayId, appId, appSecret, SignType.MD5);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static String refund(String tradeNo, String refundTradeNo, BigDecimal amount) {
|
|
||||||
// int finalAmount = amount.multiply(new BigDecimal(100)).intValueExact();
|
|
||||||
// RefundModel model = new RefundModel();
|
|
||||||
// model.setOut_trade_no(tradeNo);
|
|
||||||
// model.setOut_refund_no(refundTradeNo);
|
|
||||||
// model.setAmount(new RefundAmount(finalAmount, "CNY", finalAmount));
|
|
||||||
// model.setNotify_url(refundNotifyUrl);
|
|
||||||
//
|
|
||||||
// String info = JSONObject.toJSONString(model);
|
|
||||||
// log.info("统一退款参数: {}", info);
|
|
||||||
// IJPayHttpResponse response;
|
|
||||||
// try {
|
|
||||||
// response = WxPayApi.v3(
|
|
||||||
// RequestMethodEnum.POST,
|
|
||||||
// WxDomainEnum.CHINA.toString(),
|
|
||||||
// BasePayApiEnum.REFUND.toString(),
|
|
||||||
// mchId,
|
|
||||||
// getSerialNumber(),
|
|
||||||
// getSerialNumber(),
|
|
||||||
// certKeyPath,
|
|
||||||
// info
|
|
||||||
// );
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// throw new RuntimeException(e);
|
|
||||||
// }
|
|
||||||
// log.info("统一退款响应 {}", response);
|
|
||||||
// String body = response.getBody();
|
|
||||||
// JSONObject jsonObject = JSONObject.parseObject(body);
|
|
||||||
// if ("ABNORMAL".equals(jsonObject.getString("status")) || response.getStatus() != 200) {
|
|
||||||
// throw new CzgException("退款异常," + jsonObject.getString("message"));
|
|
||||||
// }
|
|
||||||
// return jsonObject.getString("refund_id");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static String genCode(int shopId, int id, String path) {
|
|
||||||
// Map<String, Object> params = Map.of(
|
|
||||||
// "scene", "id=" + id + "&shopId=" + shopId,
|
|
||||||
// "page", path,
|
|
||||||
// "width", 430
|
|
||||||
// );
|
|
||||||
// var response = HttpRequest.post("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + getAccessToken(false))
|
|
||||||
// .body(JSONObject.toJSONString(params))
|
|
||||||
// .execute();
|
|
||||||
//
|
|
||||||
// byte[] bodyBytes = response.bodyBytes();
|
|
||||||
// String str = new String(bodyBytes);
|
|
||||||
// if (str.contains("errmsg")) {
|
|
||||||
// JSONObject json = JSONObject.parseObject(str);
|
|
||||||
// throw new CzgException(json.getString("errmsg"));
|
|
||||||
// }
|
|
||||||
// return "data:image/png;base64," + Base64.getEncoder().encodeToString(bodyBytes);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static String addProfitSharingUser(AddReceivers params) throws Exception {
|
|
||||||
// getPlatCert();
|
|
||||||
// params.setAppid(appId);
|
|
||||||
// if (params.getName() != null && !params.getName().isBlank()) {
|
|
||||||
// params.setName(encryptByPlatformCert(params.getName()));
|
|
||||||
// } else {
|
|
||||||
// params.setName(null);
|
|
||||||
// }
|
|
||||||
// log.info("添加分账方参数: {}", JSONObject.toJSONString(params));
|
|
||||||
// var response = WxPayApi.v3(
|
|
||||||
// RequestMethodEnum.POST,
|
|
||||||
// WxDomainEnum.CHINA.toString(),
|
|
||||||
// ProfitSharingApiEnum.PROFIT_SHARING_RECEIVERS_ADD.toString(),
|
|
||||||
// mchId,
|
|
||||||
// getSerialNumber(),
|
|
||||||
// platformCertNo,
|
|
||||||
// certKeyPath,
|
|
||||||
// JSONObject.toJSONString(params)
|
|
||||||
// );
|
|
||||||
// log.info("添加分账方响应 {}", response.getBody());
|
|
||||||
// JSONObject resp = JSONObject.parseObject(response.getBody());
|
|
||||||
// if (resp.containsKey("code")) {
|
|
||||||
// throw new CzgException("分账添加失败" + resp.getString("message"));
|
|
||||||
// }
|
|
||||||
// return resp.getString("account");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static JSONObject getMchConfig(String mchIdParam) throws Exception {
|
|
||||||
// var response = WxPayApi.v3(
|
|
||||||
// RequestMethodEnum.GET,
|
|
||||||
// WxDomainEnum.CHINA.toString(),
|
|
||||||
// String.format(ProfitSharingApiEnum.PROFIT_SHARING_MERCHANT_CONFIGS.toString(), mchIdParam),
|
|
||||||
// mchId,
|
|
||||||
// getSerialNumber(),
|
|
||||||
// getSerialNumber(),
|
|
||||||
// certKeyPath,
|
|
||||||
// ""
|
|
||||||
// );
|
|
||||||
// log.info("查询分账响应 {}", response.getBody());
|
|
||||||
// JSONObject resp = JSONObject.parseObject(response.getBody());
|
|
||||||
// if (resp.containsKey("code")) {
|
|
||||||
// throw new CzgException("分账查询失败" + resp.getString("message"));
|
|
||||||
// }
|
|
||||||
// return resp;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * 获取可分账金额
|
|
||||||
// */
|
|
||||||
// public static BigDecimal getRemainAmount(String transactionId) {
|
|
||||||
// IJPayHttpResponse response;
|
|
||||||
// try {
|
|
||||||
// response = WxPayApi.v3(
|
|
||||||
// RequestMethodEnum.GET,
|
|
||||||
// WxDomainEnum.CHINA.toString(),
|
|
||||||
// String.format(ProfitSharingApiEnum.PROFIT_SHARING_UNFREEZE_QUERY.toString(), transactionId),
|
|
||||||
// mchId,
|
|
||||||
// getSerialNumber(),
|
|
||||||
// getSerialNumber(),
|
|
||||||
// certKeyPath,
|
|
||||||
// ""
|
|
||||||
// );
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// throw new RuntimeException(e);
|
|
||||||
// }
|
|
||||||
// log.info("查询可分账响应 {}", response.getBody());
|
|
||||||
// JSONObject resp = JSONObject.parseObject(response.getBody());
|
|
||||||
// if (resp.containsKey("code")) {
|
|
||||||
// throw new CzgException("分账查询失败" + resp.getString("message"));
|
|
||||||
// }
|
|
||||||
// return resp.getBigDecimal("unsplit_amount");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static void profitSharing(String transactionId, ReceiverModel... receivers) {
|
|
||||||
// for (ReceiverModel r : receivers) {
|
|
||||||
// if (r.getName() != null && !r.getName().isBlank()) {
|
|
||||||
// r.setName(encryptByPlatformCert(r.getName()));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// String tradeNo = IdUtil.simpleUUID();
|
|
||||||
// ProfitSharingModel model = new ProfitSharingModel();
|
|
||||||
// model.setAppid(appId);
|
|
||||||
// model.setTransaction_id(transactionId);
|
|
||||||
// model.setReceivers(List.of(receivers));
|
|
||||||
// model.setUnfreeze_unsplit(true);
|
|
||||||
// model.setOut_order_no(tradeNo);
|
|
||||||
//
|
|
||||||
// String params = JSONObject.toJSONString(model);
|
|
||||||
// log.info("分账参数: {}", params);
|
|
||||||
// IJPayHttpResponse response;
|
|
||||||
// try {
|
|
||||||
// response = WxPayApi.v3(
|
|
||||||
// RequestMethodEnum.POST,
|
|
||||||
// WxDomainEnum.CHINA.toString(),
|
|
||||||
// ProfitSharingApiEnum.PROFIT_SHARING_ORDERS.toString(),
|
|
||||||
// mchId,
|
|
||||||
// getSerialNumber(),
|
|
||||||
// platformCertNo,
|
|
||||||
// certKeyPath,
|
|
||||||
// params
|
|
||||||
// );
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// throw new RuntimeException(e);
|
|
||||||
// }
|
|
||||||
// log.info("分账响应 {}", response.getBody());
|
|
||||||
// JSONObject resp = JSONObject.parseObject(response.getBody());
|
|
||||||
// if (resp.containsKey("code")) {
|
|
||||||
// throw new CzgException("分账失败" + resp.getString("message") + ", 响应: " + resp.toJSONString());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static void unFreezeSharing(String transactionId, String orderNo) {
|
|
||||||
// com.ijpay.wxpay.model.ProfitSharingModel paramsModel = new com.ijpay.wxpay.model.ProfitSharingModel();
|
|
||||||
// paramsModel.setTransaction_id(transactionId);
|
|
||||||
// paramsModel.setOut_order_no(orderNo);
|
|
||||||
// paramsModel.setDescription("分账解冻");
|
|
||||||
// String params = JSONObject.toJSONString(paramsModel);
|
|
||||||
// log.info("分账解冻参数: {}", params);
|
|
||||||
// IJPayHttpResponse response;
|
|
||||||
// try {
|
|
||||||
// response = WxPayApi.v3(
|
|
||||||
// RequestMethodEnum.POST,
|
|
||||||
// WxDomainEnum.CHINA.toString(),
|
|
||||||
// ProfitSharingApiEnum.PROFIT_SHARING_UNFREEZE.toString(),
|
|
||||||
// mchId,
|
|
||||||
// getSerialNumber(),
|
|
||||||
// platformCertNo,
|
|
||||||
// certKeyPath,
|
|
||||||
// params
|
|
||||||
// );
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// throw new RuntimeException(e);
|
|
||||||
// }
|
|
||||||
// log.info("分账解冻响应 {}", response.getBody());
|
|
||||||
// JSONObject resp = JSONObject.parseObject(response.getBody());
|
|
||||||
// if (resp.containsKey("code")) {
|
|
||||||
// throw new CzgException("分账解冻失败" + resp.getString("message") + ", 响应: " + resp.toJSONString());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static JSONObject transferBalance(String openId, String name, BigDecimal amount, String remarkTxt, String billNoTxt) {
|
|
||||||
// String remark = remarkTxt == null ? "佣金" : remarkTxt;
|
|
||||||
// String billNo = billNoTxt == null ? IdUtil.simpleUUID() : billNoTxt;
|
|
||||||
// Map<String, Object> params = Map.of(
|
|
||||||
// "appid", appId,
|
|
||||||
// "out_bill_no", billNo,
|
|
||||||
// "transfer_scene_id", "1005",
|
|
||||||
// "openid", openId,
|
|
||||||
// "user_name", encryptByPlatformCert(name),
|
|
||||||
// "transfer_amount", amount.multiply(BigDecimal.valueOf(100)).intValue(),
|
|
||||||
// "transfer_remark", remark,
|
|
||||||
// "notify_url", transferNotifyUrl,
|
|
||||||
// "transfer_scene_report_infos", new Object[]{
|
|
||||||
// Map.of("info_type", "岗位类型", "info_content", "加盟商"),
|
|
||||||
// Map.of("info_type", "报酬说明", "info_content", "测试")
|
|
||||||
// }
|
|
||||||
// );
|
|
||||||
// log.info("转账到零钱参数: {}", JSONObject.toJSONString(params));
|
|
||||||
// IJPayHttpResponse response = null;
|
|
||||||
// try {
|
|
||||||
// response = WxPayApi.v3(
|
|
||||||
// RequestMethodEnum.POST,
|
|
||||||
// WxDomainEnum.CHINA.toString(),
|
|
||||||
// "/v3/fund-app/mch-transfer/transfer-bills",
|
|
||||||
// mchId,
|
|
||||||
// getSerialNumber(),
|
|
||||||
// platformCertNo,
|
|
||||||
// certKeyPath,
|
|
||||||
// JSONObject.toJSONString(params)
|
|
||||||
// );
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// throw new RuntimeException(e);
|
|
||||||
// }
|
|
||||||
// log.info("转账到零钱响应 {}", response.getBody());
|
|
||||||
// JSONObject resp = JSONObject.parseObject(response.getBody());
|
|
||||||
// if (resp.containsKey("code")) {
|
|
||||||
// throw new CzgException("转账到零钱失败" + resp.getString("message") + ", 响应: " + resp.toJSONString());
|
|
||||||
// }
|
|
||||||
// return resp;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
Reference in New Issue
Block a user