luodangjia
2024-11-05 0c569ab4b38d972213eeaf7e8965f33f8ec650fd
ruoyi-service/ruoyi-admin/src/main/java/com/ruoyi/admin/controller/FranchiseeController.java
@@ -1,29 +1,69 @@
package com.ruoyi.admin.controller;
import cn.hutool.http.HttpException;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alipay.api.AlipayApiException;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.admin.config.WeChatConfig;
import com.ruoyi.admin.entity.*;
import com.ruoyi.admin.service.*;
import com.ruoyi.admin.utils.MD5AndKL;
import com.ruoyi.admin.utils.WeChatUtil;
import com.ruoyi.admin.vo.InfoDto;
import com.ruoyi.admin.vo.MoneyRecentQuery;
import com.ruoyi.admin.vo.RencentBalance;
import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.exception.GlobalException;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.security.annotation.RequiresPermissions;
import com.ruoyi.common.security.service.TokenService;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.service.partnerpayments.app.model.Transaction;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com. wechat. pay. java. service. payments. jsapi. model. PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.Getter;
import org.apache.commons.codec.CharEncoding;
import org.apache.poi.util.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
 * <p>
@@ -50,6 +90,338 @@
    private MasterWorkerService masterWorkerService;
    @Resource
    private SiteService siteService;
    @Resource
    private JsapiService jsapiService;
    @Resource
    private WeChatConfig weChatConfig;
    @Resource
    private PrivateKeySigner privateKeySigner;
    @Resource
    private TFranchiseeBalanceChangeService balanceChangeService;
    private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final Random RANDOM = new SecureRandom();
    @ApiOperation(value = "加盟商列表余额", tags = {"后台2.0-加盟商列表余额"})
    @PostMapping(value = "/recent/money")
    public R<RencentBalance> recentmoney() {
        BigDecimal balance = new BigDecimal(0);
        List<Franchisee> list = franchiseeService.lambdaQuery().list();
        for (Franchisee franchisee : list) {
            balance = balance.add(franchisee.getBalance());
        }
        //充值的金额
        BigDecimal balance1 = new BigDecimal(0);
        List<TFranchiseeBalanceChange> list1 = balanceChangeService.lambdaQuery().eq(TFranchiseeBalanceChange::getType, 1).list();
        for (TFranchiseeBalanceChange franchiseeBalanceChange : list1) {
            balance1 = balance1.add(franchiseeBalanceChange.getAmount());
        }
        //扣除的金额
        BigDecimal balance2 = new BigDecimal(0);
        List<TFranchiseeBalanceChange> list2 = balanceChangeService.lambdaQuery().eq(TFranchiseeBalanceChange::getType, 2).list();
        for (TFranchiseeBalanceChange franchiseeBalanceChange : list1) {
            balance2 = balance2.add(franchiseeBalanceChange.getAmount());
        }
        RencentBalance balance3 = new RencentBalance();
        balance3.setBalance1(balance);
        balance3.setBalance2(balance1);
        balance3.setBalance3(balance2);
        return R.ok(balance3);
    }
    @ApiOperation(value = "扣款记录及充值记录", tags = {"后台2.0-统一充值扣款列表","师傅段2.0-统一充值扣款列表"})
    @PostMapping(value = "/recent/money/list")
    public R<Page<TFranchiseeBalanceChange>> recentmoneylist(@RequestBody MoneyRecentQuery moneyRecentQuery) {
        Page<TFranchiseeBalanceChange> page = balanceChangeService.lambdaQuery().eq(moneyRecentQuery.getType() != null, TFranchiseeBalanceChange::getType, moneyRecentQuery.getType())
                .eq(moneyRecentQuery.getFranchId() != null, TFranchiseeBalanceChange::getFranchiseeId, moneyRecentQuery.getFranchId())
                .eq(moneyRecentQuery.getFranchName() != null && !"".equals(moneyRecentQuery.getFranchName()), TFranchiseeBalanceChange::getFranchiseeName, moneyRecentQuery.getFranchName())
                .ge(moneyRecentQuery.getDate1() != null, TFranchiseeBalanceChange::getCreateTime, moneyRecentQuery.getDate1())
                .le(moneyRecentQuery.getDate2() != null, TFranchiseeBalanceChange::getCreateTime, moneyRecentQuery.getDate2())
                .page(Page.of(moneyRecentQuery.getPageNum(), moneyRecentQuery.getPageSize()));
        for (TFranchiseeBalanceChange record : page.getRecords()) {
            Franchisee franchisee = franchiseeService.getById(record.getFranchiseeId());
            String siteIds = franchisee.getSiteIds();
            String cityCode = franchisee.getCityCode();
            List<Region> list = regionService.lambdaQuery().in(Region::getCode, cityCode.split(",")).list();
            List<Site> list1 = siteService.lambdaQuery().in(Site::getId, siteIds.split(",")).list();
            record.setList(list);
            record.setList1(list1);
            record.setFranchiseeName(franchisee.getName());
        }
        return R.ok(page);
    }
    @ApiOperation(value = "导出", tags = {"后台2.0-统一充值扣款列表"})
    @PostMapping(value = "/recent/money/list/export")
    public R<Page<TFranchiseeBalanceChange>> export(@RequestBody MoneyRecentQuery moneyRecentQuery, HttpServletResponse response) {
        List<TFranchiseeBalanceChange> page = balanceChangeService.lambdaQuery().eq(moneyRecentQuery.getType() != null, TFranchiseeBalanceChange::getType, moneyRecentQuery.getType())
                .eq(moneyRecentQuery.getFranchId() != null, TFranchiseeBalanceChange::getFranchiseeId, moneyRecentQuery.getFranchId())
                .eq(moneyRecentQuery.getFranchName() != null && !"".equals(moneyRecentQuery.getFranchName()), TFranchiseeBalanceChange::getFranchiseeName, moneyRecentQuery.getFranchName())
                .ge(moneyRecentQuery.getDate1() != null, TFranchiseeBalanceChange::getCreateTime, moneyRecentQuery.getDate1())
                .le(moneyRecentQuery.getDate2() != null, TFranchiseeBalanceChange::getCreateTime, moneyRecentQuery.getDate2())
                .list();
        try {
            response.setCharacterEncoding(Constants.UTF8);
            response.setContentType("application/vnd.ms-excel");
            response.setHeader("Access-Control-Expose-Headers", "Content-disposition");
            response.setHeader("Content-Disposition", "attachment;filename=" +
                    URLEncoder.encode(Constants.EXCEL_ORDER_FILE_NAME, CharEncoding.UTF_8) + ".xlsx");
        } catch (UnsupportedEncodingException e) {
            return R.fail("excel导出失败!");
        }
        try {
            // excel模板封装
            ExcelWriterBuilder excelWriterBuilder = EasyExcelFactory.write(response.getOutputStream());
            InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream("template/" + Constants.EXCEL_ORDER_FILE_NAME1 + ".xlsx");
            // 自动释放资源
            try (ExcelWriter excelWriter = excelWriterBuilder.withTemplate(stream).build()) {
                WriteSheet writeSheet = EasyExcelFactory.writerSheet().build();
                excelWriter.fill(page, writeSheet);
                excelWriter.finish();
            } catch (Exception e) {
                return R.fail("excel导出失败!");
            }
        } catch (IOException e) {
            return R.fail("excel导出失败!");
        }
        return R.ok();
    }
    @ApiOperation(value = "扣余额", tags = {"后台2.0-加盟商列表余额"})
    @PostMapping(value = "/recent/money/consume")
    public R<Page<TFranchiseeBalanceChange>> consume(@RequestBody TFranchiseeBalanceChange franchiseeBalanceChange) {
        Franchisee byId = franchiseeService.getById(franchiseeBalanceChange.getFranchiseeId());
        franchiseeBalanceChange.setFranchiseeName(byId.getName());
        balanceChangeService.save(franchiseeBalanceChange);
        byId.setBalance(byId.getBalance().subtract(franchiseeBalanceChange.getAmount()));
        franchiseeService.updateById(byId);
        return R.ok();
    }
    @Getter
    private PrivateKey privateKey;
    @ApiOperation(value = "js支付", tags = {"2.0-支付"})
    @GetMapping(value = "/js/wxPay")
    public R jsPay(@RequestParam String openId,@RequestParam BigDecimal money,@RequestParam Integer userId) {
        SysUser byId1 = sysUserService.getById(userId);
        this.privateKey = PemUtil.loadPrivateKey(getPrivateKeyStream());
        this.privateKeySigner = new PrivateKeySigner(weChatConfig.merchantSerialNumber, privateKey);
        String code = generateTradeNumber();
        int i = money.multiply(BigDecimal.valueOf(100)).intValue();
        Franchisee byId = franchiseeService.getById(byId1.getFranchiseeId());
        PrepayRequest prepayRequest = new PrepayRequest();
        prepayRequest.setAppid(weChatConfig.appId);
        prepayRequest.setMchid(weChatConfig.merchantId);
        prepayRequest.setDescription("加盟商充值");
        prepayRequest.setOutTradeNo(code);
        prepayRequest.setNotifyUrl("http://www.zhipingwang.com.cn:9090/admin/franchisee/callBack");
        Amount amount = new Amount();
        amount.setTotal(i);
        prepayRequest.setAmount(amount);
        Payer payer = new Payer();
        payer.setOpenid(openId);
        prepayRequest.setPayer(payer);
        PrepayResponse prepay = jsapiService.prepay(prepayRequest);
        String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
        String packageStr = "prepay_id=" + prepay.getPrepayId();
        String prepay_id = prepay.getPrepayId();
        //重新进行签名后返回给前端
        Map<String, Object> map2 = new HashMap<>();
        map2.put("appid", weChatConfig.getAppId());
        map2.put("noncestr", code);
        map2.put("package", "Sign=WXPay");
        map2.put("partnerid", weChatConfig.getMerchantId());
        map2.put("prepayid", prepay_id);
        map2.put("timestamp", timeStamp);
//        String s1 = this.weixinSignature(map2);
        String signStr = Stream.of(weChatConfig.getAppId(), timeStamp, code, packageStr).collect(Collectors.joining("\n", "", "\n"));
        String packageSign = privateKeySigner.sign(signStr.getBytes(StandardCharsets.UTF_8)).getSign();
        map2.put("sign", packageSign);
        System.err.println(map2);
        TFranchiseeBalanceChange tFranchiseeBalanceChange = new TFranchiseeBalanceChange();
        tFranchiseeBalanceChange.setAmount(money);
        tFranchiseeBalanceChange.setIs_pay(0);
        tFranchiseeBalanceChange.setFranchiseeName(byId.getName());
        tFranchiseeBalanceChange.setFranchiseeId(String.valueOf(byId.getId()));
        tFranchiseeBalanceChange.setType(2);
        tFranchiseeBalanceChange.setCode(code);
        balanceChangeService.save(tFranchiseeBalanceChange);
        return R.ok(map2);
    }
    public InputStream getPrivateKeyStream() {
        // 需要证书释放
        byte[] certData;
//        InputStream certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(this.privateKeyPath);
        InputStream certStream = null;
        try {
            certStream = new FileInputStream(weChatConfig.privateKeyPath);
            certData = IOUtils.toByteArray(certStream);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("私钥文件未找到");
        }finally {
            if(null != certStream){
                try {
                    certStream.close();
                } catch (IOException e) {
                }
            }
        }
        return new ByteArrayInputStream(certData);
    }
    @Resource
    private TokenService tokenService;
    @Resource
    private NativePayService nativePayService;
    @ApiOperation(value = "扫码支付",tags = {"后台2.0-加盟商列表余额"})
    @PostMapping(value = "/code/buy")
    public R buy(@RequestParam BigDecimal money) throws AlipayApiException {
        Long userid = tokenService.getLoginUser().getUserid();
        SysUser byId1 = sysUserService.getById(userid);
        Franchisee byId = franchiseeService.getById(byId1.getFranchiseeId());
        String code = generateTradeNumber();
        int i = money.multiply(BigDecimal.valueOf(100)).intValue();
        com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest prepayRequest = new com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest();
            prepayRequest.setAppid(weChatConfig.appId);
            prepayRequest.setMchid(weChatConfig.merchantId);
            prepayRequest.setOutTradeNo(code);
            prepayRequest.setDescription("购买资料");
            prepayRequest.setNotifyUrl("http://www.zhipingwang.com.cn:9090/admin/franchisee/callBack");
            com.wechat.pay.java.service.payments.nativepay.model.Amount amount = new com.wechat.pay.java.service.payments.nativepay.model.Amount();
            amount.setTotal(i);
            prepayRequest.setAmount(amount);
            // 调用下单方法,得到应答
            com.wechat.pay.java.service.partnerpayments.app.model.PrepayResponse response;
            try {
                com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse prepay = nativePayService.prepay(prepayRequest);
                //预支付成功,创建预支付订单
                TFranchiseeBalanceChange tFranchiseeBalanceChange = new TFranchiseeBalanceChange();
                tFranchiseeBalanceChange.setAmount(money);
                tFranchiseeBalanceChange.setIs_pay(0);
                tFranchiseeBalanceChange.setFranchiseeName(byId.getName());
                tFranchiseeBalanceChange.setFranchiseeId(String.valueOf(userid));
                tFranchiseeBalanceChange.setType(2);
                tFranchiseeBalanceChange.setCode(code);
                balanceChangeService.save(tFranchiseeBalanceChange);
                return R.ok(prepay.getCodeUrl());
            } catch (HttpException e) { // 发送HTTP请求失败
//                log.error("发送HTTP请求失败: {}", e.getHttpRequest());
            } catch (ServiceException e) { // 服务返回状态小于200或大于等于300,例如500
//                log.error("服务返回状态异常: {}", e.getResponseBody());
            } catch (MalformedMessageException e) { // 服务返回成功,返回体类型不合法,或者解析返回体失败
//                log.error("返回体类型不合法: {}", e.getMessage());
            } catch (Exception e) {
//                log.error("预下单异常: {}", e.getMessage());
            }
            return null;
    }
    @Resource
    private NotificationParser notificationParser;
    @ApiOperation(value = "支付回调",tags = {"微信支付回调"})
    @RequestMapping (value = "/callBack")
    @Transactional
    public R payNotify(HttpServletRequest request) throws Exception{
        System.err.println("======回调开始");
        Transaction transaction;
        transaction = notificationParser.parse(WeChatUtil.handleNodifyRequestParam(request), Transaction.class);
        if (transaction.getTradeState() == Transaction.TradeStateEnum.SUCCESS) {
            //将记录变为已支付
            TFranchiseeBalanceChange one = balanceChangeService.lambdaQuery().eq(TFranchiseeBalanceChange::getCode, transaction.getOutTradeNo()).one();
            if (one.getIs_pay()==0) {
                //将加盟商的余额增加
                Franchisee byId = franchiseeService.getById(one.getFranchiseeId());
                byId.setBalance(byId.getBalance().add(one.getAmount()));
                franchiseeService.updateById(byId);
                one.setIs_pay(1);
                balanceChangeService.updateById(one);
            }
        }
        return R.ok(null,"SUCCESS");
    }
    public static String generateTradeNumber() {
        // 定义订单号前缀
        // 当前年月日
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String currentTimeStr =now.format(formatter);
        // 获取当前时间戳
        long timestamp = System.currentTimeMillis();
        // 构造订单号
        return currentTimeStr + timestamp;
    }
    private String weixinSignature(Map<String, Object> map){
        try {
            Set<Map.Entry<String, Object>> entries = map.entrySet();
            List<Map.Entry<String, Object>> infoIds = new ArrayList<Map.Entry<String, Object>>(entries);
            // 对所有传入参数按照字段名的 ASCII 码从小到大排序(字典序)
            Collections.sort(infoIds, new Comparator<Map.Entry<String, Object>>() {
                public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
                    return (o1.getKey()).toString().compareTo(o2.getKey());
                }
            });
            // 构造签名键值对的格式
            StringBuilder sb = new StringBuilder();
            for (Map.Entry<String, Object> item : infoIds) {
                if (item.getKey() != null || item.getKey() != "") {
                    String key = item.getKey();
                    Object val = item.getValue();
                    if (!(val == "" || val == null)) {
                        sb.append(key + "=" + val + "&");
                    }
                }
            }
            sb.append("key=" + "TA2npSNWmS0GcB0tFFRWA94rm1M0iSFs");
            String sign = MD5AndKL.MD5Encode(sb.toString(), "UTF-8").toUpperCase(); //注:MD5签名方式
            return sign;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    public static String generateNonceStr() {
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }
    /**
     * 加盟商信息分页列表
@@ -103,8 +475,13 @@
            @ApiImplicitParam(value = "加盟商信息id", name = "id", dataType = "Integer", required = true)
    })
    public R<Franchisee> detail(@RequestParam("id") Integer id) {
        return R.ok(franchiseeService.lambdaQuery()
                .eq(Franchisee::getId, id).eq(Franchisee::getIsDelete, 0).one());
        Franchisee one = franchiseeService.lambdaQuery()
                .eq(Franchisee::getId, id).eq(Franchisee::getIsDelete, 0).one();
        List<Site> list = siteService.lambdaQuery().in(Site::getId, one.getSiteIds().split(",")).list();
        //用 , 拼接
        one.setSiteStr(list.stream().map(Site::getSiteName).collect(Collectors.joining(",")));
        return R.ok(one);
    }
    /**
@@ -121,6 +498,53 @@
        return R.ok(Arrays.stream(franchisee.getCityCode().split(",")).collect(Collectors.toList()));
    }
    @ApiOperation(value = "主页信息", tags = {"2.0师傅端"})
    @GetMapping(value = "/info")
    public R<InfoDto> info() {
        Long userid = tokenService.getLoginUser().getUserid();
        SysUser byId = sysUserService.getById(userid);
        Franchisee franchisee = franchiseeService.lambdaQuery()
                .eq(Franchisee::getId, byId.getFranchiseeId()).eq(Franchisee::getIsDelete, 0).one();
        String siteIds = franchisee.getSiteIds();
        String cityCode = franchisee.getCityCode();
        List<Region> list = regionService.lambdaQuery().in(Region::getCode, cityCode.split(",")).list();
        List<Site> list1 = siteService.lambdaQuery().in(Site::getId, siteIds.split(",")).list();
        InfoDto infoDto = new InfoDto();
        infoDto.setList(list);
        infoDto.setList1(list1);
        infoDto.setFranchisee(franchisee);
        return R.ok(infoDto);
    }
    @ApiOperation(value = "主页信息", tags = {"2.0师傅端"})
    @GetMapping(value = "/info1")
    public R<InfoDto> info1(Integer id) {
        Franchisee franchisee = franchiseeService.lambdaQuery()
                .eq(Franchisee::getId, id).eq(Franchisee::getIsDelete, 0).one();
        String siteIds = franchisee.getSiteIds();
        String cityCode = franchisee.getCityCode();
        List<Region> list = regionService.lambdaQuery().in(Region::getCode, cityCode.split(",")).list();
        List<Site> list1 = siteService.lambdaQuery().in(Site::getId, siteIds.split(",")).list();
        InfoDto infoDto = new InfoDto();
        infoDto.setList(list);
        infoDto.setList1(list1);
        infoDto.setFranchisee(franchisee);
        return R.ok(infoDto);
    }
    @ApiOperation(value = "当前余额", tags = {"后台2.0-加盟商列表余额"})
    @GetMapping(value = "/rencentBalance")
    public R<Franchisee> rencentBalance() {
        Long userid = tokenService.getLoginUser().getUserid();
        SysUser byId = sysUserService.getById(userid);
        Franchisee franchisee = franchiseeService.lambdaQuery()
                .eq(Franchisee::getId, byId.getFranchiseeId()).eq(Franchisee::getIsDelete, 0).one();
        return R.ok(franchisee);
    }
    @GetMapping(value = "/getWorkPic")
    public R<String> getWorkPic(@RequestParam("id") Integer id) {
        MasterWorker byId = masterWorkerService.getById(id);