springboot开发微信小程序实现花呗支付功能

1:需求 在开发电商的微信小程序中,需要实现花呗支付功能,包括信用额度的申请,支付,还款,查看还款记录,支付记录的功能。

实现步骤:第一步设计数据库表结构

CREATE TABLE `eb_credit_amount` (
  `id` varchar(64) NOT NULL COMMENT 'id',
  `uid` int unsigned NOT NULL COMMENT '用户ID',
  `credit_amount` decimal(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '授信额度',
  `credit_pay_amount` decimal(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '已使用额度',
  `credit_repayment_amount` decimal(10,2) DEFAULT NULL COMMENT '已还款额度',
  `credit_remain_amount` decimal(10,2) NOT NULL DEFAULT '0.00' COMMENT '剩余额度',
  `contract_type` varchar(8) DEFAULT '0' COMMENT '合同类型',
  `contract_code` varchar(255) DEFAULT '1' COMMENT '合同编号',
  `settle_term` int DEFAULT NULL COMMENT '结算期限(天)',
  `credit_status` int NOT NULL COMMENT '授信状态 0:关闭,1-开启',
  `credit_time` datetime DEFAULT NULL COMMENT '授信开启时间',
  `contract_start_date` date DEFAULT NULL COMMENT '合同开始时间',
  `contract_end_date` date DEFAULT NULL COMMENT '合同结束时间',
  `agreement_pic` varchar(255) DEFAULT NULL COMMENT '协议图片',
  `audit_status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '审核状态0:待审核,1审核通过,2:审核拒绝',
  `audit_by` varchar(255) DEFAULT NULL COMMENT '审核人',
  `audit_remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '审核意见',
  `create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '提交人',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `task_start_time` timestamp NULL DEFAULT NULL COMMENT '任务执行时间',
  `status` int DEFAULT NULL COMMENT '启用状态,0:冻结;1:正常',
  `cron_expression` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '结算cron表达式',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `user_id` (`uid`) USING BTREE,
  KEY `search_id` (`id`,`uid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=COMPACT COMMENT='授信用户表';

SET FOREIGN_KEY_CHECKS = 1;
DROP TABLE IF EXISTS `eb_credit_bill`;
CREATE TABLE `eb_credit_bill` (
  `id` varchar(64) NOT NULL COMMENT 'id',
  `uid` int unsigned DEFAULT NULL COMMENT '用户ID',
  `credit_amount` decimal(10,2) unsigned DEFAULT '0.00' COMMENT '授信额度',
  `credit_pay_amount` decimal(10,2) unsigned DEFAULT '0.00' COMMENT '已使用额度',
  `credit_repayment_amount` decimal(10,2) DEFAULT NULL COMMENT '已还款额度',
  `credit_remain_amount` decimal(10,2) DEFAULT '0.00' COMMENT '剩余额度',
  `contract_type` varchar(8) DEFAULT '0' COMMENT '合同类型',
  `contract_code` varchar(255) DEFAULT '1' COMMENT '合同编号',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `user_id` (`uid`) USING BTREE,
  KEY `search_id` (`id`,`uid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=COMPACT COMMENT='授信流水表';

SET FOREIGN_KEY_CHECKS = 1;
CREATE TABLE `eb_credit_order_bill` (
  `id` varchar(64) NOT NULL COMMENT 'id',
  `uid` int unsigned NOT NULL COMMENT '用户ID',
  `order_no` varchar(255) NOT NULL COMMENT '订单号',
  `pay_price` decimal(10,2) DEFAULT NULL COMMENT '支付金额',
  `pay_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '支付类型',
  `pay_time` datetime DEFAULT NULL COMMENT '交易时间',
  `credit_repayment_amount` decimal(10,2) DEFAULT NULL COMMENT '还款金额',
  `credit_repayment_type` varchar(255) DEFAULT NULL COMMENT '还款方式',
  `credit_repayment_time` datetime DEFAULT NULL COMMENT '还款时间',
  `credit_repayment_flag` int DEFAULT NULL COMMENT '是否还款',
  `out_trade_no` varchar(255) DEFAULT NULL COMMENT '还款订单号',
  `year` int DEFAULT NULL COMMENT '年份',
  `month` int DEFAULT NULL COMMENT '月份',
  `pay_channel` varchar(255) DEFAULT NULL COMMENT '支付渠道',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `credit_repayment_no` varchar(255) DEFAULT NULL COMMENT '还款订单号',
  `payid` int DEFAULT NULL COMMENT '是否支付',
  `order_type` int DEFAULT NULL COMMENT '交易类型',
  `task_start_time` timestamp NULL DEFAULT NULL COMMENT '任务执行开始时间',
  `task_end_time` timestamp NULL DEFAULT NULL COMMENT '任务执行结束时间',
  `task_status` int DEFAULT NULL COMMENT '任务是否执行:0:未执行,1已执行',
  `is_update` int DEFAULT NULL COMMENT '是否修改',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `user_id` (`uid`) USING BTREE,
  KEY `search_id` (`id`,`uid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=COMPACT COMMENT='授信用户账单表';

SET FOREIGN_KEY_CHECKS = 1;
CREATE TABLE `eb_credit_order_bill_record` (
  `id` varchar(64) NOT NULL COMMENT 'id',
  `uid` int unsigned NOT NULL COMMENT '用户ID',
  `order_no` varchar(255) NOT NULL COMMENT '订单号',
  `pay_price` decimal(10,2) NOT NULL COMMENT '支付金额',
  `update_user` varchar(255) NOT NULL COMMENT '更新人',
  `update_time` datetime NOT NULL COMMENT '更新时间',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `create_user` varchar(255) NOT NULL COMMENT '创建人',
  `remark` varchar(255) NOT NULL COMMENT '备注',
  `bill_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '账单id',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `user_id` (`uid`) USING BTREE,
  KEY `search_id` (`id`,`uid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=COMPACT COMMENT='授信用户账单表';

SET FOREIGN_KEY_CHECKS = 1;
CREATE TABLE `eb_credit_repay_order` (
  `id` varchar(255) NOT NULL COMMENT 'id',
  `order_no` varchar(255) NOT NULL COMMENT '订单号',
  `out_trade_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '商户订单号',
  `pay_price` decimal(10,2) DEFAULT NULL COMMENT '支付金额',
  `pay_type` varchar(255) DEFAULT NULL COMMENT '支付类型',
  `pay_channel` varchar(255) DEFAULT NULL COMMENT '支付渠道',
  `pay_time` datetime DEFAULT NULL COMMENT '支付时间',
  `is_paid` int DEFAULT NULL COMMENT '是否支付',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
  `uid` int DEFAULT NULL COMMENT '用户id',
  `year` int DEFAULT NULL COMMENT '还款年份',
  `month` int DEFAULT NULL COMMENT '还款月份',
  `is_all` int DEFAULT NULL COMMENT '是否全部还款',
  PRIMARY KEY (`id`,`order_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='授信支付订单表';

SET FOREIGN_KEY_CHECKS = 1;

CREATE TABLE `eb_credit_bill_info` (
  `id` varchar(64) NOT NULL COMMENT 'id',
  `uid` int unsigned DEFAULT NULL COMMENT '用户ID',
  `credit_pay_amount` decimal(10,2) unsigned DEFAULT '0.00' COMMENT '已使用额度',
  `credit_remain_amount` decimal(10,2) DEFAULT '0.00' COMMENT '剩余额度',
  `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `credit_type` int NOT NULL COMMENT '消费类型:0:消费:1还款,2:退款;3:额度增加;4:额度减少'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='授信流水详情表';

SET FOREIGN_KEY_CHECKS = 1;

第二步骤:在平台新增额度管理功能,给用户新增额度管理,

package com.zbkj.admin.controller.platform.credit;

import com.zbkj.common.model.admin.SystemAdmin;
import com.zbkj.common.model.credit.CreditAmount;
import com.zbkj.common.model.credit.CreditBillInfo;
import com.zbkj.common.page.CommonPage;
import com.zbkj.common.request.PageParamRequest;
import com.zbkj.common.request.credit.CreditAmountCheckRequest;
import com.zbkj.common.request.credit.CreditAmountCreditStatusRequest;
import com.zbkj.common.request.credit.CreditAmountRequest;
import com.zbkj.common.request.credit.CreditAmountSearchRequest;
import com.zbkj.common.response.credit.CreditAmountResponse;
import com.zbkj.common.response.credit.CreditOrderBillResponse;
import com.zbkj.common.result.CommonResult;
import com.zbkj.common.utils.SecurityUtil;
import com.zbkj.common.vo.LoginUserVo;
import com.zbkj.service.service.UserService;
import com.zbkj.service.service.credit.CreditAmountService;
import com.zbkj.service.service.credit.CreditBillInfoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;


/**
 * 用户授信信息 前端控制器
 */
@Slf4j
@RestController
@RequestMapping("api/admin/platform/credit/amount")
@Api(tags = "用户授信信息") //配合swagger使用
public class CreditAmountController {

    @Autowired
    private CreditAmountService creditAmountService;
    @Autowired
    private CreditBillInfoService creditBillInfoService;

    /**
     * 分页显示用户授信信息
     * @param request 搜索条件
     * @param pageParamRequest 分页参数
     * @author dudianlong
     * @since 2024-11-21
     */
    @ApiOperation(value = "分页列表") //配合swagger使用
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public CommonResult<CommonPage<CreditAmountResponse>> getList(@Validated CreditAmountSearchRequest request, @Validated PageParamRequest pageParamRequest) {
        CommonPage<CreditAmountResponse> creditAmountCommonPage = CommonPage.restPage(creditAmountService.getList(request, pageParamRequest));
        return CommonResult.success(creditAmountCommonPage);
    }

    /**
     * 新增用户授信信息
     * @param creditAmountRequest 新增参数
     * @author dudianlong
     * @since 2024-11-21
     */
    @PreAuthorize("hasAuthority('platform:creditAmount:save')")
    @ApiOperation(value = "新增用户授信")
    @RequestMapping(value = "/save", method = RequestMethod.POST)
    public CommonResult<String> save(@RequestBody @Validated CreditAmountRequest creditAmountRequest) {
        SystemAdmin systemAdmin = SecurityUtil.getLoginUserVo().getUser();
        creditAmountRequest.setCreateBy(systemAdmin.getRealName());

        if(creditAmountService.saveCreditAmount(creditAmountRequest)) {
            return CommonResult.success();
        } else {
            return CommonResult.failed();
        }
    }

    /**
     * 删除用户授信信息
     * @param id Integer
     * @author dudianlong
     * @since 2024-11-21
     */
    @ApiOperation(value = "删除用户授信")
    @RequestMapping(value = "/delete", method = RequestMethod.GET)
    public CommonResult<String> delete(@RequestParam(value = "id") Integer id) {
        if(creditAmountService.removeById(id)) {
            return CommonResult.success();
        } else {
            return CommonResult.failed();
        }
    }

    /**
     * 修改用户授信信息
     * @param creditAmountRequest 修改参数
     * @author dudianlong
     * @since 2024-11-21
     */
    @PreAuthorize("hasAuthority('platform:creditAmount:edit')")
    @ApiOperation(value = "修改用户授信")
    @RequestMapping(value = "/update", method = RequestMethod.POST)
    public CommonResult<String> update(@RequestBody @Validated CreditAmountRequest creditAmountRequest) {
        if(creditAmountService.updateCreditAmount(creditAmountRequest)){
            return CommonResult.success();
        } else {
            return CommonResult.failed();
        }
    }

    @PreAuthorize("hasAuthority('platform:creditAmount:check')")
    @ApiOperation(value = "审核用户授信")
    @RequestMapping(value = "/check", method = RequestMethod.POST)
    public CommonResult<String> check(@RequestBody @Validated CreditAmountCheckRequest creditAmountCheckRequest) {
        SystemAdmin systemAdmin = SecurityUtil.getLoginUserVo().getUser();
        creditAmountCheckRequest.setAuditBy(systemAdmin.getRealName());

        if(creditAmountService.checkCreditAmount(creditAmountCheckRequest)) {
            return CommonResult.success();
        } else {
            return CommonResult.failed();
        }
    }

    @ApiOperation(value = "开启/关闭账期")
    @RequestMapping(value = "/operatorCreditStatus", method = RequestMethod.POST)
    public CommonResult<String> operatorCreditStatus(@RequestBody @Validated CreditAmountCreditStatusRequest creditAmountCreditStatusRequest) {
        if(creditAmountService.operatorCreditStatus(creditAmountCreditStatusRequest)) {
            return CommonResult.success();
        } else {
            return CommonResult.failed();
        }
    }

    /**
     * 查询用户授信信息
     * @param id Integer
     * @author dudianlong
     * @since 2024-11-21
     */
    @ApiOperation(value = "详情用户授信")
    @RequestMapping(value = "/info", method = RequestMethod.GET)
    public CommonResult<CreditAmountResponse> info(@RequestParam(value = "id") String id) {
        CreditAmountResponse creditAmountResponse = creditAmountService.getDetail(id);
        return CommonResult.success(creditAmountResponse);
    }
     /**
     * 分页显示授信流水
     * @param request 搜索条件
     * @param pageParamRequest 分页参数
     * @author dudianlong
     * @since 2024-11-21
     */
    @ApiOperation(value = "分页列表") //配合swagger使用
    @RequestMapping(value = "/page", method = RequestMethod.GET)
    public CommonResult<CommonPage<CreditAmountResponse>> list(@Validated CreditAmountSearchRequest request, @Validated PageParamRequest pageParamRequest) {
        CommonPage<CreditAmountResponse> creditBillCommonPage = CommonPage.restPage(creditAmountService.getList(request, pageParamRequest));
        return CommonResult.success(creditBillCommonPage);
    }

    @ApiOperation(value = "列表统计") //配合swagger使用
    @RequestMapping(value = "/listStatistics", method = RequestMethod.GET)
    public CommonResult<CreditAmountResponse> listStatistics(@Validated  CreditAmountSearchRequest request) {
        CreditAmountResponse creditBillReponse = creditAmountService.getListStatistics(request);
        return CommonResult.success(creditBillReponse);
    }

    /**
     * 查询用户授信流水
     * @param uid Integer
     * @author dudianlong
     * @since 2024-11-21
     */
    @ApiOperation(value = "用户授信流水")
    @RequestMapping(value = "/getCreditBillInfoList", method = RequestMethod.GET)
    public CommonResult<CommonPage<CreditBillInfo>> getCreditBillInfoList(@RequestParam(value = "uid") Integer uid, @Validated PageParamRequest pageParamRequest) {
        CreditBillInfo creditBillInfo = new CreditBillInfo();
        creditBillInfo.setUid(uid);

        CommonPage<CreditBillInfo> page = CommonPage.restPage(creditBillInfoService.getList(creditBillInfo, pageParamRequest));
        return CommonResult.success(page);
    }
}



package com.zbkj.service.service.credit;

import com.baomidou.mybatisplus.extension.service.IService;
import com.zbkj.common.model.credit.CreditAmount;
import com.zbkj.common.model.order.Order;
import com.zbkj.common.request.PageParamRequest;
import com.zbkj.common.request.credit.CreditAmountCheckRequest;
import com.zbkj.common.request.credit.CreditAmountCreditStatusRequest;
import com.zbkj.common.request.credit.CreditAmountRequest;
import com.zbkj.common.request.credit.CreditAmountSearchRequest;
import com.zbkj.common.response.credit.CreditAmountResponse;
import com.zbkj.common.response.credit.CreditOrderBillResponse;

import java.math.BigDecimal;
import java.util.List;

/**
* @author dudianlong
* @description CreditAmountService 接口
* @date 2024-11-21
*/
public interface CreditAmountService extends IService<CreditAmount> {

    List<CreditAmountResponse> getList(CreditAmountSearchRequest request, PageParamRequest pageParamRequest);

    CreditAmountResponse getDetail(String id);

    boolean saveCreditAmount(CreditAmountRequest creditAmountRequest);
    boolean updateCreditAmount(CreditAmountRequest creditAmountRequest);

    boolean checkCreditAmount(CreditAmountCheckRequest creditAmountCheckRequest);
    boolean operatorCreditStatus(CreditAmountCreditStatusRequest creditAmountCreditStatusRequest);

    CreditAmount getByUserId(Integer uid);

    Boolean updateNowMoney(Integer uid, BigDecimal payPrice, String operationTypeSubtract);
    Boolean updateRemainMoney(Integer uid, BigDecimal payPrice, String operationTypeSubtract);
    Boolean updateCreditRepaymentAmounty(Integer uid, BigDecimal payPrice, String operationTypeSubtract);

    Boolean updateUserCredit(Order order);

    List<CreditAmount> getActiveCreditAmounts();

     List<CreditAmountResponse> getPageList(CreditAmountSearchRequest request, PageParamRequest pageParamRequest);
     CreditAmountResponse getListStatistics(CreditAmountSearchRequest request);

    void updateCronExpression(String id, String cronExpression);
    void disableUserCredit(Integer uid);

    void updateStatus();

    List<CreditAmount> getUserAmountInfo(List<Integer> uidList);
}
package com.zbkj.service.service.credit;


import com.baomidou.mybatisplus.extension.service.IService;
import com.zbkj.common.model.credit.CreditBillInfo;
import com.zbkj.common.model.credit.CreditRepayOrder;
import com.zbkj.common.page.CommonPage;
import com.zbkj.common.request.PageParamRequest;

import java.math.BigDecimal;
import java.util.List;

/**
* @author dudianlong
* @description CreditBillInfoService 接口
* @date 2024-11-22
*/
public interface CreditBillInfoService extends IService<CreditBillInfo> {

    List<CreditBillInfo> getList(CreditBillInfo creditBillInfo, PageParamRequest pageParamRequest);

    /**
     * 还款 新增记录
     */
   boolean addRecord(BigDecimal payPrice, Integer uid, Integer type);
}
package com.zbkj.service.service.impl.credit;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageHelper;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zbkj.common.constants.Constants;
import com.zbkj.common.exception.CrmebException;
import com.zbkj.common.model.credit.CreditAmount;
import com.zbkj.common.model.credit.CreditBillInfo;
import com.zbkj.common.model.credit.CreditOrderBill;
import com.zbkj.common.model.order.Order;
import com.zbkj.common.model.user.User;
import com.zbkj.common.request.PageParamRequest;
import com.zbkj.common.request.credit.CreditAmountCheckRequest;
import com.zbkj.common.request.credit.CreditAmountCreditStatusRequest;
import com.zbkj.common.request.credit.CreditAmountRequest;
import com.zbkj.common.request.credit.CreditAmountSearchRequest;
import com.zbkj.common.response.credit.CreditAmountResponse;
import com.zbkj.common.response.credit.CreditOrderBillResponse;
import com.zbkj.common.result.CommonResultCode;
import com.zbkj.service.dao.credit.CreditAmountDao;
import com.zbkj.service.dao.credit.CreditBillInfoDao;
import com.zbkj.service.service.UserService;
import com.zbkj.service.service.credit.CreditAmountService;
import com.zbkj.service.service.credit.CreditOrderBillService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import cn.hutool.core.util.StrUtil;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
* @author dudianlong
* @description CreditAmountServiceImpl 接口实现
* @date 2024-11-21
*/
@Slf4j
@Service
public class CreditAmountServiceImpl extends ServiceImpl<CreditAmountDao, CreditAmount> implements CreditAmountService {

    @Resource
    private CreditAmountDao dao;
    @Resource
    private UserService userService;
    @Resource
    private CreditAmountDao creditAmountDao;
    @Resource
    private CreditOrderBillService creditOrderBillService;
    @Resource
    private CreditBillInfoDao creditBillInfoDao;


    /**
    * 列表
    * @param request 请求参数
    * @param pageParamRequest 分页类参数
    * @author dudianlong
    * @since 2024-11-21
    * @return List<CreditAmount>
    */
    @Override
    public List<CreditAmountResponse> getList(CreditAmountSearchRequest request, PageParamRequest pageParamRequest) {
        if(pageParamRequest != null){
            PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());
        }

        List<CreditAmountResponse> list = creditAmountDao.getList(request);
        return list;
    }

     /**
    * 列表
    * @param request 请求参数
    * @param pageParamRequest 分页类参数
    * @author dudianlong
    * @since 2024-11-21
    * @return List<CreditAmount>
    */
    @Override
    public List<CreditAmountResponse> getPageList(CreditAmountSearchRequest request, PageParamRequest pageParamRequest) {
        if(pageParamRequest != null){
            PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());
        }

        List<CreditAmountResponse> list = creditAmountDao.getPageList(request);
        return list;
    }
     /**
    * 列表
    * @param request 请求参数
    * @author dudianlong
    * @since 2024-11-21
    * @return List<CreditAmount>
    */
    @Override
    public CreditAmountResponse getListStatistics(CreditAmountSearchRequest request) {
        CreditAmountResponse res = dao.getListStatistics(request);
        return res;
    }


    /**
     * 禁用用户授信功能
     * @param uid 用户ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void disableUserCredit(Integer uid) {
        try {
            // 查询用户当前授信信息
            LambdaQueryWrapper<CreditAmount> lqw = new LambdaQueryWrapper<>();
            lqw.eq(CreditAmount::getUid, uid)
                    .last("LIMIT 1");

            CreditAmount creditAmount = creditAmountDao.selectOne(lqw);

            if (creditAmount == null) {
                log.warn("未找到用户{}的授信记录", uid);
                return;
            }

            // 更新授信状态为禁用
            CreditAmount updateAmount = new CreditAmount();
            updateAmount.setId(creditAmount.getId());
            updateAmount.setStatus(0);
//            updateAmount.setCreditStatus(0); // 0表示禁用
            updateAmount.setUpdateTime(new Date());
           // updateAmount.setDisableReason("订单逾期未还款");

            int rows = creditAmountDao.updateById(updateAmount);

            if (rows > 0) {
                log.info("用户{}授信功能已禁用,原因:订单逾期未还款", uid);
            } else {
                log.error("禁用用户{}授信功能失败", uid);
                throw new CrmebException("禁用授信功能失败");
            }

        } catch (Exception e) {
            log.error("禁用用户{}授信功能时发生错误", uid, e);
            throw new CrmebException("禁用授信功能失败: " + e.getMessage());
        }
    }

    @Override
    public void updateStatus() {
        User info = userService.getInfo();
        if(Objects.isNull(info)) {
            return;
        }
      LambdaQueryWrapper<CreditAmount> lqw = new LambdaQueryWrapper<>();
        lqw.eq(CreditAmount::getUid, info.getId());
        CreditAmount creditAmount = creditAmountDao.selectOne(lqw);
        if(Objects.isNull(creditAmount)){
            return;
        }
        if(creditAmount.getStatus() == 0){
            creditAmount.setStatus(1);
        }
        creditAmountDao.updateById(creditAmount);
    }

    @Override
    public List<CreditAmount> getUserAmountInfo(List<Integer> uidList) {
        if(CollectionUtils.isNotEmpty(uidList)){
            return creditAmountDao.selectList(new LambdaQueryWrapper<CreditAmount>().in(CreditAmount::getUid, uidList));
        }
        return Collections.emptyList();
    }

    @Override
    public CreditAmountResponse getDetail(String id) {
        CreditAmountSearchRequest request = new CreditAmountSearchRequest();
        request.setId(id);
        List<CreditAmountResponse> list = getList(request, null);

        if(CollectionUtils.isNotEmpty(list)){
            return list.get(0);
        }
        return null;
    }

    @Override
    @Transactional
    public boolean saveCreditAmount(CreditAmountRequest creditAmountRequest) {
        CreditAmount creditAmount = new CreditAmount();
        BeanUtils.copyProperties(creditAmountRequest, creditAmount);

        //用户
        List<CreditAmount> exists = this.list(new LambdaQueryWrapper<CreditAmount>().eq(CreditAmount::getUid, creditAmountRequest.getUid()));
        if(CollectionUtils.isNotEmpty(exists)){
            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "该用户已存在授信记录");
        }

        creditAmount.setCreditPayAmount(BigDecimal.ZERO);
        creditAmount.setCreditRepaymentAmount(BigDecimal.ZERO);
        creditAmount.setCreditRemainAmount(BigDecimal.ZERO);
        creditAmount.setCreditStatus(0);
        creditAmount.setAuditStatus("0");
        creditAmount.setStatus(0);
        creditAmount.setTaskStartTime(DateUtil.date());
        this.save(creditAmount);

        User user = userService.getById(creditAmountRequest.getUid());
        user.setCreditStatus("1");  //用户置为开启授信
        userService.updateById(user);

        return true;
    }

    @Override
    @Transactional
    public boolean updateCreditAmount(CreditAmountRequest creditAmountRequest) {
        CreditAmount creditAmount = this.getById(creditAmountRequest.getId());
        BigDecimal sourceCreditAmount = creditAmount.getCreditAmount();

        BeanUtils.copyProperties(creditAmountRequest, creditAmount, "creditStatus");

        if(creditAmount.getAuditStatus().equals("2")){
            //拒绝审核的记录,编辑后置为待审核
            creditAmount.setAuditStatus("0");
        }else if(creditAmount.getAuditStatus().equals("1")){
            //已审核的授信用户,判断额度是否增减
            if(creditAmountRequest.getCreditAmount() != null){
                BigDecimal changeCreditAmount = creditAmountRequest.getCreditAmount().subtract(sourceCreditAmount);
                if(changeCreditAmount.compareTo(BigDecimal.ZERO) != 0){
                    //授信额度调整
                    saveCreditBillInfo(creditAmount, changeCreditAmount);
                }
            }
        }

        //判断当前合同期限时间,过期则置为冻结状态
        if(creditAmount.getContractEndDate()!=null){
            String contractEndDate = DateUtil.format(creditAmount.getContractEndDate(), "yyyy-MM-dd");
            String curDateStr = DateUtil.format(DateUtil.date(), "yyyy-MM-dd");
            if(contractEndDate.compareTo(curDateStr) < 0){
                creditAmount.setStatus(0);  //冻结
            }
            else if(contractEndDate.compareTo(curDateStr) >= 0){
                creditAmount.setStatus(1);  //正常
            }
        }
        String cronExpression = generateCronExpression(creditAmount.getSettleTerm());
        creditAmount.setCronExpression(cronExpression);
        return this.updateById(creditAmount);
    }
    public void saveCreditBillInfo(CreditAmount creditAmount, BigDecimal changeCreditAmount){
        //修改用户授信额度
        creditAmount.setCreditRemainAmount(creditAmount.getCreditRemainAmount().add(changeCreditAmount));

        //新增授信流水
        CreditBillInfo creditBillInfo = new CreditBillInfo();
        creditBillInfo.setUid(creditAmount.getUid());
        creditBillInfo.setCreditPayAmount(changeCreditAmount.abs());
        creditBillInfo.setCreditRemainAmount(creditAmount.getCreditRemainAmount());
        creditBillInfo.setCreateTime(new Date());
        creditBillInfo.setCreditType(changeCreditAmount.compareTo(BigDecimal.ZERO.stripTrailingZeros())>=0 ? 3 : 4);
        creditBillInfoDao.insert(creditBillInfo);
    }

    @Override
    public boolean checkCreditAmount(CreditAmountCheckRequest creditAmountCheckRequest) {
        CreditAmount creditAmount = this.getById(creditAmountCheckRequest.getId());
        if(!creditAmount.getAuditStatus().equals("0")){
            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "只有待审核的授信记录才能进行审核");
        }

        creditAmount.setAuditStatus(creditAmountCheckRequest.getAuditStatus());
        creditAmount.setAuditBy(creditAmountCheckRequest.getAuditBy());
        creditAmount.setAuditRemark(creditAmountCheckRequest.getAuditRemark());
        if(creditAmount.getAuditStatus().equals("1")){
            //审核通过
            creditAmount.setCreditStatus(1);
            creditAmount.setCreditRemainAmount(creditAmount.getCreditAmount());

            //判断当前合同期限时间,过期则置为冻结状态
            if(creditAmount.getContractEndDate()!=null){
                String contractEndDate = DateUtil.format(creditAmount.getContractEndDate(), "yyyy-MM-dd");
                String curDateStr = DateUtil.format(DateUtil.date(), "yyyy-MM-dd");
                if(contractEndDate.compareTo(curDateStr) < 0){
                    creditAmount.setStatus(0);  //冻结
                }else{
                    //设置状态
                    creditAmount.setStatus(1);  //正常
                    String cronExpression = generateCronExpression(creditAmount.getSettleTerm());
                    creditAmount.setCronExpression(cronExpression);
                }
            }
        }
        return this.updateById(creditAmount);
    }

    @Override
    public boolean operatorCreditStatus(CreditAmountCreditStatusRequest creditAmountCreditStatusRequest) {
        CreditAmount creditAmount = this.getById(creditAmountCreditStatusRequest.getId());
        if(!creditAmount.getAuditStatus().equals("1")){
            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "只有审核通过的授信用户才能操作账期开关");
        }

        creditAmount.setCreditStatus(creditAmountCreditStatusRequest.getCreditStatus());
        return this.updateById(creditAmount);
    }

    @Override
    public CreditAmount getByUserId(Integer uid) {
     return this.getOne(new LambdaQueryWrapper<CreditAmount>().eq(CreditAmount::getUid, uid));
    }

    /**
     *  授信已使用额度 剩余额度额度变动
     * @param uid
     * @param price
     * @param type
     * @return
     */
    @Override
    public Boolean updateNowMoney(Integer uid, BigDecimal price, String type) {
         UpdateWrapper<CreditAmount> wrapper = Wrappers.update();
        if (type.equals(Constants.OPERATION_TYPE_ADD)) {
            wrapper.setSql(StrUtil.format("credit_remain_amount = credit_remain_amount + {}", price));
        } else {
            wrapper.setSql(StrUtil.format("credit_remain_amount = credit_remain_amount - {}", price));
        }
        wrapper.eq("uid", uid);
        if (type.equals(Constants.OPERATION_TYPE_SUBTRACT)) {
            wrapper.apply(StrUtil.format(" credit_remain_amount - {} >= 0", price));
        }
        return update(wrapper);
    }

    /**
     * 更新已还款额度
     * @param uid
     * @param price
     * @param type
     * @return
     */
      @Override
    public Boolean updateCreditRepaymentAmounty(Integer uid, BigDecimal price, String type) {
         UpdateWrapper<CreditAmount> wrapper = Wrappers.update();
        if (type.equals(Constants.OPERATION_TYPE_ADD)) {
            wrapper.setSql(StrUtil.format("credit_repayment_amount = credit_repayment_amount + {}", price));
        } else {
            wrapper.setSql(StrUtil.format("credit_repayment_amount = credit_remain_amount - {}", price));
        }
        wrapper.eq("uid", uid);
        if (type.equals(Constants.OPERATION_TYPE_SUBTRACT)) {
            wrapper.apply(StrUtil.format(" credit_repayment_amount - {} >= 0", price));
        }
        return update(wrapper);
    }
    /**
     *  授信已使用额度 已使用额度额度变动
     * @param uid
     * @param price
     * @param type
     * @return
     */
    @Override
    public Boolean updateRemainMoney(Integer uid, BigDecimal price, String type) {
         UpdateWrapper<CreditAmount> wrapper = Wrappers.update();
        if (type.equals(Constants.OPERATION_TYPE_ADD)) {
            wrapper.setSql(StrUtil.format("credit_pay_amount = credit_pay_amount + {}", price));
        } else {
            wrapper.setSql(StrUtil.format("credit_pay_amount = credit_pay_amount - {}", price));
        }
        wrapper.eq("uid", uid);
        if (type.equals(Constants.OPERATION_TYPE_SUBTRACT)) {
            wrapper.apply(StrUtil.format(" credit_pay_amount - {} >= 0", price));
        }
        return update(wrapper);
    }

    @Override
    public Boolean updateUserCredit(Order order) {
        String platOrderNo = order.getPlatOrderNo();
        //查询授信订单
        CreditOrderBill creditOrderBill = creditOrderBillService.getByOrderNo(platOrderNo);
        if(Objects.nonNull(creditOrderBill)){
            if(creditOrderBill.getCreditRepaymentFlag()==0){
                //更新用户的授信额度
                updateNowMoney(order.getUid(), creditOrderBill.getPayPrice(), Constants.OPERATION_TYPE_ADD);
                updateRemainMoney(order.getUid(), creditOrderBill.getPayPrice(), Constants.OPERATION_TYPE_SUBTRACT);
            }
            creditOrderBill.setCreditRepaymentFlag(1);
            creditOrderBill.setCreditRepaymentAmount(order.getPayPrice());
            creditOrderBill.setCreditRepaymentTime(DateUtil.date());
            creditOrderBill.setPayType(order.getPayType());
            creditOrderBill.setPayChannel(order.getPayChannel());
            creditOrderBill.setOutTradeNo(order.getOutTradeNo());
            creditOrderBill.setOrderType(1);
            creditOrderBillService.updateById(creditOrderBill);
        }

        return true;
    }

    @Override
    public List<CreditAmount> getActiveCreditAmounts(){
      LambdaQueryWrapper<CreditAmount> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CreditAmount::getStatus, 1);  // 启用状态
      //  wrapper.le(CreditAmount::getContractEndDate, DateUtil.date());
        return dao.selectList(wrapper);
    }

    /**
     * 更新cron表达式
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateCronExpression(String id, String cronExpression) {
        CreditAmount update = new CreditAmount();
        update.setId(id);
        update.setCronExpression(cronExpression);
        // 更新任务执行时间+7天
        update.setTaskStartTime(DateUtil.offsetDay(new Date(), 7));
        update.setUpdateTime(new Date());
        creditAmountDao.updateById(update);
    }
    /**
     * 生成cron表达式
     */
    private String generateCronExpression(Integer settlementPeriod) {
        if (settlementPeriod == null || settlementPeriod <= 0) {
            settlementPeriod = 7; // 默7天
        }
        // 生成每隔N天执行一次的cron表达式,默认凌晨1点执行
        return String.format("0 0 1 */%d * ?", settlementPeriod);
    }

    /**
     * 初始化所有用户的cron表达式
     */
    @PostConstruct  // 项目启动时自动执行
    public void initCronExpressions() {
        try {
            // 查询所有没有cron表达式的记录
            LambdaQueryWrapper<CreditAmount> lqw = new LambdaQueryWrapper<>();
            lqw.isNull(CreditAmount::getCronExpression)
                    .or()
                    .eq(CreditAmount::getCronExpression, "");

            List<CreditAmount> list = creditAmountDao.selectList(lqw);

            if (CollUtil.isNotEmpty(list)) {
                for (CreditAmount creditAmount : list) {
                    // 生成并更新cron表达式
                    String cronExpression = generateCronExpression(creditAmount.getSettleTerm());
                    updateCronExpression(creditAmount.getId(), cronExpression);

                    log.info("已为用户{}生成结算cron表达式: {}",
                            creditAmount.getUid(), cronExpression);
                }
            }
        } catch (Exception e) {
            log.error("初始化cron表达式时发生错误", e);
        }
    }

}

package com.zbkj.service.service.impl.credit;



import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zbkj.common.model.credit.CreditAmount;
import com.zbkj.common.model.credit.CreditBillInfo;
import com.zbkj.common.request.PageParamRequest;
import com.zbkj.service.dao.credit.CreditBillInfoDao;
import com.zbkj.service.service.credit.CreditAmountService;
import com.zbkj.service.service.credit.CreditBillInfoService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
* @author dudianlong
* @description CreditBillInfoServiceImpl 接口实现
* @date 2024-11-22
*/
@Service
public class CreditBillInfoServiceImpl extends ServiceImpl<CreditBillInfoDao, CreditBillInfo> implements CreditBillInfoService {

    @Resource
    private CreditBillInfoDao dao;
    @Resource
    private CreditAmountService creditAmountService;


    @Override
    public List<CreditBillInfo> getList(CreditBillInfo creditBillInfo, PageParamRequest pageParamRequest) {
        if(pageParamRequest != null){
            Page<CreditBillInfo> page = PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());
        }

        LambdaQueryWrapper<CreditBillInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(creditBillInfo.getUid() != null){
            lambdaQueryWrapper.eq(CreditBillInfo::getUid, creditBillInfo.getUid());
        }
        lambdaQueryWrapper.orderByDesc(CreditBillInfo::getCreateTime);
        List<CreditBillInfo> list = dao.selectList(lambdaQueryWrapper);

        return list;
    }

    @Override
    public boolean addRecord(BigDecimal payPrice, Integer uid,Integer type) {
            CreditAmount creditAmount = creditAmountService.getByUserId(uid);
            //创建授信流水
            if(Objects.nonNull(creditAmount)){
              CreditBillInfo creditBillInfo=new CreditBillInfo();
              creditBillInfo.setUid(uid);
              creditBillInfo.setCreditType(type);
              creditBillInfo.setCreditPayAmount(payPrice);
              //剩余授信额度
              creditBillInfo.setCreditRemainAmount(creditAmount.getCreditRemainAmount());
              creditBillInfo.setCreateTime(DateUtil.date());
              creditBillInfo.setUpdateTime(DateUtil.date());
              this.save(creditBillInfo);
            }
            return true;
    }
}

功能展示:

3:实现花呗支付功能:

package com.zbkj.front.controller;

import com.zbkj.common.request.OrderPayRequest;
import com.zbkj.common.request.WechatPaymentQueryRequest;
import com.zbkj.common.response.CashierInfoResponse;
import com.zbkj.common.response.OrderPayResultResponse;
import com.zbkj.common.response.PayConfigResponse;
import com.zbkj.common.result.CommonResult;
import com.zbkj.service.service.PayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

/**
 * 支付控制器
 * +----------------------------------------------------------------------
 * +----------------------------------------------------------------------
 */
@Slf4j
@RestController
@RequestMapping("api/front/pay")
@Api(tags = "支付管理")
public class PayController {

    @Autowired
    private PayService payService;

    @ApiOperation(value = "获取支付配置")
    @RequestMapping(value = "/get/config", method = RequestMethod.GET)
    public CommonResult<PayConfigResponse> getPayConfig() {
        return CommonResult.success(payService.getPayConfig());
    }

    @ApiOperation(value = "订单支付")
    @RequestMapping(value = "/payment", method = RequestMethod.POST)
    public CommonResult<OrderPayResultResponse> payment(@RequestBody @Validated OrderPayRequest orderPayRequest) {
        return CommonResult.success(payService.payment(orderPayRequest));
    }

    @ApiOperation(value = "查询订单微信支付结果")
    @RequestMapping(value = "/query/wechat/pay/result/{orderNo}", method = RequestMethod.GET)
    public CommonResult<Boolean> queryPayResult(@PathVariable(value = "orderNo") String orderNo) {
        return CommonResult.success(payService.queryWechatPayResult(orderNo));
    }

    @ApiOperation(value = "查询订单支付宝支付结果")
    @RequestMapping(value = "/query/ali/pay/result/{orderNo}", method = RequestMethod.GET)
    public CommonResult<Boolean> queryAliPayResult(@PathVariable(value = "orderNo") String orderNo) {
        return CommonResult.success(payService.queryAliPayResult(orderNo));
    }

    @ApiOperation(value = "获取收银台信息")
    @RequestMapping(value = "/get/cashier/{orderNo}", method = RequestMethod.GET)
    public CommonResult<CashierInfoResponse> getCashierIno(@PathVariable(value = "orderNo") String orderNo) {
        return CommonResult.success(payService.getCashierIno(orderNo));
    }

    @ApiOperation(value = "查询微信支付结果")
    @RequestMapping(value = "/query/wechat/payment/result", method = RequestMethod.GET)
    public CommonResult<Boolean> queryWechatPaymentResult(@Validated WechatPaymentQueryRequest request) {
        return CommonResult.success(payService.queryWechatPaymentResult(request));
    }
}
package com.zbkj.service.service;

import com.zbkj.common.request.OrderPayRequest;
import com.zbkj.common.request.WechatPaymentQueryRequest;
import com.zbkj.common.response.CashierInfoResponse;
import com.zbkj.common.response.OrderPayResultResponse;
import com.zbkj.common.response.PayConfigResponse;
import com.zbkj.common.vo.MyRecord;

/**
 * PayService 接口
 * +----------------------------------------------------------------------
 * +----------------------------------------------------------------------
 */
public interface PayService {

    /**
     * 获取支付配置
     */
    PayConfigResponse getPayConfig();

    /**
     * 订单支付
     * @param orderPayRequest 订单支付参数
     * @return OrderPayResultResponse
     */
    OrderPayResultResponse payment(OrderPayRequest orderPayRequest);

    /**
     * 查询订单微信支付结果
     * @param orderNo 订单编号
     */
    Boolean queryWechatPayResult(String orderNo);

    /**
     * 查询订单支付宝支付结果
     * @param orderNo 订单编号
     */
    Boolean queryAliPayResult(String orderNo);

    /**
     * 支付成功后置处理(临时)
     * @param orderNo 订单编号
     */
    Boolean payAfterProcessingTemp(String orderNo);

    /**
     * 获取收银台信息
     *
     * @param orderNo 订单号
     */
    CashierInfoResponse getCashierIno(String orderNo);

    /**
     * 查询微信支付结果
     */
    Boolean queryWechatPaymentResult(WechatPaymentQueryRequest request);
}
package com.zbkj.service.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.zbkj.common.config.CrmebConfig;
import com.zbkj.common.constants.*;
import com.zbkj.common.exception.CrmebException;
import com.zbkj.common.model.admin.SystemAdmin;
import com.zbkj.common.model.alipay.AliPayInfo;
import com.zbkj.common.model.bill.Bill;
import com.zbkj.common.model.bill.MerchantBill;
import com.zbkj.common.model.coupon.CouponUser;
import com.zbkj.common.model.credit.CreditAmount;
import com.zbkj.common.model.credit.CreditBillInfo;
import com.zbkj.common.model.credit.CreditOrderBill;
import com.zbkj.common.model.member.PaidMemberOrder;
import com.zbkj.common.model.merchant.Merchant;
import com.zbkj.common.model.merchant.MerchantBalanceRecord;
import com.zbkj.common.model.order.*;
import com.zbkj.common.model.product.ProductCoupon;
import com.zbkj.common.model.sales.XsSales;
import com.zbkj.common.model.system.SystemNotification;
import com.zbkj.common.model.user.*;
import com.zbkj.common.model.wechat.WechatPayInfo;
import com.zbkj.common.model.wechat.video.PayComponentProduct;
import com.zbkj.common.request.OrderPayRequest;
import com.zbkj.common.request.WechatPaymentQueryRequest;
import com.zbkj.common.response.CashierInfoResponse;
import com.zbkj.common.response.OrderPayResultResponse;
import com.zbkj.common.response.PayConfigResponse;
import com.zbkj.common.result.CommonResultCode;
import com.zbkj.common.result.MemberResultCode;
import com.zbkj.common.result.OrderResultCode;
import com.zbkj.common.result.UserResultCode;
import com.zbkj.common.utils.*;
import com.zbkj.common.vo.*;
import com.zbkj.common.vo.wxvedioshop.ShopOrderAddResultVo;
import com.zbkj.common.vo.wxvedioshop.order.*;
import com.zbkj.service.service.*;
import com.zbkj.service.service.credit.CreditAmountService;
import com.zbkj.service.service.credit.CreditBillInfoService;
import com.zbkj.service.service.credit.CreditOrderBillService;
import com.zbkj.service.service.sales.IXsSalesService;
import jodd.util.StringUtil;
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * PayServiceImpl 接口实现
 * +----------------------------------------------------------------------
 * +----------------------------------------------------------------------
 */
@Service
public class PayServiceImpl implements PayService {

    private static final Logger logger = LoggerFactory.getLogger(PayServiceImpl.class);

    @Autowired
    private SystemConfigService systemConfigService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private UserService userService;
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private UserTokenService userTokenService;
    @Autowired
    private WechatService wechatService;
    @Autowired
    private WechatPayInfoService wechatPayInfoService;
    @Autowired
    private AliPayService aliPayService;
    @Autowired
    private MerchantOrderService merchantOrderService;
    @Autowired
    private OrderStatusService orderStatusService;
    @Autowired
    private UserIntegralRecordService userIntegralRecordService;
    @Autowired
    private SystemNotificationService systemNotificationService;
    @Autowired
    private SmsService smsService;
    @Autowired
    private TemplateMessageService templateMessageService;
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private ProductCouponService productCouponService;
    @Autowired
    private CouponUserService couponUserService;
    @Autowired
    private CouponService couponService;
    @Autowired
    private UserBrokerageRecordService userBrokerageRecordService;
    @Autowired
    private UserBalanceRecordService userBalanceRecordService;
    @Autowired
    private MerchantService merchantService;
    @Autowired
    private MerchantBillService merchantBillService;
    @Autowired
    private OrderProfitSharingService orderProfitSharingService;
    @Autowired
    private BillService billService;
    @Autowired
    private WechatVideoOrderService wechatVideoOrderService;
    @Autowired
    private AsyncService asyncService;
    @Autowired
    private PayComponentOrderService payComponentOrderService;
    @Autowired
    private PayComponentProductService payComponentProductService;
    @Autowired
    private AliPayInfoService aliPayInfoService;
    @Autowired
    private RechargeOrderService rechargeOrderService;
    @Autowired
    private MerchantBalanceRecordService merchantBalanceRecordService;
    @Autowired
    private MerchantPrintService merchantPrintService;
    @Autowired
    private CrmebConfig crmebConfig;
    @Autowired
    private SystemAdminService systemAdminService;
    @Autowired
    private PaidMemberOrderService paidMemberOrderService;
    @Autowired
    private IXsSalesService xsSalesService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private CreditAmountService creditAmountService;
    @Autowired
    private CreditOrderBillService creditOrderBillService;
    @Autowired
    private CreditBillInfoService creditBillInfoService;

    /**
     * 获取支付配置
     */
    @Override
    public PayConfigResponse getPayConfig() {
        String payWxOpen = systemConfigService.getValueByKey(SysConfigConstants.CONFIG_PAY_WECHAT_OPEN);
        String yuePayStatus = systemConfigService.getValueByKey(SysConfigConstants.CONFIG_YUE_PAY_STATUS);
        String creditPayStatus = systemConfigService.getValueByKey(SysConfigConstants.CONFIG_CREDIT_PAY_STATUS);
        String aliPayStatus = systemConfigService.getValueByKey(SysConfigConstants.CONFIG_ALI_PAY_STATUS);
        PayConfigResponse response = new PayConfigResponse();
        response.setYuePayStatus(Constants.CONFIG_FORM_SWITCH_OPEN.equals(yuePayStatus));
        response.setCreditPayStatus(Constants.CONFIG_FORM_SWITCH_OPEN.equals(yuePayStatus));
        response.setPayWechatOpen(Constants.CONFIG_FORM_SWITCH_OPEN.equals(payWxOpen));
        response.setAliPayStatus(Constants.CONFIG_FORM_SWITCH_OPEN.equals(aliPayStatus));
        if (Constants.CONFIG_FORM_SWITCH_OPEN.equals(yuePayStatus)) {
            User user = userService.getInfo();
            response.setUserBalance(user.getNowMoney());
        }
        if (Constants.CONFIG_FORM_SWITCH_OPEN.equals(creditPayStatus)) {
            User user = userService.getInfo();
            //查询授信余额
            CreditAmount creditAmount=creditAmountService.getByUserId(user.getId());
            if(Objects.nonNull(creditAmount)){
                 response.setCreditRemainAmount(creditAmount.getCreditRemainAmount());
            }else{
                response.setCreditRemainAmount(BigDecimal.ZERO);
            }

        }
        return response;
    }

    /**
     * 订单支付
     *
     * @param orderPayRequest 订单支付参数
     * @return OrderPayResultResponse
     */

    @Override
    public OrderPayResultResponse payment(OrderPayRequest orderPayRequest) {
        logger.info("订单支付 START orderPayRequest:{}", JSON.toJSONString(orderPayRequest));
        Order order = orderService.getByOrderNo(orderPayRequest.getOrderNo());
        logger.info("订单支付 当前操作的订单信息:{}", JSON.toJSONString(order));
        if (order.getCancelStatus() > OrderConstants.ORDER_CANCEL_STATUS_NORMAL) {
            throw new CrmebException(OrderResultCode.ORDER_CANCEL);
        }
        if (order.getPaid()) {
            throw new CrmebException(OrderResultCode.ORDER_PAID);
        }
        if (order.getStatus() > OrderConstants.ORDER_STATUS_WAIT_PAY) {
            throw new CrmebException(OrderResultCode.ORDER_STATUS_ABNORMAL);
        }
        User user = userService.getInfo();
        // 根据支付类型进行校验,更换支付类型
        order.setPayType(orderPayRequest.getPayType());
        order.setPayChannel(orderPayRequest.getPayChannel());
        // 获取过期时间
        DateTime cancelTime = DateUtil.offset(order.getCreateTime(), DateField.MINUTE, crmebConfig.getOrderCancelTime());
        long between = DateUtil.between(cancelTime, DateUtil.date(), DateUnit.SECOND, false);
        if (between > 0) {
            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "订单已过期");
        }

          // 授信支付
        if (orderPayRequest.getPayType().equals(PayConstants.PAY_TYPE_CREDIT)) {
            //查询用户的授信额度
            CreditAmount creditAmount=creditAmountService.getByUserId(user.getId());
            if (creditAmount.getCreditRemainAmount().compareTo(order.getPayPrice()) < 0) {
                throw new CrmebException(UserResultCode.USER_REDIT_INSUFFICIENT);
            }
        }

        // 余额支付
        if (orderPayRequest.getPayType().equals(PayConstants.PAY_TYPE_YUE)) {
            if (user.getNowMoney().compareTo(order.getPayPrice()) < 0) {
                throw new CrmebException(UserResultCode.USER_BALANCE_INSUFFICIENT);
            }
        }

        OrderPayResultResponse response = new OrderPayResultResponse();
        response.setOrderNo(order.getOrderNo());
        response.setPayType(order.getPayType());
        response.setPayChannel(order.getPayChannel());
        if (order.getPayPrice().compareTo(BigDecimal.ZERO) <= 0) {
            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "支付金额不能低于等于0元");
        }
        // 余额支付
        if (order.getPayType().equals(PayConstants.PAY_TYPE_YUE)) {
            Boolean yueBoolean = yuePay(order, user);
            response.setStatus(yueBoolean);
            logger.info("余额支付 response : {}", JSON.toJSONString(response));
            return response;
        }
         // 授信支付
        if (order.getPayType().equals(PayConstants.PAY_TYPE_CREDIT)) {
            Boolean yueBoolean = creditPay(order, user);
            response.setStatus(yueBoolean);
            logger.info("授信支付 response : {}", JSON.toJSONString(response));
            return response;
        }
        // 微信视频号下单 需要额外调用支付参数
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_MINI_VIDEO)) {
            WxPayJsResultVo vo = new WxPayJsResultVo();
            UserToken tokenByUser = userTokenService.getTokenByUserId(user.getId(), UserConstants.USER_TOKEN_TYPE_ROUTINE);
            List<OrderDetail> orderDetailList = orderDetailService.getByOrderNo(order.getOrderNo());
            logger.info("视频号下单,订单详情:{}", JSON.toJSONString(orderDetailList));
            //  视频号下单都是单品
            PayComponentProduct payComponentProduct = payComponentProductService.getById(orderDetailList.get(0).getProductId());
            logger.info("视频号下单,当前视频号商品:{}", JSON.toJSONString(payComponentProduct));
            //组装商品信息
            ShopOrderDetailAddVo shopOrderDetailAddVo = new ShopOrderDetailAddVo();
            List<ShopOrderProductInfoAddVo> shopOrderProductInfoAddVoList = new ArrayList<>();
            for (OrderDetail orderDetail : orderDetailList) {
                ShopOrderProductInfoAddVo shopOrderProductInfoAddVo = new ShopOrderProductInfoAddVo();
                shopOrderProductInfoAddVo.setOutProductId(orderDetail.getProductId().toString());
                shopOrderProductInfoAddVo.setOutSkuId(orderDetail.getAttrValueId().toString());
                shopOrderProductInfoAddVo.setProductCnt(orderDetail.getPayNum());
                shopOrderProductInfoAddVo.setSalePrice(orderDetail.getPrice().multiply(new BigDecimal("100")).longValue());
                shopOrderProductInfoAddVo.setSkuRealPrice(orderDetail.getPayPrice().multiply(new BigDecimal("100")).longValue());
                shopOrderProductInfoAddVo.setPath(payComponentProduct.getPath());
                shopOrderProductInfoAddVo.setTitle(payComponentProduct.getTitle());
                shopOrderProductInfoAddVo.setHeadImg(payComponentProduct.getHeadImg());
                shopOrderProductInfoAddVoList.add(shopOrderProductInfoAddVo);
            }
            shopOrderDetailAddVo.setProductInfos(shopOrderProductInfoAddVoList);

            // 组装支付方式
            ShopOrderPayInfoAddVo payInfoAddVo = new ShopOrderPayInfoAddVo();
            payInfoAddVo.setPayMethodType(0);
            payInfoAddVo.setPayMethod("微信支付"); // 视频号暂时只有微信支付
            shopOrderDetailAddVo.setPayInfo(payInfoAddVo);

            // 组装支付详细信息
            ShopOrderPriceInfoVo shopOrderPriceInfoVo = new ShopOrderPriceInfoVo();
            shopOrderPriceInfoVo.setOrderPrice(order.getPayPrice().multiply(new BigDecimal("100")).longValue());
            // 视频号商品暂时面部免运费
            shopOrderPriceInfoVo.setFreight(0L);
            shopOrderPriceInfoVo.setDiscountedPrice(0L);
            shopOrderPriceInfoVo.setAdditionalPrice(0L);
            shopOrderPriceInfoVo.setAdditional_remarks(null);
            shopOrderDetailAddVo.setPriceInfo(shopOrderPriceInfoVo);

            // 组装自定义交易组件主体数据
            ShopOrderAddVo shopOrderAddVo = new ShopOrderAddVo();
            shopOrderAddVo.setOrderDetail(shopOrderDetailAddVo);
            shopOrderAddVo.setFund_type(1);
            shopOrderAddVo.setTrace_id(null);
            shopOrderAddVo.setOutOrderId(order.getOrderNo());
            shopOrderAddVo.setOpenid(tokenByUser.getToken());
            shopOrderAddVo.setOutUserId(user.getId());
            shopOrderAddVo.setMerId(order.getMerId());

            // 订单路由地址
            shopOrderAddVo.setPath("/pages/users/order_details/index?orderNo=" + orderPayRequest.getOrderNo());

            // 组装订单信息 视频号都是单品 最多是多量
            List<MerchantOrder> merchantOrderList = merchantOrderService.getByOrderNo(orderPayRequest.getOrderNo());
            if (ObjectUtil.isNull(merchantOrderList) || merchantOrderList.size() == 0) {
                throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "未找到视频号商品订单");
            }
            MerchantOrder CurrentMerchantOrder = merchantOrderList.get(0);
            ShopOrderAddressInfoAddVo shopOrderAddressInfoAddVo = new ShopOrderAddressInfoAddVo();
            shopOrderAddressInfoAddVo.setReceiverName(CurrentMerchantOrder.getRealName());
            shopOrderAddressInfoAddVo.setDetailedAddress(CurrentMerchantOrder.getUserAddress());
            shopOrderAddressInfoAddVo.setTelNumber(CurrentMerchantOrder.getUserPhone());
            shopOrderAddVo.setAddressInfo(shopOrderAddressInfoAddVo);

            // 1: 正常快递, 2: 无需快递, 3: 线下配送, 4: 用户自提,视频号场景目前只支持 1,正常快递
            ShopOrderDeliveryDetailAddVo shopOrderDeliveryDetailAddVo = new ShopOrderDeliveryDetailAddVo();
            shopOrderDeliveryDetailAddVo.setDeliveryType(1);

            shopOrderAddVo.setDeliveryDetail(shopOrderDeliveryDetailAddVo);
            shopOrderAddVo.setExpire_time(WxPayUtil.getCurrentTimestamp().intValue() + 900);
            shopOrderAddVo.setCreateTime(CrmebDateUtil.nowDateTimeStr());
            ShopOrderAddResultVo shopOrderAddResultVo = payComponentOrderService.create(shopOrderAddVo);
            ShopOrderGetPaymentParamsRequestVo videoPaymentRequestVo = new ShopOrderGetPaymentParamsRequestVo(
                    shopOrderAddResultVo.getOutOrderId(), order.getOrderNo(), tokenByUser.getToken()
            );
            logger.info("视频号下单时 支付接口参数:{}", JSON.toJSONString(videoPaymentRequestVo));
            ShopOrderGetPaymentParamsRersponseVo shopOrderGetPaymentParamsRersponseVo = wechatVideoOrderService.shopOrderGetPaymentParams(videoPaymentRequestVo);
            logger.info("视频号下单时 获取的支付参数 {}", JSON.toJSONString(shopOrderGetPaymentParamsRersponseVo));
            response.setStatus(true);
            vo.setTimeStamp(WxPayUtil.getCurrentTimestamp() + "");
            vo.setNonceStr(shopOrderGetPaymentParamsRersponseVo.getNonceStr());
            vo.setPackages(shopOrderGetPaymentParamsRersponseVo.get_package());
            vo.setPaySign(shopOrderGetPaymentParamsRersponseVo.getPaySign());
            vo.setSignType(shopOrderGetPaymentParamsRersponseVo.getSignType());
            response.setJsConfig(vo);
            logger.info("订单支付 视频号下单 response:{}", JSON.toJSONString(response));
            return response;
        }
        // 微信支付,调用微信预下单,返回拉起微信支付需要的信息
        if (order.getPayType().equals(PayConstants.PAY_TYPE_WE_CHAT)) {
            //查询redis支付有支付订单
            WxPayJsResultVo vo = redisUtil.get(order.getOrderNo());
            if(Objects.isNull(vo)){
                  logger.info("订单支付 微信下单");
                 vo = wechatPayment(order);
                redisUtil.set(order.getOrderNo(),vo,1l, TimeUnit.MINUTES);
            }
            logger.info("订单支付 微信下单的商户订单号:{}",vo.getOutTradeNo());
            order.setOutTradeNo(vo.getOutTradeNo());
            orderService.updateById(order);
            response.setStatus(true);
            response.setJsConfig(vo);
            response.setOutTradeNo(vo.getOutTradeNo());
            logger.info("订单支付 微信下单 response :{}", JSON.toJSONString(response));
            return response;
        }
        if (order.getPayType().equals(PayConstants.PAY_TYPE_ALI_PAY)) {
            logger.info("订单支付 支付宝");
            String result = aliPayment(order);
            order.setOutTradeNo(order.getOrderNo());
            orderService.updateById(order);
            response.setStatus(true);
            response.setAlipayRequest(result);
            logger.info("订单支付 支付宝 response :{}", JSON.toJSONString(response));
            return response;
        }
        response.setStatus(false);
        logger.info("订单支付 END response:{}", JSON.toJSONString(response));
        return response;
    }

    private Boolean creditPay(Order order, User user) {
        Boolean execute = transactionTemplate.execute(e -> {
            Boolean update = Boolean.TRUE;
            // 订单修改
            order.setPaid(true);
            order.setPayTime(DateUtil.date());
            order.setStatus(OrderConstants.ORDER_STATUS_WAIT_SHIPPING);
            orderService.updateById(order);
            // 这里只扣除金额,账单记录在task中处理
            if (order.getPayPrice().compareTo(BigDecimal.ZERO) > 0) {
                update = creditAmountService.updateNowMoney(order.getUid(), order.getPayPrice(), Constants.OPERATION_TYPE_SUBTRACT);
                if (!update) {
                    logger.error("授信支付,扣除用户授信额度失败,orderNo = {}", order.getOrderNo());
                    e.setRollbackOnly();
                    return update;
                }
                update = creditAmountService.updateRemainMoney(order.getUid(), order.getPayPrice(), Constants.OPERATION_TYPE_ADD);
                if (!update) {
                    logger.error("授信支付,扣除用户授信额度失败,orderNo = {}", order.getOrderNo());
                    e.setRollbackOnly();
                    return update;
                }
                 //创建授信订单记录
                if (!saveOrCreditOrderBill(order, user)) throw new CrmebException("授信余额支付订单失败");
                //创建用户授信记录
                if (!saveCreditBillInfo(order, user)) throw new CrmebException("授信余额支付订单失败");
            }
            return update;
        });
        if (!execute) throw new CrmebException("授信余额支付订单失败");
        //通知万物
        noticeWw(order.getWwOrderNo(), order.getOrderNo());
        asyncService.orderPaySuccessSplit(order.getOrderNo());
        return true;
    }
    /**
     * 支付成功,回调通知万物平台
     * */
    public void noticeWw(Integer wwOrderId, String billNo){
        HttpResponse<String> res = Unirest.put("https://hk-gateway.demo.starytech.cn/v1/mall/oms-order/"+wwOrderId+"/payment")
                .header("Authorization", "Bearer LrVErbgIkXysTMUihxxMK61iO7koYJ4yavZr5wLVgadiFvVgyqv6as4XarM7TGzh")
                .header("User-Agent", "Apifox/1.0.0 (https://apifox.com)")
                .field("bill_no", billNo)
                .asString();
        System.out.println(String.format("万物OMS支付通知请求参数==wwOrderId:%d,BillNo:%s",wwOrderId,billNo));
        System.out.println("万物OMS支付通知返回结果============================");
        System.out.println(res.getBody());
    }

     private boolean saveOrCreditOrderBill(Order order, User user){
         CreditAmount creditAmount = creditAmountService.getByUserId(user.getId());
         //创建授信订单记录
                CreditOrderBill creditOrderBill=creditOrderBillService.getByOrderNo(order.getOrderNo());
                if(Objects.nonNull(creditOrderBill)){
                    creditOrderBill.setPayid(1);
                    creditOrderBill.setPayTime(DateUtil.date());
                    creditOrderBill.setOrderType(0);
                    creditOrderBill.setPayChannel(order.getPayChannel());
                    creditOrderBill.setPayType(order.getPayType());
                    creditOrderBill.setPayPrice(order.getPayPrice());
                     creditOrderBill.setCreditRepaymentAmount(order.getPayPrice());
                     creditOrderBill.setCreditRepaymentFlag(0);
                     //合同开始时间加7天
                    creditOrderBill.setTaskEndTime(DateUtil.date().offset(DateField.DAY_OF_MONTH,creditAmount.getSettleTerm()));
                    creditOrderBill.setTaskStartTime(DateUtil.date().offset(DateField.DAY_OF_MONTH,creditAmount.getSettleTerm()));
                    creditOrderBill.setTaskStatus(0);
                    creditOrderBillService.updateById(creditOrderBill);
                }else{
                    this.saveOrUdate(order,user);
                }
                return true;
     }
     private boolean saveCreditBillInfo(Order order, User user){
                CreditAmount creditAmount = creditAmountService.getByUserId(user.getId());
                //创建授信流水
                if(Objects.nonNull(creditAmount)){
                    BigDecimal creditRemainAmount = creditAmount.getCreditRemainAmount();
                    //创建流程记录
                      CreditBillInfo creditBillInfo=new CreditBillInfo();
                      creditBillInfo.setUid(user.getId());
                      creditBillInfo.setCreditType(Constants.BILL_TYPE_PAY);
                      creditBillInfo.setCreditPayAmount(order.getPayPrice());
                      creditBillInfo.setCreditRemainAmount(creditRemainAmount);
                      creditBillInfo.setCreateTime(DateUtil.date());
                      creditBillInfo.setUpdateTime(DateUtil.date());
                      creditBillInfo.setId(IdWorker.getIdStr());
                      creditBillInfoService.save(creditBillInfo);
                }
                return true;

    }

    public boolean saveOrUdate(Order order,User user) {
        CreditOrderBill creditOrderBill = new CreditOrderBill();
        creditOrderBill.setUid(user.getId());
        creditOrderBill.setOrderNo(order.getOrderNo());
        creditOrderBill.setPayType(PayConstants.PAY_TYPE_CREDIT);
        creditOrderBill.setPayChannel(order.getPayChannel());
        creditOrderBill.setPayPrice(order.getPayPrice());
        creditOrderBill.setCreateTime(DateUtil.date());
        //获取当月是几月
        int month = DateUtil.month(DateUtil.date())+1;
        int year = DateUtil.year(DateUtil.date());
        creditOrderBill.setMonth(month);
        creditOrderBill.setYear(year);
        creditOrderBill.setCreditRepaymentAmount(order.getPayPrice());
        creditOrderBill.setCreditRepaymentFlag(0);
        creditOrderBill.setId(IdWorker.getIdStr());
        creditOrderBill.setPayid(1);
        creditOrderBill.setOrderType(0);
        creditOrderBill.setPayTime(DateUtil.date());
        creditOrderBill.setTaskEndTime(DateUtil.date().offset(DateField.DAY_OF_MONTH,7));
        creditOrderBill.setTaskStartTime(DateUtil.date());
        creditOrderBill.setTaskStatus(0);
        creditOrderBillService.save(creditOrderBill);
        return true;
    }

    /**
     * 支付成功,给万物平台发送支付消息
     * */
    public void sendPayment(Integer wwOrderId, String billNo){
        HttpResponse<String> res = Unirest.put("https://hk-gateway.demo.starytech.cn/v1/mall/oms-order/"+wwOrderId+"/payment")
                .header("Authorization", "Bearer LrVErbgIkXysTMUihxxMK61iO7koYJ4yavZr5wLVgadiFvVgyqv6as4XarM7TGzh")
                .header("User-Agent", "Apifox/1.0.0 (https://apifox.com)")
                .field("bill_no", billNo)
                .asString();
        System.out.println(String.format("万物OMS支付通知请求参数==wwOrderId:%d,BillNo:%s",wwOrderId,billNo));
        System.out.println("万物OMS支付通知返回结果============================");
        System.out.println(res.getBody());
    }

    /**
     * 查询支付结果
     *
     * @param orderNo 订单编号
     */
    @Override
    public Boolean queryWechatPayResult(String orderNo) {
        Order order = orderService.getByOrderNo(orderNo);
        if (ObjectUtil.isNull(order)) {
            throw new CrmebException(OrderResultCode.ORDER_NOT_EXIST);
        }
        if (order.getCancelStatus() > OrderConstants.ORDER_CANCEL_STATUS_NORMAL) {
            throw new CrmebException(OrderResultCode.ORDER_CANCEL);
        }
        if (!order.getPayType().equals(PayConstants.PAY_TYPE_WE_CHAT)) {
            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "不是微信支付类型订单");
        }
        if (order.getPaid()) {
            //支付成功推送万物
            logger.info("订单支付 支付成功推送万物");
            if(Objects.nonNull(order.getWwOrderNo())){
                sendPayment(order.getWwOrderNo(), orderNo);
            }
            return Boolean.TRUE;
        }
        WechatPayInfo wechatPayInfo = wechatPayInfoService.getByNo(order.getOutTradeNo());
        if (ObjectUtil.isNull(wechatPayInfo)) {
            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "未找到对应微信订单");
        }
        Map<String, String> payVo = getWechatQueryPayVo(order.getOutTradeNo(), order.getPayChannel());
        MyRecord myRecord = wechatService.payOrderQuery(payVo);
        if (myRecord.getInt("payStatus") < 1) {
            return Boolean.FALSE;
        }
        wechatPayInfo.setIsSubscribe(myRecord.getStr("is_subscribe"));
        wechatPayInfo.setTradeState(myRecord.getStr("trade_state"));
        wechatPayInfo.setBankType(myRecord.getStr("bank_type"));
        wechatPayInfo.setCashFee(myRecord.getInt("cash_fee"));
        wechatPayInfo.setCouponFee(myRecord.getInt("coupon_fee"));
        wechatPayInfo.setTransactionId(myRecord.getStr("transaction_id"));
        wechatPayInfo.setTimeEnd(myRecord.getStr("time_end"));
        wechatPayInfo.setTradeStateDesc(myRecord.getStr("trade_state_desc"));
        Boolean updatePaid = transactionTemplate.execute(e -> {
            orderService.updatePaid(orderNo);
            wechatPayInfoService.updateById(wechatPayInfo);
            logger.info("微信查询支付结果  订单支付 支付成功推送万物"+order.getWwOrderNo());
            if(Objects.nonNull(order.getWwOrderNo())){
                sendPayment(order.getWwOrderNo(), orderNo);
            }
            return Boolean.TRUE;
        });
        if (!updatePaid) {
            throw new CrmebException("支付成功更新订单失败");
        }
        asyncService.orderPaySuccessSplit(order.getOrderNo());
        // 添加支付成功task
        redisUtil.lPush(TaskConstants.ORDER_TASK_PAY_SUCCESS_AFTER, orderNo);
        return Boolean.TRUE;
    }

    /**
     * 查询订单支付宝支付结果
     *
     * @param orderNo 订单编号
     */
    @Override
    public Boolean queryAliPayResult(String orderNo) {
        AliPayInfo aliPayInfo = aliPayInfoService.getByOutTradeNo(orderNo);
        if (ObjectUtil.isNull(aliPayInfo)) {
            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "支付宝订单信息不存在");
        }
        String passbackParams = aliPayInfo.getPassbackParams();
        if (StrUtil.isBlank(passbackParams)) {
            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "未知的支付宝订单类型");
        }
        String decode;
        try {
            decode = URLDecoder.decode(passbackParams, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            throw new CrmebException("ali pay query error : 订单支付类型解码失败==》" + orderNo);
        }

        String[] split = decode.split("=");
        String orderType = split[1];
        if (PayConstants.PAY_SERVICE_TYPE_RECHARGE.equals(orderType)) {// 充值订单
            RechargeOrder rechargeOrder = rechargeOrderService.getByOutTradeNo(orderNo);
            if (ObjectUtil.isNull(rechargeOrder)) {
                throw new CrmebException(StrUtil.format("ali pay query error : 充值订单后置处理,没有找到对应订单,支付服务方订单号:{}", orderNo));
            }
            if (rechargeOrder.getPaid()) {
                return Boolean.TRUE;
            }
            aliPayQuery(orderNo);
            // 支付成功处理
            Boolean rechargePayAfter = rechargeOrderService.paySuccessAfter(rechargeOrder);
            if (!rechargePayAfter) {
                throw new CrmebException(StrUtil.format("ali pay recharge pay after error : 数据保存失败==》" + orderNo));
            }
            return Boolean.TRUE;
        }
        if (PayConstants.PAY_SERVICE_TYPE_SVIP.equals(orderType)) {// 充值订单
            PaidMemberOrder paidMemberOrder = paidMemberOrderService.getByOutTradeNo(orderNo);
            if (ObjectUtil.isNull(paidMemberOrder)) {
                throw new CrmebException(StrUtil.format("ali pay query error : SVIP订单后置处理,没有找到对应订单,支付服务方订单号:{}", orderNo));
            }
            if (paidMemberOrder.getPaid()) {
                return Boolean.TRUE;
            }
            aliPayQuery(orderNo);
            // 支付成功处理
            // 支付成功处理
            Boolean svipPayAfter = paidMemberOrderService.paySuccessAfter(paidMemberOrder);
            if (!svipPayAfter) {
                logger.error("ali pay svip pay after error : 数据保存失败==》" + paidMemberOrder);
                throw new CrmebException(StrUtil.format("ali pay svip pay after error : 数据处理失败==》" + orderNo));
            }
            return Boolean.TRUE;
        }

        Order order = orderService.getByOrderNo(orderNo);
        if (ObjectUtil.isNull(order)) {
            throw new CrmebException(OrderResultCode.ORDER_NOT_EXIST);
        }
        if (order.getCancelStatus() > OrderConstants.ORDER_CANCEL_STATUS_NORMAL) {
            throw new CrmebException(OrderResultCode.ORDER_CANCEL);
        }
        if (!order.getPayType().equals(PayConstants.PAY_TYPE_ALI_PAY)) {
            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "不是支付宝支付类型订单");
        }
        if (order.getPaid()) {
            return Boolean.TRUE;
        }
        aliPayQuery(orderNo);
        Boolean execute = transactionTemplate.execute(e -> {
            Boolean updatePaid = orderService.updatePaid(orderNo);
            if (!updatePaid) {
                logger.warn("商品订单更新支付状态失败,orderNo = {}", orderNo);
                e.setRollbackOnly();
            }
            return Boolean.TRUE;
        });

        if (!execute) {
            throw new CrmebException("支付成功更新订单失败");
        }
        asyncService.orderPaySuccessSplit(order.getOrderNo());
