package com.cyksj.service.mange.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateField; import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import com.alipay.api.AlipayClient; import com.alipay.api.domain.AlipayTradeRefundModel; import com.alipay.api.request.AlipayTradeRefundRequest; import com.alipay.api.response.AlipayTradeRefundResponse; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.cyksj.common.constant.Constant; import com.cyksj.common.exception.BusinessRuntimeException; import com.cyksj.common.task.GlobalThreadPoolTaskExecutor; import com.cyksj.common.util.Codec; import com.cyksj.common.util.Jsons; import com.cyksj.common.util.StringUtil; import com.cyksj.common.util.Xmls; import com.cyksj.config.WeChatConfig; import com.cyksj.config.zfb.AliPayClientFactory; import com.cyksj.dto.RedisKey; import com.cyksj.mapper.*; import com.cyksj.mapper.channel.ShopConfigMapper; import com.cyksj.mapper.channel.UserPayEquipmentReceiveBenefitsRecordMapper; import com.cyksj.mapper.manage.cms.CmsUserMapper; import com.cyksj.mapper.manage.distribute.DistributeWaitingSendPointsMapper; import com.cyksj.mapper.manage.distribute.UserDistributeBusinessOrderDonRecordMapper; import com.cyksj.mapper.manage.distribute.UserDistributeMapper; import com.cyksj.mapper.manage.distribute.equipment.EquipmentUserDistributeTransportBenefitsMapper; import com.cyksj.mapper.manage.sys.WorkOrderMapper; import com.cyksj.mapper.shop.YhShopUserDistributeBusinessOrderDonRecordMapper; import com.cyksj.mapper.stock.GoodsSkuStockRelateMapper; import com.cyksj.model.entity.*; import com.cyksj.model.excel.ExcelOrderDonInfo; import com.cyksj.model.manage.request.ReqSetLogisticsPost; import com.cyksj.model.manage.views.GroupsRelationView; import com.cyksj.model.request.ChangeRelationReq; import com.cyksj.model.request.ClickOutReq; import com.cyksj.model.request.OrderRefundReq; import com.cyksj.redis.RedisService; import com.cyksj.service.coupon.CouponFontService; import com.cyksj.service.distribute.equipment.EquipmentDistributeService; import com.cyksj.service.giftcard.GiftCardOrderUseRecordService; import com.cyksj.service.mange.CmsOrderDonService; import com.cyksj.service.mange.stock.GoodsDonStockService; import com.cyksj.service.market.MarketFrontService; import com.cyksj.service.order.OrderCommonService; import com.cyksj.service.order.UserRealOrderBenefitsService; import com.cyksj.service.paypal.PayPalService; import com.cyksj.service.relation.GroupRelationClearService; import com.cyksj.service.relation.GroupsRelationExpiryRecordService; import com.cyksj.service.shop.YhShopDistributeService; import com.cyksj.service.stripe.StripeService; import com.cyksj.service.user.UserBenefitsService; import com.cyksj.service.wechat.WeChatService; import com.ejlchina.searcher.BeanSearcher; import com.ejlchina.searcher.util.MapUtils; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Optional; /** * @author chan * @date 2021/10/25 下午10:14 */ @Service @Slf4j @RequiredArgsConstructor public class CmsOrderDonServiceImpl extends ServiceImpl implements CmsOrderDonService { private final OrderDonTransportMapper transportMapper; private final OrderDonWaybillMapper orderDonWaybillMapper; private final GoodsSkuStockRelateMapper skuStockRelateMapper; private final GoodsDonStockService goodsDonStockService; private final GoodsDonSkuMapper goodsDonSkuMapper; private final UserRealOrderBenefitsService userRealOrderBenefitsService; private final UserRelationKickOutRecordMapper kickOutRecordMapper; private final CmsUserMapper cmsUserMapper; private final OrderCommonService orderCommonService; private final GoodsDonMapper goodsDonMapper; private final RedisService redisService; private final UserBenefitsService userBenefitsService; private final DistributeWaitingSendPointsMapper distributeWaitingSendPointsMapper; private final RefundOrderDonMapper refundOrderDonMapper; private final UserDistributeMapper userDistributeMapper; private final OrderDonMapper orderDonMapper; private final MarketFrontService marketFrontService; private final EquipmentDistributeService equipmentDistributeService; private final CouponFontService couponFontService; private final WeChatService weChatService; private final WeChatConfig weChatConfig; private final ShopConfigMapper shopConfigMapper; private final GroupRelationClearService relationClearService; private final GroupsRelationMapper relationMapper; private final GroupsMapper groupsMapper; private final GoodsDonSkuMapper skuMapper; private final UserDistributeBusinessOrderDonRecordMapper businessOrderDonRecordMapper; private final WorkOrderMapper workOrderMapper; private final PayPalService payPalService; private final StripeService stripeService; private final OrderDiscountPlusPurchaseSkuRelationMapper orderDiscountPlusPurchaseSkuRelationMapper; private final EquipmentUserDistributeTransportBenefitsMapper transportBenefitsMapper; private final BeanSearcher beanSearcher; private final UserPayEquipmentReceiveBenefitsRecordMapper receiveBenefitsRecordMapper; private final GroupsRelationExpiryRecordService groupsRelationExpiryRecordService; private final GiftCardOrderUseRecordService giftCardOrderUseRecordService; private final GiftCardUserRecordMapper giftCardUserRecordMapper; private final YhShopDistributeService yhShopDistributeService; private final YhShopUserDistributeBusinessOrderDonRecordMapper yhShopBusinessOrderDonRecordMapper; private static final GlobalThreadPoolTaskExecutor TASK_POOL = GlobalThreadPoolTaskExecutor.getInstance(); @Override public List exportOrderInfo(Long promotionId, String start, String end) { return this.getBaseMapper().exportOrderInfo(promotionId,start,end); } @Override public OrderDonTransport getTransport(Long orderId) { return transportMapper.selectOne(Wrappers.lambdaQuery(OrderDonTransport.class).eq(OrderDonTransport::getOrderId, orderId)); } @Transactional(rollbackFor = Throwable.class) @Override public OrderDonWaybill setWaybill(ReqSetLogisticsPost reqSetLogisticsPost) { OrderDonWaybill orderDonWaybill = Optional.ofNullable(orderDonWaybillMapper.selectOne(Wrappers.lambdaQuery(OrderDonWaybill.class).eq(OrderDonWaybill::getOrderId, reqSetLogisticsPost.getOrderId()))).orElse(new OrderDonWaybill()); orderDonWaybill.setCodeCn(reqSetLogisticsPost.getCodeCn()); orderDonWaybill.setTrackingNumber(reqSetLogisticsPost.getTrackingNumber()); orderDonWaybill.setOrderId(reqSetLogisticsPost.getOrderId()); orderDonWaybill.setRemark(reqSetLogisticsPost.getRemark()); OrderDon orderDon = getById(orderDonWaybill.getOrderId()); if(orderDonWaybill.getId() == null){ try { orderDonWaybillMapper.insert(orderDonWaybill); } catch (DuplicateKeyException e) { return orderDonWaybill; } orderDon.setStatus(OrderDon.Status.transport); updateById(orderDon); GoodsDonSku sku = goodsDonSkuMapper.selectById(orderDon.getSkuId()); //库存扣减逻辑 List relateList = skuStockRelateMapper.selectList(Wrappers.lambdaQuery(GoodsSkuStockRelate.class).eq(GoodsSkuStockRelate::getSkuId,orderDon.getSkuId())); if(!relateList.isEmpty()){ relateList.forEach((relate)->{ goodsDonStockService.upStockRelate(relate.getStockId(),orderDon.getId(),"transport"); }); } //发放实物购买权益 Boolean isReceivedAll = true; if (sku != null) { if (sku.getIsBenefits()) { if (StrUtil.isNotEmpty(sku.getBenefitsList())) { try { List goodsDonSkus = Jsons.parseList(sku.getBenefitsList(), GoodsDonSku.class); //自购实物 获取权益 isReceivedAll = userRealOrderBenefitsService.getPayRealGoodsBenefits(orderDon.getUserId(), orderDon.getId(), orderDon.getYhsId(), goodsDonSkus); } catch (Exception e) { } } } } final Boolean flag = isReceivedAll; //发送微信模板消息 // TASK_POOL.execute(()->{ // try { // log.info("发送发货通知至{}用户", orderDon.getUserId()); // templateCommonService.sendTransportMsgNotify(orderDon, reqSetLogisticsPost, flag); // } catch (Exception e) { // log.error("发送发货通知至{}用户失败:{}", orderDon.getUserId(), e); // } // }); }else { if (orderDon.getStatus() == OrderDon.Status.hasPayment) { orderDon.setStatus(OrderDon.Status.transport); updateById(orderDon); } orderDonWaybillMapper.updateById(orderDonWaybill); } //实物分销订单是否存在 DistributeWaitingSendPoints waitingSendPoints = distributeWaitingSendPointsMapper.selectOne(Wrappers.lambdaQuery(DistributeWaitingSendPoints.class) .eq(DistributeWaitingSendPoints::getOrderId, orderDon.getId()) .eq(DistributeWaitingSendPoints::getIsDelivery, false) .last("limit 1")); if (waitingSendPoints != null) { //实物分销订单发货后再 进行提成结算期 waitingSendPoints.setIsDelivery(true); distributeWaitingSendPointsMapper.updateById(waitingSendPoints); } //分销有礼 分销实物是否有发货后用户权益 EquipmentUserDistributeTransportBenefits transportBenefits = transportBenefitsMapper.selectOne(Wrappers.lambdaQuery(EquipmentUserDistributeTransportBenefits.class) .eq(EquipmentUserDistributeTransportBenefits::getOrderId, orderDon.getId()) .eq(EquipmentUserDistributeTransportBenefits::getStatus, EquipmentUserDistributeTransportBenefits.Status.hasPayment).last("limit 1")); if (transportBenefits != null) { if (transportBenefits.getBalance().compareTo(BigDecimal.ZERO) > 0) { //7天后余额到账 transportBenefitsMapper.update(null, Wrappers.lambdaUpdate(EquipmentUserDistributeTransportBenefits.class) .set(EquipmentUserDistributeTransportBenefits::getStatus, EquipmentUserDistributeTransportBenefits.Status.transport) .set(EquipmentUserDistributeTransportBenefits::getSendTime, DateUtil.offsetDay(DateTime.now(), 7)) .eq(EquipmentUserDistributeTransportBenefits::getOrderId, orderDon.getId()) .eq(EquipmentUserDistributeTransportBenefits::getStatus, EquipmentUserDistributeTransportBenefits.Status.hasPayment)); } } return orderDonWaybill; } @Override public void kickOutRelationId(long adminId, ClickOutReq req) { Long orderId = req.getOrderId(); OrderDon orderDon = getById(orderId); if (orderDon != null && !orderDon.getIsKickOut()) { try { UserRelationKickOutRecord kickOutRecord = new UserRelationKickOutRecord(); kickOutRecord.setUserId(orderDon.getUserId()); kickOutRecord.setRelationId(orderDon.getRelationId()); kickOutRecord.setGoodsId(orderDon.getGoodsId()); kickOutRecord.setSkuId(orderDon.getSkuId()); kickOutRecord.setReason(req.getReason()); kickOutRecord.setImg(req.getImg()); kickOutRecord.setRemark(req.getRemark()); kickOutRecord.setOrderId(orderDon.getId()); kickOutRecord.setOrderNo(orderDon.getOrderNo()); Optional.ofNullable(cmsUserMapper.selectById(adminId)).ifPresent(cmsUser -> kickOutRecord.setOperator(cmsUser.getNickname())); kickOutRecordMapper.insert(kickOutRecord); orderDon.setIsKickOut(true); updateById(orderDon); GoodsDon goodsDon = goodsDonMapper.selectById(orderDon.getGoodsId()); GoodsDonSku goodsDonSku = goodsDonSkuMapper.selectById(orderDon.getSkuId()); //清除车票 orderCommonService.clearUnrealGoodsDetail(orderDon, goodsDon.getType(), goodsDonSku); } catch (DuplicateKeyException e) { } } } @Override @Transactional(rollbackFor = Throwable.class) public void unifiedRefund(OrderRefundReq refundReq) throws Exception { OrderDon orderDon = orderDonMapper.selectById(refundReq.getOrderId()); GoodsDonSku sku = null; if (orderDon.getSkuId() != null) { sku = goodsDonSkuMapper.selectById(orderDon.getSkuId()); } GoodsDon goodsDon = goodsDonMapper.selectById(orderDon.getGoodsId()); if (StrUtil.isEmpty(refundReq.getRefundType())) { refundReq.setRefundType("money"); } String refundType = refundReq.getRefundType(); //校验订单是否符合退款 checkOrderRefund(orderDon, goodsDon, sku, refundReq); //空订单关闭 if (orderDon.getMoney().compareTo(BigDecimal.ZERO) == 0 && orderDon.getBalance().compareTo(BigDecimal.ZERO) == 0 && orderDon.getRelationId() == 0) { orderDon.setStatus(OrderDon.Status.refund); orderDonMapper.updateById(orderDon); if (goodsDon.getType() == 2) { //扣除用户自身实物权益 userRealOrderBenefitsService.deductUserRealGoodsBenefits(orderDon.getId()); } return; } OrderDon.Type type = orderDon.getType(); String outNo = StrUtil.EMPTY; if (type == OrderDon.Type.WeChat && !refundType.equals(OrderDon.Type.BALANCE.getType())) { outNo = wxRefund(refundReq, orderDon); } if (type == OrderDon.Type.ALI_PAY && !refundType.equals(OrderDon.Type.BALANCE.getType())) { outNo = zfbRefund(refundReq, orderDon); } if (type == OrderDon.Type.PAYPAL && !refundType.equals(OrderDon.Type.BALANCE.getType())) { payPalService.refund(refundReq, orderDon); } if (type == OrderDon.Type.STRIPE && !refundType.equals(OrderDon.Type.BALANCE.getType())) { stripeService.refund(refundReq, orderDon); } orderDon.setRefundDesc(refundReq.getRefundDesc()); //记录退款信息 commonRefund(orderDon, goodsDon, sku, outNo, refundType); //修改订单状态 orderDon.setStatus(OrderDon.Status.refund); orderDonMapper.updateById(orderDon); //提交过工单的订单 //将用户异常订单关闭 workOrderMapper.update(null, Wrappers.lambdaUpdate(WorkOrder.class) .set(WorkOrder::getStatus, WorkOrder.Status.close) .eq(WorkOrder::getStatus, WorkOrder.Status.waiting) .eq(WorkOrder::getUserId, orderDon.getUserId()) .eq(WorkOrder::getRelationId, orderDon.getRelationId())); } public String wxRefund(OrderRefundReq refundReq, OrderDon orderDon) throws Exception { if (orderDon.getMoney().compareTo(BigDecimal.ZERO) <=0){ return StrUtil.EMPTY; } long time = System.currentTimeMillis(); //退款订单号 String outRefundNo = Codec.DoDigest.custom() .setAlgorithm(Codec.DoDigest.Algorithm.MD5) .setStringData(time + String.valueOf(orderDon.getId())) .toHexString(); weChatService.refundWxOrder(weChatConfig.getAppid(), Optional.ofNullable(orderDon.getShopId()).orElse(ShopConfig.WX_DEFAULT_APP_ID), orderDon.getTransactionId(), outRefundNo, orderDon.getMoney(), refundReq.getRefundMoney(), weChatConfig.getDomain() + "manage/order/wx/refund/notify"); //记录退款信息 return outRefundNo; } @Override public void wxRefundNotify(Map map) throws Exception { // 对退款数据 解密 String md5Key = Codec.DoDigest.custom().setAlgorithm(Codec.DoDigest.Algorithm.MD5).setStringData(shopConfigMapper.getByAppId(map.get("mch_id")).getSecret()).toHexString(); String reqInfoXml = Codec.DoCipher.custom().setAlgorithm(Codec.DoCipher.Trans.AES_ECB_PKCS7Padding).setBase64Data(map.get("req_info")).setStringKey(md5Key).ofDecrypt().toText(); log.info("=== 退款数据解密: \n {}", reqInfoXml); Map reqInfoMap = Xmls.toMap(reqInfoXml); // 退款失败 if (StrUtil.equals("CHANGE", reqInfoMap.get("refund_status"))) { throw BusinessRuntimeException.getInstance("退款异常."); } else if (StrUtil.equals("REFUNDCLOSE", reqInfoMap.get("refund_status"))) { throw BusinessRuntimeException.getInstance("退款关闭."); } /* 此处处理业务逻辑 */ String outRefundNo = reqInfoMap.get("out_refund_no"); String transactionId = reqInfoMap.get("transaction_id"); String refundFee = reqInfoMap.get("refund_fee"); OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getTransactionId, transactionId).last("limit 1")); if (orderDon == null) { log.error("退款回调,transactionId:{}订单不存在", transactionId); return; } log.info("微信退款: 退款单号[{}] 退款成功.", outRefundNo); } @Override @Transactional(rollbackFor = Throwable.class) public void changeRelation(ChangeRelationReq req) throws Exception { Long relationId = req.getRelationId(); Long groupId = req.getGroupsId(); UserTicketClearedRecord.Source source = req.getSource(); if (source == null) source = UserTicketClearedRecord.Source.change_ticket; GroupsRelation relation = relationMapper.selectById(relationId); Long yhsId = relation.getYhsId(); Assert.notNull(relation, "车票已不存在"); if (relation.getRechargeStatus() != null) { throw BusinessRuntimeException.getInstance("代充账号车票无法更换车票"); } Long userId = relation.getUserId(); log.info("用户userId:{}更换车票relationId:{}", userId, relationId); OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class) .eq(OrderDon::getUserId, userId) .eq(OrderDon::getRelationId, relationId) .notIn(OrderDon::getStatus, Constant.noOrderStatus) .orderByDesc(OrderDon::getId) .last("limit 1")); OrderDiscountPlusPurchaseSkuRelation plusPurchaseSkuRelation = null; List plus_relationList = null; if (orderDon == null) { List plusPurchaseSkuRelations = orderDiscountPlusPurchaseSkuRelationMapper.selectPlusRelationByIdAndUserId(relation.getId(), relation.getUserId()); for (OrderDiscountPlusPurchaseSkuRelation data : plusPurchaseSkuRelations) { String relationIds = data.getRelationIds(); if (StrUtil.isEmpty(relationIds)) { return; } List relationList = Jsons.parseList(relationIds, Long.class); if (relationList.contains(relationId)) { plusPurchaseSkuRelation = data; break; } } if (plusPurchaseSkuRelation != null) { String relationIds = plusPurchaseSkuRelation.getRelationIds(); if (StrUtil.isNotEmpty(relationIds)) { plus_relationList = Jsons.parseList(relationIds, Long.class); if (plus_relationList.contains(relationId)) { orderDon = new OrderDon(); GroupsRelationView groupsRelationView = beanSearcher.searchFirst(GroupsRelationView.class, MapUtils.builder().field(GroupsRelationView::getId, relationId).build()); Assert.notNull(groupsRelationView, "车票已不存在"); orderDon.setUserId(groupsRelationView.getUserId()); orderDon.setSkuId(groupsRelationView.getSkuId()); orderDon.setGoodsId(groupsRelationView.getGoodsId()); orderDon.setStatus(OrderDon.Status.complete); } } } } Assert.notNull(orderDon, "订单不存在"); if (orderDon.getStatus() == OrderDon.Status.refund) { throw BusinessRuntimeException.getInstance("订单已退款"); } //获取新车队 LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(GroupsTrips.class) .eq(GroupsTrips::getSkuId, orderDon.getSkuId()) .eq(GroupsTrips::getId, groupId) .ne(GroupsTrips::getId, relation.getGroupsId()) .ne(GroupsTrips::getStatus, GroupsTrips.Status.down) .last("limit 1"); GroupsTrips groups = groupsMapper.selectOne(queryWrapper); if (groups == null) throw BusinessRuntimeException.getInstance("车队不存在或已下架"); if (!Constant.AI_goodsIds.contains(orderDon.getGoodsId()) && groups.getAvailableNum() <= 0) { throw BusinessRuntimeException.getInstance("该新车位人员已满"); } Integer relationNum = groups.getNum(); //获取新车队车位 GroupsRelation newRelation; Boolean isOutside = req.getIsOutside(); if (Constant.AI_goodsIds.contains(orderDon.getGoodsId()) && ((isOutside != null && isOutside) || groups.getAvailableNum() == 0)) { //Ai车队 额外增加车位 并不让上车 newRelation = getChatGPTOutsideRelation(orderDon.getUserId(), groupId, relationNum, 1); } else { newRelation = getRelationThisTrips(orderDon.getUserId(), groupId, 1); } newRelation.setUserId(userId); newRelation.setStartTime(relation.getStartTime()); newRelation.setExpiryTime(relation.getExpiryTime()); newRelation.setYhsId(yhsId); newRelation.setCustomerService(relation.getCustomerService()); if (newRelation.getStatus() != GroupsRelation.Status.outside) { newRelation.setStatus(GroupsRelation.Status.validity); } //清除原先车票 relation.setNewRelationId(newRelation.getId()); relationClearService.clearTicket(relation, source); if (plusPurchaseSkuRelation != null && plus_relationList != null) { plus_relationList.remove(relationId); plus_relationList.add(newRelation.getId()); plusPurchaseSkuRelation.setRelationIds(plus_relationList.toString()); orderDiscountPlusPurchaseSkuRelationMapper.updateById(plusPurchaseSkuRelation); } if (source != null && source == UserTicketClearedRecord.Source.abnormal) { //将用户异常订单关闭 workOrderMapper.update(null, Wrappers.lambdaUpdate(WorkOrder.class) .set(WorkOrder::getStatus, WorkOrder.Status.close) .eq(WorkOrder::getStatus, WorkOrder.Status.waiting) .eq(WorkOrder::getUserId, userId) .eq(WorkOrder::getRelationId, relationId)); } if (orderDon.getMoney() != null && orderDon.getMoney().compareTo(BigDecimal.ZERO) == 0) { //是否是实物权益车票 UserPayEquipmentReceiveBenefitsRecord receiveBenefitsRecord = receiveBenefitsRecordMapper.selectOne(Wrappers.lambdaQuery(UserPayEquipmentReceiveBenefitsRecord.class) .eq(UserPayEquipmentReceiveBenefitsRecord::getTicketOrderId, orderDon.getId()) .eq(UserPayEquipmentReceiveBenefitsRecord::getRelationId, relationId).last("limit 1")); if (receiveBenefitsRecord != null) { receiveBenefitsRecord.setRelationId(newRelation.getId()); receiveBenefitsRecordMapper.updateById(receiveBenefitsRecord); } } if ((newRelation.getStartTime() == null || newRelation.getExpiryTime() == null)) { List orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getUserId, userId).eq(OrderDon::getRelationId, relationId).eq(OrderDon::getStatus, OrderDon.Status.hasPayment)); if (orderDonList.isEmpty()) { orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class) .eq(OrderDon::getUserId, userId) .eq(OrderDon::getRelationId, relationId) .eq(OrderDon::getStatus, OrderDon.Status.complete) .orderByDesc(OrderDon::getId) .last("limit 1")); } if (groups.getStatus() == GroupsTrips.Status.waiting) { orderDonList.forEach(hasPaymentOrder -> { hasPaymentOrder.setRelationId(newRelation.getId()); orderDonMapper.updateById(hasPaymentOrder); }); relationMapper.updateById(newRelation); return; } orderDonList.forEach((hasPaymentOrder) -> { //如果续费增加时间,如果首次则设置当前时间为初始时间 Date expiryTime = Optional.ofNullable(newRelation.getExpiryTime()).orElse(new Date()); GoodsDonSku donSku = skuMapper.selectById(hasPaymentOrder.getSkuId()); Date newDate; if (donSku.getDays() != null && donSku.getDays() > 0) { newDate = DateUtil.offsetDay(expiryTime, donSku.getDays() * hasPaymentOrder.getNum()); } else { newDate = DateUtil.offset(expiryTime, DateField.MONTH, donSku.getMonths() * hasPaymentOrder.getNum()); } newRelation.setExpiryTime(newDate); newRelation.setStartTime(newRelation.getStartTime() == null ? new Date() : null); relationMapper.updateById(newRelation); hasPaymentOrder.setStatus(OrderDon.Status.complete); hasPaymentOrder.setRelationId(newRelation.getId()); orderDonMapper.updateById(hasPaymentOrder); }); return; } List orderDonList = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getUserId, userId).eq(OrderDon::getRelationId, relationId).eq(OrderDon::getStatus, OrderDon.Status.complete)); orderDonList.forEach(completeOrder->{ completeOrder.setRelationId(newRelation.getId()); orderDonMapper.updateById(completeOrder); }); log.info("userId:{}更换车票,原座位号relationId:{}======>新座位号newRelationId:{}", newRelation.getUserId(), relationId, newRelation.getId()); relationMapper.updateById(newRelation); } public String zfbRefund(OrderRefundReq refundReq, OrderDon orderDon) throws Exception { if (orderDon.getMoney().compareTo(BigDecimal.ZERO) <=0){ return StrUtil.EMPTY; } AlipayTradeRefundResponse response; //支付宝退款 AlipayClient alipayClient = AliPayClientFactory.getAlipayClient(Optional.ofNullable(orderDon.getShopId()).orElse(ShopConfig.ZFB_DEFAULT_APP_ID)); AlipayTradeRefundRequest request = new AlipayTradeRefundRequest(); AlipayTradeRefundModel model = new AlipayTradeRefundModel(); //支付宝交易号 model.setTradeNo(orderDon.getTransactionId()); model.setRefundAmount(refundReq.getRefundMoney().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_EVEN).toString()); model.setQueryOptions(List.of("gmt_refund_pay")); long time = System.currentTimeMillis(); //退款订单号 String outRefundNo = Codec.DoDigest.custom() .setAlgorithm(Codec.DoDigest.Algorithm.MD5) .setStringData(time + String.valueOf(orderDon.getId())) .toHexString(); //退款请求号 model.setOutRequestNo(outRefundNo); request.setBizModel(model); String shopId = orderDon.getShopId(); ShopConfig shopConfig = shopConfigMapper.selectOne(Wrappers.lambdaQuery(ShopConfig.class).eq(ShopConfig::getAppId, orderDon.getShopId())); if (shopId != null && shopConfig != null && shopConfig.getIsCert()) { response = alipayClient.certificateExecute(request); } else { response = alipayClient.execute(request); } if (!response.isSuccess()) throw BusinessRuntimeException.getInstance("退款失败,e:{0}", response.getSubMsg()); // AliPayRefundRep aliPayRefundRep = Jsons.parseObject(response.getBody(), AliPayRefundRep.class); // AliPayRefundRep.AlipayTradeRefundResponse res = aliPayRefundRep.getResponse(); // orderDon.setRefundMoney(res.getRefundFee().multiply(BigDecimal.valueOf(100))); return outRefundNo; } /** * 校验订单是否符合退款操作 */ private void checkOrderRefund(OrderDon orderDon, GoodsDon goodsDon, GoodsDonSku sku, OrderRefundReq refundReq) { if (orderDon == null) { throw BusinessRuntimeException.getInstance("订单不存在"); } String refundType = refundReq.getRefundType(); if (orderDon.getType() == OrderDon.Type.BALANCE && !OrderDon.Type.BALANCE.getType().equals(refundType)) { throw BusinessRuntimeException.getInstance("余额支付的订单不支持金额退款"); } if (OrderDon.Status.refund == orderDon.getStatus()) { throw BusinessRuntimeException.getInstance("该订单已退款"); } if (OrderDon.Status.noPayment == orderDon.getStatus() || OrderDon.Status.close == orderDon.getStatus()) { throw BusinessRuntimeException.getInstance("订单{0}状态不支持退款", orderDon.getStatus()); } if (goodsDon.getType() == 1 && sku != null) { //虚拟原订单是否已过期 Integer months = sku.getMonths(); Integer days = sku.getDays(); Integer num = orderDon.getNum(); DateTime now = DateTime.now(); DateTime endTime; if (days != null && days > 0) { endTime = DateUtil.offsetDay(orderDon.getCreatedTime(), days * num); } else { endTime = DateUtil.offsetMonth(orderDon.getCreatedTime(), months * num); } if (now.isAfter(endTime)) { throw BusinessRuntimeException.getInstance("该订单车票已过期"); } if (orderDon.getOrderType() == 1) { //是否有其他付款订单是否过期 OrderDon otherOrder = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class) .eq(OrderDon::getRelationId, orderDon.getRelationId()) .eq(OrderDon::getUserId, orderDon.getUserId()) .ne(OrderDon::getId, orderDon.getId()) .notIn(OrderDon::getStatus, Constant.noOrderAllStatus) .eq(OrderDon::getOrderType, 2) .orderByDesc(OrderDon::getId) .last("limit 1")); if (otherOrder != null) { throw BusinessRuntimeException.getInstance("该笔订单存在续费订单,请先退掉续费订单"); } } } BigDecimal refundMoney = refundReq.getRefundMoney(); BigDecimal money = orderDon.getMoney(); //余额退款 if (OrderDon.Type.BALANCE.getType().equals(refundType)) { BigDecimal balance = orderDon.getBalance(); if (OrderDon.Type.BALANCE == orderDon.getType() && refundMoney.compareTo(balance) > 0) { throw BusinessRuntimeException.getInstance("退款余额大于订单支付余额"); } if (OrderDon.Type.BALANCE != orderDon.getType() && refundMoney.compareTo(money) > 0) { throw BusinessRuntimeException.getInstance("退款余额大于订单支付金额"); } orderDon.setRefundBalance(refundMoney); orderDon.setRefundMoney(BigDecimal.ZERO); } else { //退金额 if (refundMoney.compareTo(money) > 0) { throw BusinessRuntimeException.getInstance("退款金额大于订单支付金额"); } orderDon.setRefundMoney(refundMoney); } //礼品卡是否已使用 GiftCardUserRecord giftCardUserRecord = null; if (goodsDon.getSpecialType() != null && goodsDon.getSpecialType() == GoodsDon.SpecialType.giftCard) { giftCardUserRecord = giftCardUserRecordMapper.selectOne(Wrappers.lambdaQuery(GiftCardUserRecord.class) .eq(GiftCardUserRecord::getOrderId, orderDon.getId()).last("limit 1")); if (giftCardUserRecord != null && giftCardUserRecord.getIsUsed()) { throw BusinessRuntimeException.getInstance("该礼品卡已使用无法退款"); } } if (!redisService.setNx(String.format("%s", refundReq.getOrderId()), refundReq.getOrderId(), 10l)) { throw BusinessRuntimeException.getInstance("请勿重复点击,正在退款中.."); } //礼品卡购买状态 if (giftCardUserRecord != null) { giftCardUserRecord.setIsPay(false); giftCardUserRecordMapper.updateById(giftCardUserRecord); } } /** * 退款后 处理关联 */ public void commonRefund(OrderDon orderDon, GoodsDon goodsDon, GoodsDonSku sku, String outNo, String refundType) { TASK_POOL.execute(() -> { refundRecord(orderDon, goodsDon, sku, outNo, refundType); //退款一次 goodsDonStockService.upStockRelate(null, orderDon.getId(), "refund"); try { //虚物订单退款,清出车队,车票变为已过期 orderCommonService.clearUnrealGoodsDetail(orderDon, goodsDon.getType(), sku); } catch (Exception e) { log.error("清除车票错误:{}", StringUtil.getErrorText(e)); } //若存在优惠券使用,退还优惠券 if (orderDon.getCouponUserId() != 0) { couponFontService.updateOrderDonCouponStatus(orderDon); } //若存在余额支付,退还余额 if (orderDon.getBalance().compareTo(BigDecimal.ZERO) > 0) { userBenefitsService.addUserBalance(orderDon.getUserId(), orderDon.getBalance(), UserBalanceSourceRecord.Source.balance, orderDon.getYhsId()); } try { marketFrontService.subSpecificChanceNum(orderDon.getUserId(), orderDon.getId(), orderDon.getGoodsId(), orderDon.getUpdateTime()); if (goodsDon.getType() == 2) { equipmentDistributeService.subDistributeBenefitsChance(orderDon.getUserId(), orderDon.getId()); //扣除用户自身实物权益 userRealOrderBenefitsService.deductUserRealGoodsBenefits(orderDon.getId()); } } catch (Exception e) { log.error("wx减少抽奖机会错误,orderId:{},error:{}", orderDon.getId(), e); } if (OrderDon.Type.BALANCE.getType().equals(refundType)) { if (orderDon.getMoney().compareTo(BigDecimal.ZERO) > 0) { userBenefitsService.addUserBalance(orderDon.getUserId(), orderDon.getRefundBalance(), UserBalanceSourceRecord.Source.refund, orderDon.getYhsId()); } } else { //余额退款不需要扣除积分 //分销提成积分扣除 deductDsPoints(orderDon); //店铺 分销提成金额扣除 yhShopDistributeService.deductDsMoney(orderDon); } if (orderDon.getIsFixedDistribute()) { //商务提成 因订单退款去掉 UserDistributeBusinessOrderDonRecord record = businessOrderDonRecordMapper.selectOne(Wrappers.lambdaQuery(UserDistributeBusinessOrderDonRecord.class) .eq(UserDistributeBusinessOrderDonRecord::getOrderId, orderDon.getId()) .eq(UserDistributeBusinessOrderDonRecord::getStatus, UserDistributeBusinessOrderDonRecord.Status.success) .last("limit 1")); if (record != null) { record.setStatus(UserDistributeBusinessOrderDonRecord.Status.refund); businessOrderDonRecordMapper.updateById(record); } } //店铺商务提成 if (orderDon.getYhsId() != null && orderDon.getYhsId() > 0) { YhShopUserDistributeBusinessOrderDonRecord shop_record = yhShopBusinessOrderDonRecordMapper.selectOne(Wrappers.lambdaQuery(YhShopUserDistributeBusinessOrderDonRecord.class) .eq(YhShopUserDistributeBusinessOrderDonRecord::getOrderId, orderDon.getId()) .eq(YhShopUserDistributeBusinessOrderDonRecord::getStatus, YhShopUserDistributeBusinessOrderDonRecord.Status.success) .last("limit 1")); if (shop_record != null) { shop_record.setStatus(YhShopUserDistributeBusinessOrderDonRecord.Status.refund); yhShopBusinessOrderDonRecordMapper.updateById(shop_record); } } //是否是优惠加购关联订单 if (orderDon.getIsDp()) { OrderDiscountPlusPurchaseSkuRelation discountPlusPurchaseSkuRelation = orderDiscountPlusPurchaseSkuRelationMapper.selectOne(Wrappers.lambdaQuery(OrderDiscountPlusPurchaseSkuRelation.class) .eq(OrderDiscountPlusPurchaseSkuRelation::getOrderId, orderDon.getId()).last("limit 1")); if (discountPlusPurchaseSkuRelation != null) { String relationIdsStr = discountPlusPurchaseSkuRelation.getRelationIds(); if (StrUtil.isNotBlank(relationIdsStr)) { try { List relationIds = Jsons.parseList(relationIdsStr, Long.class); List groupsRelations = relationMapper.selectList(Wrappers.lambdaQuery(GroupsRelation.class) .in(GroupsRelation::getId, relationIds)); log.info("优惠加购订单orderId:{}退款,清除相关车票relation_ids:{}", orderDon.getId(), relationIds); groupsRelations.forEach(relation -> relationClearService.clearTicket(relation, UserTicketClearedRecord.Source.dp)); } catch (Exception e) { } } String plusOrderIds = discountPlusPurchaseSkuRelation.getPlusOrderIds(); if (StrUtil.isNotBlank(plusOrderIds)) { try { log.info("关闭优惠加购orderId:{}关联实物订单", orderDon.getId()); List plusOrderIdList = Jsons.parseList(plusOrderIds, Long.class); List relate_orderDons = orderDonMapper.selectList(Wrappers.lambdaQuery(OrderDon.class) .in(OrderDon::getId, plusOrderIdList) .notIn(OrderDon::getStatus, Constant.noOrderStatus)); relate_orderDons.forEach(relate_o->{ //扣除用户自身实物权益 userRealOrderBenefitsService.deductUserRealGoodsBenefits(relate_o.getId()); }); orderDonMapper.update(null, Wrappers.lambdaUpdate(OrderDon.class) .set(OrderDon::getStatus, OrderDon.Status.refund) .in(OrderDon::getId, plusOrderIdList) .ne(OrderDon::getStatus, OrderDon.Status.refund)); } catch (Exception e) { } } } } //同步车票退款 重购记录 TASK_POOL.execute(() -> { GroupsRelationExpiryRecord groupsRelationExpiryRecord = groupsRelationExpiryRecordService.getOne(Wrappers.lambdaQuery(GroupsRelationExpiryRecord.class) .in(GroupsRelationExpiryRecord::getReBuyOrderId, orderDon.getId()) .eq(GroupsRelationExpiryRecord::getRelationId, orderDon.getRelationId()).last("limit 1")); if (groupsRelationExpiryRecord == null) { log.info("订单orderId:{}退款,同步是否有重购记录不是直接续费车票",orderDon.getId()); List groupsRelationExpiryRecords = groupsRelationExpiryRecordService.list(Wrappers.lambdaQuery(GroupsRelationExpiryRecord.class) .in(GroupsRelationExpiryRecord::getReBuyOrderId, orderDon.getId())); log.info("订单orderId:{}退款,重购记录不是直接续费车票大小:{}",groupsRelationExpiryRecords.size()); if (CollUtil.isNotEmpty(groupsRelationExpiryRecords)) { groupsRelationExpiryRecords.forEach(data -> { data.setIsReBuy(false); }); groupsRelationExpiryRecordService.saveOrUpdateBatch(groupsRelationExpiryRecords); } } if (groupsRelationExpiryRecord != null) { groupsRelationExpiryRecord.setIsReBuy(false); groupsRelationExpiryRecordService.saveOrUpdate(groupsRelationExpiryRecord); } }); //是否是礼品卡 现金支付订单 BigDecimal gcCash = orderDon.getGcCash(); if (gcCash != null && gcCash.compareTo(BigDecimal.ZERO) > 0) { giftCardOrderUseRecordService.returnGiftCardCash(orderDon.getId()); } }); } /** * 退款 分销提成积分扣除 */ public void deductDsPoints(OrderDon orderDon) { if (orderDon.getIsDistribute()) { DistributeWaitingSendPoints distributeWaitingSendPoints = distributeWaitingSendPointsMapper.selectOne(Wrappers.lambdaQuery(DistributeWaitingSendPoints.class).eq(DistributeWaitingSendPoints::getOrderId, orderDon.getId()).last("limit 1")); if (distributeWaitingSendPoints != null) { BigDecimal money = orderDon.getMoney(); BigDecimal refundMoney = orderDon.getRefundMoney(); //已发送 发送中 部分 全额退款 DistributeWaitingSendPoints.Status sendStatus = distributeWaitingSendPoints.getSendStatus(); BigDecimal points = distributeWaitingSendPoints.getPoints(); if (sendStatus == DistributeWaitingSendPoints.Status.waiting) { if (refundMoney.compareTo(money) == 0) { //待发送状态 全额退款 distributeWaitingSendPoints.setSendStatus(DistributeWaitingSendPoints.Status.close); distributeWaitingSendPoints.setRefundPoints(points); distributeWaitingSendPoints.setPoints(BigDecimal.ZERO); distributeWaitingSendPointsMapper.updateById(distributeWaitingSendPoints); return; } Integer thisGoodsRate = distributeWaitingSendPoints.getRate(); if (thisGoodsRate == null || thisGoodsRate == 0) { thisGoodsRate = Optional.ofNullable(userDistributeMapper.getDistributeGoodsRateByUidAndGid(orderDon.getUserId(), orderDon.getGoodsId())).orElse(0); } if (thisGoodsRate > 0) { BigDecimal needSubPoints = refundMoney.multiply(BigDecimal.valueOf(thisGoodsRate).divide(BigDecimal.valueOf(100))).multiply(BigDecimal.valueOf(10)); if (needSubPoints.compareTo(points) > 0) { //全扣除 distributeWaitingSendPoints.setSendStatus(DistributeWaitingSendPoints.Status.close); needSubPoints = points; } distributeWaitingSendPoints.setRefundPoints(needSubPoints); //剩余积分 BigDecimal remainPoints = points.subtract(needSubPoints); distributeWaitingSendPoints.setPoints(remainPoints); distributeWaitingSendPointsMapper.updateById(distributeWaitingSendPoints); } } else if (sendStatus == DistributeWaitingSendPoints.Status.success) { //已发送的提成 部分退款 全额退款 需要扣除用户积分 //扣除固定推广者积分 if (refundMoney.compareTo(money) == 0) { userBenefitsService.deductDistributePoints(orderDon.getId(), distributeWaitingSendPoints.getSharedId(), points); distributeWaitingSendPoints.setRefundPoints(points); distributeWaitingSendPoints.setPoints(BigDecimal.ZERO); distributeWaitingSendPoints.setSendStatus(DistributeWaitingSendPoints.Status.close); distributeWaitingSendPointsMapper.updateById(distributeWaitingSendPoints); return; } Integer thisGoodsRate = distributeWaitingSendPoints.getRate(); if (thisGoodsRate == null || thisGoodsRate == 0) { thisGoodsRate = Optional.ofNullable(userDistributeMapper.getDistributeGoodsRateByUidAndGid(orderDon.getUserId(), orderDon.getGoodsId())).orElse(0); } if (thisGoodsRate > 0) { BigDecimal needSubPoints = refundMoney.multiply(BigDecimal.valueOf(thisGoodsRate).divide(BigDecimal.valueOf(100))).multiply(BigDecimal.valueOf(10)); if (needSubPoints.compareTo(points) > 0) { //全扣除 distributeWaitingSendPoints.setSendStatus(DistributeWaitingSendPoints.Status.close); needSubPoints = points; } userBenefitsService.deductDistributePoints(orderDon.getId(), distributeWaitingSendPoints.getSharedId(), needSubPoints); //部分退款 distributeWaitingSendPoints.setRefundPoints(needSubPoints); distributeWaitingSendPoints.setPoints(points.subtract(needSubPoints)); distributeWaitingSendPointsMapper.updateById(distributeWaitingSendPoints); } } } } } /** * 记录退款信息 */ @Override public void refundRecord(OrderDon orderDon, GoodsDon goodsDon, GoodsDonSku sku, String outRefundNo, String refundType) { RefundOrderDon refund = new RefundOrderDon(); refund.setOrderId(orderDon.getId()); refund.setOutRefundNo(outRefundNo); refund.setTotalFee(orderDon.getMoney()); refund.setRefundDesc(orderDon.getRefundDesc()); //退款金额 refund.setRefundFee(orderDon.getRefundMoney()); refund.setUserId(orderDon.getUserId()); refund.setGoodsId(orderDon.getGoodsId()); refund.setGoodsTitle(goodsDon == null ? null : goodsDon.getTitle()); refund.setSkuId(orderDon.getSkuId()); refund.setSpecVal(sku == null ? null : String.format("%s%s", sku.getSpecVal(), sku.getPrice().divide(BigDecimal.valueOf(100)))); refund.setRefundMethod(orderDon.getType().name()); refund.setGoodsType(goodsDon == null ? 0 : goodsDon.getType()); //退款方式 if (StrUtil.isNotBlank(refundType) && refundType.equals(OrderDon.Type.BALANCE.getType())) { refund.setRefundMethod(refundType); refund.setRefundFee(orderDon.getRefundBalance()); } refundOrderDonMapper.insert(refund); } @Override public void refundPriceDiffer(OrderRefundReq orderRefundReq) { Long orderId = orderRefundReq.getOrderId(); OrderDon orderDon = orderDonMapper.selectById(orderId); if (orderDon == null) { throw BusinessRuntimeException.getInstance("订单不存在"); } if (orderDon.getMoney().compareTo(BigDecimal.ZERO) == 0) { throw BusinessRuntimeException.getInstance("该订单是0元订单,无法补差价"); } if (Constant.noOrderAllStatus.contains(orderDon.getStatus().name())) { throw BusinessRuntimeException.getInstance("订单不是已支付状态"); } BigDecimal refundBalance = orderRefundReq.getRefundBalance(); if (refundBalance == null || refundBalance.compareTo(BigDecimal.ZERO) <= 0 || refundBalance.compareTo(orderDon.getMoney()) > 0) { throw BusinessRuntimeException.getInstance("请输入正确的差价金额"); } userBenefitsService.addUserBalance(orderDon.getUserId(), refundBalance, UserBalanceSourceRecord.Source.price_differ, orderDon.getYhsId()); } /** * 寻找该车队空余车位 */ public GroupsRelation getRelationThisTrips(Long userId, Long groupsId, Integer retryNum) { //寻找快满编车队进行占座 GroupsRelation relation = relationMapper.selectRandomOneRelationByGroupsId(groupsId); if (relation == null) { throw BusinessRuntimeException.getInstance("该车队人员已满,请选择另一车队"); } Long relationId = relation.getId(); if (!redisService.setNx(RedisKey.GROUPS_RELATION_NUM_KEY + relationId, userId, 60 * 5L)) { if (retryNum == 7) throw BusinessRuntimeException.getInstance("该车队人员已满,请选择另一车队"); retryNum++; getRelationThisTrips(userId, groupsId, retryNum); } int count = groupsMapper.decrAvailableNum(relation.getGroupsId()); if (count == 0) { log.error("车位异常 groupId:{}", groupsId); groupsMapper.updateAvailableNum(groupsId); throw new BusinessRuntimeException("车位异常"); } return relation; } private GroupsRelation getChatGPTOutsideRelation(Long userId, Long groupsId, Integer relationNum, Integer retryNum) { //寻找快满编车队额外座位 GroupsRelation relation = relationMapper.selectOutsideRelationByGroupsId(groupsId, relationNum); if (relation == null) { relation = new GroupsRelation(); relation.setStatus(GroupsRelation.Status.outside); relation.setUserId(userId); relation.setGroupsId(groupsId); GroupsRelation maxNumRelation = relationMapper.selectOne(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getGroupsId, groupsId).orderByDesc(GroupsRelation::getNum).last("limit 1")); relation.setNum(maxNumRelation.getNum() + 1); relationMapper.insert(relation); return relation; } Long relationId = relation.getId(); if (!redisService.setNx(RedisKey.GROUPS_RELATION_NUM_KEY + relationId, userId, 60 * 5L)) { if (retryNum == 7) throw BusinessRuntimeException.getInstance("该车队人员已满,请选择另一车队"); retryNum++; getChatGPTOutsideRelation(userId, groupsId, relationNum, retryNum); } return relation; } }