Przeglądaj źródła

移植支付功能

mingfu 1 tydzień temu
rodzic
commit
2d771d04f2
21 zmienionych plików z 2246 dodań i 0 usunięć
  1. 11 0
      ie-admin/pom.xml
  2. 404 0
      ie-admin/src/main/java/com/ruoyi/web/controller/front/FrontECardController.java
  3. 12 0
      ie-admin/src/main/java/com/ruoyi/web/controller/front/FrontPracticeController.java
  4. 44 0
      ie-admin/src/main/java/com/ruoyi/web/core/config/WxPayConfiguration.java
  5. 41 0
      ie-admin/src/main/java/com/ruoyi/web/core/config/WxPayProperties.java
  6. 408 0
      ie-admin/src/main/java/com/ruoyi/web/service/WeixinPayService.java
  7. 61 0
      ie-common/src/main/java/com/ruoyi/common/enums/ECardPayStatus.java
  8. 1 0
      ie-system/src/main/java/com/ruoyi/dz/mapper/DzCardsMapper.java
  9. 2 0
      ie-system/src/main/java/com/ruoyi/dz/service/IDzCardsService.java
  10. 6 0
      ie-system/src/main/java/com/ruoyi/dz/service/impl/DzCardsServiceImpl.java
  11. 108 0
      ie-system/src/main/java/com/ruoyi/voluntary/domain/BBusiEcardPrice.java
  12. 406 0
      ie-system/src/main/java/com/ruoyi/voluntary/domain/BBusiPaymentOrders.java
  13. 62 0
      ie-system/src/main/java/com/ruoyi/voluntary/mapper/BBusiEcardPriceMapper.java
  14. 64 0
      ie-system/src/main/java/com/ruoyi/voluntary/mapper/BBusiPaymentOrdersMapper.java
  15. 63 0
      ie-system/src/main/java/com/ruoyi/voluntary/service/IBBusiEcardPriceService.java
  16. 65 0
      ie-system/src/main/java/com/ruoyi/voluntary/service/IBBusiPaymentOrdersService.java
  17. 94 0
      ie-system/src/main/java/com/ruoyi/voluntary/service/impl/BBusiEcardPriceServiceImpl.java
  18. 122 0
      ie-system/src/main/java/com/ruoyi/voluntary/service/impl/BBusiPaymentOrdersServiceImpl.java
  19. 4 0
      ie-system/src/main/resources/mapper/dz/DzCardsMapper.xml
  20. 76 0
      ie-system/src/main/resources/mapper/voluntary/BBusiEcardPriceMapper.xml
  21. 192 0
      ie-system/src/main/resources/mapper/voluntary/BBusiPaymentOrdersMapper.xml

+ 11 - 0
ie-admin/pom.xml

@@ -16,6 +16,17 @@
     </description>
 
     <dependencies>
+        <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>weixin-java-pay</artifactId>
+            <version>4.6.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.wechatpay-apiv3</groupId>
+            <artifactId>wechatpay-java</artifactId>
+            <version>0.2.12</version>
+        </dependency>
+
         <dependency>
             <groupId>com.vladsch.flexmark</groupId>
             <artifactId>flexmark-all</artifactId>

+ 404 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/front/FrontECardController.java