//        // 添加支付成功task
//        redisUtil.lPush(TaskConstants.ORDER_TASK_PAY_SUCCESS_AFTER, orderNo);
        return Boolean.TRUE;
    }

    private AlipayTradeQueryResponse aliPayQuery(String orderNo) {
        //支付宝交易号
        // SDK 公共请求类,包含公共请求参数,以及封装了签名与验签,开发者无需关注签名与验签
        String aliPayAppid = systemConfigService.getValueByKey(AlipayConfig.APPID);
        String aliPayPrivateKey = systemConfigService.getValueByKey(AlipayConfig.RSA_PRIVATE_KEY);
        String aliPayPublicKey = systemConfigService.getValueByKey(AlipayConfig.ALIPAY_PUBLIC_KEY);
        AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, aliPayAppid, aliPayPrivateKey, AlipayConfig.FORMAT, AlipayConfig.CHARSET, aliPayPublicKey, AlipayConfig.SIGNTYPE);
        AlipayTradeQueryRequest alipay_request = new AlipayTradeQueryRequest();

        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        // 商户订单号,商户网站订单系统中唯一订单号,必填
        model.setOutTradeNo(orderNo);
        alipay_request.setBizModel(model);
        logger.info("alipay_request = " + alipay_request);

        AlipayTradeQueryResponse alipay_response = null;
        try {
            alipay_response = client.execute(alipay_request);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            logger.error("支付宝支付查询异常," + e.getMessage());
            throw new CrmebException("支付宝支付查询异常");
        }
        if (ObjectUtil.isNull(alipay_response)) {
            logger.error("支付宝支付结果异常,查询结果为空");
            throw new CrmebException("支付宝支付结果异常,查询结果为空");
        }
        logger.info("alipay_response = " + JSONObject.toJSONString(alipay_response));
        if (ObjectUtil.isNull(alipay_response.getTradeStatus()) || !alipay_response.getTradeStatus().equals("TRADE_SUCCESS")) {
            logger.error("支付宝支付结果异常,tradeStatus = " + alipay_response.getTradeStatus());
            throw new CrmebException("支付宝支付结果异常");
        }
        return alipay_response;
    }

    /**
     * 支付成功后置处理(临时)
     *
     * @param orderNo 订单编号
     */
    @Override
    public Boolean payAfterProcessingTemp(String orderNo) {
        Order platOrder = orderService.getByOrderNo(orderNo);
//        if(platOrder.getPaid()){
//            logger.info("订单支付 支付成功推送万物");
//            if(Objects.nonNull(platOrder.getWwOrderNo())){
//                sendPayment(platOrder.getWwOrderNo(), orderNo);
//            }
//        }
        if (ObjectUtil.isNull(platOrder)) {
            logger.error("OrderTaskServiceImpl.orderPaySuccessAfter | 订单不存在,orderNo: {}", orderNo);
            throw new CrmebException("订单不存在,orderNo: " + orderNo);
        }
        User user = userService.getById(platOrder.getUid());
        // 获取拆单后订单
        List<Order> orderList = orderService.getByPlatOrderNo(platOrder.getOrderNo());
        if (CollUtil.isEmpty(orderList)) {
            logger.error("OrderTaskServiceImpl.orderPaySuccessAfter | 商户订单信息不存在,orderNo: {}", orderNo);
            throw new CrmebException("商户订单信息不存在,orderNo: " + orderNo);
        }
        List<UserIntegralRecord> integralList = CollUtil.newArrayList();
        List<UserBrokerageRecord> brokerageRecordList = CollUtil.newArrayList();
        List<OrderProfitSharing> profitSharingList = CollUtil.newArrayList();
        List<MerchantBill> merchantBillList = CollUtil.newArrayList();
        List<Bill> billList = CollUtil.newArrayList();
        List<MerchantOrder> merchantOrderList = CollUtil.newArrayList();
        List<MerchantOrder> merchantOrderListForPrint = CollUtil.newArrayList();

        List<OrderDetail> orderDetailList = CollUtil.newArrayList();

        for (Order order : orderList) {
            // 拆单后,一个主订单只会对应一个商户订单
            MerchantOrder merchantOrder = merchantOrderService.getOneByOrderNo(order.getOrderNo());
            // 排除核销订单,核销订单在具体核销步骤再打印小票
            if (merchantOrder.getShippingType().equals(OrderConstants.ORDER_SHIPPING_TYPE_EXPRESS)) {
                merchantOrderListForPrint.add(merchantOrder);
            }
            if (order.getGainIntegral() > 0) {
                // 生成赠送积分记录
                UserIntegralRecord integralRecord = integralRecordGainInit(user.getId(), order.getOrderNo(), order.getGainIntegral());
                integralList.add(integralRecord);
            }
            List<OrderDetail> merOrderDetailList = orderDetailService.getByOrderNo(order.getOrderNo());
            // 佣金处理
            List<UserBrokerageRecord> broRecordList = assignCommission(merchantOrder, merOrderDetailList);
            if (CollUtil.isNotEmpty(broRecordList)) {
                brokerageRecordList.addAll(broRecordList);
                merchantOrderList.add(merchantOrder);
                orderDetailList.addAll(merOrderDetailList);
            }
            // 商户帐单流水、分账
            OrderProfitSharing orderProfitSharing = initOrderProfitSharing(merchantOrder);
            MerchantBill merchantBill = initPayMerchantBill(merchantOrder, orderProfitSharing.getProfitSharingMerPrice());
            List<Bill> platBillList = initPlatformBill(order, merchantOrder, orderProfitSharing);
            profitSharingList.add(orderProfitSharing);
            merchantBillList.add(merchantBill);
            billList.addAll(platBillList);
        }

        // 商户余额记录
        List<MerchantBalanceRecord> merchantBalanceRecordList = profitSharingList.stream().map(sharing -> {
            MerchantBalanceRecord merchantBalanceRecord = new MerchantBalanceRecord();
            merchantBalanceRecord.setMerId(sharing.getMerId());
            merchantBalanceRecord.setLinkNo(sharing.getOrderNo());
            merchantBalanceRecord.setLinkType("order");
            merchantBalanceRecord.setType(1);
            merchantBalanceRecord.setAmount(sharing.getProfitSharingMerPrice().add(sharing.getFreightFee()));
            merchantBalanceRecord.setTitle(StrUtil.format("订单支付,商户预计分账金额{}元", merchantBalanceRecord.getAmount()));
            merchantBalanceRecord.setBalance(BigDecimal.ZERO);
            merchantBalanceRecord.setStatus(1);
            return merchantBalanceRecord;
        }).collect(Collectors.toList());

        // 分销员逻辑
        if (!user.getIsPromoter()) {
            String funcStatus = systemConfigService.getValueByKey(SysConfigConstants.RETAIL_STORE_SWITCH);
            if (funcStatus.equals("1")) {
                String broQuota = systemConfigService.getValueByKey(SysConfigConstants.RETAIL_STORE_LINE);
                if (!broQuota.equals("-1") && platOrder.getPayPrice().compareTo(new BigDecimal(broQuota)) >= 0) {// -1 不成为分销员
                    user.setIsPromoter(true);
                }
            }
        } else {
            user.setIsPromoter(false);
        }
        Boolean execute = transactionTemplate.execute(e -> {
            // 订单、佣金
            if (CollUtil.isNotEmpty(brokerageRecordList)) {
                merchantOrderService.updateBatchById(merchantOrderList);
                orderDetailService.updateBatchById(orderDetailList);
                userBrokerageRecordService.saveBatch(brokerageRecordList);
            }
            // 订单日志
            orderList.forEach(o -> orderStatusService.createLog(o.getOrderNo(), OrderStatusConstants.ORDER_STATUS_PAY_SPLIT, StrUtil.format(OrderStatusConstants.ORDER_LOG_MESSAGE_PAY_SPLIT, platOrder.getOrderNo())));
            // 用户信息变更
            userService.paySuccessChange(user.getId(), user.getIsPromoter());
            // 积分记录
            if (CollUtil.isNotEmpty(integralList)) {
                userIntegralRecordService.saveBatch(integralList);
            }
            billService.saveBatch(billList);
            merchantBillService.saveBatch(merchantBillList);
            orderProfitSharingService.saveBatch(profitSharingList);
//            profitSharingList.forEach(p -> {
//                merchantService.operationBalance(p.getMerId(), p.getProfitSharingMerPrice(), Constants.OPERATION_TYPE_ADD);
//            });
            merchantBalanceRecordService.saveBatch(merchantBalanceRecordList);
            return Boolean.TRUE;
        });
        if (execute) {
            SystemNotification payNotification = systemNotificationService.getByMark(NotifyConstants.PAY_SUCCESS_MARK);
            // 发送短信
            if (StrUtil.isNotBlank(user.getPhone()) && payNotification.getIsSms().equals(1)) {
                try {
                    smsService.sendPaySuccess(user.getPhone(), platOrder.getOrderNo(), platOrder.getPayPrice());
                } catch (Exception e) {
                    logger.error("支付成功短信发送异常", e);
                }
            }
            if (payNotification.getIsWechat().equals(1) || payNotification.getIsRoutine().equals(1)) {
                //下发模板通知
                try {
                    pushMessageOrder(platOrder, user, payNotification);
                } catch (Exception e) {
                    logger.error("支付成功发送微信通知失败", e);
                }
            }

            // 购买成功后根据配置送优惠券
            autoSendCoupons(platOrder);
            List<String> orderNoList = orderList.stream().map(Order::getOrderNo).collect(Collectors.toList());
            asyncService.orderPayAfterFreezingOperation(orderNoList);

            SystemNotification merchantPayNotification = systemNotificationService.getByMark(NotifyConstants.MERCHANT_PAY_SUCCESS_REMINDER);
            if (merchantPayNotification.getIsSms().equals(1)) {
                try {
                    orderList.forEach(order -> {
                        List<SystemAdmin> smsAdminList = systemAdminService.findReceiveSmsAdminListByMerId(order.getMerId());
                        smsService.sendPaySuccessToMerchant(smsAdminList, order.getOrderNo());
                    });
                } catch (Exception e) {
                    logger.error("支付成功商户管理员短信发送异常", e);
                }
            }

            try {
                // 打印小票 op=1 为方法调用这里也就是支付后自动打印小票的场景
                logger.info("小票打印开始调用");
                merchantPrintService.printReceipt(merchantOrderListForPrint, 3);
            } catch (Exception e) {
                logger.error(StrUtil.format("小票打印异常,Exception:{}", e.getMessage()), e);
            }

            orderList.forEach(order -> {
                if (order.getType().equals(OrderConstants.ORDER_TYPE_CLOUD) || order.getType().equals(OrderConstants.ORDER_TYPE_CDKEY)) {
                    orderService.virtualShipment(order);
                }
            });
        }

        return execute;
    }

    /**
     * 获取收银台信息
     *
     * @param orderNo 订单号
     */
    @Override
    public CashierInfoResponse getCashierIno(String orderNo) {
        Order order = orderService.getByOrderNo(orderNo);
        if (order.getCancelStatus() > OrderConstants.ORDER_CANCEL_STATUS_NORMAL) {
            throw new CrmebException(OrderResultCode.ORDER_CANCEL);
        }
        if (order.getPaid()) {
            throw new CrmebException(OrderResultCode.ORDER_PAID);
        }
        if (order.getStatus() > OrderConstants.ORDER_STATUS_WAIT_PAY) {
            throw new CrmebException(OrderResultCode.ORDER_STATUS_ABNORMAL);
        }
        MerchantOrder merchantOrder = merchantOrderService.getOneByOrderNo(orderNo);
        CashierInfoResponse response = new CashierInfoResponse();
        response.setPayPrice(order.getPayPrice());
        response.setTotalNum(order.getTotalNum());
        response.setConsigneeName(merchantOrder.getRealName());
        response.setConsigneePhone(merchantOrder.getUserPhone());
        response.setConsigneeAddress(merchantOrder.getUserAddress());
        DateTime cancelDate = DateUtil.offsetMinute(order.getCreateTime(), crmebConfig.getOrderCancelTime());
        response.setCancelDateTime(cancelDate.getTime());
        return response;
    }

    /**
     * 查询微信支付结果
     */
    @Override
    public Boolean queryWechatPaymentResult(WechatPaymentQueryRequest request) {
        if (request.getOrderType().equals(PayConstants.PAY_SERVICE_TYPE_ORDER)) {
            return queryWechatPayResult(request.getOrderNo());
        }
        if (request.getOrderType().equals(PayConstants.PAY_SERVICE_TYPE_SVIP)) {
            return querySvipWechatPayResult(request.getOrderNo());
        }
        return queryRechargeWechatPayResult(request.getOrderNo());
    }

    private Boolean queryRechargeWechatPayResult(String orderNo) {
        RechargeOrder rechargeOrder = rechargeOrderService.getByOrderNo(orderNo);
        if (ObjectUtil.isNull(rechargeOrder)) {
            throw new CrmebException(OrderResultCode.ORDER_NOT_EXIST);
        }
        if (!rechargeOrder.getPayType().equals(PayConstants.PAY_TYPE_WE_CHAT)) {
            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "不是微信支付类型订单");
        }
        if (rechargeOrder.getPaid()) {
            return Boolean.TRUE;
        }
        WechatPayInfo wechatPayInfo = wechatPayInfoService.getByNo(rechargeOrder.getOutTradeNo());
        if (ObjectUtil.isNull(wechatPayInfo)) {
            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "未找到对应微信订单");
        }
        Map<String, String> payVo = getWechatQueryPayVo(rechargeOrder.getOutTradeNo(), rechargeOrder.getPayChannel());
        MyRecord myRecord = wechatService.payOrderQuery(payVo);
        if (myRecord.getInt("payStatus") < 1) {
            return Boolean.FALSE;
        }
        wechatPayInfo.setIsSubscribe(myRecord.getStr("is_subscribe"));
        wechatPayInfo.setTradeState(myRecord.getStr("trade_state"));
        wechatPayInfo.setBankType(myRecord.getStr("bank_type"));
        wechatPayInfo.setCashFee(myRecord.getInt("cash_fee"));
        wechatPayInfo.setCouponFee(myRecord.getInt("coupon_fee"));
        wechatPayInfo.setTransactionId(myRecord.getStr("transaction_id"));
        wechatPayInfo.setTimeEnd(myRecord.getStr("time_end"));
        wechatPayInfo.setTradeStateDesc(myRecord.getStr("trade_state_desc"));
        Boolean updatePaid = transactionTemplate.execute(e -> {
            Boolean update = rechargeOrderService.paySuccessAfter(rechargeOrder);
            if (!update) {
                logger.error("充值订单支付处理结果失败,orderNo = {}", rechargeOrder.getOrderNo());
                e.setRollbackOnly();
                return false;
            }
            wechatPayInfoService.updateById(wechatPayInfo);
            return Boolean.TRUE;
        });
        if (!updatePaid) {
            throw new CrmebException("充值支付成功更新订单失败");
        }
        return Boolean.TRUE;
    }

    /**
     * 查询svip订单微信支付结果
     */
    private Boolean querySvipWechatPayResult(String orderNo) {
        PaidMemberOrder order = paidMemberOrderService.getByOrderNo(orderNo);
        if (ObjectUtil.isNull(order)) {
            throw new CrmebException(MemberResultCode.PAID_MEMBER_ORDER_NOT_EXIST);
        }
        if (!order.getPayType().equals(PayConstants.PAY_TYPE_WE_CHAT)) {
            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "不是微信支付类型订单");
        }
        if (order.getPaid()) {
            return Boolean.TRUE;
        }
        WechatPayInfo wechatPayInfo = wechatPayInfoService.getByNo(order.getOutTradeNo());
        if (ObjectUtil.isNull(wechatPayInfo)) {
            throw new CrmebException(CommonResultCode.VALIDATE_FAILED, "未找到对应微信订单");
        }
        Map<String, String> payVo = getWechatQueryPayVo(order.getOutTradeNo(), order.getPayChannel());
        MyRecord myRecord = wechatService.payOrderQuery(payVo);
        if (myRecord.getInt("payStatus") < 1) {
            return Boolean.FALSE;
        }
        wechatPayInfo.setIsSubscribe(myRecord.getStr("is_subscribe"));
        wechatPayInfo.setTradeState(myRecord.getStr("trade_state"));
        wechatPayInfo.setBankType(myRecord.getStr("bank_type"));
        wechatPayInfo.setCashFee(myRecord.getInt("cash_fee"));
        wechatPayInfo.setCouponFee(myRecord.getInt("coupon_fee"));
        wechatPayInfo.setTransactionId(myRecord.getStr("transaction_id"));
        wechatPayInfo.setTimeEnd(myRecord.getStr("time_end"));
        wechatPayInfo.setTradeStateDesc(myRecord.getStr("trade_state_desc"));
        Boolean updatePaid = transactionTemplate.execute(e -> {
            Boolean update = paidMemberOrderService.paySuccessAfter(order);
            if (!update) {
                logger.error("svip订单支付处理结果失败,orderNo = {}", order.getOrderNo());
                e.setRollbackOnly();
                return false;
            }
            wechatPayInfoService.updateById(wechatPayInfo);
            return Boolean.TRUE;
        });
        if (!updatePaid) {
            throw new CrmebException("svip支付成功更新订单失败");
        }
        return Boolean.TRUE;
    }

    /**
     * 发送消息通知
     * 根据用户类型发送
     * 公众号模板消息
     * 小程序订阅消息
     */
    private void pushMessageOrder(Order order, User user, SystemNotification payNotification) {
        logger.info("发送微信模板消息,订单编号:" + order.getOrderNo());
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_H5)) {// H5
            return;
        }
        UserToken userToken;
        HashMap<String, String> temMap = new HashMap<>();
        if (!order.getPayType().equals(PayConstants.PAY_TYPE_WE_CHAT)) {
            return;
        }
        List<OrderDetail> orderDetailList = orderDetailService.getByOrderNo(order.getOrderNo());
        // 公众号模板消息
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_PUBLIC) && payNotification.getIsWechat().equals(1) && user.getIsWechatPublic()) {
            userToken = userTokenService.getTokenByUserId(user.getId(), UserConstants.USER_TOKEN_TYPE_WECHAT);
            if (ObjectUtil.isNull(userToken)) {
                return;
            }
            // 发送微信模板消息
            /**
             * {{first.DATA}}
             * 订单号:{{keyword1.DATA}}
             * 商品名称:{{keyword2.DATA}}
             * 支付金额:{{keyword3.DATA}}
             * 下单人:{{keyword4.DATA}}
             * 订单支付时间:{{keyword5.DATA}}
             * {{remark.DATA}}
             */
            temMap.put(Constants.WE_CHAT_TEMP_KEY_FIRST, "订单支付成功通知!");
            temMap.put("keyword1", order.getOrderNo());
            temMap.put("keyword2", orderDetailList.stream().map(OrderDetail::getProductName).collect(Collectors.joining(",")));
            temMap.put("keyword3", order.getPayPrice().toString());
            temMap.put("keyword4", user.getNickname());
            temMap.put("keyword5", order.getPayTime().toString());
            temMap.put(Constants.WE_CHAT_TEMP_KEY_END, "欢迎下次再来!");
            templateMessageService.pushTemplateMessage(payNotification.getWechatId(), temMap, userToken.getToken());
            return;
        }
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_MINI) && payNotification.getIsRoutine().equals(1)) {
            // 小程序发送订阅消息
            userToken = userTokenService.getTokenByUserId(user.getId(), UserConstants.USER_TOKEN_TYPE_ROUTINE);
            if (ObjectUtil.isNull(userToken)) {
                return;
            }
            // 组装数据
//            temMap.put("character_string1", storeOrder.getOrderId());
//            temMap.put("amount2", storeOrder.getPayPrice().toString() + "元");
//            temMap.put("thing7", "您的订单已支付成功");
            temMap.put("character_string3", order.getOrderNo());
            temMap.put("amount9", order.getPayPrice().toString() + "元");
            temMap.put("thing6", "您的订单已支付成功");
            templateMessageService.pushMiniTemplateMessage(payNotification.getRoutineId(), temMap, userToken.getToken());
        }
    }


    /**
     * 佣金处理
     *
     * @param merchantOrder   商户订单部分
     * @param orderDetailList 订单详情列表
     * @return 佣金记录列表
     */
    private List<UserBrokerageRecord> assignCommission(MerchantOrder merchantOrder, List<OrderDetail> orderDetailList) {
        // 秒杀订单不参与分佣
        if (merchantOrder.getType().equals(OrderConstants.ORDER_TYPE_SECKILL)) {
            return CollUtil.newArrayList();
        }
        // 检测商城是否开启分销功能
        String isOpen = systemConfigService.getValueByKey(SysConfigConstants.RETAIL_STORE_SWITCH);
        if (StrUtil.isBlank(isOpen) || isOpen.equals("0")) {
            return CollUtil.newArrayList();
        }
        long count = orderDetailList.stream().filter(e -> e.getSubBrokerageType() > 0).count();
        if (count == 0L) {
            return CollUtil.newArrayList();
        }
        // 查找订单所属人信息
        User user = userService.getById(merchantOrder.getUid());
        // 当前用户不存在 没有上级 或者 当用用户上级时自己  直接返回
        if (ObjectUtil.isNull(user.getSpreadUid()) || user.getSpreadUid() < 1 || user.getSpreadUid().equals(merchantOrder.getUid())) {
            return CollUtil.newArrayList();
        }
        // 获取参与分佣的人(两级)
        List<MyRecord> spreadRecordList = getSpreadRecordList(user.getSpreadUid());
        if (CollUtil.isEmpty(spreadRecordList)) {
            return CollUtil.newArrayList();
        }
        // 获取佣金冻结期
        String freezingTime = systemConfigService.getValueByKey(SysConfigConstants.RETAIL_STORE_BROKERAGE_FREEZING_TIME);
        List<UserBrokerageRecord> brokerageRecordList = new ArrayList<>();
        // 计算两级佣金金额
        if (spreadRecordList.size() == 1) {
            BigDecimal firstBrokerage = BigDecimal.ZERO;
            for (OrderDetail orderDetail : orderDetailList) {
                if (orderDetail.getSubBrokerageType().equals(0)) {
                    continue;
                }
                BigDecimal detailPrice = (orderDetail.getIsSvip() && orderDetail.getIsPaidMemberProduct()) ? orderDetail.getVipPrice() : orderDetail.getPrice();
                BigDecimal brokerage = detailPrice.multiply(new BigDecimal(orderDetail.getPayNum().toString()))
                        .subtract(orderDetail.getMerCouponPrice())
                        .multiply(new BigDecimal(orderDetail.getBrokerage().toString()))
                        .divide(new BigDecimal("100"), 2, BigDecimal.ROUND_DOWN);
                orderDetail.setFirstBrokerageFee(brokerage);
                firstBrokerage = firstBrokerage.add(brokerage);
            }
            merchantOrder.setFirstBrokerage(firstBrokerage);
            UserBrokerageRecord brokerageRecord = new UserBrokerageRecord();
            brokerageRecord.setUid(spreadRecordList.get(0).getInt("spreadUid"));
            brokerageRecord.setSubUid(merchantOrder.getUid());
            brokerageRecord.setLinkNo(merchantOrder.getOrderNo());
            brokerageRecord.setLinkType(BrokerageRecordConstants.BROKERAGE_RECORD_LINK_TYPE_ORDER);
            brokerageRecord.setType(BrokerageRecordConstants.BROKERAGE_RECORD_TYPE_ADD);
            brokerageRecord.setTitle(BrokerageRecordConstants.BROKERAGE_RECORD_TITLE_ORDER);
            brokerageRecord.setPrice(firstBrokerage);
            brokerageRecord.setMark(StrUtil.format("获得推广佣金,分佣{}", firstBrokerage));
            brokerageRecord.setStatus(BrokerageRecordConstants.BROKERAGE_RECORD_STATUS_CREATE);
            brokerageRecord.setFrozenTime(Integer.valueOf(Optional.ofNullable(freezingTime).orElse("0")));
            brokerageRecord.setCreateTime(CrmebDateUtil.nowDateTime());
            brokerageRecord.setBrokerageLevel(spreadRecordList.get(0).getInt("index"));
            brokerageRecordList.add(brokerageRecord);
            return brokerageRecordList;
        }
        BigDecimal firstBrokerage = BigDecimal.ZERO;
        BigDecimal secondBrokerage = BigDecimal.ZERO;
        for (OrderDetail orderDetail : orderDetailList) {
            if (orderDetail.getSubBrokerageType().equals(0)) {
                continue;
            }
            BigDecimal detailPrice = (orderDetail.getIsSvip() && orderDetail.getIsPaidMemberProduct()) ? orderDetail.getVipPrice() : orderDetail.getPrice();
            BigDecimal brokerage = detailPrice.multiply(new BigDecimal(orderDetail.getPayNum().toString()))
                    .subtract(orderDetail.getMerCouponPrice())
                    .multiply(new BigDecimal(orderDetail.getBrokerage().toString()))
                    .divide(new BigDecimal("100"), 2, BigDecimal.ROUND_DOWN);
            BigDecimal brokerageTwo = detailPrice.multiply(new BigDecimal(orderDetail.getPayNum().toString()))
                    .subtract(orderDetail.getMerCouponPrice())
                    .multiply(new BigDecimal(orderDetail.getBrokerageTwo().toString()))
                    .divide(new BigDecimal("100"), 2, BigDecimal.ROUND_DOWN);

            orderDetail.setFirstBrokerageFee(brokerage);
            orderDetail.setSecondBrokerageFee(brokerageTwo);
            firstBrokerage = firstBrokerage.add(brokerage);
            secondBrokerage = secondBrokerage.add(brokerageTwo);
        }
        merchantOrder.setFirstBrokerage(firstBrokerage);
        merchantOrder.setSecondBrokerage(secondBrokerage);
        // 生成佣金记录
        brokerageRecordList = spreadRecordList.stream().map(record -> {
            UserBrokerageRecord brokerageRecord = new UserBrokerageRecord();
            brokerageRecord.setUid(record.getInt("spreadUid"));
            brokerageRecord.setSubUid(merchantOrder.getUid());
            brokerageRecord.setLinkNo(merchantOrder.getOrderNo());
            brokerageRecord.setLinkType(BrokerageRecordConstants.BROKERAGE_RECORD_LINK_TYPE_ORDER);
            brokerageRecord.setType(BrokerageRecordConstants.BROKERAGE_RECORD_TYPE_ADD);
            brokerageRecord.setTitle(BrokerageRecordConstants.BROKERAGE_RECORD_TITLE_ORDER);
            BigDecimal price = record.getInt("index") == 1 ? merchantOrder.getFirstBrokerage() : merchantOrder.getSecondBrokerage();
            brokerageRecord.setPrice(price);
            brokerageRecord.setMark(StrUtil.format("获得推广佣金,分佣{}", price));
            brokerageRecord.setStatus(BrokerageRecordConstants.BROKERAGE_RECORD_STATUS_CREATE);
            brokerageRecord.setFrozenTime(Integer.valueOf(Optional.ofNullable(freezingTime).orElse("0")));
            brokerageRecord.setCreateTime(CrmebDateUtil.nowDateTime());
            brokerageRecord.setBrokerageLevel(record.getInt("index"));
            return brokerageRecord;
        }).collect(Collectors.toList());
        return brokerageRecordList;
    }

    /**
     * 获取参与分佣人员(两级)
     *
     * @param spreadUid 一级分佣人Uid
     * @return List<MyRecord>
     */
    private List<MyRecord> getSpreadRecordList(Integer spreadUid) {
        List<MyRecord> recordList = CollUtil.newArrayList();

        // 第一级
        User spreadUser = userService.getById(spreadUid);
        if (ObjectUtil.isNull(spreadUser) || !spreadUser.getIsPromoter()) {
            return recordList;
        }

        MyRecord firstRecord = new MyRecord();
        firstRecord.set("index", 1);
        firstRecord.set("spreadUid", spreadUid);
        recordList.add(firstRecord);

        // 第二级
        User spreadSpreadUser = userService.getById(spreadUser.getSpreadUid());
        if (ObjectUtil.isNull(spreadSpreadUser) || !spreadSpreadUser.getIsPromoter()) {
            return recordList;
        }
        MyRecord secondRecord = new MyRecord();
        secondRecord.set("index", 2);
        secondRecord.set("spreadUid", spreadSpreadUser.getId());
        recordList.add(secondRecord);
        return recordList;
    }

    /**
     * 初始化订单分帐表
     *
     * @param merchantOrder 商户部分订单
     * @return 分账记录
     */
    private OrderProfitSharing initOrderProfitSharing(MerchantOrder merchantOrder) {
        // 获取商户信息
        Merchant merchant = merchantService.getByIdException(merchantOrder.getMerId());
        // 分账计算
        // 商户收入 = 订单应付 - 商户优惠 -平台手续费 - 佣金
        BigDecimal orderPrice = merchantOrder.getPayPrice().add(merchantOrder.getIntegralPrice()).add(merchantOrder.getPlatCouponPrice()).subtract(merchantOrder.getPayPostage());
        // 平台手续费
        BigDecimal platFee = orderPrice.multiply(new BigDecimal(merchant.getHandlingFee())).divide(new BigDecimal(100), 2, BigDecimal.ROUND_UP);
        // 商户收入金额
        BigDecimal merchantFee = orderPrice.subtract(platFee).subtract(merchantOrder.getFirstBrokerage()).subtract(merchantOrder.getSecondBrokerage());
        OrderProfitSharing orderProfitSharing = new OrderProfitSharing();
        orderProfitSharing.setOrderNo(merchantOrder.getOrderNo());
        orderProfitSharing.setMerId(merchantOrder.getMerId());
        //查询attr
        Order order = orderService.getByOrderNo(merchantOrder.getOrderNo());
        if(Objects.nonNull(order)){
            BigDecimal costTotalPrice = order.getCostTotalPrice();
            orderProfitSharing.setOrderCostPrice(costTotalPrice);
        }else{
            orderProfitSharing.setOrderCostPrice(BigDecimal.ZERO);
        }
        orderProfitSharing.setOrderPrice(merchantOrder.getPayPrice());
        orderProfitSharing.setIntegralNum(merchantOrder.getUseIntegral());
        orderProfitSharing.setIntegralPrice(merchantOrder.getIntegralPrice());
        orderProfitSharing.setProfitSharingPlatPrice(platFee);
        orderProfitSharing.setProfitSharingMerPrice(merchantFee);
        orderProfitSharing.setFirstBrokerageFee(merchantOrder.getFirstBrokerage());
        orderProfitSharing.setSecondBrokerageFee(merchantOrder.getSecondBrokerage());
        orderProfitSharing.setPlatCouponPrice(merchantOrder.getPlatCouponPrice());
        orderProfitSharing.setFreightFee(merchantOrder.getPayPostage());
        return orderProfitSharing;
    }

    /**
     * 初始化订单支付商户账单表
     *
     * @param merchantOrder 商户订单部分
     * @param merchantFee   商户分账金额
     */
    private MerchantBill initPayMerchantBill(MerchantOrder merchantOrder, BigDecimal merchantFee) {
        MerchantBill merchantBill = new MerchantBill();
        merchantBill.setMerId(merchantOrder.getMerId());
        merchantBill.setType(BillConstants.BILL_TYPE_PAY_ORDER);
        merchantBill.setOrderNo(merchantOrder.getOrderNo());
        merchantBill.setUid(merchantOrder.getUid());
        merchantBill.setPm(BillConstants.BILL_PM_ADD);
        BigDecimal merFee = merchantOrder.getPayPostage().add(merchantFee);
        merchantBill.setAmount(merFee);
        merchantBill.setMark(StrUtil.format("订单{}支付{}元,商户收入{}元", merchantOrder.getOrderNo(), merchantOrder.getPayPrice(), merFee));
        return merchantBill;
    }

    /**
     * 初始化订单支付平台账单表
     *
     * @param order              订单
     * @param merchantOrder      商户订单部分
     * @param orderProfitSharing 分账数据
     * @return List
     */
    private List<Bill> initPlatformBill(Order order, MerchantOrder merchantOrder, OrderProfitSharing orderProfitSharing) {
        List<Bill> billList = CollUtil.newArrayList();

        Bill payBill = new Bill();
        payBill.setUid(order.getUid());
        payBill.setOrderNo(order.getOrderNo());
        payBill.setAmount(order.getPayPrice());
        if (order.getPayType().equals(PayConstants.PAY_TYPE_YUE)) {
            payBill.setPm(BillConstants.BILL_PM_SUB);
            payBill.setType(BillConstants.BILL_TYPE_YUE_PAY);
            payBill.setMark(StrUtil.format("余额支付成功,扣除用户余额{}元", order.getPayPrice()));
        } else {
            payBill.setPm(BillConstants.BILL_PM_ADD);
            payBill.setType(BillConstants.BILL_TYPE_PAY_ORDER);
            payBill.setMark(StrUtil.format("订单支付成功,支付金额{}元", order.getPayPrice()));
        }
        billList.add(payBill);

//        Bill collectBill = new Bill();
//        collectBill.setMerId(merchantOrder.getMerId());
//        collectBill.setOrderNo(order.getOrderNo());
//        collectBill.setAmount(orderProfitSharing.getProfitSharingMerPrice().add(merchantOrder.getPayPostage()));
//        collectBill.setPm(BillConstants.BILL_PM_SUB);
//        collectBill.setType(BillConstants.BILL_TYPE_MERCHANT_COLLECT);
//        collectBill.setMark(StrUtil.format("订单支付成功,商户分账{}元", orderProfitSharing.getProfitSharingMerPrice().add(merchantOrder.getPayPostage())));
//        billList.add(collectBill);

//        Bill platBill = new Bill();
//        platBill.setOrderNo(order.getOrderNo());
//        platBill.setAmount(orderProfitSharing.getProfitSharingPlatPrice());
//        platBill.setPm(BillConstants.BILL_PM_ADD);
//        platBill.setType(BillConstants.BILL_TYPE_PAY_ORDER);
//        platBill.setMark(StrUtil.format("订单支付成功,平台手续费{}元", orderProfitSharing.getProfitSharingPlatPrice()));
//        billList.add(platBill);

        if (ObjectUtil.isNotNull(orderProfitSharing.getFirstBrokerageFee()) && orderProfitSharing.getFirstBrokerageFee().compareTo(BigDecimal.ZERO) > 0) {
            Bill firstBill = new Bill();
            firstBill.setOrderNo(order.getOrderNo());
            firstBill.setAmount(orderProfitSharing.getFirstBrokerageFee());
            firstBill.setPm(BillConstants.BILL_PM_SUB);
            firstBill.setType(BillConstants.BILL_TYPE_BROKERAGE);
            firstBill.setMark(StrUtil.format("订单支付成功,分配一级佣金{}元", orderProfitSharing.getFirstBrokerageFee()));
            billList.add(firstBill);
            if (orderProfitSharing.getSecondBrokerageFee().compareTo(BigDecimal.ZERO) > 0) {
                Bill secondBill = new Bill();
                secondBill.setOrderNo(order.getOrderNo());
                secondBill.setAmount(orderProfitSharing.getSecondBrokerageFee());
                secondBill.setPm(BillConstants.BILL_PM_SUB);
                secondBill.setType(BillConstants.BILL_TYPE_BROKERAGE);
                secondBill.setMark(StrUtil.format("订单支付成功,分配二级佣金{}元", orderProfitSharing.getSecondBrokerageFee()));
                billList.add(secondBill);
            }
        }

        if (orderProfitSharing.getIntegralNum() > 0) {
            Bill integralBill = new Bill();
            integralBill.setOrderNo(order.getOrderNo());
            integralBill.setAmount(order.getIntegralPrice());
            integralBill.setPm(BillConstants.BILL_PM_SUB);
            integralBill.setType(BillConstants.BILL_TYPE_PAY_ORDER);
            integralBill.setMark(StrUtil.format("订单支付成功,用户使用{}积分抵扣{}元,平台扣除", orderProfitSharing.getIntegralNum(), orderProfitSharing.getIntegralPrice()));
            billList.add(integralBill);
        }
        return billList;
    }

    /**
     * 初始化积分赠送记录
     */
    private UserIntegralRecord integralRecordGainInit(Integer uid, String orderNo, Integer gainIntegral) {
        UserIntegralRecord integralRecord = new UserIntegralRecord();
        integralRecord.setUid(uid);
        integralRecord.setLinkId(orderNo);
        integralRecord.setLinkType(IntegralRecordConstants.INTEGRAL_RECORD_LINK_TYPE_ORDER);
        integralRecord.setType(IntegralRecordConstants.INTEGRAL_RECORD_TYPE_ADD);
        integralRecord.setTitle(IntegralRecordConstants.INTEGRAL_RECORD_TITLE_ORDER);
        integralRecord.setIntegral(gainIntegral);
//        integralRecord.setBalance(balance);
        integralRecord.setMark(StrUtil.format("订单支付成功奖励{}积分", gainIntegral));
        integralRecord.setStatus(IntegralRecordConstants.INTEGRAL_RECORD_STATUS_CREATE);
        // 获取积分冻结期
        String freezeTime = systemConfigService.getValueByKey(SysConfigConstants.CONFIG_KEY_STORE_INTEGRAL_EXTRACT_TIME);
        integralRecord.setFrozenTime(Integer.valueOf(Optional.ofNullable(freezeTime).orElse("0")));
        integralRecord.setCreateTime(CrmebDateUtil.nowDateTime());
        return integralRecord;
    }

    private Map<String, String> getWechatQueryPayVo(String outTradeNo, String payChannel) {
        // 获取appid、mch_id
        // 微信签名key
        String appId = "";
        String mchId = "";
        String signKey = "";
        switch (payChannel) {
            case PayConstants.PAY_CHANNEL_WECHAT_PUBLIC:
            case PayConstants.PAY_CHANNEL_H5:// H5使用公众号的信息
            case PayConstants.PAY_CHANNEL_WECHAT_NATIVE:// H5使用公众号的信息
                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PUBLIC_APPID);
                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_PUBLIC_MCHID);
                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_PUBLIC_KEY);
                break;
            case PayConstants.PAY_CHANNEL_WECHAT_MINI:
                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_MINI_APPID);
                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_MINI_MCHID);
                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_MINI_KEY);
                break;
            case PayConstants.PAY_CHANNEL_WECHAT_APP_IOS:
            case PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID:
                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_APP_APPID);
                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_APP_MCHID);
                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_APP_KEY);
                break;
        }

        // 生成查询订单对象
        Map<String, String> map = CollUtil.newHashMap();
        map.put("appid", appId);
        map.put("mch_id", mchId);
        map.put("out_trade_no", outTradeNo);
        map.put("nonce_str", WxPayUtil.getNonceStr());
        map.put("sign_type", PayConstants.WX_PAY_SIGN_TYPE_MD5);
        map.put("sign", WxPayUtil.getSign(map, signKey));
        return map;
    }

    /**
     * 支付宝支付
     *
     * @param order 订单
     * @return result
     */
    private String aliPayment(Order order) {
        DateTime cancelTime = DateUtil.offset(order.getCreateTime(), DateField.MINUTE, crmebConfig.getOrderCancelTime());
        String cancelStr = cancelTime.toString(DateConstants.DATE_FORMAT);
        return aliPayService.pay(order.getOrderNo(), order.getPayPrice(), "order", order.getPayChannel(), cancelStr);
    }

    /**
     * 微信支付
     *
     * @param order 订单
     * @return WxPayJsResultVo
     */
    private WxPayJsResultVo wechatPayment(Order order) {
        // 预下单
        Map<String, String> unifiedorder = unifiedorder(order);
        WxPayJsResultVo vo = new WxPayJsResultVo();
        vo.setAppId(unifiedorder.get("appId"));
        vo.setNonceStr(unifiedorder.get("nonceStr"));
        vo.setPackages(unifiedorder.get("package"));
        vo.setSignType(unifiedorder.get("signType"));
        vo.setTimeStamp(unifiedorder.get("timeStamp"));
        vo.setPaySign(unifiedorder.get("paySign"));
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_H5)) {
            vo.setMwebUrl(unifiedorder.get("mweb_url"));
        }
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_APP_IOS) ||
                order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID)) {// App
            vo.setPartnerid(unifiedorder.get("partnerid"));
        }
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_NATIVE)) {
            vo.setMwebUrl(unifiedorder.get("code_url"));
        }
        order.setOutTradeNo(unifiedorder.get("outTradeNo"));
        // 更新商户订单号
        vo.setOutTradeNo(unifiedorder.get("outTradeNo"));
        return vo;
    }

    /**
     * 余额支付
     *
     * @param order 订单
     * @return Boolean Boolean
     */
    private Boolean yuePay(Order order, User user) {
        // 用户余额扣除
        Boolean execute = transactionTemplate.execute(e -> {
            Boolean update = Boolean.TRUE;
            // 订单修改
            order.setPaid(true);
            order.setPayTime(DateUtil.date());
            order.setStatus(OrderConstants.ORDER_STATUS_WAIT_SHIPPING);
            orderService.updateById(order);
            // 这里只扣除金额,账单记录在task中处理
            if (order.getPayPrice().compareTo(BigDecimal.ZERO) > 0) {
                update = userService.updateNowMoney(order.getUid(), order.getPayPrice(), Constants.OPERATION_TYPE_SUBTRACT);
                if (!update) {
                    logger.error("余额支付,扣除用户余额失败,orderNo = {}", order.getOrderNo());
                    e.setRollbackOnly();
                    return update;
                }
                sendPayment(order.getWwOrderNo(),order.getOrderNo());
                // 用户余额记录
                UserBalanceRecord userBalanceRecord = new UserBalanceRecord();
                userBalanceRecord.setUid(user.getId());
                userBalanceRecord.setLinkId(order.getOrderNo());
                userBalanceRecord.setLinkType(BalanceRecordConstants.BALANCE_RECORD_LINK_TYPE_ORDER);
                userBalanceRecord.setType(BalanceRecordConstants.BALANCE_RECORD_TYPE_SUB);
                userBalanceRecord.setAmount(order.getPayPrice());
                userBalanceRecord.setBalance(user.getNowMoney().subtract(order.getPayPrice()));
                userBalanceRecord.setRemark(StrUtil.format(BalanceRecordConstants.BALANCE_RECORD_REMARK_ORDER, order.getPayPrice()));
                userBalanceRecordService.save(userBalanceRecord);
            }
            return update;
        });
        if (!execute) throw new CrmebException("余额支付订单失败");
        //通知万物
        noticeWw(order.getWwOrderNo(), order.getOrderNo());
        asyncService.orderPaySuccessSplit(order.getOrderNo());
        return true;
    }

    /**
     * 预下单
     *
     * @param order 订单
     * @return 预下单返回对象
     */
    private Map<String, String> unifiedorder(Order order) {
        // 获取用户openId
        // 根据订单支付类型来判断获取公众号openId还是小程序openId
        UserToken userToken = new UserToken();
        userToken.setToken("");
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_PUBLIC)) {// 公众号
            userToken = userTokenService.getTokenByUserId(order.getUid(), UserConstants.USER_TOKEN_TYPE_WECHAT);
        }
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_MINI)
                || order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_MINI_VIDEO)) {// 小程序
            userToken = userTokenService.getTokenByUserId(order.getUid(), UserConstants.USER_TOKEN_TYPE_ROUTINE);
        }

        // 获取appid、mch_id、微信签名key
        String appId = "";
        String mchId = "";
        String signKey = "";
        switch (order.getPayChannel()) {
            case PayConstants.PAY_CHANNEL_WECHAT_PUBLIC:
            case PayConstants.PAY_CHANNEL_H5:// H5使用公众号的信息
            case PayConstants.PAY_CHANNEL_WECHAT_NATIVE:// H5使用公众号的信息
                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PUBLIC_APPID);
                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_PUBLIC_MCHID);
                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_PUBLIC_KEY);
                break;
            case PayConstants.PAY_CHANNEL_WECHAT_MINI:
            case PayConstants.PAY_CHANNEL_WECHAT_MINI_VIDEO:
                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_MINI_APPID);
                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_MINI_MCHID);
                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_MINI_KEY);
                break;
            case PayConstants.PAY_CHANNEL_WECHAT_APP_IOS:
            case PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID:
                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_APP_APPID);
                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_APP_MCHID);
                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_APP_KEY);
                break;
        }
        // 获取微信预下单对象
        CreateOrderRequestVo unifiedorderVo = getUnifiedorderVo(order, userToken.getToken(), appId, mchId, signKey);

        // 预下单(统一下单)
        CreateOrderResponseVo responseVo = wechatService.payUnifiedorder(unifiedorderVo);
        // 组装前端预下单参数
        Map<String, String> map = new HashMap<>();
        map.put("appId", unifiedorderVo.getAppid());
        map.put("nonceStr", unifiedorderVo.getAppid());
        map.put("package", "prepay_id=".concat(responseVo.getPrepayId()));
        map.put("signType", unifiedorderVo.getSign_type());
        Long currentTimestamp = WxPayUtil.getCurrentTimestamp();
        map.put("timeStamp", Long.toString(currentTimestamp));
        String paySign = WxPayUtil.getSign(map, signKey);
        map.put("paySign", paySign);
        map.put("prepayId", responseVo.getPrepayId());
        map.put("prepayTime", CrmebDateUtil.nowDateTimeStr());
        map.put("outTradeNo", unifiedorderVo.getOut_trade_no());
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_H5)) {
            map.put("mweb_url", responseVo.getMWebUrl());
        }
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_APP_IOS) ||
                order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID)) {// App
            map.put("partnerid", mchId);
            map.put("package", responseVo.getPrepayId());
            Map<String, Object> appMap = new HashMap<>();
            appMap.put("appid", unifiedorderVo.getAppid());
            appMap.put("partnerid", mchId);
            appMap.put("prepayid", responseVo.getPrepayId());
            appMap.put("package", "Sign=WXPay");
            appMap.put("noncestr", unifiedorderVo.getAppid());
            appMap.put("timestamp", currentTimestamp);
            logger.info("================================================app支付签名,map = " + appMap);
            String sign = WxPayUtil.getSignObject(appMap, signKey);
            logger.info("================================================app支付签名,sign = " + sign);
            map.put("paySign", sign);
        }
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_NATIVE)) {
            map.put("code_url", responseVo.getCodeUrl());
        }
        return map;
    }

    /**
     * 获取微信预下单对象
     *
     * @return 微信预下单对象
     */
    private CreateOrderRequestVo getUnifiedorderVo(Order order, String openid, String appId, String mchId, String signKey) {
        // 获取域名
        String domain = systemConfigService.getValueByKeyException(SysConfigConstants.CONFIG_KEY_SITE_URL);
        String apiDomain = systemConfigService.getValueByKeyException(SysConfigConstants.CONFIG_KEY_API_URL);

        AttachVo attachVo = new AttachVo(PayConstants.PAY_SERVICE_TYPE_ORDER, order.getUid());

        CreateOrderRequestVo vo = new CreateOrderRequestVo();
        vo.setAppid(appId);
        vo.setMch_id(mchId);
        vo.setNonce_str(WxPayUtil.getNonceStr());
        vo.setSign_type(PayConstants.WX_PAY_SIGN_TYPE_MD5);
        String siteName = systemConfigService.getValueByKeyException(SysConfigConstants.CONFIG_KEY_SITE_NAME);
        // 因商品名称在微信侧超长更换为网站名称
        vo.setBody(siteName);
        vo.setAttach(JSONObject.toJSONString(attachVo));
        vo.setOut_trade_no(CrmebUtil.getOrderNo(OrderConstants.ORDER_PREFIX_WECHAT));
        // 订单中使用的是BigDecimal,这里要转为Integer类型
        vo.setTotal_fee(order.getPayPrice().multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).intValue());
        vo.setSpbill_create_ip(RequestUtil.getClientIp());
        vo.setNotify_url(apiDomain + PayConstants.WX_PAY_NOTIFY_API_URI);
        switch (order.getPayChannel()) {
            case PayConstants.PAY_CHANNEL_H5:
                vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_H5);
                vo.setOpenid(null);
                break;
            case PayConstants.PAY_CHANNEL_WECHAT_APP_IOS:
            case PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID:
                vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_APP);
                vo.setOpenid(null);
                break;
            case PayConstants.PAY_CHANNEL_WECHAT_NATIVE:
                vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_NATIVE);
                vo.setProduct_id(order.getOrderNo());
                vo.setOpenid(null);
                break;
            default:
                vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_JS);
                vo.setOpenid(openid);
        }
        CreateOrderH5SceneInfoVo createOrderH5SceneInfoVo = new CreateOrderH5SceneInfoVo(
                new CreateOrderH5SceneInfoDetailVo(
                        domain,
                        systemConfigService.getValueByKeyException(SysConfigConstants.CONFIG_KEY_SITE_NAME)
                )
        );
        vo.setScene_info(JSONObject.toJSONString(createOrderH5SceneInfoVo));

        vo.setTime_start(DateUtil.date().toString(DateConstants.DATE_TIME_FORMAT_NUM));
        DateTime cancelTime = DateUtil.offset(order.getCreateTime(), DateField.MINUTE, crmebConfig.getOrderCancelTime());
        String cancelStr = cancelTime.toString(DateConstants.DATE_TIME_FORMAT_NUM);
        vo.setTime_expire(cancelStr);
        String sign = WxPayUtil.getSign(vo, signKey);
        vo.setSign(sign);
        return vo;
    }

    /**
     * 商品购买后根据配置送券
     */
    private void autoSendCoupons(Order order) {
        List<OrderDetail> orderDetailList = orderDetailService.getByOrderNo(order.getOrderNo());
        if (CollUtil.isEmpty(orderDetailList)) {
            return;
        }
        List<CouponUser> couponUserList = CollUtil.newArrayList();
        Map<Integer, Boolean> couponMap = CollUtil.newHashMap();
        List<Integer> proIdList = orderDetailList.stream().map(OrderDetail::getProductId).distinct().collect(Collectors.toList());
        for (Integer proId : proIdList) {
            List<ProductCoupon> couponsForGiveUser = productCouponService.getListByProductId(proId);
            for (int i = 0; i < couponsForGiveUser.size(); ) {
                ProductCoupon productCoupon = couponsForGiveUser.get(i);
                MyRecord record = couponUserService.paySuccessGiveAway(productCoupon.getCouponId(), order.getUid());
                if (record.getStr("status").equals("fail")) {
                    logger.error(StrUtil.format("支付成功领取优惠券失败,失败原因:{}", record.getStr("errMsg")));
                    couponsForGiveUser.remove(i);
                    continue;
                }
                CouponUser couponUser = record.get("couponUser");
                couponUserList.add(couponUser);
                couponMap.put(couponUser.getCouponId(), record.getBoolean("isLimited"));
                i++;
            }
        }

        Boolean execute = transactionTemplate.execute(e -> {
            if (CollUtil.isNotEmpty(couponUserList)) {
                couponUserService.saveBatch(couponUserList);
                couponUserList.forEach(i -> couponService.deduction(i.getCouponId(), 1, couponMap.get(i.getCouponId())));
            }
            return Boolean.TRUE;
        });
        if (!execute) {
            logger.error(StrUtil.format("支付成功领取优惠券,更新数据库失败,订单编号:{}", order.getOrderNo()));
        }
    }
}

