فهرست منبع

Merge branch 'master' of http://git.zonelife.cn:3000/huangyang/national-motion-backend

zhangxin 4 روز پیش
والد
کامیت
2f068ccd89
17فایلهای تغییر یافته به همراه870 افزوده شده و 143 حذف شده
  1. 0 3
      national-motion-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java
  2. 12 1
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/controller/OrderController.java
  3. 2 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/IOrderService.java
  4. 300 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/WeChatPayService.java
  5. 173 87
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/OrderServiceImpl.java
  6. 4 7
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/UserServiceImpl.java
  7. 17 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/vo/PageOrdersVO.java
  8. 58 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/config/WechatConstants.java
  9. 42 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/config/WechatUrlConstants.java
  10. 226 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/util/WechatPayV3Utils.java
  11. 5 1
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/entity/AppOrder.java
  12. 6 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/entity/InsureOrderInfo.java
  13. 3 1
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppOrderMapper.xml
  14. 1 2
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppSitePriceRulesMapper.xml
  15. 14 29
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/controller/SysRoleController.java
  16. 0 12
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java
  17. 7 0
      pom.xml

+ 0 - 3
national-motion-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java

@@ -76,9 +76,6 @@ public interface CommonConstant {
 	 */
 	int OPERATE_TYPE_6 = 6;
 
-     /** 小程序用户注册关联orgCode */
-     String REGISTER_ORG_CODE = "A01A01";
-
 	/** {@code 500 Server Error} (HTTP/1.0 - RFC 1945) */
     Integer SC_INTERNAL_SERVER_ERROR_500 = 500;
     /** {@code 404 Not Found} (HTTP/1.0 - RFC 1945) */

+ 12 - 1
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/controller/OrderController.java

@@ -167,10 +167,21 @@ public class OrderController {
      */
     @Operation(summary = "订单主动取消")
     @PutMapping("/cancelOrder")
-    public Result<String> cancelOrder(@RequestParam(name = "orderCode")String orderId) throws IOException {
+    public Result<String> cancelOrder(@RequestParam(name = "orderId")String orderId){
         return Result.OK(appOrderService.cancelOrder(orderId));
     }
 
+    /**
+     * 订单退款
+     * @param orderCode
+     * @return
+     */
+    @Operation(summary = "订单退款")
+    @PutMapping("/refundOrder")
+    public Result<String> refundOrder(@RequestParam(name = "orderCode")String orderCode){
+        return Result.OK(appOrderService.refundOrder(orderCode));
+    }
+
     /**
      * 订单-小程序支付后回显信息
      *

+ 2 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/IOrderService.java

@@ -93,4 +93,6 @@ public interface IOrderService {
     String cancelOrder(String orderId);
 
     IPage<PageOrdersVO> pageOrders(PageOrdersForm pageOrdersForm);
+
+    String refundOrder(String orderCode);
 }

+ 300 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/WeChatPayService.java

@@ -0,0 +1,300 @@
+package org.jeecg.modules.app.service;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.aliyun.oss.ServiceException;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.jeecg.modules.pay.config.WechatConstants;
+import org.jeecg.modules.pay.config.WechatUrlConstants;
+import org.jeecg.modules.pay.util.WechatPayV3Utils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author wangzhiqiang
+ * @Date 2025/8/21
+ * @Desc 微信支付相关服务接口
+ */
+@Slf4j
+@Service
+public class WeChatPayService {
+
+    @Resource
+    private WechatPayV3Utils wechatPayV3Utils;
+
+
+    /**
+     * 小程序支付拉起
+     *
+     * @param params
+     * @return
+     * @throws ServiceException
+     */
+    public Map<String, String> wechatPay(JSONObject params) throws ServiceException {
+
+        //发起请求
+        JSONObject res = wechatPayV3Utils.sendPost(WechatUrlConstants.PAY_V3_JSAPI, params);
+        if (res == null || StringUtils.isEmpty(res.getString("prepay_id"))) {
+            throw new ServiceException("支付发起失败");
+        }
+
+        StringBuilder sb = new StringBuilder();
+        //返回给小程序拉起微信支付的参数
+        Map<String, String> result = new HashMap<>();
+        result.put("appId", WechatConstants.WECHAT_MP_APPID); //小程序appid
+        sb.append(result.get("appId")).append("\n");
+        result.put("timeStamp", (new Date().getTime() / 1000) + ""); //时间戳
+        sb.append(result.get("timeStamp")).append("\n");
+        result.put("nonceStr", RandomStringUtils.randomAlphanumeric(32)); //32位随机字符串
+        sb.append(result.get("nonceStr")).append("\n");
+        result.put("package", "prepay_id=" + res.getString("prepay_id")); //预支付id 格式为 prepay_id=xxx
+        sb.append(result.get("package")).append("\n");
+        result.put("paySign", wechatPayV3Utils.signRSA(sb.toString())); //签名
+        result.put("signType", "RSA"); //加密方式 固定RSA
+        result.put("out_trade_no", params.getString("out_trade_no")); //商户订单号 此参数不是小程序拉起支付所需的参数 因此不参与签名
+
+        return result;
+    }
+
+//    public static void main(String[] args) {
+//        String s = "{\"mchid\":\"1523499681\",\"appid\":\"wx9b0396a7507e3d66\",\"out_trade_no\":\"4022961176\"," +
+//                "\"transaction_id\":\"4200001859202306051015832415\",\"trade_type\":\"JSAPI\",\"trade_state\":\"SUCCESS\",\"trade_state_desc\":\"支付成功\",\"bank_type\":\"ICBC_DEBIT\",\"attach\":\"4022961176\",\"success_time\":\"2023-06-05T14:45:20+08:00\",\"payer\":{\"openid\":\"ok_fR5NmcrTnxFwiSlyd58_TuXrU\"},\"amount\":{\"total\":1,\"payer_total\":1,\"currency\":\"CNY\",\"payer_currency\":\"CNY\"}}";
+//        JSONObject res = JSONObject.parseObject(s);
+//        String payer_total = res.getJSONObject("amount").getString("payer_total");
+//        BigDecimal bigDecimal = new BigDecimal(payer_total);
+//        System.out.println(dealDateFormat(res.get("success_time").toString()));
+//        //获取当前日期
+//        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+//
+//        String format = sdf.format(DateUtils.getNowDate());
+//
+//        System.out.println(format);
+//    }
+
+    public static Date dealDateFormat(String oldDateStr) {
+        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
+        try {
+            Date date = df.parse(oldDateStr);
+            return date;
+        } catch (ParseException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 测试微信支付有优惠情况的数据获取
+     *
+     * @param args
+     */
+    public static void main(String[] args) {
+        String obj = "{\"amount\":{\"currency\":\"CNY\",\"payer_currency\":\"CNY\",\"payer_total\":18300,\"total\":18400}," +
+                "\"appid\":\"wx9b0396a7507e3d66\",\"attach\":\"20230915155102291908100\",\"bank_type\":\"PAB_CREDIT\",\"mchid\":\"1523499681\",\"out_trade_no\":\"20230915155102291908100\",\"payer\":{\"openid\":\"ok_fR5N24KGz9zQBCKNoWgzuT57Y\"},\"promotion_detail\":[{\"amount\":100,\"coupon_id\":\"50099133534\",\"currency\":\"CNY\",\"goods_detail\":[],\"merchant_contribute\":0,\"name\":\"平安信用卡9月专属\",\"other_contribute\":100,\"scope\":\"GLOBAL\",\"stock_id\":\"17950154\",\"type\":\"CASH\",\"wechatpay_contribute\":0}],\"success_time\":\"2023-09-15T15:51:23+08:00\",\"trade_state\":\"SUCCESS\",\"trade_state_desc\":\"支付成功\",\"trade_type\":\"JSAPI\",\"transaction_id\":\"4200001916202309158539287225\"}";
+
+        JSONObject res = JSONObject.parseObject(obj);
+
+        String payer_total = res.getJSONObject("amount").getString("payer_total");
+
+        System.out.println(payer_total);
+
+        String openid = res.getJSONObject("payer").getString("openid");
+
+        System.out.println(openid);
+
+        Date successTime = dealDateFormat(res.get("success_time").toString());
+
+        System.out.println(successTime);
+
+        BigDecimal discounts = new BigDecimal("0");
+
+        String discountsName = "";
+
+        if (ObjectUtil.isNotEmpty(res.getJSONArray("promotion_detail"))) {
+
+            JSONArray jsonArray = res.getJSONArray("promotion_detail");
+
+            for (int i = 0; i < jsonArray.size(); i++) {
+                JSONObject jsonObject = jsonArray.getJSONObject(i);
+
+                if (ObjectUtil.isNotEmpty(jsonObject.getString("amount"))) {
+                    discounts =
+                            discounts.add(new BigDecimal(jsonObject.getString("amount")).divide(new BigDecimal("100")).setScale(2,
+                                    BigDecimal.ROUND_HALF_UP));
+                }
+
+                if (ObjectUtil.isNotEmpty(jsonObject.getString("name"))) {
+                    if ("".equals(discountsName)) {
+                        discountsName = jsonObject.getString("name");
+                    } else {
+                        discountsName = discountsName + "、" + jsonObject.getString("name");
+                    }
+                }
+                System.out.println(res);
+            }
+        }
+
+        System.out.println(discountsName);
+        System.out.println(res.get("promotion_detail").toString());
+
+    }
+
+    /**
+     * 小程序微信支付回调
+     *
+     * @param request
+     * @return
+     */
+    public Map<String, String> wechatPayNotify(HttpServletRequest request) {
+        Map<String, String> result = new HashMap<>(2);
+        JSONObject res = wechatPayV3Utils.getCallbackData(request);
+        if (res == null) {
+            result.put("code", "FAIL");
+            result.put("message", "失败");
+            return result;
+        }
+        log.info("最终拿到的微信支付通知数据:" + res);
+
+        // 处理支付成功后的业务 例如 将订单状态修改为已支付 具体参数键值可参考文档 注意!!! 微信可能会多次发送重复的通知 因此要判断业务是否已经处理过了 避免重复处理
+        try {
+            String out_trade_no = res.getString("out_trade_no");
+
+//            BmsFilmOrder bmsFilmOrder = bmsFilmOrderService.getOne(Wrappers.<BmsFilmOrder>lambdaQuery().eq(BmsFilmOrder::getSysOrderNo,
+//                    out_trade_no));
+//
+//            if (bmsFilmOrder.getOrderState() != 1) {
+//
+//                String payer_total = res.getJSONObject("amount").getString("payer_total");
+//
+//                String openid = res.getJSONObject("payer").getString("openid");
+//
+//                Date successTime = dealDateFormat(res.get("success_time").toString());
+//
+//                String orderNo = genOrderNo();
+//
+//                BigDecimal paymentMoney = new BigDecimal(payer_total).divide(new BigDecimal("100")).setScale(2, BigDecimal.ROUND_HALF_UP);
+//
+//                BigDecimal amount = bmsFilmOrder.getAmount();
+//
+//                if (amount.compareTo(paymentMoney) != 0) {
+//                    bmsFilmOrder
+//                            .setOrDiscounts(1)
+//                            .setDiscounts(amount.subtract(paymentMoney));
+//
+//                    BigDecimal discounts = new BigDecimal("0");
+//
+//                    String discountsName = "";
+//
+//                    if (ObjectUtil.isNotEmpty(res.getJSONArray("promotion_detail"))) {
+//
+//                        JSONArray jsonArray = res.getJSONArray("promotion_detail");
+//
+//                        for (int i = 0; i < jsonArray.size(); i++) {
+//                            JSONObject jsonObject = jsonArray.getJSONObject(i);
+//
+//                            if (ObjectUtil.isNotEmpty(jsonObject.getString("amount"))) {
+//                                discounts =
+//                                        discounts.add(new BigDecimal(jsonObject.getString("amount")).divide(new BigDecimal("100")).setScale(2,
+//                                                BigDecimal.ROUND_HALF_UP));
+//                            }
+//
+//                            if (ObjectUtil.isNotEmpty(jsonObject.getString("name"))) {
+//                                if ("".equals(discountsName)) {
+//                                    discountsName = jsonObject.getString("name");
+//                                } else {
+//                                    discountsName = discountsName + "、" + jsonObject.getString("name");
+//                                }
+//                            }
+//                        }
+//
+//                        bmsFilmOrder.setDiscounts(discounts)
+//                                .setDiscountsName(discountsName)
+//                                .setDiscountsContent(res.get("promotion_detail").toString());
+//                    }
+//                }
+//
+//                BmsEnterprise enterprise = bmsEnterpriseService.getOne(Wrappers.<BmsEnterprise>lambdaQuery()
+//                        .eq(BmsEnterprise::getName, bmsFilmOrder.getEnterpriseName())
+//                        .eq(BmsEnterprise::getCode, bmsFilmOrder.getEnterpriseCode())
+//                );
+//
+//                if (ObjectUtil.isNotEmpty(enterprise.getCode()) && ObjectUtil.isNotEmpty(bmsFilmOrder.getEnterpriseCode())) {
+//                    if (!enterprise.getCode().equals(bmsFilmOrder.getEnterpriseCode())) {
+//                        bmsFilmOrder.setEnterpriseCode(enterprise.getCode());
+//                    }
+//                }
+//
+//                //修改订单
+//                bmsFilmOrder
+//                        .setOrderNo(orderNo)
+//                        .setOrderState(1)
+//                        .setCostDesc(res.getString("description"))
+//                        .setTransactionId(res.getString("transaction_id"))
+//                        .setUserOpenid(openid)
+//                        .setPaymentMoney(new BigDecimal(payer_total).divide(new BigDecimal("100")).setScale(2, BigDecimal.ROUND_HALF_UP))
+//                        .setPaymentTime(successTime);
+//
+//                bmsFilmOrderService.updateById(bmsFilmOrder);
+//
+//                List<BmsFilmOrderList> list = bmsFilmOrderListService.list(Wrappers.<BmsFilmOrderList>lambdaQuery().eq(BmsFilmOrderList::getSysOrderNo,
+//                        bmsFilmOrder.getSysOrderNo()));
+//
+//                for (BmsFilmOrderList bmsFilmOrderList : list) {
+//                    bmsFilmOrderList.setOrderNo(orderNo);
+//                }
+//
+//                bmsFilmOrderListService.updateBatchById(list);
+//
+//                //创建发票
+//                BmsInvoice bmsInvoice = new BmsInvoice();
+//
+//                bmsInvoice.setSysOrderNo(bmsFilmOrder.getSysOrderNo())
+//                        .setEnterpriseName(enterprise.getName())
+//                        .setSocialCode(enterprise.getSocialCode())
+//                        //.setItin()
+//                        .setEmail(enterprise.getEmail())
+//                        .setBatchNumber(bmsFilmOrder.getBatchNumber())
+//                        .setAmount(bmsFilmOrder.getAmount())
+//                        .setOrderDate(successTime)
+//                        .setSendStatus(0)
+//                        .setStatus("0")
+//                ;
+//
+//                bmsInvoiceService.save(bmsInvoice);
+
+//            }
+
+            result.put("code", "SUCCESS");
+            result.put("message", "OK");
+            return result;
+        } catch (Exception e) {
+            result.put("code", "FAIL");
+            result.put("message", "失败");
+            return result;
+        }
+
+    }
+
+    /**
+     * 通过商户订单号查询订单在微信侧支付状态
+     *
+     * @param out_trade_no 发起支付时创建的商户订单号
+     * @return null代表查询失败 SUCCESS-成功 USERPAYING和ACCEPT为中间态 其他为支付失败
+     */
+    public String orderQueryByOutTradeNo(String out_trade_no) {
+        JSONObject res = wechatPayV3Utils.sendGet(String.format(WechatUrlConstants.PAY_V3_QUERY_OUT, out_trade_no, WechatConstants.WECHAT_MCH_ID));
+        return res == null ? null : res.getString("trade_state");
+    }
+
+}

+ 173 - 87
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/OrderServiceImpl.java

@@ -5,6 +5,7 @@ import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.RandomUtil;
 import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -12,7 +13,6 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.gson.Gson;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
 import lombok.extern.log4j.Log4j2;
@@ -29,11 +29,13 @@ import org.jeecg.modules.app.form.InsureOrderInfoForm;
 import org.jeecg.modules.app.form.PageOrdersForm;
 import org.jeecg.modules.app.form.UserPayForm;
 import org.jeecg.modules.app.service.IOrderService;
+import org.jeecg.modules.app.service.WeChatPayService;
 import org.jeecg.modules.app.vo.AppGameScheduleVO;
 import org.jeecg.modules.app.vo.OrderVO;
 import org.jeecg.modules.app.vo.PageOrdersVO;
 import org.jeecg.modules.app.vo.QueryOrderVerifyRecordsVO;
-import org.jeecg.modules.pay.request.v3.labs.TradeQueryRequest;
+import org.jeecg.modules.pay.config.WechatConstants;
+import org.jeecg.modules.pay.config.WechatUrlConstants;
 import org.jeecg.modules.pay.vo.NotifyRequest;
 import org.jeecg.modules.pay.vo.NotifyResponse;
 import org.jeecg.modules.redission.RedissonDelayQueue;
@@ -47,6 +49,8 @@ import org.springframework.transaction.annotation.Transactional;
 import javax.annotation.Resource;
 import java.io.IOException;
 import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.LocalTime;
 import java.time.ZoneId;
@@ -107,6 +111,8 @@ public class OrderServiceImpl implements IOrderService {
     private RedissonDelayQueue redissonDelayQueue;
     @Resource
     private AppDeviceMapper appDeviceMapper;
+    @Resource
+    private WeChatPayService weChatPayService;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -414,13 +420,14 @@ public class OrderServiceImpl implements IOrderService {
                     AppSite appSite = appSiteMapper.selectById(appSitePlace.getSiteId());
                     appOrder
                             .setPayType(3)
-                            .setOrderStatus(2)
+                            .setOrderStatus(1)
                             .setOrgCode(appSite.getOrgCode())
                             .setTenantId(appSite.getTenantId())
                             .setType(CommonConstant.ORDER_TYPE_0)
                             //使用人IDs
                             .setFamilyIds(createOrderForm.getFamilyIds())
                             .setOriginalPrice(priceRule.getSellingPrice())
+                            .setAddressSiteId(appSite.getId())
                             .setPrice(totalPrice)
                             .setCreateTime(new Date())
                             .setUpdateTime(new Date())
@@ -497,7 +504,7 @@ public class OrderServiceImpl implements IOrderService {
 
                         proInfoList.add(appOrderProInfo);
                         appOrder.setOrgCode(appSitePlace.getOrgCode())
-                                .setTenantId(appSitePlace.getTenantId());
+                                .setTenantId(appSitePlace.getTenantId()).setAddressSiteId(appSite.getId());
 
                         sumPrice = sumPrice.add(priceRule.getSellingPrice()).setScale(2, BigDecimal.ROUND_HALF_UP);
                     }
@@ -563,6 +570,7 @@ public class OrderServiceImpl implements IOrderService {
                             .setType(CommonConstant.ORDER_TYPE_0)
                             .setTDiscounts(tDiscounts)
                             .setOriginalPrice(sumPrice)
+                            .setAddressSiteId(appSite.getId())
                             .setCreateTime(new Date())
                             .setUpdateTime(new Date())
                             .setCreateBy(user.getId())
@@ -587,7 +595,6 @@ public class OrderServiceImpl implements IOrderService {
 
                 for (int i = 1; i <= createOrderForm.getAmount(); i++) {
 
-
                     String familyUserId = createOrderForm.getFamilyIds().split(",")[i - 1];
                     FamilyMembers familyMembers = familyMembersMapper.selectById(familyUserId);
                     AppOrderProInfo appOrderProInfo = new AppOrderProInfo();
@@ -621,6 +628,7 @@ public class OrderServiceImpl implements IOrderService {
 
                 appOrder
                         .setType(CommonConstant.ORDER_TYPE_1)
+                        .setAddressSiteId(appGame.getSiteId())
                         .setOriginalPrice(sumPrice)
                         .setCreateTime(new Date())
                         .setUpdateTime(new Date())
@@ -665,6 +673,7 @@ public class OrderServiceImpl implements IOrderService {
                     appOrderProInfo.setProductId(createOrderForm.getProductIds());
                     appOrderProInfo.setProductName(appCourse.getName());
                     appOrderProInfo.setAddress(appSite.getAddress());
+                    appOrderProInfo.setProductImage(appCourse.getCover());
                     appOrderProInfo.setType(CommonConstant.ORDER_PRO_INFO_TYPE_6);
                     appOrderProInfo.setFrameTimeStr(DateUtil.format(appCourse.getStartTime(), "yyyy-MM-dd") + "-" + DateUtil.format(appCourse.getEndTime(), "MM-dd"));
                     appOrderProInfo.setExpireTime(DateUtil.format(appCourse.getEndTime(), "yyyy-MM-dd"));
@@ -726,6 +735,8 @@ public class OrderServiceImpl implements IOrderService {
                 appOrder.setOriginalPrice(sumCoursePrice);
                 //使用人IDs
                 appOrder.setFamilyIds(createOrderForm.getFamilyIds());
+
+                appOrder.setAddressSiteId(appSite.getId());
                 break;
         }
 
@@ -749,6 +760,7 @@ public class OrderServiceImpl implements IOrderService {
                         .setOrderId(appOrder.getId())
                         .setBdOrderNo(generateOrderNumber(2))
                         .setInsureName(appInsure.getName())
+                        .setCoverImg(appInsure.getCoverImg())
                         .setInsureCompany(appInsure.getInsuranceName_dictText())
                         .setInsureId(appInsure.getId())
                         .setMoney(insurePrice.getInsurePrice())
@@ -761,6 +773,20 @@ public class OrderServiceImpl implements IOrderService {
                 insureOrderInfoList.add(insureOrderInfo);
 
                 sumPrice = sumPrice.add(insurePrice.getInsurePrice()).setScale(2, BigDecimal.ROUND_HALF_UP);
+            }
+            //计算总价 = 订单金额 + 保单金额
+            totalPrice = totalPrice.add(sumPrice);
+        }
+        appOrder.setPrice(totalPrice);
+        appOrderMapper.insert(appOrder);
+        saveSignFlowRecord(appOrder);
+        //todo 优化异步执行 -> 保存订单商品信息
+
+        if(!insureOrderInfoList.isEmpty()) {
+            //保存保险
+            for (InsureOrderInfo insureOrderInfo : insureOrderInfoList) {
+                insureOrderInfo.setOrderId(appOrder.getId());
+                insureOrderInfoMapper.insert(insureOrderInfo);
 
                 AppOrderProInfo appOrderProInfo = new AppOrderProInfo();
                 appOrderProInfo.setProductId(insureOrderInfo.getId());
@@ -769,70 +795,65 @@ public class OrderServiceImpl implements IOrderService {
 
                 appOrderProInfo.setPrice(insureOrderInfo.getMoney());
                 appOrderProInfo.setQuantity(1);
-                FamilyMembers familyMembers = familyMembersMapper.selectById(id);
-                appOrderProInfo.setFamilyUserId(id);
+                FamilyMembers familyMembers = familyMembersMapper.selectById(insureOrderInfo.getFamilyMembersId());
+                appOrderProInfo.setFamilyUserId(familyMembers.getId());
                 appOrderProInfo.setUserName(familyMembers.getFullName());
                 appOrderProInfo.setUserPhone(familyMembers.getPhone());
                 appOrderProInfo.setStatus(CommonConstant.STATUS_0_INT);
                 appOrderProInfo.setDelFlag(CommonConstant.DEL_FLAG_0);
+
+                proInfoList.add(appOrderProInfo);
             }
-            //计算总价 = 订单金额 + 保单金额
-            totalPrice = totalPrice.add(sumPrice);
         }
-        appOrder.setPrice(totalPrice);
-        appOrderMapper.insert(appOrder);
-        saveSignFlowRecord(appOrder);
-        //todo 优化异步执行 -> 保存订单商品信息
+
         for (AppOrderProInfo appOrderProInfo : proInfoList) {
-            appOrderProInfo
-                    .setOrderId(appOrder.getId())
-                    .setOrderCode(appOrder.getOrderCode())
-                    //生成10位随机券号
-                    .setTicketNo(RandomUtil.randomNumbers(10))
-            ;
-            appOrderProInfoMapper.insert(appOrderProInfo);
-            //订单券号记录
-            AppIsin appIsin = new AppIsin();
-            appIsin
-                    .setOrderId(appOrder.getId())
-                    .setOrgCode(appOrder.getOrgCode())
-                    .setOrderCode(appOrder.getOrderCode())
-                    .setOrderProInfoId(appOrderProInfo.getId())
-                    .setFamilyId(appOrderProInfo.getFamilyUserId())
-                    .setFamilyUserName(appOrderProInfo.getUserName())
-                    .setUserPhone(appOrderProInfo.getUserPhone())
-                    .setUseAddress(StrUtil.isBlank(appOrderProInfo.getAddress()) ? null : appOrderProInfo.getAddress())
-                    //过期时间
-                    .setExpireTime(appOrderProInfo.getExpireTime())
-                    //生成10位随机券号
-                    .setTicketNo(appOrderProInfo.getTicketNo())
-                    .setIsinStatus(CommonConstant.ISIN_STATUS_1);
-            appIsinMapper.insert(appIsin);
-            appDeviceMapper.selectList(Wrappers.<AppDevice>lambdaQuery().eq(AppDevice::getOrgCode,appOrder.getOrgCode())).forEach(appDevice -> {
-                try {
-                    String addUser = addUser(appSitePriceRulesMapper.selectById(appOrderProInfo.getProductId()).getDateOfSale(),
-                            appDevice.getDeviceSerial(),
-                            appOrderProInfo.getUserName(),
-                            appOrderProInfo.getId());
-                    String addFace = addFace(appDevice.getDeviceSerial(), appOrderProInfo.getId(),
-                            familyMembersMapper.selectById(appOrderProInfo.getFamilyUserId()).getRealNameImg());
-                    JsonObject addUserJson = JsonParser.parseString(addUser).getAsJsonObject();
-                    JsonObject addFaceJson = JsonParser.parseString(addFace).getAsJsonObject();
-                    if(addUserJson.get("code").getAsInt() != 0 && addFaceJson.get("code").getAsInt() != 0) throw new JeecgBootException("设备录入用户信息失败!请联系管理员");
-                }catch (Exception e){
-                    throw new JeecgBootException("设备录入用户信息失败!请联系管理员");
-                }
-            });
-        }
-        if(!insureOrderInfoList.isEmpty()) {
-            //保存保险
-            for (InsureOrderInfo insureOrderInfo : insureOrderInfoList) {
-                insureOrderInfo.setOrderId(appOrder.getId());
-                insureOrderInfoMapper.insert(insureOrderInfo);
+                appOrderProInfo
+                        .setOrderId(appOrder.getId())
+                        .setOrderCode(appOrder.getOrderCode())
+                        //生成10位随机券号
+                        .setTicketNo(RandomUtil.randomNumbers(10))
+                ;
+                appOrderProInfoMapper.insert(appOrderProInfo);
+            if (!Objects.equals(appOrderProInfo.getType(), CommonConstant.ORDER_PRO_INFO_TYPE_7)) {
+                //订单券号记录
+                AppIsin appIsin = new AppIsin();
+                appIsin
+                        .setOrderId(appOrder.getId())
+                        .setOrgCode(appOrder.getOrgCode())
+                        .setOrderCode(appOrder.getOrderCode())
+                        .setOrderProInfoId(appOrderProInfo.getId())
+                        .setFamilyId(appOrderProInfo.getFamilyUserId())
+                        .setFamilyUserName(appOrderProInfo.getUserName())
+                        .setUserPhone(appOrderProInfo.getUserPhone())
+                        .setUseAddress(StrUtil.isBlank(appOrderProInfo.getAddress()) ? null : appOrderProInfo.getAddress())
+                        //过期时间
+                        .setExpireTime(appOrderProInfo.getExpireTime())
+                        //生成10位随机券号
+                        .setTicketNo(appOrderProInfo.getTicketNo())
+                        .setIsinStatus(CommonConstant.ISIN_STATUS_1);
+                appIsinMapper.insert(appIsin);
+            }
+            if (Objects.equals(appOrderProInfo.getType(), CommonConstant.ORDER_PRO_INFO_TYPE_1)){
+                appDeviceMapper.selectList(Wrappers.<AppDevice>lambdaQuery().eq(AppDevice::getOrgCode,appOrder.getOrgCode())).forEach(appDevice -> {
+                    try {
+                        String addUser = addUser(appSitePriceRulesMapper.selectById(appOrderProInfo.getProductId()).getDateOfSale(),
+                                appDevice.getDeviceSerial(),
+                                appOrderProInfo.getUserName(),
+                                appOrderProInfo.getId());
+                        String addFace = addFace(appDevice.getDeviceSerial(), appOrderProInfo.getId(),
+                                familyMembersMapper.selectById(appOrderProInfo.getFamilyUserId()).getRealNameImg());
+                        JsonObject addUserJson = JsonParser.parseString(addUser).getAsJsonObject();
+                        JsonObject addFaceJson = JsonParser.parseString(addFace).getAsJsonObject();
+                        if(addUserJson.get("code").getAsInt() != 0 && addFaceJson.get("code").getAsInt() != 0) throw new JeecgBootException("设备录入用户信息失败!请联系管理员");
+                    }catch (Exception e){
+                        throw new JeecgBootException("设备录入用户信息失败!请联系管理员");
+                    }
+                });
             }
         }
+
         //保存核销记录
-        if (CollUtil.isNotEmpty(proInfoList)) {
+        if (CollUtil.isNotEmpty(appCoursesVerificationRecordList)) {
             for (AppCoursesVerificationRecord appCoursesVerificationRecord : appCoursesVerificationRecordList) {
                 appCoursesVerificationRecord.setOrderId(appOrder.getId());
                 appCoursesVerificationRecord.setOrderCode(appOrder.getOrderCode());
@@ -846,6 +867,36 @@ public class OrderServiceImpl implements IOrderService {
                 .setOrderId(appOrder.getId())
                 .setOrderCode(orderCode)
         ;
+        Calendar calendar = Calendar.getInstance();
+        calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) + 15);
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
+
+        //构建微信支付参数
+        JSONObject params = new JSONObject();
+        params.put("appid", WechatConstants.WECHAT_MP_APPID); //小程序appid
+        params.put("mchid", WechatConstants.WECHAT_MCH_ID); //商户号
+        params.put("description", "胶片订单业务"); //商品描述
+        params.put("out_trade_no", appOrder.getOrderCode()); //商户订单号
+        params.put("time_expire", sdf.format(calendar.getTime())); //交易结束时间 选填 时间到了之后将不能再支付 遵循rfc3339标准格式
+        params.put("attach", appOrder.getOrderCode()); //附加数据 选填
+        // 在查询API和支付通知中原样返回 可作为自定义参数使用
+        params.put("notify_url", WechatUrlConstants.PAY_V3_NOTIFY); //支付结果异步通知接口
+
+        //订单金额信息
+        JSONObject amount_json = new JSONObject();
+        //支付金额 单位:分
+//        amount_json.put("total", Integer.parseInt(amount_fee(Double.valueOf("0.1"))));
+        amount_json.put("total", Integer.parseInt(amount_fee(appOrder.getPrice())));
+        params.put("amount", amount_json);
+
+        //支付者信息
+        JSONObject payer = new JSONObject();
+        //用户在小程序侧的openid
+        payer.put("openid", sysUser.getOpenid());
+        params.put("payer", payer);
+
+        //拉起支付
+//        Map<String, String> result = weChatPayService.wechatPay(params);
 
         String out_trade_no = appOrder.getOrderCode();
         Integer total_amount = appOrder.getPrice().multiply(new BigDecimal(100)).intValue();
@@ -858,17 +909,26 @@ public class OrderServiceImpl implements IOrderService {
         String goods_name = "商品名称";
         Integer quantity = appOrder.getAmount();
 
-        //拉卡拉预支付订单,返回构建小程序支付拉起参数
-//        String res = V3LabsApi.transPreorder_wxpay_applet(out_trade_no, total_amount, request_ip, subject, notify_url, sub_appid, user_id, goods_id, goods_name, quantity);
-//        payForm.setParams(res);
+        //预支付订单,返回构建小程序支付拉起参数
 
         //发布任务到redission延迟队列
         String task = CommonConstant.ORDER_TIME_OUT_TASK_PREFIX + appOrder.getId();
-        redissonDelayQueue.offerTask(task, 60 * 3);
+        redissonDelayQueue.offerTask(task, 60 * 15);
 
         return payForm;
     }
 
+    /**
+     * 金额元转分字符串
+     *
+     * @param cny 元
+     * @return
+     */
+    public String amount_fee(BigDecimal cny) {
+        BigDecimal b2 = new BigDecimal("100");
+        return cny.multiply(b2).setScale(0, RoundingMode.DOWN).toString();
+    }
+
     /**
      * 异步走保存下单信息
      * @param appOrder
@@ -1283,27 +1343,24 @@ public class OrderServiceImpl implements IOrderService {
     @Override
     public String orderQuery(String orderCode) throws IOException {
 
-        // 初始化查询交易接口请求报文
-        TradeQueryRequest request = new TradeQueryRequest();
-        // 商户交易流水号
-        request.setOut_trade_no(orderCode);
-//        String res = V3LabsApi.queryTradeQuery(request);
-        String res = "";
-        Gson gson = new Gson();
-        NotifyRequest notifyRequest = gson.fromJson(res, NotifyRequest.class);
-
-        //查询订单
-        AppOrder appOrder = appOrderMapper.selectOne(Wrappers.<AppOrder>lambdaQuery().eq(AppOrder::getOrderCode, notifyRequest.getOut_trade_no()).last("limit 1"));
-        if (ObjectUtil.isNotEmpty(appOrder)) {
-            appOrder
-                    .setPayId(notifyRequest.getAcc_trade_no())
-                    .setOrderStatus(2)
-                    .setPayStatus(2)
-                    .setPayTime(DateUtil.parse(notifyRequest.getTrade_time(),"yyyyMMddHHmmss"))
-                    .setCallbackStatus(1);
+        //null代表查询失败 SUCCESS-成功 USERPAYING和ACCEPT为中间态 其他为支付失败
+        String s = weChatPayService.orderQueryByOutTradeNo(orderCode);
+        if ("SUCCESS".equals(s)) {
+            //查询订单
+            AppOrder appOrder = appOrderMapper.selectOne(Wrappers.<AppOrder>lambdaQuery().eq(AppOrder::getOrderCode, orderCode).last("limit 1"));
+            if (ObjectUtil.isNotEmpty(appOrder)) {
+                return "支付成功!";
+            }
         }
-
-        return "支付成功!";
+        if (s == null ) {
+            //查询订单
+            return "查询失败!";
+        }
+        if ("USERPAYING".equals(s) || "ACCEPT".equals(s) ) {
+            //查询订单
+            return "查询中!";
+        }
+        return s;
     }
 
     @Override
@@ -1336,15 +1393,44 @@ public class OrderServiceImpl implements IOrderService {
         IPage<PageOrdersVO> pageOrders = appOrderMapper.pageOrders(page,pageOrdersForm);
 
         pageOrders.getRecords().forEach(record -> {
-            List<AppOrderProInfo> proInfoList = appOrderProInfoMapper.selectList(Wrappers.<AppOrderProInfo>lambdaQuery().eq(AppOrderProInfo::getOrderId, record.getOrderId()));
-            if (CollUtil.isNotEmpty(proInfoList)) {
-                record.setOrderProInfoList(proInfoList);
+
+            List<AppOrderProInfo> proInfoList = appOrderProInfoMapper.selectList(Wrappers.<AppOrderProInfo>lambdaQuery()
+                    .eq(AppOrderProInfo::getOrderId, record.getOrderId())
+            );
+            if(ObjectUtil.isNotEmpty(proInfoList)){
+                List<AppOrderProInfo> infoList = proInfoList.stream().filter(orderProInfo -> orderProInfo.getType() != 7).collect(Collectors.toList());
+                List<AppOrderProInfo> insureList = proInfoList.stream().filter(orderProInfo -> orderProInfo.getType() == 7).collect(Collectors.toList());
+                record.setOrderProInfoList(infoList);
+                record.setOrderInsureList(insureList);
             }
         });
-
         return pageOrders;
     }
 
+    @Override
+    public String refundOrder(String orderCode) {
+
+        //todo 分账退款
+
+        AppOrder appOrder = appOrderMapper.selectOne(Wrappers.<AppOrder>lambdaQuery().eq(AppOrder::getOrderCode, orderCode).last("limit 1"));
+        if(ObjectUtil.isNotEmpty(appOrder)){
+            if (appOrder.getOrderStatus() == 0){
+                log.info("修改订单:{},支付状态为退款中", orderCode);
+                appOrder.setOrderStatus(5);
+                appOrderMapper.updateById(appOrder);
+                List<AppOrderProInfo> appOrderProInfoList = appOrderProInfoMapper.selectList(Wrappers.<AppOrderProInfo>lambdaQuery().eq(AppOrderProInfo::getOrderId, appOrder.getId()));
+                for (AppOrderProInfo appOrderProInfo : appOrderProInfoList) {
+                    appOrderProInfo.setOrderStatus(3);
+                    appOrderProInfo.setAfterSaleStatus(1);
+                    appOrderProInfoMapper.updateById(appOrderProInfo);
+                }
+            }
+            return "退款成功!";
+        }
+
+        return "退款失败!";
+    }
+
     /**
      * @return String 订单号
      * @Author SheepHy

+ 4 - 7
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/UserServiceImpl.java

@@ -39,7 +39,6 @@ import java.util.Date;
 import java.util.List;
 import java.util.UUID;
 
-import static org.jeecg.common.constant.CommonConstant.REGISTER_ORG_CODE;
 import static org.jeecg.common.constant.CommonConstant.SC_INTERNAL_SERVER_ERROR_500;
 
 @Service
@@ -85,13 +84,11 @@ public class UserServiceImpl implements IUserService {
                             .setPassword(openid)
                             .setStatus(1)
                             .setDelFlag(0)
+                            .setUserIdentity(3)
                             .setSalt(oConvertUtils.randomGen(8))
                             .setCreateBy("admin")
                             .setRealname("微信用户")
-                            .setUsername("微信用户_" + UUID.randomUUID())
-                            .setOrgCode(REGISTER_ORG_CODE);
-                SysDepart sysDepart = sysDepartMapper.selectOne(Wrappers.<SysDepart>lambdaQuery().eq(SysDepart::getOrgCode, REGISTER_ORG_CODE));
-                sysUserDepartMapper.insert(new SysUserDepart(user.getId(),sysDepart.getId()));
+                            .setUsername("微信用户_" + UUID.randomUUID());
                 boolean result = sysUserMapper.insert(user) > 0;
                     if (!result) {
                         throw new JeecgBootException("登录失败", SC_INTERNAL_SERVER_ERROR_500);
@@ -165,7 +162,7 @@ public class UserServiceImpl implements IUserService {
         if(null != nickName && !nickName.isEmpty()){
             sysUserMapper.update(null,Wrappers.<SysUser>lambdaUpdate()
                     .eq(SysUser::getId, user.getId())
-                    .set(SysUser::getUsername, nickName));
+                    .set(SysUser::getRealname, nickName));
         }else if(null != avatarUrl && !avatarUrl.isEmpty()){
             sysUserMapper.update(null,Wrappers.<SysUser>lambdaUpdate()
                     .eq(SysUser::getId, user.getId())
@@ -180,7 +177,7 @@ public class UserServiceImpl implements IUserService {
         SysUser sysUser = sysUserMapper.selectById(user.getId());
         return new LoginUserVO()
                 .setId(sysUser.getId())
-                .setUserName(sysUser.getUsername())
+                .setUserName(sysUser.getRealname())
                 .setUserAvatar(sysUser.getAvatar())
                 .setToken(JwtUtil.sign(sysUser.getUsername(), sysUser.getPassword()));
     }

+ 17 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/vo/PageOrdersVO.java

@@ -18,20 +18,37 @@ import java.util.List;
 public class PageOrdersVO implements Serializable {
     private static final long serialVersionUID = 1L;
 
+    @Schema(description = "订单ID")
     private String orderId;
 
+    @Schema(description = "部门编号")
     private String orderCode;
 
+    @Schema(description = "订单状态")
     private Integer orderStatus;
 
+    @Schema(description = "订单类型")
+    private Integer orderType;
+
+    @Schema(description = "原价")
     private String originalPrice;
 
+    @Schema(description = "实际支付")
     private BigDecimal price;
 
+    @Schema(description = "地点ID")
+    private String addressSiteId;
+
+    @Schema(description = "数量")
     private BigDecimal amount;
 
+    @Schema(description = "创建时间")
     @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Data createTime;
 
+    @Schema(description = "子订单")
     private List<AppOrderProInfo>  orderProInfoList;
+
+    @Schema(description = "保险订单")
+    private List<AppOrderProInfo>  orderInsureList;
 }

+ 58 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/config/WechatConstants.java

@@ -0,0 +1,58 @@
+package org.jeecg.modules.pay.config;
+
+/**
+ * @author wangzhiqiang
+ * @Date 2022/12/22
+ * @Desc 微信支付相关配置
+ */
+public class WechatConstants {
+
+    //微信支付商户号
+    public static final String WECHAT_MCH_ID = "1523499681";
+
+    //微信商户平台v2密钥
+    public static final String WECHAT_MCH_SECRET_V2 = "";
+
+    //微信商户平台v3密钥
+    public static final String WECHAT_MCH_SECRET_V3 = "b63646f9b01e573c5bed89dc0f21039e";
+
+    //微信商户平台商户API证书序列号
+    public static final String WECHAT_MCH_SERIAL_NUM = "6CDB06258529D6EA00DE5C0AD9D09A5789EBF735";
+
+    //微信商户平台证书私钥 即证书中的apiclient_key.pem文件中的内容 可以直接写在这里 也可以用流读取文件
+    public static final String WECHAT_MCH_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n" +
+            "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQD6iXfH9KYx9qEL\n" +
+            "peWSx104M7lne8jRBit6WR2mvIWNN8xIFhnt1xZYQq21AM4g6rQCDSI+4b0Fql3p\n" +
+            "ts5PDV/uFZno5A3eKw/wJs8MPd25oIS17bUfzuvLUEA50aQaySk06ggeBd7kBHzH\n" +
+            "Vynwqv0hA9GnYANFD6tKescHHSjKl5OfNIxYDnCgt4mxJpVBCS8AdSi6iTXdfwAW\n" +
+            "l5pazkV+j0GeI6u/HeRFfhFD2VreI4/QYLyUAgJqey81QJOhinolVx99igDg17t/\n" +
+            "y9bcvtsz3nmNx2hbg9C64Tb/TyUzhcIDza/Cx5aUoHDQo44fJsHUv6oVQfzNiUh2\n" +
+            "T0ar+MTPAgMBAAECggEABJ05hoY79Vmcd7Fze/OOBPX26S//b9IUROmVQTfhocsw\n" +
+            "SPeXPKkkcTWxK087fKG19P+27L+NkqgjmKVUQWJ2rNTbA84Hb1sNrReZ4pjVF5Ec\n" +
+            "QJmDJ3XRI+pzdF0nD5M63g2dXqgvBbYLckRpslQD23LNjq6XANOcDQAb4EaqNKjy\n" +
+            "q9NTLDDL5CnkkO6cTGfuXhpa3x5XdwT9rLh9PGFUCEkNNvyT7zX/M+z+2DONEiTQ\n" +
+            "4WasNV3f0VPPZ87O2TdjtvwXWke3s50xY4wiYZ5ZLjAyDCPkDGN6AQ6EOmN2GC6y\n" +
+            "29FQZwt6rw/Gj2OIaeq53hylMZt9tlVHfvnkkEHv+QKBgQD/+u9vnemPOu4DRMLy\n" +
+            "a9W4+wSDy7F/dUfR+r5uMC95GqhdWRTMOe//+16XancSIDRhkqCi6LM2uRJTu85w\n" +
+            "/a3gWriLFgUdAeT2FBAIlFo3hkwvQM+PlTJi/7OXLaAShW+AGHPm8brwR8vcP4cp\n" +
+            "UEhHxb6bzuR1r1SA0NXtl9FkJQKBgQD6jmzGS2+7pyiZ+S78whBNFFh4gSTKsRR2\n" +
+            "Eg6hRW/WcNJso7JqfOwN4HT/2iX9uYEY/E62MA/54x533shRuGJyr7lxwQI+J0uj\n" +
+            "imBoUSV6NJjQssmR4BUcLFO9vqk+cogk9vq3/CFHzXmr3M87kOhHZupL8PUb1avN\n" +
+            "UZ0T50uY4wKBgQCkyRiMJP7uyoPgLMrGnm6mN0mvwlgQciJ65UzjyDc3YdbSyP7f\n" +
+            "fcinZF1/YfUnAP5XdbndRang54EJ0FPUXyoozJ4SQ2mlQ8vuMfokW8Q8DENNBA7a\n" +
+            "IrSeEHe/MYrjgWzG7HboS+MIvV9Z+Ld8/Aab1Yuf568gp27hwg6Fdf9A1QKBgApm\n" +
+            "Ht2cA+cl6Ol7Dhgvdb29Om7F7WD8OH0uAq1u1FVyGUmpAZ6p0KJCzphP1YPSTyla\n" +
+            "T2oAVKlqY7lV5bp+jJd185xlBlLODrWa6KVruMJ5rF39DaCgTD//FvqpDx0oY74l\n" +
+            "AgLg1ADG5mXbpD40pW9RNigwt/uPwrGi0YIh92FBAoGBAMPfRnfiEXy/JLica4/L\n" +
+            "IOq+hhy/zpskSUu0jJZU8/G2YnlcOpw1SylTPVYrLJP8F5W0O/W9hdEl7935g6tG\n" +
+            "ixsK7QnS/AvCJaG+gOe/FaAyewk5LHKJ8WaLeh1QjxbmFgiExYLf7qNlkaUveHEK\n" +
+            "rJ5ZgP1qxeXFkhECXR0/QW49\n" +
+            "-----END PRIVATE KEY-----\n";
+
+    //微信小程序appid
+    public static final String WECHAT_MP_APPID = "wx9b0396a7507e3d66";
+
+    //微信小程序密钥
+    public static final String WECHAT_MP_SECRET = "22b78f76ab5282030ffa08208b223efd";
+
+}

+ 42 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/config/WechatUrlConstants.java

@@ -0,0 +1,42 @@
+package org.jeecg.modules.pay.config;
+
+/**
+ * @author wangzhiqiang
+ * @Date 2022/12/22
+ * @Desc 微信相关接口请求地址 其中最后四个通知接口地址,是自己服务器的接口地址,必须为外网可访问的url,不能携带参数。 公网域名必须为https,如果是走专线接入,使用专线NAT IP或者私有回调域名可使用http。
+ */
+public class WechatUrlConstants {
+
+
+
+    //小程序code获取openid
+    public final static String CODE_2_SESSION = "https://api.weixin.qq.com/sns/jscode2session";
+
+    //微信支付v3 jsapi下单
+    public final static String PAY_V3_JSAPI = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
+
+    //微信支付v3 H5下单
+    public final static String PAY_V3_H5 = "https://api.mch.weixin.qq.com/v3/pay/transactions/h5";
+
+    //微信支付v3 申请退款
+    public final static String PAY_V3_REFUND = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
+
+    //微信支付v3 通过商户订单号查询订单
+    public final static String PAY_V3_QUERY_OUT = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s?mchid=%s";
+
+    //微信支付v3 查询单笔退款
+    public final static String PAY_V3_QUERY_REFUND = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/%s";
+
+    //微信支付v2 支付通知接口地址
+    public final static String PAY_V2_NOTIFY = "https://xxx.com/api/wechatPay/wechatPayNotify";
+
+    //微信支付v2 退款通知接口地址
+    public final static String PAY_V2_REFUND_NOTIFY = "https://xxx.com/api/wechatPay/wechatRefundNotify";
+
+    //微信支付v3 支付通知接口地址
+    public final static String PAY_V3_NOTIFY = "https://barcodeapp.gzspy.org.cn/applet/wechatPayNotify";
+
+    //微信支付v3 退款通知接口地址
+    public final static String PAY_V3_REFUND_NOTIFY = "https://xxx.com/api/wechatPay/v3/wechatRefundNotify";
+
+}

+ 226 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/util/WechatPayV3Utils.java

@@ -0,0 +1,226 @@
+package org.jeecg.modules.pay.util;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
+import com.wechat.pay.contrib.apache.httpclient.auth.*;
+import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
+import com.wechat.pay.contrib.apache.httpclient.constant.WechatPayHttpHeaders;
+import com.wechat.pay.contrib.apache.httpclient.notification.Notification;
+import com.wechat.pay.contrib.apache.httpclient.notification.NotificationHandler;
+import com.wechat.pay.contrib.apache.httpclient.notification.NotificationRequest;
+import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+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.jeecg.modules.pay.config.WechatConstants;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+import java.security.PrivateKey;
+
+/**
+ * @author wangzhiqiang
+ * @Date 2022/12/22
+ * @Desc 微信V3支付工具类
+ */
+@Slf4j
+@Component
+public class WechatPayV3Utils {
+
+    //商户证书私钥
+    private PrivateKey merchantPrivateKey;
+
+    //证书
+    private Verifier verifier;
+
+    //请求客户端
+    private CloseableHttpClient httpClient;
+
+    /**
+     * 获取商户证书私钥
+     */
+    private void setMerchantPrivateKey() throws Exception {
+//        ClassPathResource classPathResource = new ClassPathResource("cer/apiclient_key.pem");
+//        InputStream certStream = classPathResource.getInputStream();
+//        //读取文件形式加载商户私钥
+//        merchantPrivateKey = PemUtil.loadPrivateKey(certStream);
+        //直接把商户私钥以字符串形式配置
+        merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(WechatConstants.WECHAT_MCH_PRIVATE_KEY.getBytes(StandardCharsets.UTF_8)));
+    }
+
+    /**
+     * 获取微信证书
+     *
+     * @throws Exception
+     */
+    private void setVerifier() throws Exception {
+        if (merchantPrivateKey == null) {
+            setMerchantPrivateKey();
+        }
+        // 获取证书管理器实例
+        CertificatesManager certificatesManager = CertificatesManager.getInstance();
+        // 向证书管理器增加需要自动更新平台证书的商户信息
+        certificatesManager.putMerchant(WechatConstants.WECHAT_MCH_ID,
+                new WechatPay2Credentials(WechatConstants.WECHAT_MCH_ID, new PrivateKeySigner(WechatConstants.WECHAT_MCH_SERIAL_NUM, merchantPrivateKey)),
+                WechatConstants.WECHAT_MCH_SECRET_V3.getBytes(StandardCharsets.UTF_8));
+        // ... 若有多个商户号,可继续调用putMerchant添加商户信息
+
+        // 从证书管理器中获取verifier
+        verifier = certificatesManager.getVerifier(WechatConstants.WECHAT_MCH_ID);
+    }
+
+    /**
+     * 创建请求客户端
+     *
+     * @throws Exception
+     */
+    private void setHttpClient() throws Exception {
+        if (verifier == null) {
+            setVerifier();
+        }
+        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
+                .withMerchant(WechatConstants.WECHAT_MCH_ID, WechatConstants.WECHAT_MCH_SERIAL_NUM, merchantPrivateKey)
+                .withValidator(new WechatPay2Validator(verifier));
+        // ... 接下来,你仍然可以通过builder设置各种参数,来配置你的HttpClient
+
+        httpClient = builder.build();
+    }
+
+    /**
+     * 发送POST请求
+     *
+     * @param url    请求地址
+     * @param params json参数
+     * @return
+     */
+    public JSONObject sendPost(String url, JSONObject params) {
+        try {
+            if (httpClient == null) {
+                setHttpClient();
+            }
+            HttpPost httpPost = new HttpPost(url);
+            httpPost.addHeader("Accept", "application/json");
+            httpPost.addHeader("Content-type", "application/json; charset=utf-8");
+            httpPost.setEntity(new StringEntity(params.toJSONString(), StandardCharsets.UTF_8));
+            CloseableHttpResponse response = httpClient.execute(httpPost);
+            String bodyAsString = EntityUtils.toString(response.getEntity());
+            log.info("微信返回的内容:" + bodyAsString);
+            if (StringUtils.isEmpty(bodyAsString)) {
+                return null;
+            }
+            return JSONObject.parseObject(bodyAsString);
+        } catch (Exception e) {
+            log.error("微信支付V3请求失败");
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 发送get请求
+     *
+     * @param url 请求地址 参数直接在地址上拼接
+     * @return
+     */
+    public JSONObject sendGet(String url) {
+        try {
+            if (httpClient == null) {
+                setHttpClient();
+            }
+            URIBuilder uriBuilder = new URIBuilder(url);
+            HttpGet httpGet = new HttpGet(uriBuilder.build());
+            httpGet.addHeader("Accept", "application/json");
+            CloseableHttpResponse response = httpClient.execute(httpGet);
+            String bodyAsString = EntityUtils.toString(response.getEntity());
+            log.info("微信返回的内容:" + bodyAsString);
+            if (StringUtils.isEmpty(bodyAsString)) {
+                return null;
+            }
+            return JSONObject.parseObject(bodyAsString);
+        } catch (Exception e) {
+            log.error("微信支付V3请求失败");
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 回调通知验签与解密
+     *
+     * @param request
+     * @return
+     */
+    public JSONObject getCallbackData(HttpServletRequest request) {
+        try {
+            if (verifier == null) {
+                setVerifier();
+            }
+            String wechatPaySerial = request.getHeader(WechatPayHttpHeaders.WECHAT_PAY_SERIAL);
+            String nonce = request.getHeader(WechatPayHttpHeaders.WECHAT_PAY_NONCE);
+            String timestamp = request.getHeader(WechatPayHttpHeaders.WECHAT_PAY_TIMESTAMP);
+            String signature = request.getHeader(WechatPayHttpHeaders.WECHAT_PAY_SIGNATURE);
+            String body;
+            BufferedReader reader = request.getReader();
+            String line ;
+            StringBuilder inputString = new StringBuilder();
+            while ((line = reader.readLine()) != null) {
+                inputString.append(line);
+            }
+            body = inputString.toString();
+            log.info("body数据:"+body);
+            reader.close();
+            // 构建request,传入必要参数
+            NotificationRequest res = new NotificationRequest.Builder().withSerialNumber(wechatPaySerial)
+                    .withNonce(nonce)
+                    .withTimestamp(timestamp)
+                    .withSignature(signature)
+                    .withBody(body)
+                    .build();
+            NotificationHandler handler = new NotificationHandler(verifier, WechatConstants.WECHAT_MCH_SECRET_V3.getBytes(StandardCharsets.UTF_8));
+            // 验签和解析请求体
+            Notification notification = handler.parse(res);
+            log.info("回调通知数据:" + notification.toString());
+            // 解析开数据
+            String decryptData = notification.getDecryptData();
+            log.info("回调解析数据:" + decryptData);
+            if (StringUtils.isEmpty(decryptData)) {
+                return null;
+            }
+            return JSONObject.parseObject(decryptData);
+        } catch (Exception e) {
+            log.error("微信支付V3回调失败");
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 微信支付v3签名 RSA签名
+     *
+     * @param message 要签名的字符串
+     * @return
+     */
+    public String signRSA(String message) {
+        try {
+            if (merchantPrivateKey == null) {
+                setMerchantPrivateKey();
+            }
+            Signer signer = new PrivateKeySigner(WechatConstants.WECHAT_MCH_SERIAL_NUM, merchantPrivateKey);
+            Signer.SignatureResult signature = signer.sign(message.getBytes(StandardCharsets.UTF_8));
+            return signature.getSign();
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "";
+        }
+    }
+}
+

+ 5 - 1
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/entity/AppOrder.java

@@ -103,7 +103,7 @@ public class AppOrder implements Serializable {
     private Integer payType;
 	/**订单状态*/
 	@Excel(name = "订单状态", width = 15)
-    @Schema(description = "订单状态 0-待付款 1-待使用 2-已使用 3-已到期 4-已取消")
+    @Schema(description = "订单状态 0-待付款 1-待使用 2-已使用 3-已到期 4-已取消 5-退款中 6-已退款")
     private Integer orderStatus;
 
     @Schema(description = "售后状态 0-暂无售后 1-退款中 2-已退款")
@@ -177,4 +177,8 @@ public class AppOrder implements Serializable {
     @Excel(name = "通知次数标识 限制3次", width = 15)
     @Schema(description = "通知次数标识 限制3次")
     private Integer notifyRetryCount;
+
+    @Excel(name = "地点ID", width = 15)
+    @Schema(description = "地点ID")
+    private String addressSiteId;
 }

+ 6 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/entity/InsureOrderInfo.java

@@ -45,6 +45,12 @@ public class InsureOrderInfo implements Serializable {
 	@Excel(name = "保险名称", width = 15)
     @Schema(description = "保险名称")
     private String insureName;
+    /**
+     * 保险封面
+     */
+    @Excel(name = "保险封面", width = 15)
+    @Schema(description = "保险封面")
+    private String coverImg;
 	/**保险公司*/
 	@Excel(name = "保险公司", width = 15)
     @Schema(description = "保险公司")

+ 3 - 1
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppOrderMapper.xml

@@ -15,7 +15,7 @@
         LEFT JOIN nm_site s ON s.org_code = o.org_code
         <where>
             <if test="appOrderPageForm.orgCode != null and appOrderPageForm.orgCode !=''">
-                and o.org_code = #{appOrderPageForm.orgCode}
+                and o.org_code like CONCAT(#{appOrderPageForm.orgCode},'%')
             </if>
             <if test="appOrderPageForm.userPhone != null and appOrderPageForm.userPhone !=''">
                 and o.use_phone LIKE CONCAT('%',#{appOrderPageForm.userPhone},'%')
@@ -86,11 +86,13 @@
             o.id AS orderId,
             o.order_code,
             o.order_status,
+            o.order_type,
             o.original_price,
             o.price,
             o.amount
         FROM
             nm_order o
+            left join nm_site
         <where>
             del_flag = 0
             <if test="pageOrdersForm.orAfterSale != null and pageOrdersForm.orAfterSale == 0">

+ 1 - 2
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppSitePriceRulesMapper.xml

@@ -97,7 +97,7 @@
     </select>
 
     <insert id="insertList" parameterType="java.util.List">
-        INSERT INTO `nm_site_price_rules` (id,org_code,tenant_id,site_place_id,category_id,type,date_of_sale,start_time,end_time,day_of_week,original_price,selling_price,is_teaching,view_status,inventory,site_rule_time_id,revision,create_by,create_time,update_by,update_time,status,del_flag)
+        INSERT INTO `nm_site_price_rules` (id,org_code,tenant_id,site_place_id,category_id,type,date_of_sale,start_time,end_time,day_of_week,original_price,selling_price,is_teaching,inventory,site_rule_time_id,revision,create_by,create_time,update_by,update_time,status,del_flag)
         VALUES
         <foreach collection="list" item="item" separator=",">
             (#{item.id},
@@ -113,7 +113,6 @@
             #{item.originalPrice},
             #{item.sellingPrice},
             #{item.isTeaching},
-            #{item.viewStatus},
             #{item.inventory},
             #{item.siteRuleTimeId},
             #{item.revision},

+ 14 - 29
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/controller/SysRoleController.java

@@ -1,28 +1,23 @@
 package org.jeecg.modules.system.controller;
 
 
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 import cn.hutool.core.util.RandomUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authz.annotation.RequiresPermissions;
 import org.jeecg.common.api.vo.Result;
-import org.jeecg.common.base.BaseMap;
 import org.jeecg.common.config.TenantContext;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.constant.SymbolConstant;
 import org.jeecg.common.modules.redis.client.JeecgRedisClient;
 import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
 import org.jeecg.modules.base.service.BaseCommonService;
@@ -36,26 +31,15 @@ import org.jeecgframework.poi.excel.entity.ImportParams;
 import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 import org.springframework.web.multipart.MultipartHttpServletRequest;
 import org.springframework.web.servlet.ModelAndView;
-import org.jeecg.common.system.vo.LoginUser;
-import org.apache.shiro.SecurityUtils;
-import com.alibaba.fastjson.JSONObject;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 
-import lombok.extern.slf4j.Slf4j;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.*;
 
 /**
  * <p>
@@ -509,6 +493,7 @@ public class SysRoleController {
 		try {
 			LambdaQueryWrapper<SysPermission> query = new LambdaQueryWrapper<SysPermission>();
 			query.eq(SysPermission::getDelFlag, CommonConstant.DEL_FLAG_0);
+			query.ne(SysPermission::getName,"低代码开发");
 			query.orderByAsc(SysPermission::getSortNo);
 			List<SysPermission> list = sysPermissionService.list(query);
 			for(SysPermission sysPer : list) {

+ 0 - 12
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java

@@ -245,18 +245,6 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
                         .setName(sysDepart.getDepartName())
                         .setType(sysDepart.getOrgCategory().equals("20") ? 0 : 1);
                 appSiteMapper.insert(site);
-                //若为包场
-//                if (Objects.equals(sysDepart.getOrgCategory(), "4")) {
-//                    //常见默认类目
-//                    List<String> categoryNames = List.of("篮球","足球","羽毛球","乒乓球","排球");
-//                    for (int i = 0; i < categoryNames.size(); i++) {
-//                        AppCategory category = new AppCategory();
-//                        category.setOrgCode(site.getOrgCode());
-//                        category.setTenantId(site.getTenantId());
-//                        category.setName(categoryNames.get(i));
-//                        category.setSort(i);
-//                    }
-//                }
                 //创建学校场地表
                 if (Objects.equals(sysDepart.getOrgCategory(), "20")){
                     AppSitePlace place = new AppSitePlace();

+ 7 - 0
pom.xml

@@ -76,6 +76,7 @@
 		<httpclient.version>4.5.13</httpclient.version>
 		<gson.version>2.10</gson.version>
 		<redission.version>3.17.6</redission.version>
+		<wechatpay.version>0.4.7</wechatpay.version>
 	</properties>
 	<modules>
         <module>national-motion-base-core</module>
@@ -135,6 +136,12 @@
 			<artifactId>fastjson</artifactId>
 			<version>${fastjson.version}</version>
 		</dependency>
+		<!-- 微信支付 -->
+		<dependency>
+			<groupId>com.github.wechatpay-apiv3</groupId>
+			<artifactId>wechatpay-apache-httpclient</artifactId>
+			<version>${wechatpay.version}</version>
+		</dependency>
 		<!-- markdown -->
 		<!--<dependency>
 			<groupId>org.pegdown</groupId>