@@ -0,0 +1,404 @@
+package com.ruoyi.web.controller.front;
+
+import com.alibaba.fastjson.JSONObject;
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
+import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryV3Result;
+import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.enums.ECardPayStatus;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.ip.IpUtils;
+import com.ruoyi.common.utils.uuid.IdUtils;
+import com.ruoyi.system.service.ISysConfigService;
+import com.ruoyi.system.service.ShortMessageService;
+import com.ruoyi.voluntary.domain.BBusiEcardPrice;
+import com.ruoyi.voluntary.domain.BBusiPaymentOrders;
+import com.ruoyi.voluntary.service.IBBusiEcardPriceService;
+import com.ruoyi.voluntary.service.IBBusiPaymentOrdersService;
+import com.ruoyi.web.service.WeixinPayService;
+import com.ruoyi.web.util.IosVerifyUtil;
+import eu.bitwalker.useragentutils.UserAgent;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.Operation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.*;
+
+@Api(tags = "前端 电子卡业务")
+@RestController
+@RequestMapping("front/ecard")
+@Slf4j
+public class FrontECardController extends BaseController {
+
+    @Autowired
+    private IBBusiEcardPriceService ecardPriceService;
+    @Autowired
+    private IBBusiPaymentOrdersService paymentOrdersService;
+    @Autowired
+    private ShortMessageService shortMessageService;
+    @Autowired
+    private WeixinPayService weixinPayService;
+    @Autowired
+    private WxPayService wxService;
+    @Autowired
+    private ISysConfigService sysConfigService;
+
+    private static final String SUCCESS = "SUCCESS";
+    private static final String cardDesc = "在线购卡";
+    public static final String description = "VIP会员";
+
+//    @Value("${wxpay.pay.callback}")
+//    private String payCallback;
+    @Value("${wxpay.mchid}")
+    private String mchId;
+    @Value("${wxpay.key}")
+    private String mchKey;
+//    @Value("${wxpay.appid}")
+//    private String appId = WxMaConfiguration.getAppId();
+
+    public String getMchKey() {
+        return this.mchKey;
+    }
+
+    /**
+     * {
+     "amount": {
+     "currency": "CNY",
+     "payer_currency": "CNY",
+     "payer_total": 1,
+     "total": 1
+     },
+     "appid": "wx7b9ff116a897456a",
+     "attach": "",
+     "bank_type": "OTHERS",
+     "mchid": "1629698256",
+     "out_trade_no": "test_order_t1",
+     "payer": {
+     "openid": "o8uY95w2o4T-xq6e8tjKTDRr2tFg"
+     },
+     "promotion_detail": [],
+     "success_time": "2022-08-23T23:55:35+08:00",
+     "trade_state": "SUCCESS",
+     "trade_state_desc": "支付成功",
+     "trade_type": "NATIVE",
+     "transaction_id": "4200001565202208236598567532"
+     }
+     * @return
+     */
+
+    @ApiOperation(value = "5 重新生成二维码")
+    @GetMapping("/regenerateQrCode")
+    public AjaxResult regenerateQrCode(@RequestParam Long orderId) {
+        BBusiPaymentOrders order = paymentOrdersService.selectBBusiPaymentOrdersById(orderId);
+
+        String codeUrl = StringUtils.EMPTY;
+        if(StringUtils.isBlank(order.getQrcodeId())){
+            try {
+                codeUrl = weixinPayService.createOrderPayUrl(order.getPhonenumber()+"_"+orderId, order.getPayFee(), "单招"+cardDesc, null);
+                order.setQrcodeId(codeUrl);
+                paymentOrdersService.updateBBusiPaymentOrders(order);
+            } catch (Exception e) {
+                weixinPayService.processWxPayFail(orderId, null, e.getMessage());
+                logger.error("QrCodeId: ", e);
+            }
+        }else {
+            codeUrl = order.getQrcodeId();
+        }
+
+        String qrCode = weixinPayService.encodeQrCode(codeUrl);
+        JSONObject result = new JSONObject();
+        result.put("qrCode",qrCode);
+        result.put("orderId",orderId);
+        result.put("isPaySuccess",ECardPayStatus.isSuccess(order.getStatus()));
+
+        return AjaxResult.success(result);
+    }
+
+    @ApiOperation(value = "4 获取订单状态")
+    @GetMapping("/getOrderPayStatus")
+    public AjaxResult getOrderPayStatus(@RequestParam Long orderId) {
+        BBusiPaymentOrders order = paymentOrdersService.selectBBusiPaymentOrdersById(orderId);
+        JSONObject result = new JSONObject();
+        result.put("isPaySuccess",ECardPayStatus.isSuccess(order.getStatus()));
+        result.put("isPayFailed",ECardPayStatus.isFaild(order.getStatus()));
+        result.put("isUnPaid",ECardPayStatus.isUnPaid(order.getStatus()));
+        return AjaxResult.success(result);
+    }
+
+    @Operation(summary = "查询订单")
+    @GetMapping("/queryOrder")
+    public WxPayOrderQueryV3Result queryOrder(@RequestParam(required = false) String transactionId,
+                                                   @RequestParam(required = false) String outTradeNo) throws Exception {
+        WxPayOrderQueryV3Result result = wxService.queryOrderV3(transactionId, outTradeNo);
+        if("NOTPAY".equals(result.getTradeState())) {
+            Integer timeout = NumberUtils.toInt(sysConfigService.selectConfigByKey("pay.order.timeout"), 60);
+            Date timeoutDate = DateUtils.addSeconds(new Date(), -timeout);
+            BBusiPaymentOrders poCond = new BBusiPaymentOrders();
+            poCond.setOutTradeNo(outTradeNo);
+            poCond.setTransactionId(transactionId);
+            List<BBusiPaymentOrders> orders = paymentOrdersService.selectBBusiPaymentOrdersList(poCond);
+            if(CollectionUtils.isEmpty(orders) || orders.get(0).getCreateTime().before(timeoutDate)) {
+                result.setTradeState("CLOSED");
+                result.setTradeStateDesc("超时关闭");
+            }
+        }
+        return result;
+    }
+
+    @ApiOperation(value = "3 支付通知(回调)")
+    @PostMapping("/payResult")
+    public AjaxResult wxPayResult(HttpServletRequest request,
+                                  @RequestHeader("wechatpay-serial") String serial, @RequestHeader("wechatpay-signature-type") String signatureType,
+                                  @RequestHeader("wechatpay-timestamp") String timestamp, @RequestHeader("wechatpay-nonce") String nonce,
+                                  @RequestHeader("wechatpay-signature") String signature, @RequestBody String json) {
+        logger.error("----------------------开始处理微信支付回调--------------");
+        // String json = readBody(req);
+        try {
+            weixinPayService.processWxPayResult(serial, signatureType, timestamp, nonce, signature, json);
+        } catch (Exception e) {
+            logger.error("处理微信回调失败: " + signature + "\n" + json, e);
+            return AjaxResult.error("解析异常");
+        }
+        return AjaxResult.success();
+    }
+
+    @ApiOperation("02 测试支付")
+    @GetMapping(value = "checktest")
+    public AjaxResult checkTest() {
+        weixinPayService.checkWxPay();
+        return AjaxResult.success();
+    }
+
+    @ApiOperation("02 测试支付")
+    @GetMapping(value = "paytest")
+    public AjaxResult paytest(String id, Integer amount, @RequestParam(defaultValue = "false") boolean h5, HttpServletRequest request) {
+        try {
+            String os = UserAgent.parseUserAgentString(request.getHeader("User-Agent")).getOperatingSystem().getName();
+            String ip = IpUtils.getIpAddr(request);
+            WeixinPayService.PayOrderSceneInfo sceneInfo = h5 ? new WeixinPayService.PayOrderSceneInfo(ip, os) : null;
+            String codeUrl = weixinPayService.createOrderPayUrl("test_pay_" + id, amount, "Test" + id, sceneInfo);
+            return AjaxResult.success(weixinPayService.encodeQrCode(codeUrl));
+        } catch (Exception e) {
+            logger.error("QrCodeId: ", e);
+            return AjaxResult.error(e.getMessage());
+        }
+    }
+
+    @ApiOperation("02 下单生成地址")
+    @PostMapping(value = "createOrder")
+    public AjaxResult createOrder(HttpServletRequest request, Double totalFee, @RequestParam(required = false) String type) throws WxPayException {
+        if (null==totalFee){
+            AjaxResult.error("金额不能为空");
+        }
+        if(StringUtils.isBlank(type)) {
+            type = "h5";
+        }
+        SysUser u = SecurityUtils.getLoginUser().getUser();
+        Integer totalFee2 = (int)(totalFee * 100D);
+
+        BBusiPaymentOrders insertOrder = new BBusiPaymentOrders();
+        insertOrder.setCode(IdUtils.simpleUUID());
+        insertOrder.setType(cardDesc);
+//        insertOrder.setOutTime(ecardPrice.getOutTime());
+        int num = 1;
+        insertOrder.setNum(num);
+        insertOrder.setPrice(totalFee2);
+        insertOrder.setFee(totalFee2);
+        insertOrder.setTotalFee(totalFee2*num);
+        insertOrder.setPayFee(totalFee2*num);
+        insertOrder.setBody(cardDesc+"_"+description+"_" + type);
+        insertOrder.setPhonenumber(u.getPhonenumber());
+        insertOrder.setCustomerCode(String.valueOf(u.getUserId()));
+        insertOrder.setYear(String.valueOf(Calendar.getInstance().get(Calendar.YEAR)));
+        //状态(-2:已退费,-1:支付失败,0:无效,1:未支付,2:已支付)
+        insertOrder.setStatus(ECardPayStatus.unpaid.getValue());
+        insertOrder.setCreateTime(new Date());
+        paymentOrdersService.insertBBusiPaymentOrders(insertOrder);
+
+        Long orderId = insertOrder.getId();
+        if("ios".equals(type)) {
+            Map data = new HashMap<>();
+            data.put("orderId", String.valueOf(orderId));
+            return AjaxResult.success(data);
+        }
+        WxPayUnifiedOrderV3Request order = new WxPayUnifiedOrderV3Request();
+//        Integer totalFee = 1;
+        String notifyUrl = sysConfigService.selectConfigByKey("pay.callback.url") + "/front/ecard/payResult";
+        String outTradeNo = u.getPhonenumber() + "_" + orderId + "_" + u.getUserId() +"_"+System.currentTimeMillis();
+        if(outTradeNo.length() > 30) {
+            outTradeNo = outTradeNo.substring(0,20) + outTradeNo.substring(outTradeNo.length() - 10);
+        }
+        order.setDescription(description).setOutTradeNo(outTradeNo);
+
+        order.setNotifyUrl(notifyUrl).setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(totalFee2));
+
+        WxPayUnifiedOrderV3Request.SceneInfo sceneInfo = new WxPayUnifiedOrderV3Request.SceneInfo();
+        sceneInfo.setPayerClientIp(IpUtils.getIpAddr(request));
+        WxPayUnifiedOrderV3Request.H5Info h5Info = new WxPayUnifiedOrderV3Request.H5Info();
+        String os = UserAgent.parseUserAgentString(request.getHeader("User-Agent")).getOperatingSystem().getName();
+        h5Info.setType(os);
+        sceneInfo.setH5Info(h5Info);
+        order.setSceneInfo(sceneInfo);
+        String h5Url = wxService.createOrderV3(TradeTypeEnum.H5, order);
+        String prepayId = StringUtils.substringBetween(h5Url, "prepay_id=", "&package=");
+
+        BBusiPaymentOrders upOrder = new BBusiPaymentOrders();
+        upOrder.setPrepayId(prepayId);
+        upOrder.setDetail(h5Url);
+        upOrder.setOutTradeNo(outTradeNo);
+        upOrder.setId(orderId);
+        paymentOrdersService.updateBBusiPaymentOrders(upOrder);
+
+        Map data = new HashMap<>();
+        data.put("h5url", h5Url);
+        data.put("outTradeNo", outTradeNo);
+        return AjaxResult.success(data);
+    }
+
+    @ApiOperation("02 下单生成二维码")
+    @GetMapping(value = "prepayCard")
+    public AjaxResult prepayCard(Long ecardPayId, String mobile, String code) {
+        Pair<Long, String> pair = prepayCard(ecardPayId, mobile, code, null);
+        if(null == pair) {
+            return AjaxResult.error("验证码校验失败");
+        }
+        String qrCode = weixinPayService.encodeQrCode(pair.getRight());
+        JSONObject result = new JSONObject();
+        result.put("qrCode",qrCode);
+        result.put("orderId",pair.getLeft());
+        return AjaxResult.success(result);
+    }
+
+    private Pair<Long, String> prepayCard(Long ecardPayId, String mobile, String code, WeixinPayService.PayOrderSceneInfo sceneInfo) {
+        boolean isSuccess = shortMessageService.checkCode(mobile, code);
+        if(!isSuccess){
+            return null;
+        }
+        //生成订单
+        BBusiEcardPrice ecardPrice = ecardPriceService.selectBBusiEcardPriceById(ecardPayId);
+        //未支付订单,不要多次生成
+        BBusiPaymentOrders order= paymentOrdersService.selectBBusiPaymentOrdersNoPaid(mobile);
+        Boolean isInsert = false;
+        if(null==order){
+            order=new BBusiPaymentOrders();
+            isInsert = true;
+        }
+        order.setCode(IdUtils.simpleUUID());
+        order.setType(cardDesc);
+        //cardId在回调中处理
+//        order.setCardId(1L);
+//        order.setCardNo("");
+        order.setOutTime(ecardPrice.getOutTime());
+        int num = 1;
+        order.setNum(num);
+        order.setFee(ecardPrice.getPrice());
+        order.setTotalFee(ecardPrice.getPrice()*num);
+        order.setPayFee(ecardPrice.getPrice()*num);
+        order.setBody(cardDesc);
+        order.setPhonenumber(mobile);
+        order.setYear(String.valueOf(ecardPrice.getYear()));
+        //状态(-2:已退费,-1:支付失败,0:无效,1:未支付,2:已支付)
+        order.setStatus(ECardPayStatus.unpaid.getValue());
+        if(isInsert){
+            paymentOrdersService.insertBBusiPaymentOrders(order);
+        }else {
+            paymentOrdersService.updateBBusiPaymentOrders(order);
+        }
+        Long orderId = order.getId();
+
+        // TODO 调用微信支付生成二维码返回给前端
+        try {
+            String codeUrl = weixinPayService.createOrderPayUrl(mobile+"_"+orderId+"_"+System.currentTimeMillis(), order.getPayFee(), "金鲤志愿"+cardDesc, sceneInfo);
+            order.setQrcodeId(codeUrl);
+        } catch (Exception e) {
+            weixinPayService.processWxPayFail(orderId, null, e.getMessage());
+            logger.error("QrCodeId: ", e);
+        }
+        order.setPrepayId("");//预支付ID
+        order.setTransactionId("");//交易ID
+        paymentOrdersService.updateBBusiPaymentOrders(order);
+        return Pair.of(orderId, order.getQrcodeId());
+    }
+
+
+    @ApiOperation("01 获取电子卡价格")
+    @GetMapping(value = "getEcardPrices")
+    public AjaxResult getEcardPrices() {
+        BBusiEcardPrice cond = new BBusiEcardPrice();
+        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
+        cond.setLocation(sysUser.getLocation());
+        cond.setExamType(sysUser.getExamType().name());
+        return AjaxResult.success(ecardPriceService.selectBBusiEcardPriceList(cond));
+    }
+
+    @PostMapping("/iosVerifyResult")
+    public AjaxResult iosPay(@RequestBody String payload) {
+        log.info("苹果内购校验开始,base64校验体:{}", payload);
+        JSONObject reqData = JSONObject.parseObject(payload);
+        String receiptData;
+        if(null == reqData || StringUtils.isBlank(receiptData = reqData.getString("receipt"))) {
+            return error("苹果验证失败,返回数据为空");
+        }
+        Long orderId = reqData.getLong("orderId");
+        String transactionId = reqData.getString("transId");
+        //线上环境验证
+        String verifyResult = IosVerifyUtil.buyAppVerify(receiptData, 1);
+        if (verifyResult == null) {
+            return error("苹果验证失败,返回数据为空");
+        } else {
+            log.info("线上,{}苹果平台返回JSON:{}", orderId, verifyResult);
+            JSONObject appleReturn = JSONObject.parseObject(verifyResult);
+            String states = appleReturn.getString("status");
+            //无数据则沙箱环境验证
+            if ("21007".equals(states)) {
+                verifyResult = IosVerifyUtil.buyAppVerify(receiptData, 0);
+                log.info("沙盒环境,{}苹果平台返回JSON:{}", orderId, verifyResult);
+                appleReturn = JSONObject.parseObject(verifyResult);
+                states = appleReturn.getString("status");
+            }
+            log.info("苹果平台返回值:appleReturn" + appleReturn);
+            // 前端所提供的收据是有效的 验证成功
+            if (states.equals("0")) {
+                String receipt = appleReturn.getString("receipt");
+                JSONObject returnJson = JSONObject.parseObject(receipt);
+                String inApp = returnJson.getString("in_app");
+                List<HashMap> inApps = JSONObject.parseArray(inApp, HashMap.class);
+                if (!org.apache.commons.collections.CollectionUtils.isEmpty(inApps)) {
+                    ArrayList<String> transactionIds = new ArrayList<String>();
+                    for (HashMap app : inApps) {
+                        transactionIds.add((String) app.get("transaction_id"));
+                    }
+                    //交易列表包含当前交易,则认为交易成功
+                    if (transactionIds.contains(transactionId)) {
+                        //处理业务逻辑
+                        weixinPayService.processPaySuccess(orderId, transactionId, "SUCCESS", "ios", "");
+                        log.info("交易成功,处理订单:{}",orderId);
+                        return success("交易成功");
+                    }
+                    return error("当前交易不在交易列表中");
+                }
+                return error("未能获取获取到交易列表");
+            } else {
+                weixinPayService.processPaySuccess(orderId, transactionId, "FAILURE", "ios", states);
+                return error("支付失败,错误码:" + states);
+            }
+        }
+    }
+
+    // https://blog.csdn.net/Arhhhhhhh/article/details/130082795?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0-130082795-blog-121291537.235^v43^pc_blog_bottom_relevance_base6&spm=1001.2101.3001.4242.1&utm_relevant_index=2
+    // https://developer.apple.com/documentation/appstoreserverapi/get-v2-refund-lookup-_transactionid_
+}