package com.zbkj.service.service.credit;

import com.zbkj.common.model.credit.CreditOrderBill;
import com.zbkj.common.model.credit.CreditRepayOrder;
import com.zbkj.common.request.PageParamRequest;
import com.zbkj.common.request.credit.CreditOrderBillRequest;
import com.zbkj.common.request.credit.CreditOrderBillSearchRequest;
import com.baomidou.mybatisplus.extension.service.IService;
import com.zbkj.common.response.OrderPayResultResponse;
import com.zbkj.common.response.credit.CreditAmountInfoReponse;
import com.zbkj.common.response.credit.CreditOrderBillResponse;
import com.zbkj.common.response.credit.CreditOrderBillStaticReponse;
import com.zbkj.common.vo.MyRecord;

import java.util.List;

/**
* @author dudianlong
* @description CreditOrderBillService 接口
* @date 2024-11-21
*/
public interface CreditOrderBillService extends IService<CreditOrderBill> {

    List<CreditOrderBillResponse> getList(CreditOrderBillSearchRequest request, PageParamRequest pageParamRequest);

    CreditOrderBillResponse getDetail(String id);

    CreditOrderBillStaticReponse monthAmountInfo(CreditOrderBillRequest request);

    OrderPayResultResponse menthPayment(CreditOrderBillRequest request);

