diff --git a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/bo/EasyLearnUnionPayBo.java b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/bo/EasyLearnUnionPayBo.java new file mode 100644 index 0000000..20bef40 --- /dev/null +++ b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/bo/EasyLearnUnionPayBo.java @@ -0,0 +1,84 @@ +package com.cpop.jambox.business.bo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; + +/** + * @author DB + * @version 1.0.0 + * @since 2023-12-28 15:44 + */ +@Data +@Accessors(chain = true) +@ApiModel(value = "EasyLearnUnionPayBo对象", description = "统一支付参数") +public class EasyLearnUnionPayBo { + + /** + * 品牌或校区id + */ + @NotBlank(message = "云品牌或云校区id不能为空") + @ApiModelProperty(value = "云品牌或云校区id",required = true) + private String brandOrStoreCloudId; + + /** + * 联合支付外部订单id + */ + @NotBlank(message = "联合支付外部订单id不能为空") + @ApiModelProperty(value = "联合支付外部订单id",required = true) + private String unionPayOutOrderId; + + /** + * 客户名 + */ + @NotBlank(message = "客户名不能为空") + @ApiModelProperty(value = "客户名",required = true) + private String customerName; + + /** + * 客户电话 + */ + @NotBlank(message = "客户电话不能为空") + @ApiModelProperty(value = "客户电话",required = true) + private String customerPhone; + + /** + * 总金额 + */ + @NotNull(message = "总金额不能为空") + @ApiModelProperty(value = "总金额",required = true) + private BigDecimal totalAmount; + + /** + * 总支付金额 + */ + @NotNull(message = "总支付金额不能为空") + @ApiModelProperty(value = "总支付金额",required = true) + private BigDecimal totalPayAmount; + + /** + * 订单类型 + */ + @NotNull(message = "联合支付类型不能为空") + @ApiModelProperty(value = "联合支付类型(PREPAYMENT:预付;REPAYMENT:还款;MEMBER:会员)",required = true) + private String easyLearnUnionPay; + + /** + * 分账比率 + */ + @ApiModelProperty(value = "分账比率(不传不分帐)") + private Double rate; + + /** + * openId + */ + @NotBlank(message = "openId不能为空") + @ApiModelProperty(value = "openId", required = true) + private String openId; + +} diff --git a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/controller/backstage/EasyLearnController.java b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/controller/backstage/EasyLearnController.java index be01110..e5ad979 100644 --- a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/controller/backstage/EasyLearnController.java +++ b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/controller/backstage/EasyLearnController.java @@ -3,6 +3,7 @@ package com.cpop.jambox.business.controller.backstage; import com.alibaba.excel.EasyExcel; import com.cpop.core.base.R; import com.cpop.jambox.business.bo.EasyLearnPageBo; +import com.cpop.jambox.business.bo.EasyLearnUnionPayBo; import com.cpop.jambox.business.bo.OncePlaceOrderBo; import com.cpop.jambox.business.dto.EasyLearnPageDto; import com.cpop.jambox.business.service.EasyLearnOrderService; @@ -98,4 +99,17 @@ public class EasyLearnController { public R oncePlaceOrder(@RequestBody @Validated @ApiParam("一次性支付") OncePlaceOrderBo bo) { return R.ok(easyLearnOrderService.oncePlaceOrder(bo)); } + + /** + * 放心学统一支付 + * @author DB + * @since 2023/12/28 + * @param bo 请求参数 + * @return R + */ + @PostMapping("/unionPay") + @ApiOperation("放心学统一支付") + public R unionPay(@RequestBody @Validated @ApiParam("一次性支付") EasyLearnUnionPayBo bo) { + return R.ok(easyLearnOrderService.unionPay(bo)); + } } diff --git a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/controller/callback/EasyLearnCallBackController.java b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/controller/callback/EasyLearnCallBackController.java index 069cd56..51fd1e3 100644 --- a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/controller/callback/EasyLearnCallBackController.java +++ b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/controller/callback/EasyLearnCallBackController.java @@ -35,4 +35,15 @@ public class EasyLearnCallBackController { return WxPayNotifyResponse.success("成功"); } + /** + * 微信支付联合支付订单通知 + * @param xmlData 数据 + * @return java.lang.String + */ + @PostMapping("/notify/unionPay") + public String unionPay(@RequestBody String xmlData){ + easyLearnOrderService.unionPayResult(xmlData); + return WxPayNotifyResponse.success("成功"); + } + } diff --git a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/entity/EasyLearnOrder.java b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/entity/EasyLearnOrder.java index a1ab76c..fe57dfd 100644 --- a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/entity/EasyLearnOrder.java +++ b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/entity/EasyLearnOrder.java @@ -38,6 +38,11 @@ public class EasyLearnOrder extends BaseEntity implements Serializable { */ private Integer orderStatus; + /** + * 联合支付外部订单id + */ + private String unionPayOutOrderId; + /** * 云id */ @@ -98,6 +103,11 @@ public class EasyLearnOrder extends BaseEntity implements Serializable { */ private Integer orderType; + /** + * 分账比例 + */ + private Double rate; + /** * 逻辑删除(0否1是) */ diff --git a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/entity/StorePlug.java b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/entity/StorePlug.java new file mode 100644 index 0000000..0ea54b6 --- /dev/null +++ b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/entity/StorePlug.java @@ -0,0 +1,61 @@ +package com.cpop.jambox.business.entity; + +import com.cpop.core.base.entity.BaseEntity; +import com.cpop.core.base.entity.BaseInsertListener; +import com.cpop.core.base.entity.BaseUpdateListener; +import com.mybatisflex.annotation.Column; +import com.mybatisflex.annotation.Id; +import com.mybatisflex.annotation.Table; +import lombok.*; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * 校区-插件记录表 实体类。 + * + * @author DB + * @since 2023-12-29 + */ +@Data +@EqualsAndHashCode(callSuper=false) +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +@Table(value = "cp_j_store_plug", onInsert = BaseInsertListener.class, onUpdate = BaseUpdateListener.class, mapperGenerateEnable = false) +public class StorePlug extends BaseEntity implements Serializable { + + /** + * 主键 + */ + @Id + private String id; + + /** + * 校区id + */ + private String storeId; + + /** + * 插件标记 + */ + private String plugTag; + + /** + * 备注 + */ + private String remarks; + + /** + * 是否开启 + */ + private Boolean isOpen; + + /** + * 逻辑删除(0否1是) + */ + @Column(isLogicDelete = true) + private Boolean isDelete; + +} diff --git a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/mapper/StorePlugMapper.java b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/mapper/StorePlugMapper.java new file mode 100644 index 0000000..52cc995 --- /dev/null +++ b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/mapper/StorePlugMapper.java @@ -0,0 +1,14 @@ +package com.cpop.jambox.business.mapper; + +import com.mybatisflex.core.BaseMapper; +import com.cpop.jambox.business.entity.StorePlug; + +/** + * 校区-插件记录表 映射层。 + * + * @author DB + * @since 2023-12-29 + */ +public interface StorePlugMapper extends BaseMapper { + +} diff --git a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/service/EasyLearnOrderService.java b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/service/EasyLearnOrderService.java index e1a7d7f..2f7728e 100644 --- a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/service/EasyLearnOrderService.java +++ b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/service/EasyLearnOrderService.java @@ -1,6 +1,7 @@ package com.cpop.jambox.business.service; import com.cpop.jambox.business.bo.EasyLearnPageBo; +import com.cpop.jambox.business.bo.EasyLearnUnionPayBo; import com.cpop.jambox.business.bo.OncePlaceOrderBo; import com.cpop.jambox.business.dto.EasyLearnPageDto; import com.cpop.jambox.business.entity.EasyLearnOrder; @@ -51,4 +52,19 @@ public interface EasyLearnOrderService extends IService { * @param bo 下单请求对象 */ Object oncePlaceOrder(OncePlaceOrderBo bo); + + /** + * 放心学统一支付 + * @author DB + * @since 2023/12/28 + * @param bo 请求参数 + * @return R + */ + Object unionPay(EasyLearnUnionPayBo bo); + + /** + * 微信支付联合支付订单通知 + * @param xmlData 数据 + */ + void unionPayResult(String xmlData); } diff --git a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/service/StorePlugService.java b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/service/StorePlugService.java new file mode 100644 index 0000000..8c05675 --- /dev/null +++ b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/service/StorePlugService.java @@ -0,0 +1,26 @@ +package com.cpop.jambox.business.service; + +import com.cpop.jambox.business.vo.StorePlugListVo; +import com.mybatisflex.core.service.IService; +import com.cpop.jambox.business.entity.StorePlug; + +import java.util.List; + +/** + * 校区-插件记录表 服务层。 + * + * @author DB + * @since 2023-12-29 + */ +public interface StorePlugService extends IService { + + /** + * 查询校区插件列表 + * @author DB + * @since 2023/12/29 + * @param brandId 品牌 + * @param storeId 校区 + * @return List + */ + List getStorePlugList(String brandId, String storeId); +} diff --git a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/service/impl/EasyLearnOrderServiceImpl.java b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/service/impl/EasyLearnOrderServiceImpl.java index 1c754bf..73d7940 100644 --- a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/service/impl/EasyLearnOrderServiceImpl.java +++ b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/service/impl/EasyLearnOrderServiceImpl.java @@ -3,6 +3,7 @@ package com.cpop.jambox.business.service.impl; import com.alibaba.fastjson.JSONObject; import com.cpop.common.utils.StringUtils; import com.cpop.common.utils.bean.BeanUtils; +import com.cpop.common.utils.http.HttpUtils; import com.cpop.common.utils.ip.IpUtils; import com.cpop.core.base.entity.PageDomain; import com.cpop.core.base.enums.OrderSource; @@ -12,6 +13,7 @@ import com.cpop.core.utils.SecurityUtils; import com.cpop.core.utils.SpringUtils; import com.cpop.core.utils.sql.SqlUtils; import com.cpop.jambox.business.bo.EasyLearnPageBo; +import com.cpop.jambox.business.bo.EasyLearnUnionPayBo; import com.cpop.jambox.business.bo.OncePlaceOrderBo; import com.cpop.jambox.business.dto.EasyLearnPageDto; import com.cpop.jambox.business.entity.BrandExtend; @@ -24,9 +26,12 @@ import com.cpop.jambox.business.service.StoreExtendService; import com.cpop.jambox.business.vo.EasyLearnPageVo; import com.cpop.jambox.framework.constant.JamboxCloudUrl; import com.cpop.jambox.framework.constant.JamboxRedisConstant; +import com.cpop.jambox.framework.enums.EasyLearnPayPayEnum; 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.service.StoreService; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; import com.github.binarywang.wxpay.config.WxPayConfig; @@ -45,8 +50,10 @@ import com.zaxxer.hikari.HikariDataSource; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.client.RestTemplate; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.locks.Lock; @@ -374,15 +381,12 @@ public class EasyLearnOrderServiceImpl extends ServiceImpl= Math.ceil(1 / OrderSource.EASY_LEARN.getRate())) { //设置子商户 WxPayConfig config = wxPayService.getConfig(); config.setSubMchId(subMchId); wxPayAsyncTask.asyncWxPayProfitSharing(orderId, notifyResult, wxPayService, OrderSource.EASY_LEARN); } - //更新订单 - this.updateChain().set(EASY_LEARN_ORDER.OUT_ORDER_NO, notifyResult.getTransactionId()).where(EASY_LEARN_ORDER.ID.eq(orderId)).update(); //课卡信息 JSONObject jsonBody = new JSONObject(); jsonBody.put("_type", "addPeriod"); @@ -407,8 +411,11 @@ public class EasyLearnOrderServiceImpl extends ServiceImpl= Math.ceil(1 / OrderSource.EASY_LEARN.getRate())) { + easyLearnOrder.setRate(OrderSource.EASY_LEARN.getRate()); + } this.save(easyLearnOrder); } else { if (easyLearnOrder.getOrderStatus() == 1){ @@ -453,7 +464,8 @@ public class EasyLearnOrderServiceImpl extends ServiceImpl= Math.ceil(1 / OrderSource.EASY_LEARN.getRate())) { + if (easyLearnOrder.getRate() != null) { //需要分账 orderRequest.setProfitSharing("Y"); } @@ -487,4 +498,147 @@ public class EasyLearnOrderServiceImpl extends ServiceImpl + */ + @Override + @Transactional(rollbackFor = Exception.class) + public Object unionPay(EasyLearnUnionPayBo bo) { + //分布式锁进行幂等处理 + RedisService redisService = SpringUtils.getBean(RedisService.class); + //分布式锁进行幂等处理 + Lock userIdLock = redisService.distributedLock(JamboxRedisConstant.ONCE_PAY_LOCK_USER_PAY + bo.getCustomerPhone()); + if (userIdLock.tryLock()) { + try { + //创建订单 + EasyLearnOrder easyLearnOrder = BeanUtils.mapToClass(bo, EasyLearnOrder.class); + //获取校区 + StoreExtend storeExtend = SpringUtils.getBean(StoreExtendService.class).queryChain().where(STORE_EXTEND.STORE_CLOUD_ID.eq(bo.getBrandOrStoreCloudId())).one(); + //获取品牌 + BrandExtend brandExtend; + if (storeExtend == null) { + brandExtend = SpringUtils.getBean(BrandExtendService.class).queryChain().where(BRAND_EXTEND.BRAND_CLOUD_ID.eq(bo.getBrandOrStoreCloudId())).one(); + easyLearnOrder.setBrandId(brandExtend.getBrandId()); + } else { + //获取品牌 + Store store = SpringUtils.getBean(StoreService.class).getById(storeExtend.getStoreId()); + easyLearnOrder.setBrandId(store.getBrandId()); + easyLearnOrder.setStoreId(storeExtend.getStoreId()); + } + EasyLearnPayPayEnum easyLearnPayPayEnum = EasyLearnPayPayEnum.valueOf(bo.getEasyLearnUnionPay()); + easyLearnOrder.setOrderType(easyLearnPayPayEnum.getOrderType()); + this.save(easyLearnOrder); + String payNotifyUrl; + if (StringUtils.equals("prod", SpringUtils.getActiveProfile())) { + //联合支付 + payNotifyUrl = SpringUtils.getBean(WxPayConfiguration.class).getProperties().getEasyLearnUnionPayNotifyUrl(); + } else if (StringUtils.equals("test", SpringUtils.getActiveProfile())){ + payNotifyUrl = UNION_PAY_TEST_NOTIFY_URL; + } else { + payNotifyUrl = UNION_PAY_DEV_NOTIFY_URL; + } + //获取商户信息 + WxPayService wxPayService = wxPayHandler.getWxPayService(null, wxPayHandler.getSubMchId(easyLearnOrder.getBrandId(), easyLearnOrder.getStoreId()), payNotifyUrl); + WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest(); + //需要分账 + if (easyLearnOrder.getRate() != null && easyLearnOrder.getTotalAmount().scaleByPowerOfTen(2).intValue() >= Math.ceil(1 / easyLearnOrder.getRate())) { + //需要分账 + orderRequest.setProfitSharing("Y"); + } + orderRequest.setSpbillCreateIp(IpUtils.getHostIp()) + .setOpenid(bo.getOpenId()) + //商品描述 + .setBody("一次性支付") + .setOutTradeNo(easyLearnOrder.getId()) + //元转分 + .setTotalFee(easyLearnOrder.getTotalAmount().scaleByPowerOfTen(2).intValue()) + .setTradeType("JSAPI"); + return wxPayService.createOrder(orderRequest); + } catch (Exception e) { + throw new ServiceException(e.getMessage()); + } finally { + //释放锁 + userIdLock.unlock(); + } + } else { + //获取锁失败,直接返回空 + throw new ServiceException("请勿重复支付"); + } + } + + /** + * 果酱通知地址(本地) + */ + private final String UNION_PAY_DEV_JAMBOX_NOTIFY_URL = "http://localhost:8078/test/ass/jambox/contract/unionPayNotify"; + + /** + * 果酱通知地址(测试地址) + */ + private final String UNION_PAY_TEST_JAMBOX_NOTIFY_URL = "https://test.cpopsz.com/test/ass/jambox/contract/unionPayNotify"; + + /** + * 果酱通知地址(线上) + */ + private final String UNION_PAY_PROD_JAMBOX_NOTIFY_URL = "https://api.jamboxsys.com/jambox/ass/jambox/contract/unionPayNotify"; + + /** + * 微信支付联合支付订单通知 + * @param xmlData 数据 + */ + @Override + public void unionPayResult(String xmlData) { + try { + WxPayService wxPayService = wxPayHandler.getWxPayService(); + WxPayOrderNotifyResult notifyResult = wxPayService.parseOrderNotifyResult(xmlData); + if (!StringUtils.equals(notifyResult.getResultCode(), "SUCCESS")) { + throw new ServiceException(notifyResult.getReturnMsg()); + } + String orderId = notifyResult.getOutTradeNo(); + //获取订单信息 + EasyLearnOrder easyLearnOrder = this.getById(orderId); + if (easyLearnOrder.getRate() != null && easyLearnOrder.getTotalAmount().scaleByPowerOfTen(2).intValue() >= Math.ceil(1 / easyLearnOrder.getRate())) { + //设置子商户 + WxPayConfig config = wxPayService.getConfig(); + //需要分账 + String subMchId = wxPayHandler.getSubMchId(easyLearnOrder.getBrandId(), easyLearnOrder.getStoreId()); + config.setSubMchId(subMchId); + wxPayAsyncTask.asyncWxPayProfitSharing(orderId, notifyResult, wxPayService, OrderSource.EASY_LEARN, easyLearnOrder.getRate()); + } + JSONObject jsonObject = new JSONObject(); + EasyLearnPayPayEnum easyLearnPayPayEnum = EasyLearnPayPayEnum.getEasyLearnPayPayEnum(easyLearnOrder.getOrderType()); + jsonObject.put("wxOrderId", easyLearnOrder.getId()); + jsonObject.put("unionPayOutOrderId", easyLearnOrder.getUnionPayOutOrderId()); + jsonObject.put("easyLearnUnionPay", easyLearnPayPayEnum.toString()); + String url; + if (StringUtils.equals("prod", SpringUtils.getActiveProfile())) { + url = UNION_PAY_PROD_JAMBOX_NOTIFY_URL; + } else if (StringUtils.equals("test", SpringUtils.getActiveProfile())) { + url = UNION_PAY_TEST_JAMBOX_NOTIFY_URL; + } else { + url = UNION_PAY_DEV_JAMBOX_NOTIFY_URL; + } + HttpUtils.sendOkHttpPost(url, jsonObject.toJSONString()); + //更新订单 + this.updateChain().set(EASY_LEARN_ORDER.OUT_ORDER_NO, notifyResult.getTransactionId()) + .set(EASY_LEARN_ORDER.ORDER_STATUS, 1) + .where(EASY_LEARN_ORDER.ID.eq(orderId)).update(); + } catch (WxPayException | IOException e) { + throw new ServiceException(e.getMessage()); + } + } } diff --git a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/service/impl/StorePlugServiceImpl.java b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/service/impl/StorePlugServiceImpl.java new file mode 100644 index 0000000..a336d12 --- /dev/null +++ b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/service/impl/StorePlugServiceImpl.java @@ -0,0 +1,77 @@ +package com.cpop.jambox.business.service.impl; + +import com.cpop.common.utils.StringUtils; +import com.cpop.jambox.business.entity.StorePlug; +import com.cpop.jambox.business.mapper.StorePlugMapper; +import com.cpop.jambox.business.service.StorePlugService; +import com.cpop.jambox.business.vo.StorePlugListVo; +import com.mybatisflex.core.datasource.DataSourceKey; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.core.row.Db; +import com.mybatisflex.core.row.Row; +import com.mybatisflex.spring.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static com.cpop.jambox.business.entity.table.StorePlugTableDef.STORE_PLUG; + +/** + * 校区-插件记录表 服务层实现。 + * + * @author DB + * @since 2023-12-29 + */ +@Service("storePlugService") +public class StorePlugServiceImpl extends ServiceImpl implements StorePlugService { + + /** + * 查询校区插件列表 + * + * @param brandId 品牌 + * @param storeId 校区 + * @return List + * @author DB + * @since 2023/12/29 + */ + @Override + public List getStorePlugList(String brandId, String storeId) { + if (StringUtils.isBlank(brandId) || StringUtils.isBlank(storeId)) { + return new ArrayList<>(); + } + List rows; + try { + DataSourceKey.use("jambox"); + rows = Db.selectListByQuery("t_application_info", QueryWrapper.create() + .select("application", "char_tag as plugTag", "pic", "tag", "status","creation_time as listingTime") + .from("t_application_info") + .where("char_tag IS NOT NULL")); + } finally { + DataSourceKey.clear(); + } + if (!rows.isEmpty()) { + Map rowsMap = rows.stream().collect(Collectors.toMap(item -> item.getString("plugTag"), item -> item)); + List storePlugListVos = this.listAs(QueryWrapper.create() + .select(STORE_PLUG.PLUG_TAG, STORE_PLUG.ID, STORE_PLUG.CREATE_TIME,STORE_PLUG.IS_OPEN) + .where(STORE_PLUG.STORE_ID.eq(storeId)), + StorePlugListVo.class); + storePlugListVos.forEach(item -> { + if (rowsMap.get(item.getPlugTag()) != null) { + Row row = rowsMap.get(item.getPlugTag()); + item.setListingTime(row.getLocalDateTime("listingTime")); + item.setPlugName(row.getString("application")); + item.setPlugType("tag"); + } + }); + return storePlugListVos; + } else { + return new ArrayList<>(); + } + } + + + +} diff --git a/Cpop-Jambox/src/main/java/com/cpop/jambox/business/vo/StorePlugListVo.java b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/vo/StorePlugListVo.java new file mode 100644 index 0000000..8cb4722 --- /dev/null +++ b/Cpop-Jambox/src/main/java/com/cpop/jambox/business/vo/StorePlugListVo.java @@ -0,0 +1,70 @@ +package com.cpop.jambox.business.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +/** + * @author DB + * @version 1.0.0 + * @since 2023-12-29 16:36 + */ +@Data +@Accessors(chain = true) +@ApiModel(value = "StorePlugListVo对象") +public class StorePlugListVo { + + /** + * 主键 + */ + @ApiModelProperty("主键") + private String id; + + /** + * 插件标记 + */ + @ApiModelProperty("插件标记") + private String plugTag; + + /** + * 插件名 + */ + @ApiModelProperty("插件名") + private String plugName; + + /** + * 插件类型 + */ + @ApiModelProperty("插件类型") + private String plugType; + + /** + * 备注 + */ + @ApiModelProperty("备注") + private String remarks; + + /** + * 最后修改时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" , timezone = "GMT+8") + @ApiModelProperty("上架时间") + private LocalDateTime listingTime; + + /** + * 最后修改时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss" , timezone = "GMT+8") + @ApiModelProperty("开启时间") + private LocalDateTime createTime; + + /** + * 是否开启 + */ + @ApiModelProperty("是否开启") + private Boolean isOpen; +} diff --git a/Cpop-Jambox/src/main/java/com/cpop/jambox/framework/enums/EasyLearnPayPayEnum.java b/Cpop-Jambox/src/main/java/com/cpop/jambox/framework/enums/EasyLearnPayPayEnum.java new file mode 100644 index 0000000..395ed92 --- /dev/null +++ b/Cpop-Jambox/src/main/java/com/cpop/jambox/framework/enums/EasyLearnPayPayEnum.java @@ -0,0 +1,56 @@ +package com.cpop.jambox.framework.enums; + +import lombok.Getter; + +/** + * @author DB + * @version 1.0.0 + * @since 2023-12-28 16:23 + */ +@Getter +public enum EasyLearnPayPayEnum { + + /** + * 预付 + */ + PREPAYMENT("Prepayment",5), + + /** + * 还款 + */ + REPAYMENT("Repayment",6), + + /** + * 会员 + */ + MEMBER("MEMBER",7);; + + EasyLearnPayPayEnum(String name, Integer orderType) { + this.orderType = orderType; + this.name = name; + } + + /** + * 分账比例 + */ + private Integer orderType; + + private String name; + + public void setOrderType(Integer orderType) { + this.orderType = orderType; + } + + public void setName(String name) { + this.name = name; + } + + public static EasyLearnPayPayEnum getEasyLearnPayPayEnum(int orderType) { + for (EasyLearnPayPayEnum c : EasyLearnPayPayEnum.values()) { + if (c.orderType == orderType) { + return c; + } + } + return null; + } +} diff --git a/Cpop-Jambox/src/main/resources/application-jambox.yml b/Cpop-Jambox/src/main/resources/application-jambox.yml index 6ffa629..0415f39 100644 --- a/Cpop-Jambox/src/main/resources/application-jambox.yml +++ b/Cpop-Jambox/src/main/resources/application-jambox.yml @@ -1,4 +1,8 @@ wx: pay: #支付通知地址 - notify-url: https://oamapi.cpopsz.com/Cpop-Oam/easyLearn/callback/notify/oncePay \ No newline at end of file + notify-url: https://oamapi.cpopsz.com/Cpop-Oam/easyLearn/callback/notify/oncePay + #支付通知地址 + easy-learn-once-pay-notify-url: https://oamapi.cpopsz.com/Cpop-Oam/easyLearn/callback/notify/oncePay + #放心学联合支付 + easy-learn-union-pay-notify-url: https://oamapi.cpopsz.com/Cpop-Oam/easyLearn/callback/notify/unionPay diff --git a/Cpop-Jambox/src/main/resources/mapper/StorePlugMapper.xml b/Cpop-Jambox/src/main/resources/mapper/StorePlugMapper.xml new file mode 100644 index 0000000..11a4440 --- /dev/null +++ b/Cpop-Jambox/src/main/resources/mapper/StorePlugMapper.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/Cpop-Mall/Cpop-Mall-Web/src/test/java/com/cpop/mall/web/CpopWxPayTests.java b/Cpop-Mall/Cpop-Mall-Web/src/test/java/com/cpop/mall/web/CpopWxPayTests.java index eff2ed7..3b39e21 100644 --- a/Cpop-Mall/Cpop-Mall-Web/src/test/java/com/cpop/mall/web/CpopWxPayTests.java +++ b/Cpop-Mall/Cpop-Mall-Web/src/test/java/com/cpop/mall/web/CpopWxPayTests.java @@ -9,6 +9,7 @@ import com.github.binarywang.wxpay.bean.profitsharing.ProfitSharingQueryResult; import com.github.binarywang.wxpay.bean.profitsharing.ProfitSharingReceiverRequest; import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingResult; import com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingReturnRequest; +import com.github.binarywang.wxpay.bean.request.WxPayOrderReverseRequest; import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request; import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult; import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result; @@ -50,13 +51,13 @@ public class CpopWxPayTests { WxPayRefundV3Request.Amount amount = new WxPayRefundV3Request.Amount(); //退款金额(单位分) //int refund = order.getTotalAmount().scaleByPowerOfTen(2).intValue(); - int refund = 500; + int refund = 101; amount.setRefund(refund) .setTotal(refund) .setCurrency("CNY"); request.setSubMchid(wxPayService.getConfig().getSubMchId()) - .setTransactionId("4200002091202312282284574621") - .setOutTradeNo("97795855209209856") + .setTransactionId("4200002126202312283733408828") + .setOutTradeNo("97945790336548864") //.setTransactionId(order.getOutOrderNo()) //.setOutTradeNo(order.getId()) .setNotifyUrl(wxPayProperties.getNotifyRefund()) @@ -80,16 +81,28 @@ public class CpopWxPayTests { //ProfitSharing profitSharing = SpringUtils.getBean(ProfitSharingService.class).getById("77860920238751744"); //profitSharingReturnRequest.setOrderId(profitSharing.getOutProfitSharingId()); //profitSharingReturnRequest.setOutReturnNo(profitSharing.getId()); - profitSharingReturnRequest.setOrderId("30000502582023122858656805224"); - profitSharingReturnRequest.setOutReturnNo("97795889866743808"); + profitSharingReturnRequest.setOrderId("30001002562023122858679309202"); + profitSharingReturnRequest.setOutReturnNo("97948799695069184"); profitSharingReturnRequest.setDescription("分账退款"); profitSharingReturnRequest.setSubMchId("1661323640"); profitSharingReturnRequest.setReturnMchid("1618884922"); //profitSharingReturnRequest.setAmount(profitSharing.getAmount()); - profitSharingReturnRequest.setAmount(1L); + profitSharingReturnRequest.setAmount(6L); wxPayService.getProfitSharingV3Service().profitSharingReturn(profitSharingReturnRequest); } + /** + * 取消订单 + * @throws WxPayException + */ + @Test + public void reverse() throws WxPayException { + WxPayOrderReverseRequest wxPayOrderReverseRequest = new WxPayOrderReverseRequest(); + wxPayOrderReverseRequest.setOutTradeNo("97945902236385280"); + wxPayOrderReverseRequest.setSubMchId("1661323640"); + wxPayService.reverseOrder(wxPayOrderReverseRequest); + } + /** * @descriptions 添加分账接收方 * @author DB @@ -121,8 +134,8 @@ public class CpopWxPayTests { @Test public void getOrderInfo() throws WxPayException { WxPayConfig config = wxPayService.getConfig(); - config.setSubMchId("1661807764"); - WxPayOrderQueryResult wxPayOrderQueryResult = wxPayService.queryOrder("4200002028202312069539269015", null); + config.setSubMchId("1661323640"); + WxPayOrderQueryResult wxPayOrderQueryResult = wxPayService.queryOrder(null, "97976926051770368"); System.out.println(wxPayOrderQueryResult); } @@ -148,8 +161,8 @@ public class CpopWxPayTests { * @return: void */ @Test - public void getRefundResult() throws WxPayException { - ProfitSharingResult profitSharingResult = wxPayService.getProfitSharingV3Service().getProfitSharingResult("84052505520087040", "4200002010202311202693854147", "1659765332"); + public void getProfitSharingResult() throws WxPayException { + ProfitSharingResult profitSharingResult = wxPayService.getProfitSharingV3Service().getProfitSharingResult("97976952480079872", "4200002127202312282719627535", "1661323640"); System.out.println(profitSharingResult); } @@ -160,10 +173,10 @@ public class CpopWxPayTests { @Test public void profitSharingFinish() throws WxPayException { ProfitSharingFinishRequest profitSharingFinishRequest = new ProfitSharingFinishRequest(); - profitSharingFinishRequest.setTransactionId("4200002028202312069539269015"); - profitSharingFinishRequest.setOutOrderNo("89825115260416000"); + profitSharingFinishRequest.setTransactionId("4200002093202312282215936862"); + profitSharingFinishRequest.setOutOrderNo("97973671418667008"); profitSharingFinishRequest.setDescription("结束分账"); - profitSharingFinishRequest.setSubMchId("1661807764"); + profitSharingFinishRequest.setSubMchId("1661323640"); wxPayService.getProfitSharingService().profitSharingFinish(profitSharingFinishRequest); } diff --git a/Cpop-Oam/Cpop-Oam-Web/src/main/resources/application-dev.yml b/Cpop-Oam/Cpop-Oam-Web/src/main/resources/application-dev.yml index 20804ad..5cabdb2 100644 --- a/Cpop-Oam/Cpop-Oam-Web/src/main/resources/application-dev.yml +++ b/Cpop-Oam/Cpop-Oam-Web/src/main/resources/application-dev.yml @@ -4,7 +4,7 @@ cpop: profile: E:/Cpop/uploadPath jwt: #白名单 - whiteList: /websocket/*,/login,/getCaptcha,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources,/wxCp/*,/wxCp/portal/*/registerCode,/sysCommon/miniSyncBrandAndStore,/easyLearn/callback/**,/easyLearn/oncePlaceOrder + whiteList: /websocket/*,/login,/getCaptcha,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources,/wxCp/*,/wxCp/portal/*/registerCode,/sysCommon/miniSyncBrandAndStore,/easyLearn/callback/*/*,/easyLearn/* gateway: rsa-keypair: # 公钥文件 diff --git a/Cpop-Oam/Cpop-Oam-Web/src/main/resources/application-prod.yml b/Cpop-Oam/Cpop-Oam-Web/src/main/resources/application-prod.yml index 71ab860..234e7f4 100644 --- a/Cpop-Oam/Cpop-Oam-Web/src/main/resources/application-prod.yml +++ b/Cpop-Oam/Cpop-Oam-Web/src/main/resources/application-prod.yml @@ -4,7 +4,7 @@ cpop: profile: /root/cpop-union/cpop-oam/upload jwt: #白名单 - whiteList: /websocket/*,/login,/getCaptcha,/profile/**,/wxOpen/receiveTicket,/wxOpen/*/callback,/wxOpen/bindOpenAccount/*,/wxCp/portal/*,/wxCp/*,/wxCp/portal/*/registerCode,/sysCommon/miniSyncBrandAndStore,/easyLearn/callback/**,/easyLearn/oncePlaceOrder + whiteList: /websocket/*,/login,/getCaptcha,/profile/**,/wxOpen/receiveTicket,/wxOpen/*/callback,/wxOpen/bindOpenAccount/*,/wxCp/portal/*,/wxCp/*,/wxCp/portal/*/registerCode,/sysCommon/miniSyncBrandAndStore,/easyLearn/callback/*/*,/easyLearn/* #拦截 gateway: rsa-keypair: diff --git a/Cpop-Oam/Cpop-Oam-Web/src/main/resources/application-test.yml b/Cpop-Oam/Cpop-Oam-Web/src/main/resources/application-test.yml index 5a63257..8f005b9 100644 --- a/Cpop-Oam/Cpop-Oam-Web/src/main/resources/application-test.yml +++ b/Cpop-Oam/Cpop-Oam-Web/src/main/resources/application-test.yml @@ -4,7 +4,7 @@ cpop: profile: /root/cpop-union/cpop-mall/upload jwt: #白名单 - whiteList: /websocket/*,/login,/getCaptcha,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources,/wxOpen/receiveTicket,/wxOpen/*/callback,/wxOpen/bindOpenAccount/*,/wxCp/portal/*,/wxCp/portal/*/registerCode,/wxCp/*,/sysCommon/miniSyncBrandAndStore,/easyLearn/callback/**,/easyLearn/oncePlaceOrder + whiteList: /websocket/*,/login,/getCaptcha,/profile/**,/doc.html,/webjars/**,/favicon.ico,/v2/api-docs/**,/swagger-resources,/wxOpen/receiveTicket,/wxOpen/*/callback,/wxOpen/bindOpenAccount/*,/wxCp/portal/*,/wxCp/portal/*/registerCode,/wxCp/*,/sysCommon/miniSyncBrandAndStore,/easyLearn/callback/*/*,/easyLearn/* #拦截 gateway: rsa-keypair: diff --git a/Cpop-Oam/Cpop-Oam-Web/src/test/java/com/cpop/oam/web/CpopEasyLearnTest.java b/Cpop-Oam/Cpop-Oam-Web/src/test/java/com/cpop/oam/web/CpopEasyLearnTest.java new file mode 100644 index 0000000..038d40b --- /dev/null +++ b/Cpop-Oam/Cpop-Oam-Web/src/test/java/com/cpop/oam/web/CpopEasyLearnTest.java @@ -0,0 +1,202 @@ +package com.cpop.oam.web; + +import com.alibaba.fastjson.JSONObject; +import com.cpop.common.utils.StringUtils; +import com.cpop.core.base.enums.OrderSource; +import com.cpop.core.base.exception.ServiceException; +import com.cpop.core.utils.SpringUtils; +import com.cpop.jambox.business.entity.EasyLearnOrder; +import com.cpop.jambox.business.entity.StoreExtend; +import com.cpop.jambox.business.service.EasyLearnOrderService; +import com.cpop.jambox.business.service.StoreExtendService; +import com.cpop.jambox.framework.constant.JamboxCloudUrl; +import com.cpop.pay.framewok.config.wxPay.WxPayProperties; +import com.cpop.pay.framewok.handler.wxPay.WxPayHandler; +import com.github.binarywang.wxpay.bean.profitsharing.ProfitSharingRequest; +import com.github.binarywang.wxpay.bean.profitsharing.ProfitSharingResult; +import com.github.binarywang.wxpay.config.WxPayConfig; +import com.github.binarywang.wxpay.exception.WxPayException; +import com.github.binarywang.wxpay.service.WxPayService; +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.RowKey; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.web.client.RestTemplate; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static com.cpop.jambox.business.entity.table.EasyLearnOrderTableDef.EASY_LEARN_ORDER; +import static com.cpop.jambox.business.entity.table.StoreExtendTableDef.STORE_EXTEND; + +/** + * @author DB + * @version 1.0.0 + * @since 2023-12-29 9:50 + */ +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles({"prod", "core", "jambox"}) +public class CpopEasyLearnTest { + + @Autowired + private WxPayService wxPayService; + + @Autowired + private WxPayProperties wxPayProperties; + + @Autowired + private WxPayHandler wxPayHandler; + + /** + * 关闭订单一次性支付 + * @author DB + * @since 2023/12/29 + */ + @Test + public void finishOncePay() throws WxPayException { + String outTradeNo = "97973645262987264"; + /*String transactionId = "4200002093202312282215936862"; + ProfitSharingFinishRequest profitSharingFinishRequest = new ProfitSharingFinishRequest(); + profitSharingFinishRequest.setTransactionId(transactionId); + profitSharingFinishRequest.setOutOrderNo(outTradeNo); + profitSharingFinishRequest.setDescription("结束分账"); + profitSharingFinishRequest.setSubMchId("1661323640"); + //结束分账 + wxPayService.getProfitSharingService().profitSharingFinish(profitSharingFinishRequest);*/ + //完结订单 + WxPayConfig wxPayConfig = wxPayService.getConfig(); + wxPayConfig.setSubMchId("1661323640"); + wxPayService.setConfig(wxPayConfig); + wxPayService.closeOrder(outTradeNo); + } + + /** + * 放心学一次性支付 + * @author DB + * @since 2023/12/29 + */ + @Test + public void easyLearnOncePay(){ + String orderId = "97976926051770368"; + //获取订单信息 + EasyLearnOrderService easyLearnOrderService = SpringUtils.getBean(EasyLearnOrderService.class); + EasyLearnOrder easyLearnOrder = easyLearnOrderService.getById(orderId); + //需要分账 + String subMchId = wxPayHandler.getSubMchId(easyLearnOrder.getBrandId(), easyLearnOrder.getStoreId()); + String transactionId = "4200002127202312282719627535"; + //课卡信息 + JSONObject jsonBody = new JSONObject(); + jsonBody.put("_type", "addPeriod"); + //办卡实收金额 + jsonBody.put("money", easyLearnOrder.getTotalPayAmount()); + //获取云校区id + StoreExtend storeExtend = SpringUtils.getBean(StoreExtendService.class).getOne(QueryWrapper.create().where(STORE_EXTEND.STORE_ID.eq(easyLearnOrder.getStoreId()))); + //店铺/校区 + jsonBody.put("storeId", storeExtend.getStoreCloudId()); + //手机号 + jsonBody.put("phone", easyLearnOrder.getCustomerPhone()); + //客户名称 + jsonBody.put("customerName", easyLearnOrder.getCustomerName()); + //模板id + jsonBody.put("templateId", easyLearnOrder.getOrderCloudId()); + //订单来源 + jsonBody.put("orderSource", OrderSource.EASY_LEARN.toString()); + //订单来源 + jsonBody.put("subMchId", subMchId); + //获取课卡信息 + JSONObject result = SpringUtils.getBean(RestTemplate.class).postForObject(JamboxCloudUrl.COMMON_CARD_URL, jsonBody, JSONObject.class); + if (result == null){ + throw new ServiceException("放心学一次性支付办卡失败!"); + } + easyLearnOrderService.updateChain().set(EASY_LEARN_ORDER.OUT_ORDER_NO, transactionId) + .set(EASY_LEARN_ORDER.PRODUCT_ID, result.getString("data")) + .set(EASY_LEARN_ORDER.ORDER_STATUS, 1) + .where(EASY_LEARN_ORDER.ID.eq(orderId)).update(); + } + + /** + * 构建分账请求参数 + * @author DB + * @since 2023/12/28 + * @param orderId 订单号 + * @param orderSource 订单来源 + * @return ProfitSharingRequest + */ + private ProfitSharingRequest buildProfitSharingRequest(String orderId, OrderSource orderSource,Integer totalFee,String subMchId,String transactionId) { + LocalDateTime now = LocalDateTime.now(); + Double ceil = Math.ceil(totalFee * orderSource.getRate()); + Row row = Row.ofKey(RowKey.SNOW_FLAKE_ID) + .set("order_id", orderId) + .set("profit_sharing_status", 0) + .set("amount", ceil.longValue()) + .set("pay_account", subMchId) + .set("order_source",orderSource.toString()) + .set("create_time", now) + .set("update_time", now) + .set("create_user_id", "1") + .set("update_user_id", "1"); + Db.insert("cp_sys_profit_sharing", row); + //固定商户信息 + Map mapReceiver = new HashMap<>(4); + mapReceiver.put("type", "MERCHANT_ID"); + mapReceiver.put("account", wxPayProperties.getSharingAccount()); + mapReceiver.put("amount", ceil.longValue()); + mapReceiver.put("description","分账到服务商"); + List> receivers = new ArrayList<>(); + receivers.add(mapReceiver); + //分账请求参数 + ProfitSharingRequest profitSharingRequest = new ProfitSharingRequest(); + profitSharingRequest.setReceivers(JSONObject.toJSONString(receivers)); + profitSharingRequest.setOutOrderNo(row.getString("id")); + profitSharingRequest.setTransactionId(transactionId); + profitSharingRequest.setSubMchId(subMchId); + return profitSharingRequest; + } + + /** + * 微信支付分账 + * @author DB + * @since 2023/11/03 11:09 + * @param profitSharingRequest 请求参数 + * @param wxPayService 微信服务类 + * @param flag 标记 + */ + private void wxPayProfitSharing(ProfitSharingRequest profitSharingRequest, WxPayService wxPayService, Integer flag, OrderSource orderSource) { + try { + ProfitSharingResult profitSharingResult = wxPayService.getProfitSharingService().profitSharing(profitSharingRequest); + if (StringUtils.equals(profitSharingResult.getResultCode(), "SUCCESS")) { + //存入系统 + DbChain.table("cp_sys_profit_sharing") + .set("out_profit_sharing_id", profitSharingResult.getOrderId()) + .set("profit_sharing_status", 1) + .where("id = ?", profitSharingResult.getOutOrderNo()) + .update(); + } else { + throw new ServiceException(profitSharingResult.getReturnMsg()); + } + } catch (WxPayException e) { + if (flag > 5) { + if (OrderSource.MALL == orderSource) { + //关闭商城支付 + DbChain.table("cp_sys_brand") + .set("is_open_sharing", false) + .where("wx_mch_id = ?", wxPayService.getConfig().getSubMchId()) + .update(); + } + throw new ServiceException(e.getMessage()); + } else { + //重复调用 + flag = flag + 1; + wxPayProfitSharing(profitSharingRequest, wxPayService, flag, orderSource); + } + } + } +} diff --git a/Cpop-Oam/Cpop-Oam-Web/src/test/java/com/cpop/oam/web/CpopImportTests.java b/Cpop-Oam/Cpop-Oam-Web/src/test/java/com/cpop/oam/web/CpopImportTests.java index a47d9ea..6ae9550 100644 --- a/Cpop-Oam/Cpop-Oam-Web/src/test/java/com/cpop/oam/web/CpopImportTests.java +++ b/Cpop-Oam/Cpop-Oam-Web/src/test/java/com/cpop/oam/web/CpopImportTests.java @@ -10,15 +10,23 @@ import com.cpop.core.utils.SpringUtils; import com.cpop.jambox.business.entity.BrandExtend; import com.cpop.jambox.business.entity.EasyLearnOrder; import com.cpop.jambox.business.entity.StoreExtend; +import com.cpop.jambox.business.entity.StorePlug; import com.cpop.jambox.business.service.BrandExtendService; import com.cpop.jambox.business.service.EasyLearnOrderService; import com.cpop.jambox.business.service.StoreExtendService; +import com.cpop.jambox.business.service.StorePlugService; import com.cpop.oam.business.entity.BrandManager; import com.cpop.oam.business.entity.BrandManagerStore; import com.cpop.oam.business.service.BrandManagerService; import com.cpop.oam.business.service.BrandManagerStoreService; -import com.cpop.system.business.entity.*; -import com.cpop.system.business.service.*; +import com.cpop.system.business.entity.Store; +import com.cpop.system.business.entity.StoreLicense; +import com.cpop.system.business.entity.StoreRenew; +import com.cpop.system.business.entity.StoreSign; +import com.cpop.system.business.service.StoreLicenseService; +import com.cpop.system.business.service.StoreRenewService; +import com.cpop.system.business.service.StoreService; +import com.cpop.system.business.service.StoreSignService; import com.mybatisflex.core.FlexGlobalConfig; import com.mybatisflex.core.datasource.DataSourceKey; import com.mybatisflex.core.datasource.FlexDataSource; @@ -32,7 +40,6 @@ import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; import java.io.*; import java.time.LocalDate; @@ -51,7 +58,7 @@ import static com.cpop.system.business.entity.table.StoreTableDef.STORE; */ @Slf4j @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@ActiveProfiles(profiles = {"prod", "core"}) +//@ActiveProfiles(profiles = {"prod", "core"}) public class CpopImportTests { /** @@ -495,6 +502,34 @@ public class CpopImportTests { }*/ } + /** + * 导入校区插件 + * @author DB + * @since 2023/12/29 + */ + @Test + public void importStorePlug(){ + List rowList; + try { + //数币订单 + DataSourceKey.use("jambox"); + rowList = DbChain.table("t_application_mechanism") + .select("store_id as storeCloudId", "char_tag as plugTag", "remarks","creation_time as createTime","deleted as isOpen") + .list(); + } finally { + DataSourceKey.clear(); + } + //获取所有校区 + Map storeCloudToStore = SpringUtils.getBean(StoreExtendService.class).list().stream().collect(Collectors.toMap(StoreExtend::getStoreCloudId, StoreExtend::getStoreId)); + rowList.forEach(item -> { + item.put("storeId", storeCloudToStore.get(item.getString("storeCloudId"))); + item.set("isOpen", !item.getBoolean("isOpen")); + }); + List filterRow = rowList.stream().filter(item -> item.getString("storeId") != null).collect(Collectors.toList()); + List entityList = RowUtil.toEntityList(filterRow, StorePlug.class); + SpringUtils.getBean(StorePlugService.class).saveBatch(entityList); + } + private static final String URL = "jdbc:mysql://localhost:3306/cpop_dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8"; /** * 数据库用户名 diff --git a/Cpop-Oam/src/main/java/com/cpop/oam/business/controller/backstage/BusinessController.java b/Cpop-Oam/src/main/java/com/cpop/oam/business/controller/backstage/BusinessController.java index 8eb34d8..bc07085 100644 --- a/Cpop-Oam/src/main/java/com/cpop/oam/business/controller/backstage/BusinessController.java +++ b/Cpop-Oam/src/main/java/com/cpop/oam/business/controller/backstage/BusinessController.java @@ -12,6 +12,7 @@ import com.cpop.oam.business.service.BusinessService; import com.cpop.oam.business.service.StaffService; import com.cpop.oam.business.vo.BusinessInfoPageVo; import com.cpop.oam.business.vo.BusinessPageVo; +import com.cpop.oam.business.vo.PersonBusinessInfoVo; import com.cpop.oam.business.vo.StaffVo; import com.mybatisflex.core.paginate.Page; import io.swagger.annotations.Api; @@ -121,6 +122,20 @@ public class BusinessController { return R.ok(page); } + /** + * 获取个人当前事务详情 + * @author DB + * @since 2023/12/29 + * @param id 事务详情id + * @return R + */ + @GetMapping("/getPersonBusinessInfoById/{id}") + @ApiOperation("获取个人当前事务详情") + public R getPersonBusinessInfoById(@ApiParam("请求参数") @PathVariable String id) { + PersonBusinessInfoVo vo = businessService.getPersonBusinessInfoById(id); + return R.ok(vo); + } + /** * 员工事务处理 * @author DB diff --git a/Cpop-Oam/src/main/java/com/cpop/oam/business/controller/backstage/StorePlugController.java b/Cpop-Oam/src/main/java/com/cpop/oam/business/controller/backstage/StorePlugController.java new file mode 100644 index 0000000..f7acc63 --- /dev/null +++ b/Cpop-Oam/src/main/java/com/cpop/oam/business/controller/backstage/StorePlugController.java @@ -0,0 +1,55 @@ +package com.cpop.oam.business.controller.backstage; + +import com.cpop.core.base.R; +import com.cpop.jambox.business.service.StorePlugService; +import com.cpop.jambox.business.vo.StorePlugListVo; +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.web.bind.annotation.*; + +import java.util.List; + +import static com.cpop.jambox.business.entity.table.StorePlugTableDef.STORE_PLUG; + +/** + * 校区-插件记录表 控制层。 + * + * @author DB + * @since 2023-12-29 + */ +@RestController +@Api(tags = "校区-插件记录表接口") +@RequestMapping("/storePlug") +public class StorePlugController { + + @Autowired + private StorePlugService storePlugService; + + /** + * 查询校区插件列表 + * + * @param brandId brandId + * @param storeId storeId + */ + @GetMapping("/getStorePlugList") + @ApiOperation("查询校区插件列表") + public R> getStorePlugList(@ApiParam("品牌id") String brandId, @ApiParam("校区id") String storeId) { + List list = storePlugService.getStorePlugList(brandId,storeId); + return R.ok(list); + } + + /** + * 插件开启与关闭 + */ + @PutMapping("/changePlugOpen/{id}") + @ApiOperation("插件开启与关闭") + public R changePlugOpen(@PathVariable String id) { + storePlugService.updateChain().setRaw(STORE_PLUG.IS_OPEN, "if(is_open = 0, 1, 0)") + .where(STORE_PLUG.ID.eq(id)) + .update(); + return R.ok(); + } + +} diff --git a/Cpop-Oam/src/main/java/com/cpop/oam/business/service/BusinessService.java b/Cpop-Oam/src/main/java/com/cpop/oam/business/service/BusinessService.java index 7145341..97c0f34 100644 --- a/Cpop-Oam/src/main/java/com/cpop/oam/business/service/BusinessService.java +++ b/Cpop-Oam/src/main/java/com/cpop/oam/business/service/BusinessService.java @@ -6,6 +6,7 @@ import com.cpop.oam.business.bo.BusinessInfoPageBo; import com.cpop.oam.business.bo.BusinessRemoveBo; import com.cpop.oam.business.vo.BusinessInfoPageVo; import com.cpop.oam.business.vo.BusinessPageVo; +import com.cpop.oam.business.vo.PersonBusinessInfoVo; import com.mybatisflex.core.paginate.Page; import com.mybatisflex.core.service.IService; import com.cpop.oam.business.entity.Business; @@ -59,4 +60,13 @@ public interface BusinessService extends IService { * @param bo 删除参数 */ void businessRemove(BusinessRemoveBo bo); + + /** + * 获取个人当前事务详情 + * @author DB + * @since 2023/12/29 + * @param id 事务详情id + * @return PersonBusinessInfoVo + */ + PersonBusinessInfoVo getPersonBusinessInfoById(String id); } diff --git a/Cpop-Oam/src/main/java/com/cpop/oam/business/service/impl/BusinessServiceImpl.java b/Cpop-Oam/src/main/java/com/cpop/oam/business/service/impl/BusinessServiceImpl.java index cfbdc9f..d528405 100644 --- a/Cpop-Oam/src/main/java/com/cpop/oam/business/service/impl/BusinessServiceImpl.java +++ b/Cpop-Oam/src/main/java/com/cpop/oam/business/service/impl/BusinessServiceImpl.java @@ -26,6 +26,7 @@ import com.cpop.oam.business.service.BusinessService; import com.cpop.oam.business.service.BusinessStaffService; import com.cpop.oam.business.vo.BusinessInfoPageVo; import com.cpop.oam.business.vo.BusinessPageVo; +import com.cpop.oam.business.vo.PersonBusinessInfoVo; import com.cpop.system.business.entity.Store; import com.cpop.system.business.service.StoreService; import com.mybatisflex.core.paginate.Page; @@ -133,7 +134,7 @@ public class BusinessServiceImpl extends ServiceImpl i List businessStaffs = BeanUtils.mapToList(bo.getSign(), BusinessStaff.class); businessStaffs.forEach(item -> { item.setBusinessId(businessId); - flag.set(item.getSurplusQuantity()); + flag.updateAndGet(v -> v + item.getSurplusQuantity()); }); //保存负责员工 SpringUtils.getBean(BusinessStaffService.class).saveBatch(businessStaffs); @@ -402,4 +403,25 @@ public class BusinessServiceImpl extends ServiceImpl i business.setAllSurplusQuantity(business.getAllSurplusQuantity() - 1); this.updateById(business); } + + /** + * 获取个人当前事务详情 + * @author DB + * @since 2023/12/29 + * @param id 事务详情id + * @return PersonBusinessInfoVo + */ + @Override + public PersonBusinessInfoVo getPersonBusinessInfoById(String id) { + JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo(); + return this.getOneAs(QueryWrapper.create() + .select(BUSINESS.BUSINESS_LEVEL,BUSINESS.BUSINESS_TYPE,BUSINESS.DESC,BUSINESS.START_DATE,BUSINESS.END_DATE,BUSINESS.REMARK) + .select(STAFF.NAME.as(PersonBusinessInfoVo::getInitiatorName)) + .select(BUSINESS_STAFF.SURPLUS_QUANTITY.as(PersonBusinessInfoVo::getSurplusQuantity)) + .leftJoin(STAFF).on(STAFF.ID.eq(BUSINESS.INITIATOR_ID)) + .leftJoin(BUSINESS_STAFF).on(BUSINESS_STAFF.BUSINESS_ID.eq(BUSINESS.ID)) + .where(BUSINESS.ID.eq(id)) + .and(BUSINESS_STAFF.STAFF_ID.eq(loginUserInfo.getString("id"))), + PersonBusinessInfoVo.class); + } } diff --git a/Cpop-Oam/src/main/java/com/cpop/oam/business/service/impl/TaskDemandServiceImpl.java b/Cpop-Oam/src/main/java/com/cpop/oam/business/service/impl/TaskDemandServiceImpl.java index 7c87604..7ae5b02 100644 --- a/Cpop-Oam/src/main/java/com/cpop/oam/business/service/impl/TaskDemandServiceImpl.java +++ b/Cpop-Oam/src/main/java/com/cpop/oam/business/service/impl/TaskDemandServiceImpl.java @@ -22,6 +22,7 @@ import com.cpop.oam.business.bo.TaskDemandUrgentBo; import com.cpop.oam.business.entity.Task; import com.cpop.oam.business.entity.TaskDemand; import com.cpop.oam.business.mapper.TaskDemandMapper; +import com.cpop.oam.business.service.CommonService; import com.cpop.oam.business.service.TaskDemandService; import com.cpop.oam.business.service.TaskService; import com.cpop.oam.business.vo.TaskDemandPageVo; @@ -183,12 +184,12 @@ public class TaskDemandServiceImpl extends ServiceImpl phoneList = new ArrayList(); diff --git a/Cpop-Oam/src/main/java/com/cpop/oam/business/service/impl/TaskServiceImpl.java b/Cpop-Oam/src/main/java/com/cpop/oam/business/service/impl/TaskServiceImpl.java index f033d66..2d3b721 100644 --- a/Cpop-Oam/src/main/java/com/cpop/oam/business/service/impl/TaskServiceImpl.java +++ b/Cpop-Oam/src/main/java/com/cpop/oam/business/service/impl/TaskServiceImpl.java @@ -361,7 +361,7 @@ public class TaskServiceImpl extends ServiceImpl implements Ta .on(TASK_STAFF_GROUP.TASK_ID.eq(TASK.ID)) // 员工表 .leftJoin(STAFF) - .on(STAFF.ID.eq(TASK_STAFF_GROUP.STAFF_ID)) + .on(STAFF.ID.eq(TASK.RESPONSIBLE_STAFF_ID)) .where(TASK.TASK_TYPE.in(0, 1)) .orderBy(TASK.EXPECTED_COMPLETION_DATE.asc()), PersonTaskPageVo.class); @@ -484,16 +484,16 @@ public class TaskServiceImpl extends ServiceImpl implements Ta taskStaffGroups.forEach(item -> { //向下取整 Integer oldGradePoint = item.getGradePoint(); - double deductGradePoint = Math.floor(item.getGradePoint() * 0.8); - item.setGradePoint(oldGradePoint - (int) deductGradePoint).setRemark("任务完成超时扣除绩点:" + deductGradePoint); + Double deductGradePoint = Math.floor(item.getGradePoint() * 0.2); + item.setGradePoint(oldGradePoint - deductGradePoint.intValue()).setRemark("任务完成超时扣除绩点:" + deductGradePoint); }); } else { //3天以上50% taskStaffGroups.forEach(item -> { //向下取整 Integer oldGradePoint = item.getGradePoint(); - double deductGradePoint = Math.floor(item.getGradePoint() * 0.5); - item.setGradePoint(oldGradePoint - (int) deductGradePoint).setRemark("任务完成超时扣除绩点:" + deductGradePoint); + Double deductGradePoint = Math.floor(item.getGradePoint() * 0.5); + item.setGradePoint(oldGradePoint - deductGradePoint.intValue()).setRemark("任务完成超时扣除绩点:" + deductGradePoint); }); } taskStaffGroupService.updateBatch(taskStaffGroups); diff --git a/Cpop-Oam/src/main/java/com/cpop/oam/business/vo/PersonBusinessInfoVo.java b/Cpop-Oam/src/main/java/com/cpop/oam/business/vo/PersonBusinessInfoVo.java new file mode 100644 index 0000000..5e0abbe --- /dev/null +++ b/Cpop-Oam/src/main/java/com/cpop/oam/business/vo/PersonBusinessInfoVo.java @@ -0,0 +1,63 @@ +package com.cpop.oam.business.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.time.LocalDate; + +/** + * @author DB + * @version 1.0.0 + * @since 2023-12-29 15:16 + */ +@Data +@Accessors(chain = true) +@ApiModel(value = "PersonBusinessInfoVo对象") +public class PersonBusinessInfoVo { + + /** + * 剩余数量 + */ + @ApiModelProperty(value = "剩余数量") + private Integer surplusQuantity; + /** + * 业务等级,业务等级(0:轻;1:重;2:缓;3:急) + */ + @ApiModelProperty(value = "业务等级(0:轻;1:重;2:缓;3:急)") + private Integer businessLevel; + /** + * 业务类型,业务类型(0:机构对接;1:机构签约) + */ + @ApiModelProperty(value = "业务类型(0:机构对接;1:机构签约)") + private Integer businessType; + /** + * 描述 + */ + @ApiModelProperty(value = "描述") + private String desc; + /** + * 结束时间 + */ + @ApiModelProperty(value = "结束时间") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate endDate; + /** + * 分发人 + */ + @ApiModelProperty(value = "分发人") + private String initiatorName; + /** + * 备注 + */ + @ApiModelProperty(value = "备注") + private String remark; + /** + * 开始时间 + */ + @JsonFormat(pattern = "yyyy-MM-dd") + @ApiModelProperty(value = "开始时间") + private LocalDate startDate; +} diff --git a/Cpop-Oam/src/main/java/com/cpop/oam/framework/tasks/OamScheduledTasks.java b/Cpop-Oam/src/main/java/com/cpop/oam/framework/tasks/OamScheduledTasks.java index 14b9476..5750051 100644 --- a/Cpop-Oam/src/main/java/com/cpop/oam/framework/tasks/OamScheduledTasks.java +++ b/Cpop-Oam/src/main/java/com/cpop/oam/framework/tasks/OamScheduledTasks.java @@ -76,7 +76,7 @@ public class OamScheduledTasks { log.info("==============开始检查进行中任务==========="); TaskService taskService = SpringUtils.getBean(TaskService.class); List taskList = taskService.queryChain().where(TASK.TASK_STATUS.in(2, 3)).and(TASK.TASK_TYPE.in(0, 1)).list(); - List filterList = taskList.stream().filter(item -> item.getExpectedCompletionDate().isBefore(LocalDate.now().plusDays(1))).collect(Collectors.toList()); + List filterList = taskList.stream().filter(item -> item.getExpectedCompletionDate().plusDays(1).isBefore(LocalDate.now())).collect(Collectors.toList()); if (!filterList.isEmpty()) { //任务项逾期 taskService.updateChain().set(TASK.TASK_ITEM, -1).where(TASK.ID.in(filterList.stream().map(Task::getId).collect(Collectors.toSet()))).update(); diff --git a/Cpop-Pay/src/main/java/com/cpop/pay/framewok/config/wxPay/WxPayProperties.java b/Cpop-Pay/src/main/java/com/cpop/pay/framewok/config/wxPay/WxPayProperties.java index 512d808..bdf4a17 100644 --- a/Cpop-Pay/src/main/java/com/cpop/pay/framewok/config/wxPay/WxPayProperties.java +++ b/Cpop-Pay/src/main/java/com/cpop/pay/framewok/config/wxPay/WxPayProperties.java @@ -71,4 +71,14 @@ public class WxPayProperties { */ private String sharingAccountName; + /** + * 一次性支付 + */ + private String easyLearnOncePayNotifyUrl; + + /** + * 放心学联合支付通知地址 + */ + private String easyLearnUnionPayNotifyUrl; + } diff --git a/Cpop-Pay/src/main/java/com/cpop/pay/framewok/handler/wxPay/WxPayHandler.java b/Cpop-Pay/src/main/java/com/cpop/pay/framewok/handler/wxPay/WxPayHandler.java index 9897268..94feedd 100644 --- a/Cpop-Pay/src/main/java/com/cpop/pay/framewok/handler/wxPay/WxPayHandler.java +++ b/Cpop-Pay/src/main/java/com/cpop/pay/framewok/handler/wxPay/WxPayHandler.java @@ -103,16 +103,28 @@ public class WxPayHandler { * @return String */ public String getSubMchId(String brandId, String storeId) { - //先查校区 - Row store = Db.selectOneByQuery("cp_sys_store", QueryWrapper.create().where("id = ?", storeId)); - String wxMchId = store.getString("wxMchId"); - if (StringUtils.isBlank(wxMchId)){ + String wxMchId; + if (StringUtils.isNotEmpty(storeId)){ + //先查校区 + Row store = Db.selectOneByQuery("cp_sys_store", QueryWrapper.create().where("id = ?", storeId)); + if (store != null && StringUtils.isNotBlank(store.getString("wxMchId"))){ + wxMchId = store.getString("wxMchId"); + } else { + //查询品牌 + Row brand = Db.selectOneByQuery("cp_sys_brand", QueryWrapper.create().where("id = ?", brandId)); + if (brand != null && StringUtils.isNotBlank(brand.getString("wxMchId"))){ + wxMchId = brand.getString("wxMchId"); + }else { + wxMchId = "1661323640"; + } + } + } else { //查询品牌 Row brand = Db.selectOneByQuery("cp_sys_brand", QueryWrapper.create().where("id = ?", brandId)); - wxMchId = brand.getString("wxMchId"); - if (StringUtils.isBlank(wxMchId)){ - //果酱默认商户 - wxMchId = "1618925571"; + if (brand != null && StringUtils.isNotBlank(brand.getString("wxMchId"))){ + wxMchId = brand.getString("wxMchId"); + }else { + wxMchId = "1661323640"; } } return wxMchId; diff --git a/Cpop-Pay/src/main/java/com/cpop/pay/framewok/task/WxPayAsyncTask.java b/Cpop-Pay/src/main/java/com/cpop/pay/framewok/task/WxPayAsyncTask.java index 7f08f11..c3ed39e 100644 --- a/Cpop-Pay/src/main/java/com/cpop/pay/framewok/task/WxPayAsyncTask.java +++ b/Cpop-Pay/src/main/java/com/cpop/pay/framewok/task/WxPayAsyncTask.java @@ -45,7 +45,7 @@ public class WxPayAsyncTask { * @return: void */ @Async("customAsyncThreadPool") - public void asyncWxPayProfitSharing(String orderId, WxPayOrderNotifyResult notifyResult, WxPayService wxPayService,OrderSource orderSource) { + public void asyncWxPayProfitSharing(String orderId, WxPayOrderNotifyResult notifyResult, WxPayService wxPayService, OrderSource orderSource) { ProfitSharingRequest profitSharingRequest = buildProfitSharingRequest(orderId, notifyResult, orderSource); try { Thread.sleep(5000); @@ -55,17 +55,43 @@ public class WxPayAsyncTask { } } + @Async("customAsyncThreadPool") + public void asyncWxPayProfitSharing(String orderId, WxPayOrderNotifyResult notifyResult, WxPayService wxPayService, OrderSource orderSource, Double rate) { + ProfitSharingRequest profitSharingRequest = buildProfitSharingRequest(orderId, notifyResult, orderSource, rate); + try { + Thread.sleep(5000); + wxPayProfitSharing(profitSharingRequest, wxPayService, 0, orderSource); + } catch (InterruptedException e) { + throw new ServiceException(e.getMessage()); + } + } + /** - * @descriptions 构建分账请求参数 + * 构建分账请求参数 * @author DB - * @date 2023/11/03 11:12 + * @since 2023/12/28 * @param orderId 订单号 * @param notifyResult 通知结果 - * @return: com.github.binarywang.wxpay.bean.profitsharingV3.ProfitSharingRequest + * @param orderSource 订单来源 + * @return ProfitSharingRequest */ - private ProfitSharingRequest buildProfitSharingRequest(String orderId, WxPayOrderNotifyResult notifyResult,OrderSource orderSource) { + private ProfitSharingRequest buildProfitSharingRequest(String orderId, WxPayOrderNotifyResult notifyResult, OrderSource orderSource) { + return buildProfitSharingRequest(orderId, notifyResult, orderSource, orderSource.getRate()); + } + + /** + * 构建分账请求参数 + * @author DB + * @since 2023/12/28 + * @param orderId 订单号 + * @param notifyResult 通知结果 + * @param orderSource 订单来源 + * @param rate 分账比例 + * @return ProfitSharingRequest + */ + private ProfitSharingRequest buildProfitSharingRequest(String orderId, WxPayOrderNotifyResult notifyResult, OrderSource orderSource, Double rate) { LocalDateTime now = LocalDateTime.now(); - Double ceil = Math.ceil(notifyResult.getTotalFee() * OrderSource.MALL.getRate()); + Double ceil = Math.ceil(notifyResult.getTotalFee() * rate); Row row = Row.ofKey(RowKey.SNOW_FLAKE_ID) .set("order_id", orderId) .set("profit_sharing_status", 0) @@ -95,13 +121,12 @@ public class WxPayAsyncTask { } /** - * @descriptions 微信支付分账 + * 微信支付分账 * @author DB - * @date 2023/11/03 11:09 + * @since 2023/11/03 11:09 * @param profitSharingRequest 请求参数 * @param wxPayService 微信服务类 * @param flag 标记 - * @return: void */ private void wxPayProfitSharing(ProfitSharingRequest profitSharingRequest, WxPayService wxPayService, Integer flag, OrderSource orderSource) { try {