+ 12 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/front/FrontPracticeController.java

@@ -0,0 +1,12 @@
+package com.ruoyi.web.controller.front;
+
+import io.swagger.annotations.Api;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/front/practice")
+@Api(tags = "前台-学习-练习")
+public class FrontPracticeController {
+
+}

+ 44 - 0
ie-admin/src/main/java/com/ruoyi/web/core/config/WxPayConfiguration.java

@@ -0,0 +1,44 @@
+package com.ruoyi.web.core.config;
+
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
+import lombok.AllArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author Binary Wang
+ */
+@Configuration
+@ConditionalOnClass(WxPayService.class)
+@EnableConfigurationProperties(WxPayProperties.class)
+@AllArgsConstructor
+public class WxPayConfiguration {
+    private WxPayProperties properties;
+
+    @Bean
+    @ConditionalOnMissingBean
+    public WxPayService wxService() {
+        WxPayConfig payConfig = new WxPayConfig();
+        payConfig.setAppId(StringUtils.trimToNull(this.properties.getAppId()));
+        payConfig.setMchId(StringUtils.trimToNull(this.properties.getMchId()));
+        payConfig.setMchKey(StringUtils.trimToNull(this.properties.getMchKey()));
+        payConfig.setSubAppId(StringUtils.trimToNull(this.properties.getSubAppId()));
+        payConfig.setSubMchId(StringUtils.trimToNull(this.properties.getSubMchId()));
+        payConfig.setKeyPath(properties.getKeyPath() + "apiclient_cert.p12");
+        payConfig.setPrivateKeyPath(properties.getKeyPath() + "apiclient_key.pem");
+        payConfig.setPrivateCertPath(properties.getKeyPath() + "apiclient_cert.pem");
+        payConfig.setApiV3Key(StringUtils.trimToNull(this.properties.getApiV3Key()));
+        // 可以指定是否使用沙箱环境
+        payConfig.setUseSandboxEnv(false);
+
+        WxPayService wxPayService = new WxPayServiceImpl();
+        wxPayService.setConfig(payConfig);
+        return wxPayService;
+    }
+}

+ 41 - 0
ie-admin/src/main/java/com/ruoyi/web/core/config/WxPayProperties.java

@@ -0,0 +1,41 @@
+package com.ruoyi.web.core.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@Data
+@ConfigurationProperties(prefix = "wxpay")
+public class WxPayProperties {
+    /**
+     * 设置微信公众号或者小程序等的appid
+     */
+    private String appId;
+
+    /**
+     * 微信支付商户号
+     */
+    private String mchId;
+
+    /**
+     * 微信支付商户密钥
+     */
+    private String mchKey;
+
+    /**
+     * 服务商模式下的子商户公众账号ID,普通模式请不要配置,请在配置文件中将对应项删除
+     */
+    private String subAppId;
+
+    /**
+     * 服务商模式下的子商户号,普通模式请不要配置,最好是请在配置文件中将对应项删除
+     */
+    private String subMchId;
+
+    /**
+     * apiclient_cert.p12文件的绝对路径,或者如果放在项目中,请以classpath:开头指定
+     */
+    private String keyPath;
+
+    private String apiV3Key;
+}
+

+ 408 - 0
ie-admin/src/main/java/com/ruoyi/web/service/WeixinPayService.java

