先学后付签约,核销,取消签约;调整云函数添加课卡

This commit is contained in:
DB 2024-01-20 22:03:35 +08:00
parent 792ac276c9
commit 394fa8d8be
24 changed files with 735 additions and 62 deletions

View File

@ -14,7 +14,7 @@ public interface CloudDbUrl {
/**
* 课卡相关云函数
*/
String COMMON_CARD_URL = BASE_URL + "/merchant_cloud";
String COMMON_USE_URL = BASE_URL + "/merchant_cloud";
/**
* 查询云数据专用

View File

@ -3,8 +3,6 @@ package com.cpop.api.cloudDb.core.dto;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import java.time.OffsetDateTime;
/**
* @author DB
* @version 1.0.0
@ -101,4 +99,75 @@ public class CloudClassCardDto {
@SerializedName("isDrainage")
private boolean isDrainageCard;
/**
* 实收金额
*/
@SerializedName("money")
private String payAmount;
/**
* 云校区id
*/
@SerializedName("storeId")
private String storeCloudId;
/**
* 客户手机号
*/
@SerializedName("phone")
private String customerPhone;
/**
* 模板id
*/
@SerializedName("templateId")
private String orderCloudId;
/**
* 订单来源
*/
private String orderSource;
/**
* 子商户
*/
private String subMchId;
/**
* 模板路径
*/
private String templateUrl;
/**
* 客户openid
*/
@SerializedName("openid")
private String openId;
/**
* 商户侧签约计划号
*/
private String merchantSignPlanNo;
/**
* 签约计划id
*/
private String signPlanId;
/**
* 计划id
*/
private String planId;
/**
* 每期课次
*/
private Integer classHour;
/**
* 签约计划详情,json格式
*/
@SerializedName("signedDetailList")
private String signPlanDetails;
}

View File

@ -4,9 +4,9 @@ import com.alibaba.fastjson.JSONObject;
import com.cpop.api.cloudDb.core.constant.CloudDbUrl;
import com.cpop.api.cloudDb.core.dto.CloudClassCardDto;
import com.cpop.api.cloudDb.core.dto.CloudClassCardRecordDto;
import com.cpop.api.cloudDb.core.dto.CloudClassStudentDto;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.entity.ExtendPage;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.base.exception.UtilException;
import com.mybatisflex.core.paginate.Page;
import org.springframework.beans.factory.annotation.Autowired;
@ -139,4 +139,27 @@ public class CloudClassCardHandler {
return page;
}
}
/**
* 添加课卡
* @author DB
* @since 2024/1/20
* @param dto 课卡中间表
* @return String
*/
public String insertCloudClassCard(CloudClassCardDto dto){
JSONObject jsonBody = JSONObject.parseObject(JSONObject.toJSONString(dto));
jsonBody.put("_type", "addPeriod");
JSONObject result = restTemplate.postForObject(CloudDbUrl.COMMON_USE_URL, jsonBody, JSONObject.class);
if (result != null) {
if (result.getBoolean("success")) {
return result.getString("data");
} else {
throw new UtilException(result.getString("error"));
}
} else {
throw new ServiceException("办卡失败!");
}
}
}

View File