    CreditOrderBill getByOrderNo(String orderNo);

    CreditAmountInfoReponse getUserAmountInfo(Integer uid);

    CreditRepayOrder create(CreditOrderBillRequest request);

    Boolean updateCreditAmountAndCreditOrderBill(CreditRepayOrder order, Integer uid);
      List<CreditOrderBill> getNoStartTask();

    void updateRefundStatus(String wwOrderNo);

    List<CreditOrderBill> getCreditRepaymentFlag();

    boolean updateInfo(CreditOrderBillRequest creditOrderBillRequest);
}
package com.zbkj.service.service.impl.credit;

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.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.github.pagehelper.PageHelper;



import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zbkj.common.config.CrmebConfig;
import com.zbkj.common.constants.*;
import com.zbkj.common.exception.CrmebException;
import com.zbkj.common.model.admin.SystemAdmin;
import com.zbkj.common.model.bill.Bill;
import com.zbkj.common.model.credit.*;
import com.zbkj.common.model.order.OrderDetail;
import com.zbkj.common.model.user.User;
import com.zbkj.common.model.user.UserBalanceRecord;
import com.zbkj.common.model.user.UserToken;
import com.zbkj.common.request.PageParamRequest;
import com.zbkj.common.request.credit.CreditOrderBillRequest;
import com.zbkj.common.request.credit.CreditOrderBillSearchRequest;
import com.zbkj.common.response.OrderInfoFrontDataResponse;
import com.zbkj.common.response.OrderPayResultResponse;
import com.zbkj.common.response.credit.CreditAmountInfoReponse;
import com.zbkj.common.response.credit.CreditAmountResponse;
import com.zbkj.common.response.credit.CreditOrderBillResponse;
import com.zbkj.common.response.credit.CreditOrderBillStaticReponse;
import com.zbkj.common.utils.*;
import com.zbkj.common.vo.*;
import com.zbkj.service.dao.credit.CreditOrderBillDao;
import com.zbkj.service.dao.credit.CreditOrderBillRecordDao;
import com.zbkj.service.service.*;
import com.zbkj.service.service.credit.*;
import kong.unirest.HttpResponse;
import kong.unirest.Unirest;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.List;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author dudianlong
 * @description CreditOrderBillServiceImpl 接口实现
 * @date 2024-11-21
 */