@@ -0,0 +1,408 @@
+package com.ruoyi.web.service;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.core.domain.model.RegisterBody;
+import com.ruoyi.common.core.text.Convert;
+import com.ruoyi.common.enums.BoolValues;
+import com.ruoyi.common.enums.ECardPayStatus;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.QRCodeUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.dz.domain.DzCards;
+import com.ruoyi.dz.service.IDzCardsService;
+import com.ruoyi.enums.CardDistributeStatus;
+import com.ruoyi.enums.CardStatus;
+import com.ruoyi.enums.CardTimeStatus;
+import com.ruoyi.enums.PayStatus;
+import com.ruoyi.system.service.ISysConfigService;
+import com.ruoyi.system.service.ShortMessageService;
+import com.ruoyi.voluntary.domain.BBusiPaymentOrders;
+import com.ruoyi.voluntary.service.IBBusiPaymentOrdersService;
+import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
+import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
+import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
+import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
+import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
+import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
+import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.util.EntityUtils;
+import org.apache.tomcat.util.codec.binary.Base64;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.stereotype.Service;
+
+import javax.imageio.ImageIO;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.PrivateKey;
+import java.util.Date;
+
+@Service
+@Slf4j
+public class WeixinPayService {
+    CloseableHttpClient httpClient;
+    @Value("${wxpay.appId}")
+    private String appId;
+    private String mchId;
+    private String notifyUrl;
+    private AesUtil aesUtil;
+    private ObjectMapper om = new ObjectMapper();
+    @Autowired
+    private IBBusiPaymentOrdersService paymentOrdersService;
+    @Autowired
+    private SysRegisterService registerService;
+    @Autowired
+    private IDzCardsService cardsService;
+    private final ISysConfigService sysConfigService;
+
+
+    public WeixinPayService(@Value("${wxpay.mchid}") String mchId, @Value("${wxpay.key}") String apiV3Key,
+                            @Value("${wxpay.mchsn}") String mchSerialNo, @Value("${wxpay.privateKey}") String privateKey, ISysConfigService sysConfigService) throws Exception {
+        this.mchId = mchId;
+        this.sysConfigService = sysConfigService;
+        // 加载商户私钥(privateKey:私钥字符串)
+        // String privateKey = getKey();
+        // String mchSerialNo = "21925f369f23cdf8ea3a913c541d4239d1bcc8af";
+        // String apiV3Key = "zhilongsanjiasanzhilongsanjiasan";
+        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(privateKey.getBytes("utf-8")));
+        byte[] apiV3KeyBytes = apiV3Key.getBytes("utf-8");
+        // 加载平台证书(mchId:商户号,mchSerialNo:商户证书序列号,apiV3Key:V3密钥)
+        AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
+                new WechatPay2Credentials(mchId, new PrivateKeySigner(mchSerialNo, merchantPrivateKey)), apiV3KeyBytes);
+        aesUtil = new AesUtil(apiV3KeyBytes);
+        // 初始化httpClient
+        httpClient = WechatPayHttpClientBuilder.create()
+                .withMerchant(mchId, mchSerialNo, merchantPrivateKey)
+                .withValidator(new WechatPay2Validator(verifier)).build();
+        om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+        String urlPrefix = sysConfigService.selectConfigByKey("pay.callback.url");
+        notifyUrl = urlPrefix + "/front/ecard/payResult";
+
+//        Date timeExpire = DateUtils.addMonths(new Date(), 1);
+//        PayOrderReq req = new PayOrderReq(timeExpire, 1, mchId, "description", "notifyUrl", "orderId", "appId");
+//        String reqData = om.writeValueAsString(req);
+
+//        String url = "https://online.fliphtml5.com/jkrou/kfob/";
+//        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+//        try {
+//            Image src = ImageIO.read(WeixinPayService.class.getClassLoader().getResourceAsStream("mingxue60.jpg"));
+//            QRCodeUtils.encode(url, src, bos);
+//            String img = "data:image/jpeg;base64," + Base64.encodeBase64String(bos.toByteArray());
+//            System.out.println(img);
+//        } catch (Exception e) {
+//            e.printStackTrace();
+//        }
+        return;
+    }
+
+    public void checkWxPay() {
+        BBusiPaymentOrders cond = new BBusiPaymentOrders();
+        cond.setStatus(ECardPayStatus.unpaid.getValue());
+        Date limit = DateUtils.addDays(new Date(), -2);
+        for (BBusiPaymentOrders order : paymentOrdersService.selectBBusiPaymentOrdersList(cond)) {
+            if (order.getCreateTime().before(limit)) { // 忽略两天前的
+                continue;
+            }
+            String outTradeNo = order.getPhonenumber() + "_" + order.getId();
+            try {
+                PayOrderReq payResult = queryOrder(outTradeNo);
+                if (null == payResult.getCode()) {
+                    processPaySuccess(payResult);
+                } else if ("404".equals(payResult.getCode())) {
+                    continue;
+                } else {
+                    log.warn("check Pay code: {}, text: {}", payResult.getCode(), payResult.getText());
+                }
+            } catch (Exception e) {
+                log.warn("check Pay ", e);
+                continue;
+            }
+        }
+    }
+
+    public void processWxPayFail(Long orderId, String payer, String feedback) {
+        BBusiPaymentOrders order = paymentOrdersService.selectBBusiPaymentOrdersById(orderId);
+        if (null == order || ECardPayStatus.unpaid.getValue() != order.getStatus()) {
+            log.warn("订单状态更新失败{}", orderId);
+            return;
+        }
+        BBusiPaymentOrders upOrder = new BBusiPaymentOrders();
+        upOrder.setId(order.getId());
+        upOrder.setStatus(ECardPayStatus.payFailed.getValue());
+        upOrder.setFeedBack(feedback);
+        upOrder.setPayer(payer);
+        upOrder.setPayTime(new Date());
+        paymentOrdersService.updateBBusiPaymentOrders(upOrder);
+    }
+
+    public void processPaySuccess(Long orderId, String transactionId, String tradeState, String payer, String feedback) {
+        BBusiPaymentOrders order = paymentOrdersService.selectBBusiPaymentOrdersById(orderId);
+        if (null == order || ECardPayStatus.unpaid.getValue() != order.getStatus()) {
+            log.warn("WxPay 订单不存在或非未支付状态 {}", orderId);
+            return;
+        }
+        if (!"SUCCESS".equals(tradeState)) {
+            BBusiPaymentOrders upOrder = new BBusiPaymentOrders();
+            upOrder.setId(order.getId());
+            upOrder.setStatus(ECardPayStatus.payFailed.getValue());
+            upOrder.setFeedBack(feedback);
+            upOrder.setPayer(payer);
+            upOrder.setPayTime(new Date());
+            upOrder.setTransactionId(transactionId);
+            upOrder.setStatus(ECardPayStatus.payFailed.getValue());
+            paymentOrdersService.updateBBusiPaymentOrders(upOrder);
+            log.warn("WxPay 订单支付失败 {}", orderId);
+            return;
+        }
+        //根据orderNo获取订单
+        String phonenumber = order.getPhonenumber();
+        //查找一张未使用的电子卡
+        DzCards eCard = cardsService.selectOneECard();
+        //修改电子卡已使用的状态。 电子卡新增时需要直接分配代理商,学生注册时year与outTime需要取b_busi_payment_orders里面的值(20220901已完成)
+        eCard.setStatus(CardStatus.Active.getVal());
+        eCard.setOpenTime(DateUtils.getNowDate());
+        eCard.setDistributeStatus(CardDistributeStatus.Assign.getVal());
+        eCard.setTimeStatus(CardTimeStatus.Valid.getVal());
+        eCard.setPayStatus(PayStatus.Paid.getVal());
+        cardsService.updateDzCards(eCard);
+
+        order.setCardId(eCard.getCardId());
+        order.setCardNo(eCard.getCardNo());
+
+        order.setTransactionId(transactionId);
+        order.setStatus(ECardPayStatus.paid.getValue());
+        paymentOrdersService.updateBBusiPaymentOrders(order);
+    }
+
+    public void processPaySuccess(PayOrderReq payResult) {
+        if(!payResult.getOutTradeNo().startsWith("test")) {
+            //15111096866_59  phonenumber_orderId
+            Long orderId = Convert.toLongArray("_", payResult.getOutTradeNo())[1];
+            PayOrderPayer payer = payResult.getPayer();
+            processPaySuccess(orderId, payResult.getTransactionId(), payResult.getTradeState(), null != payer ? payer.openid : "", payResult.getText());
+        }
+    }
+
+    public void processWxPayResult(String serial, String signatureType, String timestamp, String nonce, String signature, String json) throws Exception {
+        log.info("WxPay {}-{}-{}-{}-{} recv {}", serial, signatureType, timestamp, nonce, signature, json);
+        PayCallback payCallback = om.readValue(json, PayCallback.class);
+        PayCallbackResource resource = payCallback.getResource();
+
+        String result = aesUtil.decryptToString(resource.getAssociatedData().getBytes(), resource.getNonce().getBytes(), resource.getCiphertext());
+        PayOrderReq payResult = om.readValue(result, PayOrderReq.class);
+        payResult.setText(result);
+        log.info("WxPay {} proc {}", serial, result);
+        processPaySuccess(payResult);
+        return;
+    }
+
+    public String encodeQrCode(String url) {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        try {
+            InputStream is = new ClassPathResource("/mingxue60.jpg").getInputStream();
+            QRCodeUtils.encode(url, null != is ? ImageIO.read(is) : null, bos);
+            return "data:image/jpeg;base64," + Base64.encodeBase64String(bos.toByteArray());
+        } catch (Exception e) {
+            log.error("encodeQrCode", e);
+        }
+        return url;
+    }
+
+    public PayOrderReq queryOrder(String outTradeNo) throws Exception {
+        URIBuilder uriBuilder = new URIBuilder("https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/" + outTradeNo);
+        uriBuilder.setParameter("mchid", mchId);
+
+        //完成签名并执行请求
+        HttpGet httpGet = new HttpGet(uriBuilder.build());
+        httpGet.addHeader("Accept", "application/json");
+        CloseableHttpResponse response = httpClient.execute(httpGet);
+
+        try {
+            int statusCode = response.getStatusLine().getStatusCode();
+            String result = EntityUtils.toString(response.getEntity());
+            if (statusCode == 200) {
+                PayOrderReq payResult = om.readValue(result, PayOrderReq.class);
+                payResult.setText(result);
+                return payResult;
+            } else if (StringUtils.isNotBlank(result)) {
+                PayOrderReq payResult = new PayOrderReq();
+                payResult.setCode(String.valueOf(statusCode));
+                payResult.setText(result);
+                return payResult;
+            } else {
+                throw new IOException("failed,code = " + statusCode + ",body = " + result);
+            }
+        } finally {
+            response.close();
+        }
+    }
+
+    public String createOrderPayUrl(String orderId, Integer total, String description, PayOrderSceneInfo sceneInfo) throws Exception{
+        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/" + (null != sceneInfo ? "h5" : "native"));
+        Date timeExpire = DateUtils.addMonths(new Date(), 1);
+        PayOrderReq req = new PayOrderReq(timeExpire, total, mchId, description, notifyUrl, orderId, appId);
+        req.setSceneInfo(sceneInfo);
+        log.info("PayOrderReq is {}", JSONObject.toJSONString(req));
+        String reqData = om.writeValueAsString(req);
+        StringEntity entity = new StringEntity(reqData,"utf-8");
+        entity.setContentType("application/json");
+        httpPost.setEntity(entity);
+        httpPost.setHeader("Accept", "application/json");
+        //完成签名并执行请求
+        CloseableHttpResponse response = httpClient.execute(httpPost);
+        try {
+            int statusCode = response.getStatusLine().getStatusCode();
+            if (statusCode == 200) { //处理成功
+                CreateOrderResp resp = om.readValue(EntityUtils.toString(response.getEntity()), CreateOrderResp.class);
+                return null != sceneInfo ? resp.h5Url : resp.codeUrl;
+            } else {
+                throw new IOException("WxFail, code = " + statusCode + ",body = " + EntityUtils.toString(response.getEntity()));
+            }
+        } finally {
+            response.close();
+        }
+    }
+
+    @Data
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    @AllArgsConstructor
+    @NoArgsConstructor
+    public static class PayOrderSceneH5Info {
+        String type;
+    }
+
+    @Data
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    @AllArgsConstructor
+    @NoArgsConstructor
+    public static class PayOrderSceneInfo {
+        @JsonProperty("payer_client_ip")
+        String payerClientIp;
+        @JsonProperty("h5_info")
+        PayOrderSceneH5Info h5Info;
+
+        public PayOrderSceneInfo(String ip, String os) {
+            payerClientIp = ip;
+            h5Info = new PayOrderSceneH5Info(os);
+        }
+    }
+
+    @Data
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    public static class PayOrderAmount {
+        Integer total;
+        String currency = "CNY";
+        @JsonProperty("payer_total")
+        Integer payTotal;
+        @JsonProperty("payer_currency")
+        String payCurrency;
+    }
+    @Data
+    public static class PayOrderPayer {
+        String openid;
+    }
+    @Data
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    @NoArgsConstructor
+    public static class PayOrderReq {
+        @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX", timezone="GMT+8")
+        @JsonProperty("time_expire")
+        Date timeExpire;
+        PayOrderAmount amount;
+        @JsonProperty("scene_info")
+        PayOrderSceneInfo sceneInfo;
+        String mchid;
+        String description;
+        @JsonProperty("notify_url")
+        String notifyUrl;
+        @JsonProperty("out_trade_no")
+        String outTradeNo;
+        String appid;
+
+        PayOrderPayer payer;
+        @JsonProperty("transaction_id")
+        String transactionId;
+        @JsonProperty("trade_type")
+        String tradeType;
+        @JsonProperty("trade_state")
+        String tradeState;
+        @JsonProperty("trade_state_desc")
+        String tradeStateDesc;
+        @JsonProperty("bank_type")
+        String bankType;
+        String attach;
+        @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX", timezone="GMT+8")
+        @JsonProperty("success_time")
+        Date successTime;
+        @JsonIgnore
+        String text;
+        @JsonIgnore
+        String code;
+
+        public PayOrderReq(Date timeExpire, Integer total, String mchid, String description, String notifyUrl, String outTradeNo, String appid) {
+            this.timeExpire = timeExpire;
+            amount = new PayOrderAmount();
+            amount.setTotal(total);
+            this.mchid = mchid;
+            this.description = description;
+            this.notifyUrl = notifyUrl;
+            this.outTradeNo = outTradeNo;
+            this.appid = appid;
+        }
+    }
+
+    @Data
+    public static class CreateOrderResp {
+        @JsonProperty("code_url")
+        String codeUrl;
+        @JsonProperty("h5_url")
+        String h5Url;
+    }
+
+    @Data
+    public static class PayCallbackResource {
+        @JsonProperty("original_type")
+        String originalType;
+        String algorithm;
+        String ciphertext;
+        @JsonProperty("associated_data")
+        String associatedData;
+        String nonce;
+    }
+
+    @Data
+    public static class PayCallback {
+        String id;
+        @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ssXXX", timezone="GMT+8")
+        @JsonProperty("create_time")
+        Date createTime;
+        @JsonProperty("resource_type")
+        String resourceType;
+        @JsonProperty("event_type")
+        String eventType;
+        String summary;
+        PayCallbackResource resource;
+    }
+}

+ 61 - 0
ie-common/src/main/java/com/ruoyi/common/enums/ECardPayStatus.java