@ -2,20 +2,13 @@ package com.cpop.api.cloudDb.handler;
import com.alibaba.fastjson.JSONObject;
import com.cpop.api.cloudDb.core.constant.CloudDbUrl;
import com.cpop.api.cloudDb.core.dto.CloudOrderDto;
import com.cpop.api.cloudDb.core.dto.CloudStoreDto;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.entity.ExtendPage;
import com.cpop.core.base.exception.UtilException;
import com.mybatisflex.core.paginate.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 云校区工具类
* @author DB
@ -54,7 +47,7 @@ public class CloudStoreHandler {
if (StringUtils.isNotBlank(dto.getStoreAddr())) {
jsonBody.put("address", dto.getStoreAddr());
}
JSONObject jsonObject = restTemplate.postForObject(CloudDbUrl.COMMON_CARD_URL, jsonBody, JSONObject.class);
JSONObject jsonObject = restTemplate.postForObject(CloudDbUrl.COMMON_USE_URL, jsonBody, JSONObject.class);
if (jsonObject != null) {
if (!jsonObject.getBoolean("success")) {
throw new UtilException(jsonObject.getString("error"));

View File

@ -14,9 +14,15 @@ public enum OrderSource {
MALL("Mall",0.002),
/**
* 微信支付
* 一次性支付
*/
EASY_LEARN("EasyLearn",0.002);
EASY_LEARN("EasyLearn",0.002),
/**
* 先学后付
*/
LEARN_NOW_PAY_LATER("LearnNowPayLater",0.06)
;
OrderSource(String name, Double rate) {
this.rate = rate;

View File

@ -61,4 +61,10 @@ public class LearnNowPayLaterPlanBo {
@ApiModelProperty("支付分计划明细列表")
private List<LearnNowPayLaterPlanDetailBo> planDetailList;
/**
* 课次
*/
@ApiModelProperty("支付分计划原总金额")
private String classHour;
}

View File

@ -0,0 +1,77 @@
package com.cpop.jambox.business.bo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-20 12:33
*/
@Data
@ApiModel(value = "先学后付用户核销")
public class LearnNowPayLaterServiceOrderBo {
/**
* 支付分订单在商户侧的订单号必须和创建签约计划时传入的该笔订单对应的商户侧计划明细使用订单号(merchant\_plan\_detail\_no)一致
*/
@NotBlank(message = "待创建服务订单对应的用户的签约计划不能为空")
@ApiModelProperty(value = "待创建服务订单对应的用户的签约计划",required = true)
private String signPlanId;
/**
* 待创建服务订单对应的用户的签约计划详情序号
*/
@NotNull(message = "planDetailNo不能为空")
@ApiModelProperty(value = "待创建服务订单对应的用户的签约计划详情序号",required = true)
private Integer planDetailNo;
/**
* 服务商公众号下的用户标识
*/
@NotBlank(message = "openid不能为空")
@ApiModelProperty(value = "服务商公众号下的用户标识",required = true)
private String openid;
/**
* 支付分订单在商户侧的订单号必须和创建签约计划时传入的该笔订单对应的商户侧计划明细使用订单号(merchant\_plan\_detail\_no)一致
*/
@NotBlank(message = "outTradeNo不能为空")
@ApiModelProperty(value = "支付分订单在商户侧的订单号,必须和创建签约计划时传入的该笔订单对应的商户侧计划明细使用订单号(merchant_plan_detail_no)一致",required = true)
private String outTradeNo;
/**
* 卡号
*/
@NotBlank(message = "cardNo不能为空")
@ApiModelProperty(value = "卡号",required = true)
private String cardNo;
/**
* 课程信息
*/
@NotBlank(message = "课程信息不能为空")
@ApiModelProperty(value = "课程信息",required = true)
private String serviceIntroduction;
/**
* 核销金额
*/
@NotNull(message = "核销金额不能为空")
@ApiModelProperty(value = "核销金额",required = true)
private Integer price;
/**
* 是否是旧卡
*/
@ApiModelProperty(value = "是否是旧卡")
private Boolean isOldCard;
}

View File

@ -0,0 +1,26 @@
package com.cpop.jambox.business.bo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-20 15:01
*/
@Data
@ApiModel(value = "停止用户签约计划")
public class LearnNowPayLaterStopUserSignPlansBo {
/**
* 签约计划id
*/
@ApiModelProperty(value = "签约计划id")
private String signPlanId;
/**
* 取消理由
*/
private String stopReason;
}

View File

@ -0,0 +1,56 @@
package com.cpop.jambox.business.bo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-19 22:40
*/
@Data
@ApiModel(value = "先学后付用户签约计划")
public class LearnNowPayLaterUserSignPlansBo {
/**
* 支付分id
*/
@NotBlank(message = "支付分id不能为空")
@ApiModelProperty(value = "支付分id",required = true)
private String id;
/**
* 云校区id
*/
@NotBlank(message = "云校区id不能为空")
@ApiModelProperty(value = "云校区id",required = true)
private String storeCloudId;
/**
* 子商户下用户openid
*/
@NotBlank(message = "子商户下用户openid不能为空")
@ApiModelProperty(value = "子商户下用户openid",required = true)
private String subOpenId;
/**
* 支付分计划名称
*/
@ApiModelProperty("支付分计划名称")
private String planName;
/**
* 客户名
*/
@ApiModelProperty("客户名")
private String customerName;
/**
* 客户手机号
*/
@ApiModelProperty("客户手机号")
private String customerPhone;
}

View File

@ -0,0 +1,51 @@
package com.cpop.jambox.business.controller.callback;
import com.cpop.jambox.business.service.EasyLearnOrderService;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author DB
* @version 1.0.0
* @since 2024-01-20 0:22
*/
@RestController
@Api(tags = "果酱-放心学回调接口")
@RequestMapping("/callback/easyLearn")
public class CallBackEasyLearnController {
@Autowired
private EasyLearnOrderService easyLearnOrderService;
/**
* 用户签约成功回调
* @author DB
* @since 2024/1/20
* @param notifyData 返回参数
*/
@ApiOperation("放心学先学后付支付分回调通知")
@PostMapping("/learnNowPayLaterUserSignPlanNotify")
public String learnNowPayLaterUserSignPlanNotifyUrl(@RequestBody String notifyData) {
easyLearnOrderService.learnNowPayLaterUserSignPlanNotify(notifyData);
return WxPayNotifyResponse.success("成功");
}
/**
* 支付分用户核销成功回调
* @author DB
* @since 2024/1/20
* @param notifyData 返回参数
*/
@ApiOperation("支付分用户核销成功回调")
@PostMapping("/userServiceOrderSuccess")
public String userServiceOrderSuccess(@RequestBody String notifyData) {
easyLearnOrderService.userServiceOrderSuccess(notifyData);
return WxPayNotifyResponse.success("成功");
}
}

View File

@ -46,4 +46,6 @@ public class EasyLearnCallBackController {
return WxPayNotifyResponse.success("成功");
}
}

View File

@ -1,6 +1,5 @@
package com.cpop.jambox.business.controller.mini;
import com.cpop.core.annontation.SimpleSignatureCheck;
import com.cpop.core.base.R;
import com.cpop.core.utils.SpringUtils;
import com.cpop.jambox.business.bo.CardTemplateUnionBo;
@ -9,7 +8,6 @@ import com.cpop.jambox.business.service.CardTemplateExtendService;
import com.cpop.jambox.business.service.CardTemplateService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.ibatis.annotations.Delete;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -26,7 +24,7 @@ import static com.cpop.jambox.business.entity.table.CardTemplateTableDef.CARD_TE
@RestController
@Api(tags = "果酱-课卡模板接口")
@RequestMapping("/mini/cardTemplate")
public class CardTemplateController {
public class MiniCardTemplateController {
@Autowired
private CardTemplateService cardTemplateService;

View File

@ -1,14 +1,19 @@
package com.cpop.jambox.business.controller.mini;
import com.cpop.core.base.R;
import com.cpop.jambox.business.bo.LearnNowPayLaterServiceOrderBo;
import com.cpop.jambox.business.bo.LearnNowPayLaterStopUserSignPlansBo;
import com.cpop.jambox.business.bo.LearnNowPayLaterUserSignPlansBo;
import com.cpop.jambox.business.service.CardTemplateService;
import com.cpop.jambox.business.service.EasyLearnOrderService;
import com.cpop.jambox.business.vo.LearnNowPayLaterPlanDetailVo;
import com.cpop.jambox.business.vo.LearnNowPayLaterPlanVo;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreSignPlanResult;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreUserSignPlanResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
@ -46,25 +51,42 @@ public class MiniEasyLearnController {
/**
* 获取支付分计划
*
* @param oldTemplateId 旧模板id
* @param isMonth 是否月付
* @param bo 请求参数
* @return R<LearnNowPayLaterPlanDetailVo>
* @author DB
* @since 2024/1/18
*/
@ApiOperation("创建用户签约计划")
@PostMapping("/createUserSignPlans")
public R<Void> createUserSignPlans(@ApiParam(value = "旧模板id", required = true) @RequestParam("oldTemplateId") String oldTemplateId,
@ApiParam(value = "是否月付(0否1是)", required = true) @RequestParam("isMonth") Boolean isMonth) {
return R.ok();
public R<WxPartnerPayScoreUserSignPlanResult> createUserSignPlans(@RequestBody @Validated LearnNowPayLaterUserSignPlansBo bo) {
WxPartnerPayScoreUserSignPlanResult result = easyLearnOrderService.createUserSignPlans(bo);
return R.ok(result);
}
/**
* 创建用户服务订单(核销)
* @author DB
* @since 2024/1/20
* @param bo 请求参数
*/
@ApiOperation("创建用户服务订单(核销)")
@PostMapping("/createServiceOrder")
public R<Void> createServiceOrder() {
public R<WxPartnerPayScoreSignPlanResult> createServiceOrder(@RequestBody @Validated LearnNowPayLaterServiceOrderBo bo) {
WxPartnerPayScoreSignPlanResult result = easyLearnOrderService.createServiceOrder(bo);
return R.ok(result);
}
/**
* 取消用户签约计划
* @author DB
* @since 2024/1/20
* @param bo 请求参数
* @return R<Void>
*/
@ApiOperation("取消用户签约计划")
@PostMapping("/stopUserSignPlans/{signPlanId}")
public R<Void> stopUserSignPlans(@RequestBody @Validated LearnNowPayLaterStopUserSignPlansBo bo){
easyLearnOrderService.stopUserSignPlans(bo);
return R.ok();
}
}

View File

@ -4,6 +4,8 @@ import com.cpop.jambox.business.bo.*;
import com.cpop.jambox.business.dto.EasyLearnPageDto;
import com.cpop.jambox.business.entity.EasyLearnOrder;
import com.cpop.jambox.business.vo.EasyLearnPageVo;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreSignPlanResult;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreUserSignPlanResult;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
@ -75,4 +77,44 @@ public interface EasyLearnOrderService extends IService<EasyLearnOrder> {
*/
Object unifiedPay(EasyLearnUnifiedPayBo bo);
/**
* 创建用户签约计划
* @author DB
* @since 2024/1/19
* @param bo 请求参数
*/
WxPartnerPayScoreUserSignPlanResult createUserSignPlans(LearnNowPayLaterUserSignPlansBo bo);
/**
* 用户签约成功回调
* @author DB
* @since 2024/1/20
* @param notifyData 返回参数
*/
void learnNowPayLaterUserSignPlanNotify(String notifyData);
/**
* 创建用户服务订单(核销)
* @author DB
* @since 2024/1/20
* @param bo 请求参数
* @return WxPartnerPayScoreSignPlanResult
*/
WxPartnerPayScoreSignPlanResult createServiceOrder(LearnNowPayLaterServiceOrderBo bo);
/**
* 支付分用户核销成功回调
* @author DB
* @since 2024/1/20
* @param notifyData 返回数据
*/
void userServiceOrderSuccess(String notifyData);
/**
* 取消用户签约计划
* @author DB
* @since 2024/1/20
* @param bo 请求参数
*/
void stopUserSignPlans(LearnNowPayLaterStopUserSignPlansBo bo);
}

View File

@ -19,6 +19,7 @@ import com.cpop.jambox.business.vo.LearnNowPayLaterPlanDetailVo;
import com.cpop.jambox.business.vo.LearnNowPayLaterPlanVo;
import com.cpop.jambox.framework.tasks.LearnNowPayLaterTask;
import com.cpop.system.business.entity.Store;
import com.cpop.system.business.entity.WxPayScore;
import com.cpop.system.business.entity.WxPayScoreDetail;
import com.cpop.system.business.service.StoreService;
import com.cpop.system.business.service.WxPayScoreDetailService;
@ -288,12 +289,12 @@ public class CardTemplateServiceImpl extends ServiceImpl<CardTemplateMapper, Car
CardTemplateExtend cardTemplateExtend = cardTemplateExtendService.getOne(QueryWrapper.create()
.where(CARD_TEMPLATE_EXTEND.TEMPLATE_ID.eq(cardTemplate.getId()))
.and(CARD_TEMPLATE_EXTEND.PAY_TYPE.eq(isMonth ? 5 : 1)));
LearnNowPayLaterPlanVo vo = SpringUtils.getBean(WxPayScoreService.class).getOneAs(QueryWrapper.create()
.where(WX_PAY_SCORE.ID.eq(cardTemplateExtend.getExtendId())),
LearnNowPayLaterPlanVo.class);
List<LearnNowPayLaterPlanDetailVo> detailVos = SpringUtils.getBean(WxPayScoreDetailService.class).listAs(QueryWrapper.create()
.where(WX_PAY_SCORE_DETAIL.SYS_WX_PAY_SCORE_ID.eq(vo.getId())),
LearnNowPayLaterPlanDetailVo.class);
WxPayScore wxPayScore = SpringUtils.getBean(WxPayScoreService.class).getOne(QueryWrapper.create()
.where(WX_PAY_SCORE.ID.eq(cardTemplateExtend.getExtendId())));
LearnNowPayLaterPlanVo vo = BeanUtils.mapToClass(wxPayScore, LearnNowPayLaterPlanVo.class);
List<WxPayScoreDetail> wxPayScoreDetails = SpringUtils.getBean(WxPayScoreDetailService.class).list(QueryWrapper.create()
.where(WX_PAY_SCORE_DETAIL.SYS_WX_PAY_SCORE_ID.eq(vo.getId())));
List<LearnNowPayLaterPlanDetailVo> detailVos = BeanUtils.mapToList(wxPayScoreDetails, LearnNowPayLaterPlanDetailVo.class);
vo.setPlanDetailList(detailVos);
return vo;
}

View File

@ -1,6 +1,9 @@
package com.cpop.jambox.business.service.impl;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cpop.api.cloudDb.core.dto.CloudClassCardDto;
import com.cpop.api.cloudDb.handler.CloudClassCardHandler;
import com.cpop.common.utils.StringUtils;
import com.cpop.common.utils.bean.BeanUtils;
import com.cpop.common.utils.http.HttpUtils;
@ -15,11 +18,12 @@ import com.cpop.core.utils.sql.SqlUtils;
import com.cpop.jambox.business.bo.*;
import com.cpop.jambox.business.dto.EasyLearnPageDto;
import com.cpop.jambox.business.entity.BrandExtend;
import com.cpop.jambox.business.entity.CardTemplate;
import com.cpop.jambox.business.entity.EasyLearnOrder;
import com.cpop.jambox.business.entity.EasyLearnOrderDetail;
import com.cpop.jambox.business.entity.StoreExtend;
import com.cpop.jambox.business.mapper.EasyLearnOrderMapper;
import com.cpop.jambox.business.service.BrandExtendService;
import com.cpop.jambox.business.service.EasyLearnOrderDetailService;
import com.cpop.jambox.business.service.EasyLearnOrderService;
import com.cpop.jambox.business.service.StoreExtendService;
import com.cpop.jambox.business.vo.EasyLearnPageVo;
@ -30,11 +34,18 @@ import com.cpop.pay.framewok.config.wxPay.WxPayConfiguration;
import com.cpop.pay.framewok.handler.wxPay.WxPayHandler;
import com.cpop.pay.framewok.task.WxPayAsyncTask;
import com.cpop.system.business.entity.Store;
import com.cpop.system.business.entity.WxPayScore;
import com.cpop.system.business.entity.WxPayScoreDetail;
import com.cpop.system.business.service.StoreService;
import com.cpop.system.business.service.WxPayScoreDetailService;
import com.cpop.system.business.service.WxPayScoreService;
import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.payscore.*;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.PartnerPayScoreSignPlanService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.mybatisflex.core.FlexGlobalConfig;
import com.mybatisflex.core.datasource.DataSourceKey;
@ -53,13 +64,19 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import static com.cpop.jambox.business.entity.table.BrandExtendTableDef.BRAND_EXTEND;
import static com.cpop.jambox.business.entity.table.EasyLearnOrderDetailTableDef.EASY_LEARN_ORDER_DETAIL;
import static com.cpop.jambox.business.entity.table.EasyLearnOrderTableDef.EASY_LEARN_ORDER;
import static com.cpop.jambox.business.entity.table.StoreExtendTableDef.STORE_EXTEND;
import static com.cpop.system.business.entity.table.StoreTableDef.STORE;
import static com.cpop.system.business.entity.table.WxPayScoreDetailTableDef.WX_PAY_SCORE_DETAIL;
/**
* 果酱-放心学订单表 服务层实现
@ -77,6 +94,9 @@ public class EasyLearnOrderServiceImpl extends ServiceImpl<EasyLearnOrderMapper,
@Autowired
private WxPayAsyncTask wxPayAsyncTask;
@Autowired
private WxPayConfiguration wxPayConfiguration;
/**
* 一次性支付回调地址本地内网穿透
*/
@ -388,6 +408,7 @@ public class EasyLearnOrderServiceImpl extends ServiceImpl<EasyLearnOrderMapper,
}
//课卡信息
JSONObject jsonBody = new JSONObject();
jsonBody.put("_type", "addPeriod");
//办卡实收金额
jsonBody.put("money", easyLearnOrder.getTotalPayAmount());
@ -654,5 +675,252 @@ public class EasyLearnOrderServiceImpl extends ServiceImpl<EasyLearnOrderMapper,
return null;
}
/**
* 创建用户签约计划
* @author DB
* @since 2024/1/19
* @param bo 请求参数
*/
@Override
@Transactional(rollbackFor = Exception.class)
public WxPartnerPayScoreUserSignPlanResult createUserSignPlans(LearnNowPayLaterUserSignPlansBo bo) {
// 获取计划
WxPayScore wxPayScore = SpringUtils.getBean(WxPayScoreService.class).getById(bo.getId());
//获取计划详情
List<WxPayScoreDetail> wxPayScoreDetails = SpringUtils.getBean(WxPayScoreDetailService.class).queryChain()
.where(WX_PAY_SCORE_DETAIL.SYS_WX_PAY_SCORE_ID.eq(bo.getId()))
.list();
Row brandAndStore = Db.selectOneByQuery(QueryWrapper.create()
.select(STORE.ID,STORE.BRAND_ID)
.leftJoin(STORE_EXTEND).on(STORE_EXTEND.STORE_ID.eq(STORE.ID))
.where(STORE_EXTEND.STORE_CLOUD_ID.eq(bo.getStoreCloudId())));
//创建用户签约计划
String orderId = createEasyLearnUserSignPlans(bo, brandAndStore, wxPayScore);
String subMchId = wxPayHandler.getSubMchId(brandAndStore.getString("brandId"), brandAndStore.getString("id"));
WxPayService wxPayService = wxPayHandler.getWxPayService(null, subMchId);
PartnerPayScoreSignPlanService partnerPayScoreSignPlanService = wxPayService.getPartnerPayScoreSignPlanService();
List<PayScorePlanDetailRequest> payScorePlanDetailRequests = BeanUtils.mapToList(wxPayScoreDetails, PayScorePlanDetailRequest.class);
WxPartnerPayScoreSignPlanRequest signPlanRequest = new WxPartnerPayScoreSignPlanRequest();
signPlanRequest.setPlanId(wxPayScore.getOutPlanId()).setSubAppid(subMchId)
.setSubOpenid(bo.getSubOpenId())
.setMerchantSignPlanNo(orderId)
.setPlanDetailList(payScorePlanDetailRequests)
.setNotifyUrl(wxPayConfiguration.getProperties().getLearnNowPayLaterUserSignPlanNotifyUrl());
try {
return partnerPayScoreSignPlanService.createUserSignPlans(signPlanRequest);
} catch (WxPayException e) {
throw new ServiceException(e.getMessage());
}
}
/**
* 创建用户支付计划
* @author DB
* @since 2024/1/19
* @param wxPayScore 支付分
* @return String
*/
private String createEasyLearnUserSignPlans(LearnNowPayLaterUserSignPlansBo bo, Row brandAndStore, WxPayScore wxPayScore) {
EasyLearnOrder easyLearnOrder = new EasyLearnOrder();
easyLearnOrder.setBrandId(brandAndStore.getString("brandId"))
.setStoreId(brandAndStore.getString("id"))
.setOrderContent(bo.getPlanName())
.setOrderStatus(0)
.setCustomerName(bo.getCustomerName())
.setCustomerPhone(bo.getCustomerPhone())
.setTotalAmount(new BigDecimal(wxPayScore.getTotalOriginalPrice()).divide(BigDecimal.valueOf(100)))
.setTotalPayAmount(BigDecimal.ZERO)
.setOrderType(0)
.setRate(OrderSource.LEARN_NOW_PAY_LATER.getRate());
this.save(easyLearnOrder);
return easyLearnOrder.getId();
}
/**
* 用户签约成功回调
* @author DB
* @since 2024/1/20
* @param notifyData 响应数据
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void learnNowPayLaterUserSignPlanNotify(String notifyData) {
try {
PayScoreNotifyData payScoreNotifyData = JSONObject.parseObject(notifyData, PayScoreNotifyData.class);
PartnerPayScoreSignPlanService partnerPayScoreSignPlanService = wxPayHandler.getWxPayService().getPartnerPayScoreSignPlanService();
SignatureHeader signatureHeader = wxPayHandler.getSignatureHeader();
PartnerUserSignPlanEntity result = partnerPayScoreSignPlanService.parseSignPlanNotifyResult(notifyData, signatureHeader);
String orderId = result.getMerchantSignPlanNo();
EasyLearnOrder easyLearnOrder = this.getById(orderId);
//支付成功
if (StringUtils.equals("PAYSCORE.USER_SIGN_PLAN", payScoreNotifyData.getEventType())) {
//订单已支付
if (easyLearnOrder.getOrderStatus() == 1){
return;
}
easyLearnOrder.setOrderStatus(1).setOutOrderNo(result.getSignPlanId());
//添加支付分详情
List<EasyLearnOrderDetail> easyLearnOrderDetails = new ArrayList<>();
result.getSignedDetailList().forEach(item->{
EasyLearnOrderDetail easyLearnOrderDetail = new EasyLearnOrderDetail();
easyLearnOrderDetail.setOrderId(easyLearnOrder.getId())
.setPeriodNo(item.getPlanDetailNo())
.setAmount(new BigDecimal(item.getOriginalPrice()).divide(BigDecimal.valueOf(100)))
.setDetailDesc(item.getPlanDiscountDescription())
.setActualPrice(new BigDecimal(item.getActualPrice()).divide(BigDecimal.valueOf(100)))
.setDetailStatus(0)
.setOutOrderNo(item.getOrderId())
.setDetailName(item.getPlanDetailName());
easyLearnOrderDetails.add(easyLearnOrderDetail);
});
SpringUtils.getBean(EasyLearnOrderDetailService.class).saveBatch(easyLearnOrderDetails);
//云办卡
CloudClassCardDto dto = new CloudClassCardDto();
//TODO: 模板路径的用途
//dto.setTemplateUrl();
//jsonObject.put("templateUrl", templateUrl);
// jsonObject.put("templateUrl", "https://test.cpopsz.com/test/ass/");
// jsonObject.put("templateUrl","https://api.jamboxsys.com/jambox/ass/");
// 办卡
dto.setOpenId(result.getSubOpenid());
dto.setMerchantSignPlanNo(result.getMerchantSignPlanNo());
dto.setSignPlanId(result.getSignPlanId());
//TODO: 模板id
//dto.setOrderCloudId(easyLearnOrder);
StoreExtend storeExtend = SpringUtils.getBean(StoreExtendService.class).queryChain()
.where(STORE_EXTEND.STORE_ID.eq(easyLearnOrder.getStoreId()))
.one();
dto.setStoreCloudId(storeExtend.getStoreCloudId());
dto.setCustomerPhone(easyLearnOrder.getCustomerPhone());
dto.setCustomerName(easyLearnOrder.getCustomerName());
dto.setPlanId(result.getPlanId());
dto.setSignPlanDetails(JSONArray.toJSONString(result.getSignedDetailList()));
//TODO: 课次
String cloudCardId = SpringUtils.getBean(CloudClassCardHandler.class).insertCloudClassCard(dto);
easyLearnOrder.setProductId(cloudCardId);
this.updateById(easyLearnOrder);
} else if (StringUtils.equals("PAYSCORE.USER_CANCEL_SIGN_PLAN", payScoreNotifyData.getEventType())){
//取消合约
easyLearnOrder.setOrderStatus(2);
this.updateById(easyLearnOrder);
//批量修改订单详情状态
SpringUtils.getBean(EasyLearnOrderDetailService.class).updateChain()
.set(EASY_LEARN_ORDER_DETAIL.DETAIL_STATUS, 3)
.where(EASY_LEARN_ORDER_DETAIL.ORDER_ID.eq(easyLearnOrder.getId()))
.and(EASY_LEARN_ORDER_DETAIL.DETAIL_STATUS.eq(0))
.update();
//TODO: 通知波哥取消课卡
}
} catch (WxPayException e) {
throw new ServiceException(e.getMessage());
}
}
/**
* 创建用户服务订单(核销)
* @author DB
* @since 2024/1/20
* @param bo 请求参数
* @return WxPartnerPayScoreSignPlanResult
*/
@Override
@Transactional(rollbackFor = Exception.class)
public WxPartnerPayScoreSignPlanResult createServiceOrder(LearnNowPayLaterServiceOrderBo bo) {
EasyLearnOrder easyLearnOrder = this.queryChain().where(EASY_LEARN_ORDER.OUT_ORDER_NO.eq(bo.getSignPlanId())).one();
EasyLearnOrderDetailService easyLearnOrderDetailService = SpringUtils.getBean(EasyLearnOrderDetailService.class);
EasyLearnOrderDetail easyLearnOrderDetail = easyLearnOrderDetailService.queryChain()
.where(EASY_LEARN_ORDER_DETAIL.ORDER_ID.eq(easyLearnOrder.getId()))
.and(EASY_LEARN_ORDER_DETAIL.PERIOD_NO.eq(bo.getPlanDetailNo()))
.one();
String subMchId = wxPayHandler.getSubMchId(easyLearnOrder.getBrandId(), easyLearnOrder.getStoreId());
WxPayService wxPayService = wxPayHandler.getWxPayService(null, subMchId);
PartnerPayScoreSignPlanService partnerPayScoreSignPlanService = wxPayService.getPartnerPayScoreSignPlanService();
WxPartnerPayScoreSignPlanRequest signPlanRequest = new WxPartnerPayScoreSignPlanRequest();
signPlanRequest.setSignPlanId(easyLearnOrder.getOutOrderNo())
.setPlanDetailNo(easyLearnOrderDetail.getPeriodNo())
.setSubMchid(subMchId)
.setSubOpenid(bo.getOpenid())
.setNotifyUrl(wxPayConfiguration.getProperties().getLearnNowPayLaterServiceOrderNotifyUrl())
.setServiceIntroduction(easyLearnOrderDetail.getDetailDesc());
TimeRange timeRange = new TimeRange();
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter yyyyMMddHHmmss = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
String startTime = now.plusSeconds(10).format(yyyyMMddHHmmss);
timeRange.setStartTime(startTime);
String endTime = now.plusSeconds(60).format(yyyyMMddHHmmss);
timeRange.setEndTime(endTime);
signPlanRequest.setTimeRange(timeRange)
.setOutOrderNo(easyLearnOrderDetail.getId());
easyLearnOrderDetail.setDetailStatus(1);
easyLearnOrderDetailService.updateById(easyLearnOrderDetail);
try {
return partnerPayScoreSignPlanService.signPlanServiceOrder(signPlanRequest);
} catch (WxPayException e) {
throw new ServiceException(e.getMessage());
}
}
/**
* 支付分用户核销成功回调
* @author DB
* @since 2024/1/20
* @param notifyData 返回数据
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void userServiceOrderSuccess(String notifyData) {
try {
WxPayOrderNotifyResult notifyResult = wxPayHandler.getWxPayService().parseOrderNotifyResult(notifyData);
EasyLearnOrderDetailService easyLearnOrderDetailService = SpringUtils.getBean(EasyLearnOrderDetailService.class);
EasyLearnOrderDetail easyLearnOrderDetail = easyLearnOrderDetailService.queryChain()
.where(EASY_LEARN_ORDER_DETAIL.ORDER_ID.eq(notifyResult.getOutTradeNo()))
.and(EASY_LEARN_ORDER_DETAIL.OUT_ORDER_NO.eq(notifyResult.getTransactionId()))
.one();
EasyLearnOrder easyLearnOrder = this.getById(easyLearnOrderDetail.getOrderId());
//需要分账
String subMchId = wxPayHandler.getSubMchId(easyLearnOrder.getBrandId(), easyLearnOrder.getStoreId());
if (notifyResult.getTotalFee() >= Math.ceil(1 / OrderSource.EASY_LEARN.getRate())) {
//设置子商户
WxPayService wxPayService = wxPayHandler.getWxPayService(null, subMchId);
wxPayAsyncTask.asyncWxPayProfitSharing(notifyResult.getOutTradeNo(), notifyResult, wxPayService, OrderSource.LEARN_NOW_PAY_LATER);
}
BigDecimal payAmount = new BigDecimal(notifyResult.getTotalFee()).divide(BigDecimal.valueOf(100));
easyLearnOrderDetail.setDetailStatus(2)
.setActualPrice(payAmount);
easyLearnOrderDetailService.updateById(easyLearnOrderDetail);
//修改订单实际支付金额
easyLearnOrder.setTotalPayAmount(easyLearnOrder.getTotalPayAmount() == null ? payAmount : easyLearnOrder.getTotalPayAmount().add(payAmount));
this.updateById(easyLearnOrder);
} catch (WxPayException e) {
throw new ServiceException(e.getMessage());
}
}
/**
* 取消用户签约计划
* @author DB
* @since 2024/1/20
* @param bo 请求参数
*/
@Override
public void stopUserSignPlans(LearnNowPayLaterStopUserSignPlansBo bo) {
EasyLearnOrder easyLearnOrder = this.queryChain().where(EASY_LEARN_ORDER.OUT_ORDER_NO.eq(bo.getSignPlanId())).one();
String subMchId = wxPayHandler.getSubMchId(easyLearnOrder.getBrandId(), easyLearnOrder.getStoreId());
WxPayService wxPayService = wxPayHandler.getWxPayService(null, subMchId);
try {
wxPayService.getPartnerPayScoreSignPlanService().stopUserSignPlans(easyLearnOrder.getId(), subMchId, bo.getStopReason());
//取消合约
easyLearnOrder.setOrderStatus(2);
this.updateById(easyLearnOrder);
//批量修改订单详情状态
SpringUtils.getBean(EasyLearnOrderDetailService.class).updateChain()
.set(EASY_LEARN_ORDER_DETAIL.DETAIL_STATUS, 3)
.where(EASY_LEARN_ORDER_DETAIL.ORDER_ID.eq(easyLearnOrder.getId()))
.and(EASY_LEARN_ORDER_DETAIL.DETAIL_STATUS.eq(0))
.update();
//TODO: 通知波哥取消课卡
} catch (WxPayException e) {
throw new ServiceException(e.getMessage());
}
}
}

View File

@ -37,7 +37,7 @@ public class LearnNowPayLaterPlanDetailVo {
@ApiModelProperty("计划明细实际支付金额(单位分)")
private BigDecimal actualPrice;
public void setActualPrice(Integer actualPrice) {
public void setActualPrice(Long actualPrice) {
this.actualPrice = new BigDecimal(actualPrice).divide(BigDecimal.valueOf(100));
}
@ -46,4 +46,10 @@ public class LearnNowPayLaterPlanDetailVo {
*/
@ApiModelProperty("计划明细名称")
private String planDetailName;
/**
* 签约计划编号
*/
@ApiModelProperty("签约计划编号")
private Integer planDetailNo;
}

View File

@ -1,6 +1,5 @@
package com.cpop.jambox.framework.tasks;
import com.alibaba.fastjson.JSONArray;
import com.cpop.common.utils.StringUtils;
import com.cpop.common.utils.bean.BeanUtils;
import com.cpop.core.base.exception.ServiceException;
@ -33,7 +32,6 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.List;
import static com.cpop.jambox.business.entity.table.CardTemplateExtendTableDef.CARD_TEMPLATE_EXTEND;
import static com.cpop.system.business.entity.table.WxPayScoreTableDef.WX_PAY_SCORE;
/**
@ -64,7 +62,7 @@ public class LearnNowPayLaterTask {
String subMchId = wxPayHandler.getSubMchId(cardTemplate.getBrandId(), cardTemplate.getStoreId());
//录入计划与详情
WxPayScore wxPayScore = BeanUtils.mapToClass(bo, WxPayScore.class);
wxPayScore.setSignAccount(subMchId);
wxPayScore.setSignAccount(subMchId).setClassHour(bo.getClassHour());
WxPayScoreService wxPayScoreService = SpringUtils.getBean(WxPayScoreService.class);
wxPayScoreService.save(wxPayScore);
//创建计划

View File

@ -108,3 +108,7 @@ wx:
privateKeyPath: E:/Cpop/Cpop-Union/Cpop-Core/src/main/resources/static/keyPair/wxPay_key.pem
# 私钥文件
privateCertPath: E:/Cpop/Cpop-Union/Cpop-Core/src/main/resources/static/keyPair/wxPay_cert.pem
# 先学后付用户签约通知地址
learn-now-pay-later-user-sign-plan-notify-url:
# 先学后付用户核销通知地址
learn-now-pay-later-service-order-notify-url:

View File

@ -1,12 +1,15 @@
package com.cpop.oam.web;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.cpop.common.utils.StringUtils;
import com.cpop.core.utils.SpringUtils;
import com.cpop.jambox.business.entity.*;
import com.cpop.jambox.business.service.*;
import com.cpop.oam.business.service.StaffService;
import com.cpop.jambox.business.entity.BrandExtend;
import com.cpop.jambox.business.entity.CardTemplate;
import com.cpop.jambox.business.entity.CardTemplateExtend;
import com.cpop.jambox.business.entity.StoreExtend;
import com.cpop.jambox.business.service.BrandExtendService;
import com.cpop.jambox.business.service.CardTemplateExtendService;
import com.cpop.jambox.business.service.CardTemplateService;
import com.cpop.jambox.business.service.StoreExtendService;
import com.cpop.system.business.entity.Store;
import com.cpop.system.business.entity.StoreSign;
import com.cpop.system.business.entity.WxPayScore;
@ -15,18 +18,15 @@ import com.cpop.system.business.service.StoreService;
import com.cpop.system.business.service.StoreSignService;
import com.cpop.system.business.service.WxPayScoreService;
import com.mybatisflex.core.datasource.DataSourceKey;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.DbChain;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.row.RowUtil;
import com.mybatisflex.core.update.UpdateChain;
import org.apache.poi.ss.formula.functions.T;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import java.security.PublicKey;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
@ -46,7 +46,7 @@ import static com.mybatisflex.core.query.QueryMethods.max;
* @since 2024-01-16 17:17
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles(profiles = {"prod", "core"})
@ActiveProfiles(profiles = {"prod", "core", "pay"})
public class CpopDataSyncTests {
/**
@ -139,7 +139,6 @@ public class CpopDataSyncTests {
.setPayType(4);
cardTemplateExtends.add(cardTemplateExtend);
}
});
List<CardTemplate> entityList = RowUtil.toEntityList(rowList, CardTemplate.class);
SpringUtils.getBean(CardTemplateService.class).saveBatch(entityList);
@ -172,7 +171,8 @@ public class CpopDataSyncTests {
if (StringUtils.isNotBlank(row.getString("oncePlanId"))){
WxPayScore oncePlan = wxPayScoreMap.get(row.getString("oncePlanId"));
if (oncePlan != null){
cardTemplateExtend.setExtendId(oncePlan.getId())
cardTemplateExtend.setTemplateId(row.getString("oldTemplateId"))
.setExtendId(oncePlan.getId())
.setPayType(1);
cardTemplateExtends.add(cardTemplateExtend);
}
@ -192,7 +192,8 @@ public class CpopDataSyncTests {
if (StringUtils.isNotBlank(row.getString("monthPlanId"))){
WxPayScore monthPlan = wxPayScoreMap.get(row.getString("monthPlanId"));
if (monthPlan != null){
cardTemplateExtend.setExtendId(monthPlan.getId())
cardTemplateExtend.setTemplateId(row.getString("oldTemplateId"))
.setExtendId(monthPlan.getId())
.setPayType(5);
cardTemplateExtends.add(cardTemplateExtend);
}

View File

@ -90,4 +90,14 @@ public class WxPayProperties {
* 服务商模式下的子商户公众账号ID
*/
private String serviceAppId;
/**
* 先学后付用户签约计划通知地址
*/
private String learnNowPayLaterUserSignPlanNotifyUrl;
/**
* 先学后付用户支付成功通知地址
*/
private String learnNowPayLaterServiceOrderNotifyUrl;
}

View File

@ -1,27 +1,21 @@
package com.cpop.pay.framewok.handler.wxPay;
import com.alibaba.fastjson.JSONObject;
import com.cpop.common.utils.ServletUtils;
import com.cpop.common.utils.StringUtils;
import com.cpop.common.utils.bean.BeanUtils;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.base.exception.UtilException;
import com.cpop.core.utils.SecurityUtils;
import com.cpop.pay.framewok.core.dto.LearnNowPayLaterPlanDto;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreSignPlanRequest;
import com.github.binarywang.wxpay.bean.payscore.WxPartnerPayScoreSignPlanResult;
import com.github.binarywang.wxpay.bean.ecommerce.SignatureHeader;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.PartnerPayScoreSignPlanService;
import com.github.binarywang.wxpay.service.WxPayService;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.row.RowKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import javax.servlet.http.HttpServletRequest;
/**
* @author DB
@ -29,6 +23,7 @@ import java.util.ArrayList;
* @description
*/
@Component
@Slf4j
public class WxPayHandler {
@Autowired
@ -141,4 +136,20 @@ public class WxPayHandler {
return wxMchId;
}
/**
* 获取签约头
* @author DB
* @since 2024/1/20
* @return SignatureHeader
*/
public SignatureHeader getSignatureHeader() {
HttpServletRequest request = ServletUtils.getRequest();
SignatureHeader signatureHeader = new SignatureHeader();
signatureHeader.setSigned(request.getHeader("Wechatpay-Signature"));
signatureHeader.setNonce(request.getHeader("Wechatpay-Nonce"));
signatureHeader.setSerialNo(request.getHeader("Wechatpay-Serial"));
signatureHeader.setTimeStamp(request.getHeader("Wechatpay-Timestamp"));
log.info("微信支付分回调ID:{}",request.getHeader("Request-ID"));
return signatureHeader;
}
}

View File

@ -142,7 +142,7 @@ public class WxPayAsyncTask {
throw new ServiceException(profitSharingResult.getReturnMsg());
}
} catch (WxPayException e) {
if (flag > 5) {
if (flag > 2) {
if (OrderSource.MALL == orderSource) {
//关闭商城支付
DbChain.table("cp_sys_brand")

View File

@ -6,13 +6,11 @@ import com.cpop.core.base.entity.BaseUpdateListener;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.*;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* 微信支付分计划表 实体类
*
@ -74,6 +72,11 @@ public class WxPayScore extends BaseEntity implements Serializable {
*/
private String planSource;
/**
* 课次
*/
private String classHour;
/**
* 逻辑删除0否1是
*/