@Service
public class CreditOrderBillServiceImpl extends ServiceImpl<CreditOrderBillDao, CreditOrderBill> implements CreditOrderBillService {

    @Resource
    private CreditOrderBillDao dao;

    private static final Logger logger = LoggerFactory.getLogger(CreditOrderBillServiceImpl.class);

    @Autowired
    private CreditRepayOrderService creditRepayOrderService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private UserService userService;
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private UserBalanceRecordService userBalanceRecordService;
    @Autowired
    private UserTokenService userTokenService;
    @Autowired
    private WechatService wechatService;
    @Autowired
    private SystemConfigService systemConfigService;
    @Autowired
    private CrmebConfig crmebConfig;
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private CreditAmountService creditAmountService;
    @Autowired
    private CreditBillInfoService creditBillInfoService;
    @Autowired
    private CreditOrderBillService creditOrderBillService;
    @Autowired
    private CreditOrderBillRecordDao creditOrderBillRecordDao;
    @Autowired
    private BillService billService;

    /**
     * 列表
     * @param request 请求参数
     * @param pageParamRequest 分页类参数
     * @author dudianlong
     * @since 2024-11-21
     * @return List<CreditOrderBill>
     */
    @Override
    public List<CreditOrderBillResponse> getList(CreditOrderBillSearchRequest request, PageParamRequest pageParamRequest) {
        if(pageParamRequest != null){
            PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());
        }
        List<CreditOrderBillResponse> list = dao.getList(request);
        return list;
    }

    @Override
    public CreditOrderBillResponse getDetail(String id) {
        CreditOrderBillSearchRequest request = new CreditOrderBillSearchRequest();
        request.setId(id);

        List<CreditOrderBillResponse> list = getList(request, null);
        if(CollectionUtils.isNotEmpty(list)){
            CreditOrderBillResponse response = list.get(0);
            List<OrderDetail> orderDetailList = orderDetailService.getByOrderNo(response.getOrderNo());
            List<OrderInfoFrontDataResponse> orderInfoList = orderDetailList.stream().map(e -> {
                OrderInfoFrontDataResponse dataResponse = new OrderInfoFrontDataResponse();
                BeanUtils.copyProperties(e, dataResponse);
                return dataResponse;
            }).collect(Collectors.toList());
            response.setOrderDetailList(orderInfoList);
            //查询修改记录
            LambdaQueryWrapper<CreditOrderBillRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(CreditOrderBillRecord::getBillId, id);
            List<CreditOrderBillRecord> recordList = creditOrderBillRecordDao.selectList(lambdaQueryWrapper);
            response.setRecords(recordList);
            return response;
        }

        return null;
    }

    @Override
    public CreditOrderBillStaticReponse monthAmountInfo(CreditOrderBillRequest request) {
        CreditOrderBillStaticReponse reponse=new CreditOrderBillStaticReponse();
        LambdaQueryWrapper<CreditOrderBill> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        Integer uid = userService.getUserIdException();
        //查询授信用户信息
        CreditAmount creditAmount = creditAmountService.getByUserId(uid);
        BeanUtils.copyProperties(creditAmount, reponse);
        lambdaQueryWrapper.eq(CreditOrderBill::getUid, uid);
        if(Objects.nonNull(request.getYear())){
            //根据创建时间查询年的账单
            lambdaQueryWrapper.eq(CreditOrderBill::getYear, request.getYear());
        }
        if(Objects.nonNull(request.getMonth())){
            lambdaQueryWrapper.eq(CreditOrderBill::getMonth, request.getMonth());
        }
        if(Objects.nonNull(request.getCreditRepaymentFlag())){
            lambdaQueryWrapper.eq(CreditOrderBill::getCreditRepaymentFlag, request.getCreditRepaymentFlag());
        }
        if(Objects.nonNull(request.getOrderNo())){
            lambdaQueryWrapper.like(CreditOrderBill::getOrderNo, request.getOrderNo());
        }
        List<CreditOrderBill> list = this.dao.selectList(lambdaQueryWrapper);
        //统计待还款金额
        BigDecimal noAmount = list.stream().filter(e -> e.getCreditRepaymentFlag() == 0).map(CreditOrderBill::getPayPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
        //统计已还款金额
        BigDecimal paidAmount = list.stream().filter(e -> e.getCreditRepaymentFlag() == 1).map(CreditOrderBill::getPayPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
        reponse.setFinishTotal(paidAmount);
        reponse.setNoTotal(noAmount);
        reponse.setCreditOrderBillList(list);
        reponse.setContractStartDate(creditAmount.getContractStartDate());
        reponse.setContractEndDate(creditAmount.getContractEndDate());
        reponse.setSettle_term(creditAmount.getSettleTerm());
        return reponse;
    }

    @Override
    public OrderPayResultResponse menthPayment(CreditOrderBillRequest request) {
        OrderPayResultResponse response = new OrderPayResultResponse();
        response.setPayType(request.getPayType());
        response.setPayChannel(request.getPayChannel());
        User user = userService.getInfo();
        String orderNo = request.getOrderNo();
        CreditRepayOrder order = creditRepayOrderService.getByOrderNo(orderNo);
        order.setPayChannel(request.getPayChannel());
        order.setPayType(request.getPayType());
        if(Objects.nonNull(order)){
            Integer isPaid = order.getIsPaid();
            if(isPaid==1){
                throw new CrmebException("该订单已还款");
            }
        }
        // 余额支付
        if (request.getPayType().equals(PayConstants.PAY_TYPE_YUE)) {
            Boolean yueBoolean = yuePay(order, user);
            response.setStatus(yueBoolean);
            logger.info("余额还款 response : {}", JSON.toJSONString(response));
            return response;
        }
        // 微信支付,调用微信预下单,返回拉起微信支付需要的信息
        if (request.getPayType().equals(PayConstants.PAY_TYPE_WE_CHAT)) {
            //查询redis支付有支付订单
            WxPayJsResultVo  vo = wechatPayment(order);
            logger.info("还款信息 微信下单的商户订单号:{}",vo.getOutTradeNo());
            order.setOutTradeNo(vo.getOutTradeNo());
            creditRepayOrderService.updateById(order);
            response.setStatus(true);
            response.setJsConfig(vo);
            response.setOutTradeNo(vo.getOutTradeNo());
            logger.info("还款信息 微信下单 response :{}", JSON.toJSONString(response));
            return response;
        }
        response.setStatus(false);
        logger.info("还款信息 END response:{}", JSON.toJSONString(response));
        return response;
    }

    @Override
    public CreditOrderBill getByOrderNo(String orderNo) {
        CreditOrderBill orderBill = this.getOne(new LambdaQueryWrapper<CreditOrderBill>().eq(CreditOrderBill::getOrderNo, orderNo));
        return orderBill;
    }

    @Override
    public CreditAmountInfoReponse getUserAmountInfo(Integer uid) {
        //查询用户授信的基本信息
        CreditAmount creditAmount=creditAmountService.getByUserId(uid);
        if(Objects.nonNull(creditAmount)){
            CreditAmountInfoReponse creditAmountInfoReponse=new CreditAmountInfoReponse();
            BeanUtils.copyProperties(creditAmount,creditAmountInfoReponse);
            //查询用户的所有账单信息
            LambdaQueryWrapper<CreditOrderBill> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(CreditOrderBill::getUid,uid);
            //计算每个月需要还款的总金额是多少
            List<CreditOrderBillStaticReponse> list = this.dao.monthAmountInfo(uid);
            if(CollUtil.isNotEmpty(list)){
                creditAmountInfoReponse.setReponse(list);
            }
            return creditAmountInfoReponse;

        }

        return null;
    }

    @Override
    public CreditRepayOrder create(CreditOrderBillRequest request) {
        User user = userService.getInfo();
        CreditRepayOrder order= creditRepayOrderService.getByOrderNo(request.getOrderNo());
        String orderNo=  CrmebUtil.getOrderNo(PayConstants.PAY_TYPE_CREDIT_REPAYMENT);
        if(StringUtils.isNotEmpty(request.getOrderNo())){
            orderNo=request.getOrderNo();
        }
        if(Objects.isNull(order)){
            order=new CreditRepayOrder();
            order.setId(IdWorker.getIdStr());
        }
        order.setOrderNo(orderNo);
        order.setUid(user.getId());
        order.setPayType(request.getPayType());
        order.setPayChannel(request.getPayChannel());
        order.setPayPrice(request.getPayPrice());
        order.setIsPaid(0);
        order.setYear(request.getYear());
        order.setMonth(request.getMonth());
        order.setIsAll(request.getIsAll()==1?1:0);
        order.setCreateTime(DateUtil.date());
        order.setUpdateTime(DateUtil.date());
        creditRepayOrderService.saveOrUpdate(order);
        return order;
    }


    /**
     * 微信支付
     *
     * @param order 订单
     * @return WxPayJsResultVo
     */
    private WxPayJsResultVo wechatPayment(CreditRepayOrder order) {
        // 预下单
        Map<String, String> unifiedorder = unifiedorder(order);
        WxPayJsResultVo vo = new WxPayJsResultVo();
        vo.setAppId(unifiedorder.get("appId"));
        vo.setNonceStr(unifiedorder.get("nonceStr"));
        vo.setPackages(unifiedorder.get("package"));
        vo.setSignType(unifiedorder.get("signType"));
        vo.setTimeStamp(unifiedorder.get("timeStamp"));
        vo.setPaySign(unifiedorder.get("paySign"));
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_H5)) {
            vo.setMwebUrl(unifiedorder.get("mweb_url"));
        }
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_APP_IOS) ||
                order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID)) {// App
            vo.setPartnerid(unifiedorder.get("partnerid"));
        }
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_NATIVE)) {
            vo.setMwebUrl(unifiedorder.get("code_url"));
        }
        order.setOutTradeNo(unifiedorder.get("outTradeNo"));
        // 更新商户订单号
        vo.setOutTradeNo(unifiedorder.get("outTradeNo"));
        return vo;
    }

    /**
     * 预下单
     *
     * @param order 订单
     * @return 预下单返回对象
     */
    private Map<String, String> unifiedorder(CreditRepayOrder order) {
        // 获取用户openId
        // 根据订单支付类型来判断获取公众号openId还是小程序openId
        UserToken userToken = new UserToken();
        userToken.setToken("");
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_PUBLIC)) {// 公众号
            userToken = userTokenService.getTokenByUserId(order.getUid(), UserConstants.USER_TOKEN_TYPE_WECHAT);
        }
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_MINI)
                || order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_MINI_VIDEO)) {// 小程序
            userToken = userTokenService.getTokenByUserId(order.getUid(), UserConstants.USER_TOKEN_TYPE_ROUTINE);
        }

        // 获取appid、mch_id、微信签名key
        String appId = "";
        String mchId = "";
        String signKey = "";
        switch (order.getPayChannel()) {
            case PayConstants.PAY_CHANNEL_WECHAT_PUBLIC:
            case PayConstants.PAY_CHANNEL_H5:// H5使用公众号的信息
            case PayConstants.PAY_CHANNEL_WECHAT_NATIVE:// H5使用公众号的信息
                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PUBLIC_APPID);
                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_PUBLIC_MCHID);
                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_PUBLIC_KEY);
                break;
            case PayConstants.PAY_CHANNEL_WECHAT_MINI:
            case PayConstants.PAY_CHANNEL_WECHAT_MINI_VIDEO:
                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_MINI_APPID);
                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_MINI_MCHID);
                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_MINI_KEY);
                break;
            case PayConstants.PAY_CHANNEL_WECHAT_APP_IOS:
            case PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID:
                appId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_APP_APPID);
                mchId = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_APP_MCHID);
                signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_APP_KEY);
                break;
        }
        // 获取微信预下单对象
        CreateOrderRequestVo unifiedorderVo = getUnifiedorderVo(order, userToken.getToken(), appId, mchId, signKey);

        // 预下单(统一下单)
        CreateOrderResponseVo responseVo = wechatService.payUnifiedorder(unifiedorderVo);
        // 组装前端预下单参数
        Map<String, String> map = new HashMap<>();
        map.put("appId", unifiedorderVo.getAppid());
        map.put("nonceStr", unifiedorderVo.getAppid());
        map.put("package", "prepay_id=".concat(responseVo.getPrepayId()));
        map.put("signType", unifiedorderVo.getSign_type());
        Long currentTimestamp = WxPayUtil.getCurrentTimestamp();
        map.put("timeStamp", Long.toString(currentTimestamp));
        String paySign = WxPayUtil.getSign(map, signKey);
        map.put("paySign", paySign);
        map.put("prepayId", responseVo.getPrepayId());
        map.put("prepayTime", CrmebDateUtil.nowDateTimeStr());
        map.put("outTradeNo", unifiedorderVo.getOut_trade_no());
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_H5)) {
            map.put("mweb_url", responseVo.getMWebUrl());
        }
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_APP_IOS) ||
                order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID)) {// App
            map.put("partnerid", mchId);
            map.put("package", responseVo.getPrepayId());
            Map<String, Object> appMap = new HashMap<>();
            appMap.put("appid", unifiedorderVo.getAppid());
            appMap.put("partnerid", mchId);
            appMap.put("prepayid", responseVo.getPrepayId());
            appMap.put("package", "Sign=WXPay");
            appMap.put("noncestr", unifiedorderVo.getAppid());
            appMap.put("timestamp", currentTimestamp);
            logger.info("================================================app支付签名,map = " + appMap);
            String sign = WxPayUtil.getSignObject(appMap, signKey);
            logger.info("================================================app支付签名,sign = " + sign);
            map.put("paySign", sign);
        }
        if (order.getPayChannel().equals(PayConstants.PAY_CHANNEL_WECHAT_NATIVE)) {
            map.put("code_url", responseVo.getCodeUrl());
        }
        return map;
    }

    /**
     * 获取微信预下单对象
     *
     * @return 微信预下单对象
     */
    private CreateOrderRequestVo getUnifiedorderVo(CreditRepayOrder order, String openid, String appId, String mchId, String signKey) {
        // 获取域名
        String domain = systemConfigService.getValueByKeyException(SysConfigConstants.CONFIG_KEY_SITE_URL);
        String apiDomain = systemConfigService.getValueByKeyException(SysConfigConstants.CONFIG_KEY_API_URL);

        AttachVo attachVo = new AttachVo(PayConstants.PAY_SERVICE_TYPE_ORDER, order.getUid());

        CreateOrderRequestVo vo = new CreateOrderRequestVo();
        vo.setAppid(appId);
        vo.setMch_id(mchId);
        vo.setNonce_str(WxPayUtil.getNonceStr());
        vo.setSign_type(PayConstants.WX_PAY_SIGN_TYPE_MD5);
        String siteName = systemConfigService.getValueByKeyException(SysConfigConstants.CONFIG_KEY_SITE_NAME);
        // 因商品名称在微信侧超长更换为网站名称
        vo.setBody(siteName);
        vo.setAttach(JSONObject.toJSONString(attachVo));
        vo.setOut_trade_no(CrmebUtil.getOrderNo(OrderConstants.ORDER_PREFIX_WECHAT));
        // 订单中使用的是BigDecimal,这里要转为Integer类型
        vo.setTotal_fee(order.getPayPrice().multiply(BigDecimal.TEN).multiply(BigDecimal.TEN).intValue());
        vo.setSpbill_create_ip(RequestUtil.getClientIp());
        vo.setNotify_url(apiDomain + PayConstants.WX_PAY_NOTIFY_API_URI);
        switch (order.getPayChannel()) {
            case PayConstants.PAY_CHANNEL_H5:
                vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_H5);
                vo.setOpenid(null);
                break;
            case PayConstants.PAY_CHANNEL_WECHAT_APP_IOS:
            case PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID:
                vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_APP);
                vo.setOpenid(null);
                break;
            case PayConstants.PAY_CHANNEL_WECHAT_NATIVE:
                vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_NATIVE);
                vo.setProduct_id(order.getOrderNo());
                vo.setOpenid(null);
                break;
            default:
                vo.setTrade_type(PayConstants.WX_PAY_TRADE_TYPE_JS);
                vo.setOpenid(openid);
        }
        CreateOrderH5SceneInfoVo createOrderH5SceneInfoVo = new CreateOrderH5SceneInfoVo(
                new CreateOrderH5SceneInfoDetailVo(
                        domain,
                        systemConfigService.getValueByKeyException(SysConfigConstants.CONFIG_KEY_SITE_NAME)
                )
        );
        vo.setScene_info(JSONObject.toJSONString(createOrderH5SceneInfoVo));

        vo.setTime_start(DateUtil.date().toString(DateConstants.DATE_TIME_FORMAT_NUM));
        DateTime cancelTime = DateUtil.offset(order.getCreateTime(), DateField.MINUTE, crmebConfig.getOrderCancelTime());
        String cancelStr = cancelTime.toString(DateConstants.DATE_TIME_FORMAT_NUM);
        vo.setTime_expire(cancelStr);
        String sign = WxPayUtil.getSign(vo, signKey);
        vo.setSign(sign);
        return vo;
    }

    private Boolean yuePay(CreditRepayOrder order, User user) {
        // 用户余额扣除
        Boolean execute = transactionTemplate.execute(e -> {
            Boolean update = Boolean.TRUE;
            // 订单修改
            order.setIsPaid(1);
            order.setPayTime(DateUtil.date());
            order.setPayChannel(order.getPayChannel());
            order.setPayType(PayConstants.PAY_TYPE_YUE);
            order.setUpdateTime(DateUtil.date());
            creditRepayOrderService.updateById(order);
            // 这里只扣除金额,账单记录在task中处理
            if (order.getPayPrice().compareTo(BigDecimal.ZERO) > 0) {
                update = userService.updateNowMoney(user.getId(), order.getPayPrice(), Constants.OPERATION_TYPE_SUBTRACT);
                if (!update) {
                    logger.error("余额支付授信还款,扣除用户余额失败,orderNo = {}", order.getOrderNo());
                    e.setRollbackOnly();
                    return update;
                }
                update = creditAmountService.updateNowMoney(order.getUid(), order.getPayPrice(), Constants.OPERATION_TYPE_ADD);
                if (!update) {
                    logger.error("余额支付授信还款,剩余额度额度变动失败,orderNo = {}", order.getOrderNo());
                    e.setRollbackOnly();
                    return update;
                }
                update = creditAmountService.updateRemainMoney(order.getUid(), order.getPayPrice(), Constants.OPERATION_TYPE_SUBTRACT);
                if (!update) {
                    logger.error("余额支付授信还款, 授信已使用额度 已使用额度额度变动,orderNo = {}", order.getOrderNo());
                    e.setRollbackOnly();
                    return update;
                }
                update = creditAmountService.updateCreditRepaymentAmounty(order.getUid(), order.getPayPrice(), Constants.OPERATION_TYPE_ADD);
                if (!update) {
                    logger.error("余额支付授信还款,更新已还款额度,orderNo = {}", order.getOrderNo());
                    e.setRollbackOnly();
                    return update;
                }

                // 用户余额记录
                UserBalanceRecord userBalanceRecord = new UserBalanceRecord();
                userBalanceRecord.setUid(user.getId());
                userBalanceRecord.setLinkId(order.getOrderNo());
                userBalanceRecord.setLinkType(BalanceRecordConstants.BALANCE_RECORD_LINK_TYPE_ORDER);
                userBalanceRecord.setType(BalanceRecordConstants.BALANCE_RECORD_TYPE_SUB);
                userBalanceRecord.setAmount(order.getPayPrice());
                userBalanceRecord.setBalance(user.getNowMoney().subtract(order.getPayPrice()));
                userBalanceRecord.setRemark(StrUtil.format(BalanceRecordConstants.BALANCE_RECORD_REMARK_ORDER, order.getPayPrice()));
                userBalanceRecordService.save(userBalanceRecord);
            }
            // 授信账单
            Boolean b = updateCreditAmountAndCreditOrderBill(order, user.getId());
            if(!b) throw new CrmebException("余额还款订单失败");
            //用户授信流水
            if(!saveOrCreditBill(order,user))  throw new CrmebException("余额还款订单失败");
            if (!b) throw new CrmebException("余额还款订单失败");
            //查询是否存在超出还款时间待还款订单
            List<CreditOrderBill> list = creditOrderBillService.getCreditRepaymentFlag();
            if (CollUtil.isEmpty(list)) {
                creditAmountService.updateStatus();
            }
            return update;
        });
        if (!execute) throw new CrmebException("余额还款订单失败");
        // 平台分账返还
        Bill platBill = new Bill();
        platBill.setOrderNo(order.getOrderNo());
        platBill.setUid(order.getUid());
        platBill.setPm(BillConstants.BILL_PM_ADD);
        platBill.setAmount(order.getPayPrice());
        platBill.setType(BillConstants.BILL_TYPE_YUE_PAY_REFUND);
        platBill.setMark(StrUtil.format("余额还款,平台返还分账金额{}元", order.getPayPrice()));
        billService.save(platBill);
        //余额还款
        Bill yueBill = new Bill();
        yueBill.setOrderNo(order.getOrderNo());
        yueBill.setUid(order.getUid());
        yueBill.setPm(BillConstants.BILL_PM_ADD);
        yueBill.setAmount(order.getPayPrice());
        yueBill.setType(BillConstants.BILL_TYPE_YUE_PAY_REFUND);
        yueBill.setMark(StrUtil.format("用户余额减少金额{}元", order.getPayPrice()));
        billService.save(platBill);
        return true;
    }
    private boolean saveOrCreditBill(CreditRepayOrder order, User user){
        //创建授信流水
        return  creditBillInfoService.addRecord(order.getPayPrice(),user.getId(),1);
    }


    @Override
    public Boolean updateCreditAmountAndCreditOrderBill( CreditRepayOrder order,Integer uid) {
        //更新账单信息  判断是否为全部还款
        if(order.getIsAll()==1){
            //查询当年月份的账单 全部List<CreditOrderBill> creditOrderBillList =
            LambdaQueryWrapper<CreditOrderBill> lqw = new LambdaQueryWrapper<CreditOrderBill>();
            lqw.eq(CreditOrderBill::getUid, uid);
            lqw.eq(CreditOrderBill::getYear, order.getYear());
            lqw.eq(CreditOrderBill::getMonth, order.getMonth());
            lqw.eq(CreditOrderBill::getCreditRepaymentFlag, 0);
            List<CreditOrderBill> creditOrderBillList = this.list(lqw);
            if(CollUtil.isNotEmpty(creditOrderBillList)){
                for (CreditOrderBill creditOrderBill : creditOrderBillList) {
                    creditOrderBill.setCreditRepaymentFlag(1);
                    creditOrderBill.setPayType(order.getPayType());
                    creditOrderBill.setPayChannel(order.getPayChannel());
                    creditOrderBill.setOrderType(2);
                    creditOrderBill.setCreditRepaymentAmount(creditOrderBill.getPayPrice());
                    creditOrderBill.setCreditRepaymentTime(DateUtil.date());
                    this.updateById(creditOrderBill);
                }
            }
        }
        else{
            LambdaQueryWrapper<CreditOrderBill> lqw = new LambdaQueryWrapper<CreditOrderBill>();
            lqw.eq(CreditOrderBill::getUid, uid);
            lqw.eq(CreditOrderBill::getOrderNo, order.getOrderNo());
            lqw.eq(CreditOrderBill::getCreditRepaymentFlag, 0);
            CreditOrderBill creditOrderBill = this.getOne(lqw);
            if(Objects.nonNull(creditOrderBill)){
                logger.info("查询到的还款单:"+creditOrderBill.getOrderNo());
                creditOrderBill.setCreditRepaymentFlag(1);
                creditOrderBill.setOrderType(2);
                creditOrderBill.setPayType(order.getPayType());
                creditOrderBill.setPayChannel(order.getPayChannel());
                creditOrderBill.setCreditRepaymentAmount(creditOrderBill.getPayPrice());
                creditOrderBill.setCreditRepaymentTime(DateUtil.date());
                return this.updateById(creditOrderBill);
            }

        }
        return true;
    }

    @Override
    public List<CreditOrderBill> getNoStartTask() {
        LambdaQueryWrapper<CreditOrderBill> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(CreditOrderBill::getTaskStatus, 0);
        lambdaQueryWrapper.eq(CreditOrderBill::getCreditRepaymentFlag, 0);
//        //查询当前时间大于等于任务执行时间
        lambdaQueryWrapper.ge(CreditOrderBill::getTaskStartTime, DateUtil.date());
        return this.list(lambdaQueryWrapper);
    }

    @Override
    public void updateRefundStatus(String orderNo) {
        LambdaQueryWrapper<CreditOrderBill> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(CreditOrderBill::getOrderNo, orderNo);
        CreditOrderBill creditOrderBill = this.getOne(lambdaQueryWrapper);
        creditOrderBill.setCreditRepaymentFlag(1);
        this.updateById(creditOrderBill);
    }

    @Override
    public List<CreditOrderBill> getCreditRepaymentFlag() {
        LambdaQueryWrapper<CreditOrderBill> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(CreditOrderBill::getCreditRepaymentFlag, 0);
        //还款时间是否大于当前时间
        lambdaQueryWrapper.gt(CreditOrderBill::getTaskEndTime, DateUtil.date());
        return this.list(lambdaQueryWrapper);
    }

    @Override
    public boolean updateInfo(CreditOrderBillRequest creditOrderBillRequest) {
        CreditOrderBill creditOrderBill = this.getById(creditOrderBillRequest.getId());
        //判断creditOrderBillRequest.creditOrderBillRequest.getPayPrice()不能大于等于creditOrderBill.getPayPrice()
        if(creditOrderBillRequest.getPayPrice().compareTo(creditOrderBill.getPayPrice())==1){
            throw new CrmebException("还款金额不能大于订单金额");
        }
        //  creditOrderBillRequest.getPayPrice()减去creditOrderBill.getPayPrice()
        BigDecimal creditRepaymentAmount =creditOrderBill.getCreditRepaymentAmount().subtract(creditOrderBillRequest.getPayPrice());
        creditOrderBill.setPayPrice(creditOrderBillRequest.getPayPrice());
        creditOrderBill.setCreditRepaymentAmount(creditOrderBillRequest.getPayPrice());
        creditOrderBill.setIsUpdate(1);
        this.dao.updateById(creditOrderBill);
        //更新已使用额度
        CreditAmount creditAmount = creditAmountService.getByUserId(creditOrderBill.getUid());
        creditAmount.setCreditPayAmount(creditAmount.getCreditPayAmount().subtract(creditRepaymentAmount));
        //更新creditRemainAmount
        creditAmount.setCreditRemainAmount(creditAmount.getCreditRemainAmount().add(creditRepaymentAmount));
        creditAmountService.updateById(creditAmount);
        //生成一条流水详情
        CreditBillInfo billInfo = new CreditBillInfo();
        billInfo.setCreditPayAmount(creditRepaymentAmount);
        billInfo.setCreditRemainAmount(creditAmount.getCreditRemainAmount());
        billInfo.setUid(creditAmount.getUid());
        billInfo.setCreditType(5);
        billInfo.setCreateTime(DateUtil.date());
        billInfo.setUpdateTime(DateUtil.date());
        billInfo.setId(IdWorker.getIdStr());
        creditBillInfoService.save(billInfo);
        //生成修改记录
        CreditOrderBillRecord record=new CreditOrderBillRecord();
        record.setBillId(creditOrderBill.getId());
        record.setOrderNo(creditOrderBill.getOrderNo());
        record.setPayPrice(creditOrderBillRequest.getPayPrice());
        record.setUid(creditOrderBill.getUid());
        SystemAdmin systemAdmin = SecurityUtil.getLoginUserVo().getUser();
        record.setCreateTime(DateUtil.date());
        record.setCreateUser(systemAdmin.getRealName());
        record.setRemark(creditOrderBillRequest.getRemark());
        record.setUpdateTime(DateUtil.date());
        record.setUpdateUser(systemAdmin.getRealName());
        record.setId(IdWorker.getIdStr());

        creditOrderBillRecordDao.insert(record);
        return true;
    }
}