@@ -0,0 +1,61 @@
+package com.ruoyi.common.enums;
+
+public enum ECardPayStatus {
+    refund(-2, "已退费"),
+    payFailed(-1, "支付失败"),
+    payInvalid(0, "无效"),
+    unpaid(1, "未支付"),
+    paid(2, "已支付");
+
+    private Integer value;
+    private String remark;
+
+    private ECardPayStatus(Integer value, String remark) {
+        this.value = value;
+        this.remark = remark;
+    }
+
+    public Integer getValue() {
+        return value;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public static ECardPayStatus getByValue(String value) {
+        for (ECardPayStatus o : ECardPayStatus.values()) {
+            if (o.getValue().equals(value)) {
+                return o;
+            }
+        }
+        return null;
+    }
+
+    public static Boolean isSuccess(Object value) {
+        if (value instanceof String) {
+            return paid.name().equalsIgnoreCase(String.valueOf(value));
+        }else if (value instanceof Integer) {
+            return paid.getValue()==Integer.parseInt(String.valueOf(value));
+        }
+        return false;
+    }
+
+    public static Boolean isFaild(Object value) {
+        if (value instanceof String) {
+            return payFailed.name().equalsIgnoreCase(String.valueOf(value));
+        }else if (value instanceof Integer) {
+            return payFailed.getValue()==Integer.parseInt(String.valueOf(value));
+        }
+        return false;
+    }
+
+    public static Boolean isUnPaid(Object value) {
+        if (value instanceof String) {
+            return unpaid.name().equalsIgnoreCase(String.valueOf(value));
+        }else if (value instanceof Integer) {
+            return unpaid.getValue()==Integer.parseInt(String.valueOf(value));
+        }
+        return false;
+    }
+}

+ 1 - 0
ie-system/src/main/java/com/ruoyi/dz/mapper/DzCardsMapper.java

@@ -33,6 +33,7 @@ public interface DzCardsMapper
     public List<DzCards> selectDzCardsList(DzCards dzCards);
     public List<DzCards> selectDzCardsList2(DzCards dzCards);
 
+    public DzCards selectOneECard();
     /**
      * 新增学习卡
      * 

+ 2 - 0
ie-system/src/main/java/com/ruoyi/dz/service/IDzCardsService.java

@@ -28,6 +28,8 @@ public interface IDzCardsService
 
     public DzCards selectDzCardsByCardNo(String cardNo);
 
+    public DzCards selectOneECard();
+
     /**
      * 查询学习卡列表
      *

+ 6 - 0
ie-system/src/main/java/com/ruoyi/dz/service/impl/DzCardsServiceImpl.java

@@ -82,6 +82,12 @@ public class DzCardsServiceImpl implements IDzCardsService
         return list.size() != 1 ? null : list.get(0);
     }
 
+    @Override
+    public DzCards selectOneECard()
+    {
+        return dzCardsMapper.selectOneECard();
+    }
+
     private List<DzCards> fillNames(List<DzCards> list) {
         Set<Long> classIdSet = Sets.newHashSet();
         Set<Long> schoolIdSet = Sets.newHashSet();

+ 108 - 0
ie-system/src/main/java/com/ruoyi/voluntary/domain/BBusiEcardPrice.java

@@ -0,0 +1,108 @@
+package com.ruoyi.voluntary.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.util.Date;
+
+/**
+ * 在线电子卡价格对象 b_busi_ecard_price
+ * 
+ * @author mingxue
+ * @date 2022-08-06
+ */
+public class BBusiEcardPrice extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** ID */
+    private Long id;
+
+    /** 地区 */
+    @Excel(name = "地区")
+    private String location;
+
+    /** 考生类型 */
+    @Excel(name = "考生类型")
+    private String examType;
+
+    /** 价格(分) */
+    @Excel(name = "价格(分)")
+    private Integer price;
+
+    /** 学年 */
+    @Excel(name = "学年")
+    private Integer year;
+
+    /** 到期时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "到期时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date outTime;
+
+    public void setId(Long id) 
+    {
+        this.id = id;
+    }
+
+    public Long getId() 
+    {
+        return id;
+    }
+
+    public String getLocation() {
+        return location;
+    }
+
+    public void setLocation(String location) {
+        this.location = location;
+    }
+
+    public String getExamType() {
+        return examType;
+    }
+
+    public void setExamType(String examType) {
+        this.examType = examType;
+    }
+
+    public void setPrice(Integer price)
+    {
+        this.price = price;
+    }
+
+    public Integer getPrice() 
+    {
+        return price;
+    }
+    public void setYear(Integer year) 
+    {
+        this.year = year;
+    }
+
+    public Integer getYear() 
+    {
+        return year;
+    }
+    public void setOutTime(Date outTime) 
+    {
+        this.outTime = outTime;
+    }
+
+    public Date getOutTime() 
+    {
+        return outTime;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("price", getPrice())
+            .append("year", getYear())
+            .append("outTime", getOutTime())
+            .toString();
+    }
+}

+ 406 - 0
ie-system/src/main/java/com/ruoyi/voluntary/domain/BBusiPaymentOrders.java

@@ -0,0 +1,406 @@
+package com.ruoyi.voluntary.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.util.Date;
+
+/**
+ * 在线电子卡订单对象 b_busi_payment_orders
+ * 
+ * @author mingxue
+ * @date 2022-08-06
+ */
+public class BBusiPaymentOrders extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** ID */
+    private Long id;
+
+    /** 订单号 */
+    @Excel(name = "订单号")
+    private String code;
+
+    private String outTradeNo;
+
+    /** 二维码标识 */
+    @Excel(name = "二维码标识")
+    private String qrcodeId;
+
+    /** 类型 */
+    @Excel(name = "类型")
+    private String type;
+
+    /** 电子卡 */
+    @Excel(name = "电子卡")
+    private Long cardId;
+
+    /** 账号 */
+    @Excel(name = "账号")
+    private String cardNo;
+
+    /** 价目标识 */
+    @Excel(name = "价目标识")
+    private String year;
+
+    /** 手机号码 */
+    @Excel(name = "手机号码")
+    private String phonenumber;
+
+    /** 微信订单号 */
+    @Excel(name = "微信订单号")
+    private String transactionId;
+
+    /** 用户 */
+    @Excel(name = "用户")
+    private String customerCode;
+
+    /** 失效期 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "失效期", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date outTime;
+
+    /** 单价 */
+    @Excel(name = "单价")
+    private Integer price;
+
+    /** 数量 */
+    @Excel(name = "数量")
+    private Integer num;
+
+    /** 金额 */
+    @Excel(name = "金额")
+    private Integer fee;
+
+    /** 应付金额 */
+    @Excel(name = "应付金额")
+    private Integer totalFee;
+
+    /** 实付金额 */
+    @Excel(name = "实付金额")
+    private Integer payFee;
+
+    /** 创建者 */
+    @Excel(name = "创建者")
+    private String creator;
+
+    /** 描述 */
+    @Excel(name = "描述")
+    private String body;
+
+    /** 详情 */
+    @Excel(name = "详情")
+    private String detail;
+
+    /** 附加数据 */
+    @Excel(name = "附加数据")
+    private String attach;
+
+    /** 微信预支付标识 */
+    @Excel(name = "微信预支付标识")
+    private String prepayId;
+
+    /** 支付者 */
+    @Excel(name = "支付者")
+    private String payer;
+
+    /** 支付时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date payTime;
+
+    /** 支付回调结果 */
+    @Excel(name = "支付回调结果")
+    private String feedBack;
+
+    /** 确认时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "确认时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date syncTime;
+
+    /** 状态(-2:已退费,-1:支付失败,0:无效,1:未支付,2:已支付) */
+    @Excel(name = "状态(-2:已退费,-1:支付失败,0:无效,1:未支付,2:已支付)")
+    private Integer status;
+
+    public void setId(Long id) 
+    {
+        this.id = id;
+    }
+
+    public Long getId() 
+    {
+        return id;
+    }
+    public void setCode(String code) 
+    {
+        this.code = code;
+    }
+
+    public String getCode() 
+    {
+        return code;
+    }
+
+    public String getOutTradeNo() {
+        return outTradeNo;
+    }
+
+    public void setOutTradeNo(String outTradeNo) {
+        this.outTradeNo = outTradeNo;
+    }
+
+    public void setQrcodeId(String qrcodeId)
+    {
+        this.qrcodeId = qrcodeId;
+    }
+
+    public String getQrcodeId() 
+    {
+        return qrcodeId;
+    }
+    public void setType(String type) 
+    {
+        this.type = type;
+    }
+
+    public String getType() 
+    {
+        return type;
+    }
+    public void setCardId(Long cardId) 
+    {
+        this.cardId = cardId;
+    }
+
+    public Long getCardId() 
+    {
+        return cardId;
+    }
+    public void setCardNo(String cardNo) 
+    {
+        this.cardNo = cardNo;
+    }
+
+    public String getCardNo() 
+    {
+        return cardNo;
+    }
+    public void setYear(String year) 
+    {
+        this.year = year;
+    }
+
+    public String getYear() 
+    {
+        return year;
+    }
+    public void setPhonenumber(String phonenumber) 
+    {
+        this.phonenumber = phonenumber;
+    }
+
+    public String getPhonenumber() 
+    {
+        return phonenumber;
+    }
+    public void setTransactionId(String transactionId) 
+    {
+        this.transactionId = transactionId;
+    }
+
+    public String getTransactionId() 
+    {
+        return transactionId;
+    }
+    public void setCustomerCode(String customerCode) 
+    {
+        this.customerCode = customerCode;
+    }
+
+    public String getCustomerCode() 
+    {
+        return customerCode;
+    }
+    public void setOutTime(Date outTime) 
+    {
+        this.outTime = outTime;
+    }
+
+    public Date getOutTime() 
+    {
+        return outTime;
+    }
+    public void setPrice(Integer price) 
+    {
+        this.price = price;
+    }
+
+    public Integer getPrice() 
+    {
+        return price;
+    }
+    public void setNum(Integer num) 
+    {
+        this.num = num;
+    }
+
+    public Integer getNum() 
+    {
+        return num;
+    }
+    public void setFee(Integer fee) 
+    {
+        this.fee = fee;
+    }
+
+    public Integer getFee() 
+    {
+        return fee;
+    }
+    public void setTotalFee(Integer totalFee) 
+    {
+        this.totalFee = totalFee;
+    }
+
+    public Integer getTotalFee() 
+    {
+        return totalFee;
+    }
+    public void setPayFee(Integer payFee) 
+    {
+        this.payFee = payFee;
+    }
+
+    public Integer getPayFee() 
+    {
+        return payFee;
+    }
+    public void setCreator(String creator) 
+    {
+        this.creator = creator;
+    }
+
+    public String getCreator() 
+    {
+        return creator;
+    }
+    public void setBody(String body) 
+    {
+        this.body = body;
+    }
+
+    public String getBody() 
+    {
+        return body;
+    }
+    public void setDetail(String detail) 
+    {
+        this.detail = detail;
+    }
+
+    public String getDetail() 
+    {
+        return detail;
+    }
+    public void setAttach(String attach) 
+    {
+        this.attach = attach;
+    }
+
+    public String getAttach() 
+    {
+        return attach;
+    }
+    public void setPrepayId(String prepayId) 
+    {
+        this.prepayId = prepayId;
+    }
+
+    public String getPrepayId() 
+    {
+        return prepayId;
+    }
+    public void setPayer(String payer) 
+    {
+        this.payer = payer;
+    }
+
+    public String getPayer() 
+    {
+        return payer;
+    }
+    public void setPayTime(Date payTime) 
+    {
+        this.payTime = payTime;
+    }
+
+    public Date getPayTime() 
+    {
+        return payTime;
+    }
+    public void setFeedBack(String feedBack) 
+    {
+        this.feedBack = feedBack;
+    }
+
+    public String getFeedBack() 
+    {
+        return feedBack;
+    }
+    public void setSyncTime(Date syncTime) 
+    {
+        this.syncTime = syncTime;
+    }
+
+    public Date getSyncTime() 
+    {
+        return syncTime;
+    }
+    public BBusiPaymentOrders setStatus(Integer status)
+    {
+        this.status = status;
+        return this;
+    }
+
+    public Integer getStatus() 
+    {
+        return status;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("code", getCode())
+            .append("qrcodeId", getQrcodeId())
+            .append("type", getType())
+            .append("cardId", getCardId())
+            .append("cardNo", getCardNo())
+            .append("year", getYear())
+            .append("phonenumber", getPhonenumber())
+            .append("transactionId", getTransactionId())
+            .append("customerCode", getCustomerCode())
+            .append("outTime", getOutTime())
+            .append("price", getPrice())
+            .append("num", getNum())
+            .append("fee", getFee())
+            .append("totalFee", getTotalFee())
+            .append("payFee", getPayFee())
+            .append("createTime", getCreateTime())
+            .append("creator", getCreator())
+            .append("body", getBody())
+            .append("detail", getDetail())
+            .append("attach", getAttach())
+            .append("prepayId", getPrepayId())
+            .append("payer", getPayer())
+            .append("payTime", getPayTime())
+            .append("feedBack", getFeedBack())
+            .append("syncTime", getSyncTime())
+            .append("status", getStatus())
+            .toString();
+    }
+}