4:实现花呗还款

package com.zbkj.front.controller.credit;

import com.zbkj.common.model.credit.CreditRepayOrder;
import com.zbkj.common.request.credit.CreditOrderBillRequest;
import com.zbkj.common.response.OrderPayResultResponse;
import com.zbkj.common.response.credit.CreditAmountInfoReponse;
import com.zbkj.common.response.credit.CreditOrderBillStaticReponse;
import com.zbkj.common.result.CommonResult;
import com.zbkj.service.service.credit.CreditOrderBillService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;

import java.util.List;


/**
 * 授信流水表 前端控制器
 */
@Slf4j
@RestController
@RequestMapping("api/front/credit/order/bill")
@Api(tags = "授信账单流水表") //配合swagger使用

public class CreditOrderBillController {

    @Autowired
    private CreditOrderBillService creditOrderBillService;

    @ApiOperation(value = "根据年月查看用户账单详情")
    @RequestMapping(value = "/month/amount/info", method = RequestMethod.GET)
    public CommonResult<CreditOrderBillStaticReponse> monthAmountInfo(CreditOrderBillRequest request) {
        return CommonResult.success(creditOrderBillService.monthAmountInfo(request));
    }
    @ApiOperation(value = "账单还款支付")
    @RequestMapping(value = "/month/amount/payment", method = RequestMethod.POST)
    public CommonResult<OrderPayResultResponse> menthPayment(@RequestBody CreditOrderBillRequest request) {
        return CommonResult.success(creditOrderBillService.menthPayment(request));
    }

    @ApiOperation(value = "还款创建订单号")
    @RequestMapping(value = "/month/amount/create/order", method = RequestMethod.POST)
    public CommonResult<CreditRepayOrder> create(@RequestBody CreditOrderBillRequest request) {
        return CommonResult.success(creditOrderBillService.create(request));
    }
     @ApiOperation(value = "根据当前用户查看账单详情")
    @RequestMapping(value = "/user/amount/info/{uid}", method = RequestMethod.GET)
    public CommonResult<CreditAmountInfoReponse> getUserAmountInfo(@PathVariable(value = "uid") Integer uid) {
        return CommonResult.success(creditOrderBillService.getUserAmountInfo(uid));
    }
}



package com.zbkj.service.service.credit;

import com.baomidou.mybatisplus.extension.service.IService;
import com.zbkj.common.model.credit.CreditRepayOrder;

import java.util.List;

/**
* @author dudianlong
* @description CreditRepayOrderService 接口
* @date 2024-11-21
*/
public interface CreditRepayOrderService extends IService<CreditRepayOrder> {

     CreditRepayOrder getByOrderNo(String orderNo);

    CreditRepayOrder getByOutTradeNo(String outTradeNo);

    String wechatPayCallback(String xmlInfo);
}
package com.zbkj.service.service.impl.credit;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zbkj.common.constants.*;
import com.zbkj.common.exception.CrmebException;
import com.zbkj.common.model.bill.Bill;
import com.zbkj.common.model.credit.*;
import com.zbkj.common.model.user.User;
import com.zbkj.common.model.wechat.WechatPayInfo;
import com.zbkj.common.utils.CrmebDateUtil;
import com.zbkj.common.utils.CrmebUtil;
import com.zbkj.common.utils.RedisUtil;
import com.zbkj.common.utils.WxPayUtil;
import com.zbkj.common.vo.AttachVo;
import com.zbkj.common.vo.WechatPayCallbackVo;
import com.zbkj.service.dao.credit.CreditRepayOrderDao;
import com.zbkj.service.service.*;
import com.zbkj.service.service.credit.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
* @author dudianlong
* @description CreditRepayOrderServiceImpl 接口实现
* @date 2024-11-21
*/
@Service
public class CreditRepayOrderServiceImpl extends ServiceImpl<CreditRepayOrderDao, CreditRepayOrder> implements CreditRepayOrderService {
    private static final Logger logger = LoggerFactory.getLogger(CreditRepayOrderServiceImpl.class);