+ 62 - 0
ie-system/src/main/java/com/ruoyi/voluntary/mapper/BBusiEcardPriceMapper.java

@@ -0,0 +1,62 @@
+package com.ruoyi.voluntary.mapper;
+
+import com.ruoyi.voluntary.domain.BBusiEcardPrice;
+
+import java.util.List;
+
+/**
+ * 在线电子卡价格Mapper接口
+ * 
+ * @author mingxue
+ * @date 2022-08-06
+ */
+public interface BBusiEcardPriceMapper 
+{
+    /**
+     * 查询在线电子卡价格
+     * 
+     * @param id 在线电子卡价格ID
+     * @return 在线电子卡价格
+     */
+    public BBusiEcardPrice selectBBusiEcardPriceById(Long id);
+
+    /**
+     * 查询在线电子卡价格列表
+     * 
+     * @param bBusiEcardPrice 在线电子卡价格
+     * @return 在线电子卡价格集合
+     */
+    public List<BBusiEcardPrice> selectBBusiEcardPriceList(BBusiEcardPrice bBusiEcardPrice);
+
+    /**
+     * 新增在线电子卡价格
+     * 
+     * @param bBusiEcardPrice 在线电子卡价格
+     * @return 结果
+     */
+    public int insertBBusiEcardPrice(BBusiEcardPrice bBusiEcardPrice);
+
+    /**
+     * 修改在线电子卡价格
+     * 
+     * @param bBusiEcardPrice 在线电子卡价格
+     * @return 结果
+     */
+    public int updateBBusiEcardPrice(BBusiEcardPrice bBusiEcardPrice);
+
+    /**
+     * 删除在线电子卡价格
+     * 
+     * @param id 在线电子卡价格ID
+     * @return 结果
+     */
+    public int deleteBBusiEcardPriceById(Long id);
+
+    /**
+     * 批量删除在线电子卡价格
+     * 
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteBBusiEcardPriceByIds(Long[] ids);
+}

+ 64 - 0
ie-system/src/main/java/com/ruoyi/voluntary/mapper/BBusiPaymentOrdersMapper.java

@@ -0,0 +1,64 @@
+package com.ruoyi.voluntary.mapper;
+
+
+import com.ruoyi.voluntary.domain.BBusiPaymentOrders;
+
+import java.util.List;
+
+/**
+ * 在线电子卡订单Mapper接口
+ * 
+ * @author mingxue
+ * @date 2022-08-06
+ */
+public interface BBusiPaymentOrdersMapper 
+{
+    /**
+     * 查询在线电子卡订单
+     * 
+     * @param id 在线电子卡订单ID
+     * @return 在线电子卡订单
+     */
+    public BBusiPaymentOrders selectBBusiPaymentOrdersById(Long id);
+    public BBusiPaymentOrders selectBBusiPaymentOrdersByCardNo(String cardNo);
+
+    /**
+     * 查询在线电子卡订单列表
+     * 
+     * @param bBusiPaymentOrders 在线电子卡订单
+     * @return 在线电子卡订单集合
+     */
+    public List<BBusiPaymentOrders> selectBBusiPaymentOrdersList(BBusiPaymentOrders bBusiPaymentOrders);
+
+    /**
+     * 新增在线电子卡订单
+     * 
+     * @param bBusiPaymentOrders 在线电子卡订单
+     * @return 结果
+     */
+    public int insertBBusiPaymentOrders(BBusiPaymentOrders bBusiPaymentOrders);
+
+    /**
+     * 修改在线电子卡订单
+     * 
+     * @param bBusiPaymentOrders 在线电子卡订单
+     * @return 结果
+     */
+    public int updateBBusiPaymentOrders(BBusiPaymentOrders bBusiPaymentOrders);
+
+    /**
+     * 删除在线电子卡订单
+     * 
+     * @param id 在线电子卡订单ID
+     * @return 结果
+     */
+    public int deleteBBusiPaymentOrdersById(Long id);
+
+    /**
+     * 批量删除在线电子卡订单
+     * 
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteBBusiPaymentOrdersByIds(Long[] ids);
+}

+ 63 - 0
ie-system/src/main/java/com/ruoyi/voluntary/service/IBBusiEcardPriceService.java

@@ -0,0 +1,63 @@
+package com.ruoyi.voluntary.service;
+
+
+import com.ruoyi.voluntary.domain.BBusiEcardPrice;
+
+import java.util.List;
+
+/**
+ * 在线电子卡价格Service接口
+ * 
+ * @author mingxue
+ * @date 2022-08-06
+ */
+public interface IBBusiEcardPriceService 
+{
+    /**
+     * 查询在线电子卡价格
+     * 
+     * @param id 在线电子卡价格ID
+     * @return 在线电子卡价格
+     */
+    public BBusiEcardPrice selectBBusiEcardPriceById(Long id);
+
+    /**
+     * 查询在线电子卡价格列表
+     * 
+     * @param bBusiEcardPrice 在线电子卡价格
+     * @return 在线电子卡价格集合
+     */
+    public List<BBusiEcardPrice> selectBBusiEcardPriceList(BBusiEcardPrice bBusiEcardPrice);
+
+    /**
+     * 新增在线电子卡价格
+     * 
+     * @param bBusiEcardPrice 在线电子卡价格
+     * @return 结果
+     */
+    public int insertBBusiEcardPrice(BBusiEcardPrice bBusiEcardPrice);
+
+    /**
+     * 修改在线电子卡价格
+     * 
+     * @param bBusiEcardPrice 在线电子卡价格
+     * @return 结果
+     */
+    public int updateBBusiEcardPrice(BBusiEcardPrice bBusiEcardPrice);
+
+    /**
+     * 批量删除在线电子卡价格
+     * 
+     * @param ids 需要删除的在线电子卡价格ID
+     * @return 结果
+     */
+    public int deleteBBusiEcardPriceByIds(Long[] ids);
+
+    /**
+     * 删除在线电子卡价格信息
+     * 
+     * @param id 在线电子卡价格ID
+     * @return 结果
+     */
+    public int deleteBBusiEcardPriceById(Long id);
+}

+ 65 - 0
ie-system/src/main/java/com/ruoyi/voluntary/service/IBBusiPaymentOrdersService.java

@@ -0,0 +1,65 @@
+package com.ruoyi.voluntary.service;
+
+
+import com.ruoyi.voluntary.domain.BBusiPaymentOrders;
+
+import java.util.List;
+
+/**
+ * 在线电子卡订单Service接口
+ * 
+ * @author mingxue
+ * @date 2022-08-06
+ */
+public interface IBBusiPaymentOrdersService 
+{
+    /**
+     * 查询在线电子卡订单
+     * 
+     * @param id 在线电子卡订单ID
+     * @return 在线电子卡订单
+     */
+    public BBusiPaymentOrders selectBBusiPaymentOrdersById(Long id);
+    public BBusiPaymentOrders selectBBusiPaymentOrdersNoPaid(String phonenumber);
+    public BBusiPaymentOrders selectBBusiPaymentOrdersByCardNo(String cardNo);
+
+    /**
+     * 查询在线电子卡订单列表
+     * 
+     * @param bBusiPaymentOrders 在线电子卡订单
+     * @return 在线电子卡订单集合
+     */
+    public List<BBusiPaymentOrders> selectBBusiPaymentOrdersList(BBusiPaymentOrders bBusiPaymentOrders);
+
+    /**
+     * 新增在线电子卡订单
+     * 
+     * @param bBusiPaymentOrders 在线电子卡订单
+     * @return 结果
+     */
+    public int insertBBusiPaymentOrders(BBusiPaymentOrders bBusiPaymentOrders);
+
+    /**
+     * 修改在线电子卡订单
+     * 
+     * @param bBusiPaymentOrders 在线电子卡订单
+     * @return 结果
+     */
+    public int updateBBusiPaymentOrders(BBusiPaymentOrders bBusiPaymentOrders);
+
+    /**
+     * 批量删除在线电子卡订单
+     * 
+     * @param ids 需要删除的在线电子卡订单ID
+     * @return 结果
+     */
+    public int deleteBBusiPaymentOrdersByIds(Long[] ids);
+
+    /**
+     * 删除在线电子卡订单信息
+     * 
+     * @param id 在线电子卡订单ID
+     * @return 结果
+     */
+    public int deleteBBusiPaymentOrdersById(Long id);
+}

+ 94 - 0
ie-system/src/main/java/com/ruoyi/voluntary/service/impl/BBusiEcardPriceServiceImpl.java

@@ -0,0 +1,94 @@
+package com.ruoyi.voluntary.service.impl;
+
+import com.ruoyi.voluntary.domain.BBusiEcardPrice;
+import com.ruoyi.voluntary.mapper.BBusiEcardPriceMapper;
+import com.ruoyi.voluntary.service.IBBusiEcardPriceService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 在线电子卡价格Service业务层处理
+ * 
+ * @author mingxue
+ * @date 2022-08-06
+ */
+@Service
+public class BBusiEcardPriceServiceImpl implements IBBusiEcardPriceService
+{
+    @Autowired
+    private BBusiEcardPriceMapper bBusiEcardPriceMapper;
+
+    /**
+     * 查询在线电子卡价格
+     * 
+     * @param id 在线电子卡价格ID
+     * @return 在线电子卡价格
+     */
+    @Override
+    public BBusiEcardPrice selectBBusiEcardPriceById(Long id)
+    {
+        return bBusiEcardPriceMapper.selectBBusiEcardPriceById(id);
+    }
+
+    /**
+     * 查询在线电子卡价格列表
+     * 
+     * @param bBusiEcardPrice 在线电子卡价格
+     * @return 在线电子卡价格
+     */
+    @Override
+    public List<BBusiEcardPrice> selectBBusiEcardPriceList(BBusiEcardPrice bBusiEcardPrice)
+    {
+        return bBusiEcardPriceMapper.selectBBusiEcardPriceList(bBusiEcardPrice);
+    }
+
+    /**
+     * 新增在线电子卡价格
+     * 
+     * @param bBusiEcardPrice 在线电子卡价格
+     * @return 结果
+     */
+    @Override
+    public int insertBBusiEcardPrice(BBusiEcardPrice bBusiEcardPrice)
+    {
+        return bBusiEcardPriceMapper.insertBBusiEcardPrice(bBusiEcardPrice);
+    }
+
+    /**
+     * 修改在线电子卡价格
+     * 
+     * @param bBusiEcardPrice 在线电子卡价格
+     * @return 结果
+     */
+    @Override
+    public int updateBBusiEcardPrice(BBusiEcardPrice bBusiEcardPrice)
+    {
+        return bBusiEcardPriceMapper.updateBBusiEcardPrice(bBusiEcardPrice);
+    }
+
+    /**
+     * 批量删除在线电子卡价格
+     * 
+     * @param ids 需要删除的在线电子卡价格ID
+     * @return 结果
+     */
+    @Override
+    public int deleteBBusiEcardPriceByIds(Long[] ids)
+    {
+        return bBusiEcardPriceMapper.deleteBBusiEcardPriceByIds(ids);
+    }
+
+    /**
+     * 删除在线电子卡价格信息
+     * 
+     * @param id 在线电子卡价格ID
+     * @return 结果
+     */
+    @Override
+    public int deleteBBusiEcardPriceById(Long id)
+    {
+        return bBusiEcardPriceMapper.deleteBBusiEcardPriceById(id);
+    }
+}

+ 122 - 0
ie-system/src/main/java/com/ruoyi/voluntary/service/impl/BBusiPaymentOrdersServiceImpl.java

@@ -0,0 +1,122 @@
+package com.ruoyi.voluntary.service.impl;
+
+import com.ruoyi.common.enums.ECardPayStatus;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.voluntary.domain.BBusiPaymentOrders;
+import com.ruoyi.voluntary.mapper.BBusiPaymentOrdersMapper;
+import com.ruoyi.voluntary.service.IBBusiPaymentOrdersService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.List;
+
+/**
+ * 在线电子卡订单Service业务层处理
+ * 
+ * @author mingxue
+ * @date 2022-08-06
+ */
+@Service
+public class BBusiPaymentOrdersServiceImpl implements IBBusiPaymentOrdersService 
+{
+    @Autowired
+    private BBusiPaymentOrdersMapper bBusiPaymentOrdersMapper;
+
+    /**
+     * 查询在线电子卡订单
+     * 
+     * @param id 在线电子卡订单ID
+     * @return 在线电子卡订单
+     */
+    @Override
+    public BBusiPaymentOrders selectBBusiPaymentOrdersById(Long id)
+    {
+        return bBusiPaymentOrdersMapper.selectBBusiPaymentOrdersById(id);
+    }
+
+    /**
+     * 查询在线电子卡订单列表
+     * 
+     * @param bBusiPaymentOrders 在线电子卡订单
+     * @return 在线电子卡订单
+     */
+    @Override
+    public List<BBusiPaymentOrders> selectBBusiPaymentOrdersList(BBusiPaymentOrders bBusiPaymentOrders)
+    {
+        return bBusiPaymentOrdersMapper.selectBBusiPaymentOrdersList(bBusiPaymentOrders);
+    }
+
+    @Override
+    public BBusiPaymentOrders selectBBusiPaymentOrdersNoPaid(String phonenumber)
+    {
+        BBusiPaymentOrders bBusiPaymentOrders = new BBusiPaymentOrders();
+        bBusiPaymentOrders.setPhonenumber(phonenumber);
+        bBusiPaymentOrders.setStatus(ECardPayStatus.unpaid.getValue());//状态(-2:已退费,-1:支付失败,0:无效,1:未支付,2:已支付)
+        List<BBusiPaymentOrders> list = bBusiPaymentOrdersMapper.selectBBusiPaymentOrdersList(bBusiPaymentOrders);
+        if(!CollectionUtils.isEmpty(list)){
+            //其他订单全部设置为无效
+            for (int i = 0; i < list.size(); i++) {
+                if(i!=0){
+                    bBusiPaymentOrdersMapper.updateBBusiPaymentOrders(list.get(i).setStatus(ECardPayStatus.payInvalid.getValue()));
+                }
+            }
+            return list.get(0);
+        }
+        return null;
+    }
+
+    @Override
+    public BBusiPaymentOrders selectBBusiPaymentOrdersByCardNo(String cardNo) {
+        return bBusiPaymentOrdersMapper.selectBBusiPaymentOrdersByCardNo(cardNo);
+    }
+
+    /**
+     * 新增在线电子卡订单
+     * 
+     * @param bBusiPaymentOrders 在线电子卡订单
+     * @return 结果
+     */
+    @Override
+    public int insertBBusiPaymentOrders(BBusiPaymentOrders bBusiPaymentOrders)
+    {
+        bBusiPaymentOrders.setCreateTime(DateUtils.getNowDate());
+        return bBusiPaymentOrdersMapper.insertBBusiPaymentOrders(bBusiPaymentOrders);
+    }
+
+    /**
+     * 修改在线电子卡订单
+     * 
+     * @param bBusiPaymentOrders 在线电子卡订单
+     * @return 结果
+     */
+    @Override
+    public int updateBBusiPaymentOrders(BBusiPaymentOrders bBusiPaymentOrders)
+    {
+        return bBusiPaymentOrdersMapper.updateBBusiPaymentOrders(bBusiPaymentOrders);
+    }
+
+    /**
+     * 批量删除在线电子卡订单
+     * 
+     * @param ids 需要删除的在线电子卡订单ID
+     * @return 结果
+     */
+    @Override
+    public int deleteBBusiPaymentOrdersByIds(Long[] ids)
+    {
+        return bBusiPaymentOrdersMapper.deleteBBusiPaymentOrdersByIds(ids);
+    }
+
+    /**
+     * 删除在线电子卡订单信息
+     * 
+     * @param id 在线电子卡订单ID
+     * @return 结果
+     */
+    @Override
+    public int deleteBBusiPaymentOrdersById(Long id)
+    {
+        return bBusiPaymentOrdersMapper.deleteBBusiPaymentOrdersById(id);
+    }
+}

+ 4 - 0
ie-system/src/main/resources/mapper/dz/DzCardsMapper.xml

@@ -45,6 +45,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         select card_id, card_no, password, type, status, distribute_status, time_status, pay_status, is_settlement, dept_id, agent_id, leaf_agent_id, campus_id, campus_class_id, assign_location,assign_exam_type,assign_school_id, school_id, class_id, year, end_year, open_id, remark, distribute_time, out_date, open_time, pay_time, active_time, days, settlement_time, refund_time, close_time, create_time, update_time from dz_cards
     </sql>
 
+    <select id="selectOneECard" resultMap="DzCardsResult">
+        SELECT * from dz_cards where status=0 and card_no like '7%' and LENGTH(card_no)=8 limit 1
+    </select>
+
     <select id="selectDzCardsList" parameterType="DzCards" resultMap="DzCardsResult">
         <include refid="selectDzCardsVo"/>
         <where>

+ 76 - 0
ie-system/src/main/resources/mapper/voluntary/BBusiEcardPriceMapper.xml

@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.voluntary.mapper.BBusiEcardPriceMapper">
+    
+    <resultMap type="BBusiEcardPrice" id="BBusiEcardPriceResult">
+        <result property="id"    column="id"    />
+        <result property="location"    column="location"    />
+        <result property="examType"    column="examType"    />
+        <result property="price"    column="price"    />
+        <result property="year"    column="year"    />
+        <result property="outTime"    column="outTime"    />
+    </resultMap>
+
+    <sql id="selectBBusiEcardPriceVo">
+        select id, location,examType, price, year, outTime from b_busi_ecard_price
+    </sql>
+
+    <select id="selectBBusiEcardPriceList" parameterType="BBusiEcardPrice" resultMap="BBusiEcardPriceResult">
+        <include refid="selectBBusiEcardPriceVo"/>
+        <where>  
+            <if test="location != null "> and location = #{location}</if>
+            <if test="examType != null "> and examType = #{examType}</if>
+            <if test="price != null "> and price = #{price}</if>
+            <if test="year != null "> and year = #{year}</if>
+            <if test="outTime != null "> and outTime = #{outTime}</if>
+        </where>
+    </select>
+    
+    <select id="selectBBusiEcardPriceById" parameterType="Long" resultMap="BBusiEcardPriceResult">
+        <include refid="selectBBusiEcardPriceVo"/>
+        where id = #{id}
+    </select>
+        
+    <insert id="insertBBusiEcardPrice" parameterType="BBusiEcardPrice" useGeneratedKeys="true" keyProperty="id">
+        insert into b_busi_ecard_price
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="location != null">location,</if>
+            <if test="examType != null">examType,</if>
+            <if test="price != null">price,</if>
+            <if test="year != null">year,</if>
+            <if test="outTime != null">outTime,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="location != null">#{location},</if>
+            <if test="examType != null">#{examType},</if>
+            <if test="price != null">#{price},</if>
+            <if test="year != null">#{year},</if>
+            <if test="outTime != null">#{outTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateBBusiEcardPrice" parameterType="BBusiEcardPrice">
+        update b_busi_ecard_price
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="location != null">location = #{location},</if>
+            <if test="examType != null">examType = #{examType},</if>
+            <if test="price != null">price = #{price},</if>
+            <if test="year != null">year = #{year},</if>
+            <if test="outTime != null">outTime = #{outTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteBBusiEcardPriceById" parameterType="Long">
+        delete from b_busi_ecard_price where id = #{id}
+    </delete>
+
+    <delete id="deleteBBusiEcardPriceByIds" parameterType="String">
+        delete from b_busi_ecard_price where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 192 - 0
ie-system/src/main/resources/mapper/voluntary/BBusiPaymentOrdersMapper.xml

@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.voluntary.mapper.BBusiPaymentOrdersMapper">
+    
+    <resultMap type="BBusiPaymentOrders" id="BBusiPaymentOrdersResult">
+        <result property="id"    column="id"    />
+        <result property="code"    column="code"    />
+        <result property="outTradeNo"    column="outTradeNo"    />
+        <result property="qrcodeId"    column="qrcodeId"    />
+        <result property="type"    column="type"    />
+        <result property="cardId"    column="cardId"    />
+        <result property="cardNo"    column="cardNo"    />
+        <result property="year"    column="year"    />
+        <result property="phonenumber"    column="phonenumber"    />
+        <result property="transactionId"    column="transaction_id"    />
+        <result property="customerCode"    column="customerCode"    />
+        <result property="outTime"    column="outTime"    />
+        <result property="price"    column="price"    />
+        <result property="num"    column="num"    />
+        <result property="fee"    column="fee"    />
+        <result property="totalFee"    column="totalFee"    />
+        <result property="payFee"    column="payFee"    />
+        <result property="createTime"    column="createTime"    />
+        <result property="creator"    column="creator"    />
+        <result property="body"    column="body"    />
+        <result property="detail"    column="detail"    />
+        <result property="attach"    column="attach"    />
+        <result property="prepayId"    column="prepayId"    />
+        <result property="payer"    column="payer"    />
+        <result property="payTime"    column="payTime"    />
+        <result property="feedBack"    column="feedBack"    />
+        <result property="syncTime"    column="syncTime"    />
+        <result property="status"    column="status"    />
+    </resultMap>
+
+    <sql id="selectBBusiPaymentOrdersVo">
+        select id, code, outTradeNo, qrcodeId, type, cardId, cardNo, year, phonenumber, transaction_id, customerCode, outTime, price, num, fee, totalFee, payFee, createTime, creator, body, detail, attach, prepayId, payer, payTime, feedBack, syncTime, status from b_busi_payment_orders
+    </sql>
+
+    <select id="selectBBusiPaymentOrdersList" parameterType="BBusiPaymentOrders" resultMap="BBusiPaymentOrdersResult">
+        <include refid="selectBBusiPaymentOrdersVo"/>
+        <where>  
+            <if test="code != null  and code != ''"> and code = #{code}</if>
+            <if test="outTradeNo != null  and outTradeNo != ''"> and outTradeNo = #{outTradeNo}</if>
+            <if test="qrcodeId != null  and qrcodeId != ''"> and qrcodeId = #{qrcodeId}</if>
+            <if test="type != null  and type != ''"> and type = #{type}</if>
+            <if test="cardId != null "> and cardId = #{cardId}</if>
+            <if test="cardNo != null  and cardNo != ''"> and cardNo = #{cardNo}</if>
+            <if test="year != null  and year != ''"> and year = #{year}</if>
+            <if test="phonenumber != null  and phonenumber != ''"> and phonenumber = #{phonenumber}</if>
+            <if test="transactionId != null  and transactionId != ''"> and transaction_id = #{transactionId}</if>
+            <if test="customerCode != null  and customerCode != ''"> and customerCode = #{customerCode}</if>
+            <if test="outTime != null "> and outTime = #{outTime}</if>
+            <if test="price != null "> and price = #{price}</if>
+            <if test="num != null "> and num = #{num}</if>
+            <if test="fee != null "> and fee = #{fee}</if>
+            <if test="totalFee != null "> and totalFee = #{totalFee}</if>
+            <if test="payFee != null "> and payFee = #{payFee}</if>
+            <if test="createTime != null "> and createTime = #{createTime}</if>
+            <if test="creator != null  and creator != ''"> and creator = #{creator}</if>
+            <if test="body != null  and body != ''"> and body = #{body}</if>
+            <if test="detail != null  and detail != ''"> and detail = #{detail}</if>
+            <if test="attach != null  and attach != ''"> and attach = #{attach}</if>
+            <if test="prepayId != null  and prepayId != ''"> and prepayId = #{prepayId}</if>
+            <if test="payer != null  and payer != ''"> and payer = #{payer}</if>
+            <if test="payTime != null "> and payTime = #{payTime}</if>
+            <if test="feedBack != null  and feedBack != ''"> and feedBack = #{feedBack}</if>
+            <if test="syncTime != null "> and syncTime = #{syncTime}</if>
+            <if test="status != null "> and status = #{status}</if>
+        </where>
+        order by id desc
+    </select>
+    
+    <select id="selectBBusiPaymentOrdersById" parameterType="Long" resultMap="BBusiPaymentOrdersResult">
+        <include refid="selectBBusiPaymentOrdersVo"/>
+        where id = #{id}
+    </select>
+
+    <select id="selectBBusiPaymentOrdersByCardNo" parameterType="String" resultMap="BBusiPaymentOrdersResult">
+        <include refid="selectBBusiPaymentOrdersVo"/>
+        where cardNo = #{cardNo}
+    </select>
+        
+    <insert id="insertBBusiPaymentOrders" parameterType="BBusiPaymentOrders" useGeneratedKeys="true" keyProperty="id">
+        insert into b_busi_payment_orders
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="code != null and code != ''">code,</if>
+            <if test="outTradeNo != null and outTradeNo != ''">outTradeNo,</if>
+            <if test="qrcodeId != null">qrcodeId,</if>
+            <if test="type != null">type,</if>
+            <if test="cardId != null">cardId,</if>
+            <if test="cardNo != null">cardNo,</if>
+            <if test="year != null and year != ''">year,</if>
+            <if test="phonenumber != null">phonenumber,</if>
+            <if test="transactionId != null">transaction_id,</if>
+            <if test="customerCode != null">customerCode,</if>
+            <if test="outTime != null">outTime,</if>
+            <if test="price != null">price,</if>
+            <if test="num != null">num,</if>
+            <if test="fee != null">fee,</if>
+            <if test="totalFee != null">totalFee,</if>
+            <if test="payFee != null">payFee,</if>
+            <if test="createTime != null">createTime,</if>
+            <if test="creator != null and creator != ''">creator,</if>
+            <if test="body != null">body,</if>
+            <if test="detail != null">detail,</if>
+            <if test="attach != null">attach,</if>
+            <if test="prepayId != null">prepayId,</if>
+            <if test="payer != null">payer,</if>
+            <if test="payTime != null">payTime,</if>
+            <if test="feedBack != null">feedBack,</if>
+            <if test="syncTime != null">syncTime,</if>
+            <if test="status != null">status,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="code != null and code != ''">#{code},</if>
+            <if test="outTradeNo != null and outTradeNo != ''">#{outTradeNo},</if>
+            <if test="qrcodeId != null">#{qrcodeId},</if>
+            <if test="type != null">#{type},</if>
+            <if test="cardId != null">#{cardId},</if>
+            <if test="cardNo != null">#{cardNo},</if>
+            <if test="year != null and year != ''">#{year},</if>
+            <if test="phonenumber != null">#{phonenumber},</if>
+            <if test="transactionId != null">#{transactionId},</if>
+            <if test="customerCode != null">#{customerCode},</if>
+            <if test="outTime != null">#{outTime},</if>
+            <if test="price != null">#{price},</if>
+            <if test="num != null">#{num},</if>
+            <if test="fee != null">#{fee},</if>
+            <if test="totalFee != null">#{totalFee},</if>
+            <if test="payFee != null">#{payFee},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="creator != null and creator != ''">#{creator},</if>
+            <if test="body != null">#{body},</if>
+            <if test="detail != null">#{detail},</if>
+            <if test="attach != null">#{attach},</if>
+            <if test="prepayId != null">#{prepayId},</if>
+            <if test="payer != null">#{payer},</if>
+            <if test="payTime != null">#{payTime},</if>
+            <if test="feedBack != null">#{feedBack},</if>
+            <if test="syncTime != null">#{syncTime},</if>
+            <if test="status != null">#{status},</if>
+         </trim>
+    </insert>
+
+    <update id="updateBBusiPaymentOrders" parameterType="BBusiPaymentOrders">
+        update b_busi_payment_orders
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="code != null and code != ''">code = #{code},</if>
+            <if test="outTradeNo != null and outTradeNo != ''">outTradeNo = #{outTradeNo},</if>
+            <if test="qrcodeId != null">qrcodeId = #{qrcodeId},</if>
+            <if test="type != null">type = #{type},</if>
+            <if test="cardId != null">cardId = #{cardId},</if>
+            <if test="cardNo != null">cardNo = #{cardNo},</if>
+            <if test="year != null and year != ''">year = #{year},</if>
+            <if test="phonenumber != null">phonenumber = #{phonenumber},</if>
+            <if test="transactionId != null">transaction_id = #{transactionId},</if>
+            <if test="customerCode != null">customerCode = #{customerCode},</if>
+            <if test="outTime != null">outTime = #{outTime},</if>
+            <if test="price != null">price = #{price},</if>
+            <if test="num != null">num = #{num},</if>
+            <if test="fee != null">fee = #{fee},</if>
+            <if test="totalFee != null">totalFee = #{totalFee},</if>
+            <if test="payFee != null">payFee = #{payFee},</if>
+            <if test="createTime != null">createTime = #{createTime},</if>
+            <if test="creator != null and creator != ''">creator = #{creator},</if>
+            <if test="body != null">body = #{body},</if>
+            <if test="detail != null">detail = #{detail},</if>
+            <if test="attach != null">attach = #{attach},</if>
+            <if test="prepayId != null">prepayId = #{prepayId},</if>
+            <if test="payer != null">payer = #{payer},</if>
+            <if test="payTime != null">payTime = #{payTime},</if>
+            <if test="feedBack != null">feedBack = #{feedBack},</if>
+            <if test="syncTime != null">syncTime = #{syncTime},</if>
+            <if test="status != null">status = #{status},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteBBusiPaymentOrdersById" parameterType="Long">
+        delete from b_busi_payment_orders where id = #{id}
+    </delete>
+
+    <delete id="deleteBBusiPaymentOrdersByIds" parameterType="String">
+        delete from b_busi_payment_orders where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>