    @Resource
    private CreditRepayOrderDao dao;
    @Autowired
    private WechatPayInfoService wechatPayInfoService;
    @Autowired
    private SystemConfigService systemConfigService;
    @Autowired
    private UserService userService;
    @Autowired
    private AsyncService asyncService;
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private CreditOrderBillService creditOrderBillService;
    @Autowired
    private CreditBillInfoService creditBillInfoService;
    @Autowired
    private CreditAmountService creditAmountService;
    @Autowired
    private BillService billService;


    @Override
    public CreditRepayOrder getByOrderNo(String orderNo) {
        LambdaQueryWrapper<CreditRepayOrder> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CreditRepayOrder::getOrderNo, orderNo);
       return dao.selectOne(queryWrapper);

    }

    @Override
    public CreditRepayOrder getByOutTradeNo(String outTradeNo) {
         LambdaQueryWrapper<CreditRepayOrder> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CreditRepayOrder::getOutTradeNo, outTradeNo);
       return dao.selectOne(queryWrapper);
    }

    @Override
    public String wechatPayCallback(String xmlInfo) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        if (StrUtil.isBlank(xmlInfo)) {
            sb.append("<return_code><![CDATA[FAIL]]></return_code>");
            sb.append("<return_msg><![CDATA[xmlInfo is blank]]></return_msg>");
            sb.append("</xml>");
            logger.error("wechat callback error : " + sb);
            return sb.toString();
        }

        try {
            HashMap<String, Object> map = WxPayUtil.processResponseXml(xmlInfo);
            // 通信是否成功
            String returnCode = (String) map.get("return_code");
            if (!returnCode.equals(Constants.SUCCESS)) {
                sb.append("<return_code><![CDATA[SUCCESS]]></return_code>");
                sb.append("<return_msg><![CDATA[OK]]></return_msg>");
                sb.append("</xml>");
                logger.error("wechat callback error : wx pay return code is fail returnMsg : " + map.get("return_msg"));
                return sb.toString();
            }
            // 交易是否成功
            String resultCode = (String) map.get("result_code");
            if (!resultCode.equals(Constants.SUCCESS)) {
                sb.append("<return_code><![CDATA[SUCCESS]]></return_code>");
                sb.append("<return_msg><![CDATA[OK]]></return_msg>");
                sb.append("</xml>");
                logger.error("wechat callback error : wx pay result code is fail");
                return sb.toString();
            }

            //解析xml
            WechatPayCallbackVo callbackVo = CrmebUtil.mapToObj(map, WechatPayCallbackVo.class);
            AttachVo attachVo = JSONObject.toJavaObject(JSONObject.parseObject(callbackVo.getAttach()), AttachVo.class);

            //判断openid
            User user = userService.getById(attachVo.getUserId());
            if (ObjectUtil.isNull(user)) {
                //用户信息错误
                throw new CrmebException("用户信息错误!");
            }

            //根据类型判断是订单或者充值
            if (!PayConstants.PAY_SERVICE_TYPE_ORDER.equals(attachVo.getType()) && !PayConstants.PAY_SERVICE_TYPE_RECHARGE.equals(attachVo.getType())
                    && !PayConstants.PAY_SERVICE_TYPE_SVIP.equals(attachVo.getType())) {
                logger.error("wechat pay err : 未知的支付类型==》" + callbackVo.getOutTradeNo());
                throw new CrmebException("未知的支付类型!");
            }
            // 订单
            if (PayConstants.PAY_SERVICE_TYPE_ORDER.equals(attachVo.getType())) {
                  CreditRepayOrder order = this.getByOutTradeNo(callbackVo.getOutTradeNo());
                if (ObjectUtil.isNull(order) || !order.getUid().equals(attachVo.getUserId())) {
                    logger.error("还款订单 wechat pay error : 还款订单订单信息不存在==》" + callbackVo.getOutTradeNo());
                    throw new CrmebException("wechat pay error : 还款订单订单信息不存在==》" + callbackVo.getOutTradeNo());
                }
                if (order.getIsPaid()==1) {
                    sb.append("<return_code><![CDATA[SUCCESS]]></return_code>");
                    sb.append("<return_msg><![CDATA[OK]]></return_msg>");
                    sb.append("</xml>");
                    return sb.toString();
                }

                String signKey = "";
                String payChannel = order.getPayChannel();
                if (payChannel.equals(PayConstants.PAY_CHANNEL_H5) || payChannel.equals(PayConstants.PAY_CHANNEL_WECHAT_NATIVE)) {
                    String source = systemConfigService.getValueByKey(SysConfigConstants.WECHAT_PAY_SOURCE_H5_PC);
                    if (StrUtil.isNotBlank(source) && source.equals(PayConstants.WECHAT_PAY_SOURCE_MINI)) {
                        payChannel = PayConstants.PAY_CHANNEL_WECHAT_MINI;
                    } else {
                        payChannel = PayConstants.PAY_CHANNEL_WECHAT_PUBLIC;
                    }
                }
                switch (payChannel) {
                    case PayConstants.PAY_CHANNEL_WECHAT_PUBLIC:
                        signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_PUBLIC_KEY);
                        break;
                    case PayConstants.PAY_CHANNEL_WECHAT_MINI:
                    case PayConstants.PAY_CHANNEL_WECHAT_MINI_VIDEO:
                        signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_MINI_KEY);
                        break;
                    case PayConstants.PAY_CHANNEL_WECHAT_APP_IOS:
                    case PayConstants.PAY_CHANNEL_WECHAT_APP_ANDROID:
                        signKey = systemConfigService.getValueByKeyException(WeChatConstants.WECHAT_PAY_APP_KEY);
                        break;
                }
                Map<String, String> stringMap = WxPayUtil.xmlToMap(xmlInfo);
                String sign = WxPayUtil.getSign(stringMap, signKey);
                if (!sign.equals(stringMap.get(PayConstants.FIELD_SIGN))) {
                    logger.error("wechat pay error : 微信订单回调验签失败 ==> {}", xmlInfo);
                    throw new CrmebException(StrUtil.format("wechat pay error : 微信订单回调验签失败 ==> {}", xmlInfo));
                }

                WechatPayInfo wechatPayInfo = wechatPayInfoService.getByNo(order.getOutTradeNo());
                if (ObjectUtil.isNull(wechatPayInfo)) {
                    logger.error("wechat pay error : 微信订单信息不存在==》" + callbackVo.getOutTradeNo());
                    throw new CrmebException("wechat pay error : 微信订单信息不存在==》" + callbackVo.getOutTradeNo());
                }
                wechatPayInfo.setIsSubscribe(callbackVo.getIsSubscribe());
                wechatPayInfo.setBankType(callbackVo.getBankType());
                wechatPayInfo.setCashFee(callbackVo.getCashFee());
                wechatPayInfo.setCouponFee(callbackVo.getCouponFee());
                wechatPayInfo.setTransactionId(callbackVo.getTransactionId());
                wechatPayInfo.setTimeEnd(callbackVo.getTimeEnd());

                // 添加支付成功redis队列
                Boolean execute = transactionTemplate.execute(e -> {
                    logger.error("微信还款。执行execute方法" + order.getOrderNo());
                    order.setIsPaid(1);
                    order.setPayTime(CrmebDateUtil.nowDateTime());
                    this.updateById(order);
                    wechatPayInfoService.updateById(wechatPayInfo);
                    //更新授信信息
                         Boolean  update = creditAmountService.updateNowMoney(order.getUid(), order.getPayPrice(), Constants.OPERATION_TYPE_ADD);
                        if (!update) {
                            logger.error("微信支付授信还款,剩余额度额度变动失败,orderNo = {}", order.getOrderNo());
                            e.setRollbackOnly();
                            return update;
                        }
                        update = creditAmountService.updateRemainMoney(order.getUid(), order.getPayPrice(), Constants.OPERATION_TYPE_SUBTRACT);
                        if (!update) {
                            logger.error("微信支付授信还款, 授信已使用额度 已使用额度额度变动,orderNo = {}", order.getOrderNo());
                            e.setRollbackOnly();
                            return update;
                        }
                        update = creditAmountService.updateCreditRepaymentAmounty(order.getUid(), order.getPayPrice(), Constants.OPERATION_TYPE_ADD);
                        if (!update) {
                            logger.error("微信支付授信还款,更新已还款额度,orderNo = {}", order.getOrderNo());
                            e.setRollbackOnly();
                            return update;
                        }
                    creditOrderBillService.updateCreditAmountAndCreditOrderBill(order,order.getUid());
                    if(!saveOrCreditBill(order,user))  throw new CrmebException("微信还款订单失败");
                    //查询是否存在超出还款时间待还款订单
                    List<CreditOrderBill> list = creditOrderBillService.getCreditRepaymentFlag();
                    if (CollUtil.isEmpty(list)) {
                        creditAmountService.updateStatus();
                    }
                    // 平台分账返还
                    Bill platBill = new Bill();
                    platBill.setOrderNo(order.getOrderNo());
                    platBill.setUid(order.getUid());
                    platBill.setPm(BillConstants.BILL_PM_ADD);
                    platBill.setAmount(order.getPayPrice());
                    platBill.setType(BillConstants.BILL_TYPE_WEIXIN_PAY_REFUND);
                    platBill.setMark(StrUtil.format("微信还款,平台返还分账金额{}元", order.getPayPrice()));
                    billService.save(platBill);
                    return Boolean.TRUE;
                });
                if (!execute) {
                    logger.error("wechat pay error : 订单更新失败==》" + callbackVo.getOutTradeNo());
                    sb.append("<return_code><![CDATA[SUCCESS]]></return_code>");
                    sb.append("<return_msg><![CDATA[OK]]></return_msg>");
                    sb.append("</xml>");
                    return sb.toString();
                }
                asyncService.orderPaySuccessSplit(order.getOrderNo());
//                redisUtil.lPush(TaskConstants.ORDER_TASK_PAY_SUCCESS_AFTER, order.getOrderNo());
            }
            sb.append("<return_code><![CDATA[SUCCESS]]></return_code>");
            sb.append("<return_msg><![CDATA[OK]]></return_msg>");
        } catch (Exception e) {
            sb.append("<return_code><![CDATA[FAIL]]></return_code>");
            sb.append("<return_msg><![CDATA[").append(e.getMessage()).append("]]></return_msg>");
            logger.error("wechat pay error : 业务异常==》" + e.getMessage());
        }
        sb.append("</xml>");
        return sb.toString();
    }
    private boolean saveOrCreditBill(CreditRepayOrder order, User user){
      return  creditBillInfoService.addRecord(order.getPayPrice(),user.getId(),1);
    }



}

这样就实现啦花呗支付,使用微信还款,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

典龙330

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值