Prechádzať zdrojové kódy

新增
1、餐饮计划增加额外可选菜品
2、增加消费券功能
3、增加出入库单导入
4、增加小程序微信支付

liangwenxuan 2 mesiacov pred
rodič
commit
5cb7d0ba69
23 zmenil súbory, kde vykonal 821 pridanie a 311 odobranie
  1. 5 0
      yudao-module-system/yudao-module-system-biz/pom.xml
  2. 3 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/materialio/MaterialIoOrderSaveReqVO.java
  3. 14 6
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/materialio/inbound/MaterialInboundImportExcelVO.java
  4. 20 7
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/materialio/outbound/MaterialOutboundImportExcelVO.java
  5. 188 80
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/pay/WeChatPayController.java
  6. 0 167
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/pay/vo/WechatUnifiedOrderRequest.java
  7. 7 21
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/biz/ElderlyConsumerVouchersDO.java
  8. 88 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/miniapp/MiniAppUserDO.java
  9. 71 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/pay/WechatMiniOrderDO.java
  10. 54 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/pay/WechatMiniOrderItemDO.java
  11. 56 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/pay/WechatMiniPayRequestInfoDO.java
  12. 36 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/restaurant/CateringPlanItemDO.java
  13. 18 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/miniapp/MiniAppUserMapper.java
  14. 10 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/pay/WechatMiniOrderItemMapper.java
  15. 10 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/pay/WechatMiniOrderMapper.java
  16. 9 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/pay/WechatMiniPayRequestInfoMapper.java
  17. 9 4
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ElderlyConsumerVouchersServiceImpl.java
  18. 25 2
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ExpenseOrderServiceImpl.java
  19. 133 19
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/MaterialIoServiceImpl.java
  20. 19 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/miniapp/MiniAppUserService.java
  21. 25 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/miniapp/MiniAppUserServiceImpl.java
  22. 4 4
      yudao-server/src/main/resources/application-dev.yaml
  23. 17 1
      yudao-server/src/main/resources/application.yaml

+ 5 - 0
yudao-module-system/yudao-module-system-biz/pom.xml

@@ -24,6 +24,11 @@
             <version>0.2.15</version>
         </dependency>
         <dependency>
+            <groupId>com.github.wechatpay-apiv3</groupId>
+            <artifactId>wechatpay-java</artifactId>
+            <version>0.2.17</version>
+        </dependency>
+        <dependency>
             <groupId>cn.iocoder.boot</groupId>
             <artifactId>yudao-module-system-api</artifactId>
             <version>${revision}</version>

+ 3 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/materialio/MaterialIoOrderSaveReqVO.java

@@ -52,6 +52,9 @@ public class MaterialIoOrderSaveReqVO {
     @Schema(description = "出库原因")
     private String outReason;
 
+    @Schema(description = "单据号(导入场景可指定)")
+    private String orderNo;
+
     @Schema(description = "备注")
     private String remark;
 

+ 14 - 6
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/materialio/inbound/MaterialInboundImportExcelVO.java

@@ -1,28 +1,36 @@
 package cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.inbound;
 
 import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
 import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
 
 import java.math.BigDecimal;
 import java.time.LocalDate;
 
 @Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题
 public class MaterialInboundImportExcelVO {
 
-    @ExcelProperty("单据号(同单号多行自动合并)")
+    @ExcelProperty("入库单号")
     private String orderNo;
 
-    @ExcelProperty("单据日期(yyyy-MM-dd)")
+    @ExcelProperty("入库日期(yyyy-MM-dd)")
     private LocalDate orderDate;
 
     @ExcelProperty("备注")
     private String remark;
 
-    @ExcelProperty("物资ID")
-    private Long materialId;
+    @ExcelProperty("物资编号")
+    private String materialNumber;
 
-    @ExcelProperty("入库仓库ID")
-    private Long refInStoreId;
+    @ExcelProperty("入库仓库编号")
+    private String refInStoreNumber;
 
     @ExcelProperty("数量")
     private Integer quantity;

+ 20 - 7
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/materialio/outbound/MaterialOutboundImportExcelVO.java

@@ -1,12 +1,20 @@
 package cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.outbound;
 
 import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
 import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
 
 import java.math.BigDecimal;
 import java.time.LocalDate;
 
 @Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题
 public class MaterialOutboundImportExcelVO {
 
     @ExcelProperty("单据号(同单号多行自动合并)")
@@ -15,8 +23,11 @@ public class MaterialOutboundImportExcelVO {
     @ExcelProperty("单据日期(yyyy-MM-dd)")
     private LocalDate orderDate;
 
-    @ExcelProperty("领用部门ID")
-    private Long outDeptId;
+    @ExcelProperty("领用部门编号")
+    private String outDeptNumber;
+
+    @ExcelProperty("领用部门名称(无编号时填)")
+    private String outDeptName;
 
     @ExcelProperty("领用人")
     private String outUser;
@@ -27,11 +38,14 @@ public class MaterialOutboundImportExcelVO {
     @ExcelProperty("备注")
     private String remark;
 
-    @ExcelProperty("物资ID")
-    private Long materialId;
+    @ExcelProperty("物资编号")
+    private String materialNumber;
+
+    @ExcelProperty("物资名称(无编号时填)")
+    private String materialName;
 
-    @ExcelProperty("入库批次明细ID")
-    private Long inboundItemId;
+    @ExcelProperty("关联入库单号")
+    private String inboundOrderNo;
 
     @ExcelProperty("数量")
     private Integer quantity;
@@ -45,4 +59,3 @@ public class MaterialOutboundImportExcelVO {
     @ExcelProperty("生产日期(yyyy-MM-dd)")
     private LocalDate produceDate;
 }
-

+ 188 - 80
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/pay/WeChatPayController.java

@@ -1,29 +1,45 @@
 package cn.iocoder.yudao.module.system.controller.admin.pay;
 
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
-import cn.iocoder.yudao.module.system.controller.admin.pay.vo.WechatUnifiedOrderRequest;
+import cn.iocoder.yudao.module.system.dal.dataobject.pay.WechatMiniOrderDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.pay.WechatMiniOrderItemDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.pay.WechatMiniPayRequestInfoDO;
+import cn.iocoder.yudao.module.system.dal.mysql.pay.WechatMiniOrderItemMapper;
+import cn.iocoder.yudao.module.system.dal.mysql.pay.WechatMiniOrderMapper;
+import cn.iocoder.yudao.module.system.dal.mysql.pay.WechatMiniPayRequestInfoMapper;
+import cn.iocoder.yudao.module.system.enums.ErrorCodeConstants;
+import cn.iocoder.yudao.module.system.service.miniapp.MiniAppUserService;
 import cn.iocoder.yudao.module.system.util.pay.CertUtils;
-import com.fasterxml.jackson.databind.ObjectMapper;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.wechat.pay.java.core.Config;
 import com.wechat.pay.java.core.RSAPublicKeyConfig;
+import com.wechat.pay.java.core.notification.NotificationConfig;
+import com.wechat.pay.java.core.notification.NotificationParser;
+import com.wechat.pay.java.core.notification.RSAPublicKeyNotificationConfig;
 import com.wechat.pay.java.service.partnerpayments.jsapi.JsapiServiceExtension;
-import com.wechat.pay.java.service.partnerpayments.jsapi.model.Amount;
-import com.wechat.pay.java.service.partnerpayments.jsapi.model.Payer;
-import com.wechat.pay.java.service.partnerpayments.jsapi.model.PrepayRequest;
-import com.wechat.pay.java.service.partnerpayments.jsapi.model.PrepayWithRequestPaymentResponse;
+import com.wechat.pay.java.service.partnerpayments.jsapi.model.*;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.util.EntityUtils;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.security.PermitAll;
-import java.util.Arrays;
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.Collectors;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exceptionCustomMsg;
+
 
 /**
  * 微信小程序统一下单控制器
@@ -33,59 +49,51 @@ import java.util.Arrays;
 @RequestMapping("/pay/wx")
 public class WeChatPayController {
 
-    private static final String privateKey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzbDDaK6pFz8fEBIM/pFlIV4uApuhr/TDm8mlK0+Cw1+om1p2s2RFItgBw7Gk9qTN72L68utj5bEDJRQgdr1ixAjc4AH1AOYeV4YZnWTQkcjsRiEimqo+bkIm+osTpFEO9kdvfFMILOl1MDipIAcUrNq9CMs6s6nFDLxLlwy8Ap4VrP4N+FF04efG+8dj35z8dUdi/8WrAe4p7GYGojHHoZ/mIqEDnLdt+PM5pRizCfUCtmSF5UxnmNUlUAutIedvtOAT9rs9E71aO+ldhXNMfA+jLxuBmyp+oy3hWS4Vqp4RbC1a2xRSULvEgSUwrdNq/rytpK66/XY7Vk2f/onCdAgMBAAECggEAXtI/ox1OeGSN01b7MggeMzApBo2u6Vs+m97irGv7JBqHoYzseWuiScX9x6/5EmA4WCw86Srp/i8qsfOsjVucyLc+DXecufNtZ1VvnXC0MMq50tMuaf5btMAXO8tzuyY9gpLyGxwyTJLEuawGxlVBKUxWJOsK9LFVuEbJeunDDlmWsn+euRw3F7jxtNnjVjfqXsY9O+TtB8p0bOduWZc7OvDHoIZQL4NnDivnAR5q1dSLt77pzdinvGiXNYNuTTULstR+KVhJy5Kmsldtj3nrP/fcy/N+JsXm9+3xgaJ2edKwmfnwvQjJAWOtltOSoHx4RK3kzbC8UhKs/E3iaUEUgQKBgQDp0qoNKHbTCiwDhmrnnCyaoW16qEOj0MqHOy5mKYmJkcSDGgNQM/44gN7vOu5BBJHXdkizxaoX3w/ufW2ahhJ/LcjITjFIq8gpiFKbLNfhkCw47ZDtmhB9jAnaB+9+rLeAFXkfXKi+PYJGZIIzbgn0u5LADzRjvzaxe/Z+Ed5ooQKBgQDEcKkk0SmcsHdTkLs2kf6fu8z7MAg9l42fCO18TPt3PeoRcvf8AKw+WDjARSo0ojqL23T9U0IydKdsbcxrYsHETUBS+MAP09Ckpd8p7F5evJghXwhhQRx0gzVuNMkbeP1a3xnC3yL7V5fluGQqz7Xiv3sg9dxYDh8cVQBu6ckafQKBgQCcoF0Ay2YtH9cz1UqvMtI+Enw/eY81oJrJ0z7VeGWFHXvBRh+KDgnw14J+Rb9rFiCLb9Rrd7DkpKsLWkGdDMo/HvAsHRSuVUOTbpnHEFbb5bN5vskiH92D+9Ztkns/I3sX9UpZU7xFEva9KH5+7OsGYM+Aj67MUj3UzfDjqhyNgQKBgFcNojeZpbo1jbvvsLd/PXqmLDHI2G4LIoyu1Se3qdzvCDLRY0o/NhWu3P9/5zNKDW37RD4bToOzpJptkiCotDv9DBt49wxMjvLYOyyF/lA3faeUSM9onmaX2u7K37CYDpbdtbnhTsxZxgvcii9auz0QJE24BvzSzUCt/rIoUqG1AoGAX9sTEp77kdVrM8ECEKgLsOtRWEAgeNkWLgHZKYcEYyu3D4XEVScYNtTBLBHXs3n1GIYdLjWEAWWb55sqKSlVzVWfOhpnOqoFq51xi2TGr3pkp9cqZf0lxYKs7P4tlgeL0icXfb+lFTPmgfgE5vjHBvYQcj7o9lO5hRe46fVoxT8=";
-
-    private static final String merchantId = "1105835366";
-
-    private static final String certPem = "MIIELjCCAxagAwIBAgIUOjdSdMmYC2qOKZOM68wXFlQcfbEwDQYJKoZIhvcNAQEL\n" +
-            "BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT\n" +
-            "FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg\n" +
-            "Q0EwHhcNMjYwMzAyMDM0MzM5WhcNMzEwMzAxMDM0MzM5WjCBhzETMBEGA1UEAwwK\n" +
-            "MTEwNTgzNTM2NjEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTMwMQYDVQQL\n" +
-            "DCrpopDlubTlgaXlurfkuqfkuJrvvIjpm4blm6LvvInmnInpmZDlhazlj7gxCzAJ\n" +
-            "BgNVBAYTAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQAD\n" +
-            "ggEPADCCAQoCggEBALNsMNorqkXPx8QEgz+kWUhXi4Cm6Gv9MObyaUrT4LDX6ibW\n" +
-            "nazZEUi2AHDsaT2pM3vYvry62PlsQMlFCB2vWLECNzgAfUA5h5XhhmdZNCRyOxGI\n" +
-            "SKaqj5uQib6ixOkUQ72R298Uwgs6XUwOKkgBxSs2r0IyzqzqcUMvEuXDLwCnhWs/\n" +
-            "g34UXTh58b7x2PfnPx1R2L/xasB7insZgaiMcehn+YioQOct2348zmlGLMJ9QK2Z\n" +
-            "IXlTGeY1SVQC60h52+04BP2uz0TvVo76V2Fc0x8D6MvG4GbKn6jLeFZLhWqnhFsL\n" +
-            "VrbFFJQu8SBJTCt02r+vK2krrr9djtWTZ/+icJ0CAwEAAaOBuTCBtjAJBgNVHRME\n" +
-            "AjAAMAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDov\n" +
-            "L2V2Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUw\n" +
-            "REJDMDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJF\n" +
-            "MTJCMjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IB\n" +
-            "AQAVEO4RR9o+W0SySh9S6RwLV9e+GNl96K8BnfswLMeTcZTA5XJQRTfCSlE5v/mf\n" +
-            "NQw5HdDigF2BeIDJqWSDyApbILfngsZadH0I6fDk1u2zifeIQcN0C9yFRPn2uf3O\n" +
-            "YRc2sX7CJdPSbMGFaozaH40uZDl86/63qVFMuaOa3iAwiqQVVsSOcnhUhLBL1fh/\n" +
-            "0AauGFk5fyGgNqMIJ+7+z+nBtWfq1i2quRda66Ao0ytQP+L5CV0jePmQ0uOiv8AE\n" +
-            "EcqAqJ+/d0nqhFd7hVcmW+uzQ3eTTeuHnsAZt7bkUhTF5PJBvZipI+CYtUhZFlaT\n" +
-            "rXbHeFgiQcZb/sR8sTBV0KXR";
-
-    private static final String apiV3Key = "W2sE4rF6tY8uI0oP1aQ2wS3dF4gH5jK6";
-
-    private static final String wechatpayPublicKeyPem = "-----BEGIN PUBLIC KEY-----\n" +
-            "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuh82JjfQ/r0+mz8W9ZAr\n" +
-            "Uw5nLSSzUKxvepSnWny0a7ccZFB+j8q9pZWq7gmfyOmsC6uq8gmzPDnOD+xrBfj7\n" +
-            "t8R3x/VU7tpmGtdNecQFTaJ6NrausM82sMVdf9XOpQvERgVtfIO5U1q3jqSfTyNk\n" +
-            "MchXhQMoWa3RXDl7EO0okLIKoNgA1o4AWZZaVyiJ0BjF/URwk6O0eg+g2PqDldFr\n" +
-            "RxQIHLsaFnFsDJx5bNia9Jb48g+nNpoKtW1njsPDn/ckTOvnZxdkbkwIaQ2NDli1\n" +
-            "ehsaDK6ACReD/A6nIlDQB50duKhVNzx10MZwikD2OWAPUnY6rIE9cqWwKUH4okWJ\n" +
-            "BwIDAQAB\n" +
-            "-----END PUBLIC KEY-----\n";
-
-    //Call Unified Order API
+    @Autowired
+    private WechatMiniPayRequestInfoMapper wechatMiniPayRequestInfoMapper;
+
+    @Autowired
+    private MiniAppUserService miniAppUserService;
+
+    @Autowired
+    private WechatMiniOrderMapper wechatMiniOrderMapper;
+
+    @Autowired
+    private WechatMiniOrderItemMapper wechatMiniOrderItemMapper;
+
+    @Value("${wechat.miniapp.pay.public-key}")
+    private String publicKey;
+
+    @Value("${wechat.miniapp.pay.public-key-id}")
+    private String publicKeyId;
+
+    @Value("${wechat.miniapp.pay.api-v3-key}")
+    private String apiV3Key;
+
+    private static final String PREFIX = "OUT_TRADE_NO_";
+    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
+    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HHmmss");
+
     @PostMapping(value = "/unifiedOrder", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE})
     @PermitAll
     @TenantIgnore
-    public CommonResult<String> unifiedOrder() throws Exception {
-        String merchantSerialNumber = CertUtils.getMerchantSerialNumberFromPem(certPem);
-        // 1. 构建配置类(就是你之前写的那部分)
+    public CommonResult<JSONObject> unifiedOrder(@RequestBody WechatMiniOrderDO req) throws Exception {
+        String openId = miniAppUserService.getByPhone(req.getPhone()).getOpenId();
+        String outTradeNo = generateOrderNo();
+        req.setOutTradeNo(outTradeNo);
+        // 记录支付订单信息
+        String description = insertMiniOrder(req);
+        WechatMiniPayRequestInfoDO wechatMiniPayRequestInfoDO = wechatMiniPayRequestInfoMapper.selectOne(new LambdaQueryWrapperX<WechatMiniPayRequestInfoDO>()
+                .eq(WechatMiniPayRequestInfoDO::getStatus, 1)
+                .eq(WechatMiniPayRequestInfoDO::getTenantId, req.getTenantId()));
+        String merchantSerialNumber = CertUtils.getMerchantSerialNumberFromPem(wechatMiniPayRequestInfoDO.getCertPem());
+        // 1. 构建配置类
         Config config =
                 new RSAPublicKeyConfig.Builder()
-                        .merchantId(merchantId)
-                        .privateKey(privateKey)          // 商户私钥字符串
-                        .publicKey(wechatpayPublicKeyPem)   // 微信支付公钥字符串
-                        .publicKeyId("PUB_KEY_ID_0111058353662026030200381966000601")  // 公钥ID(必须!)
+                        .merchantId(wechatMiniPayRequestInfoDO.getSpMchid())
+                        .privateKey(wechatMiniPayRequestInfoDO.getPrivateKey())          // 商户私钥字符串
+                        .publicKey(publicKey)   // 微信支付公钥字符串
+                        .publicKeyId(publicKeyId)  // 公钥ID(必须!)
                         .merchantSerialNumber(merchantSerialNumber)
                         .apiV3Key(apiV3Key)
                         .build();
@@ -96,36 +104,136 @@ public class WeChatPayController {
         // 3. 构造统一下单请求
         PrepayRequest request = new PrepayRequest();
         Amount amount = new Amount();
-        amount.setTotal(1); // 金额,单位:分
+        amount.setTotal(req.getTotalAmount()); // 金额,单位:分
         request.setAmount(amount);
-        request.setSpAppid("wx0fe6b44ff9e5d4d6");
-        request.setSpMchid(merchantId);
-        request.setSubAppid("wx0fe6b44ff9e5d4d6");
-        request.setSpMchid("1739815694");
-        request.setDescription("测试商品");
-        request.setNotifyUrl("https://47.112.126.153:48080//pay/wx/callback");
-        request.setOutTradeNo("OUT_TRADE_NO_20250303_001");
+        request.setSpAppid(wechatMiniPayRequestInfoDO.getSpAppid());
+        request.setSpMchid(wechatMiniPayRequestInfoDO.getSpMchid());
+        request.setSubAppid(wechatMiniPayRequestInfoDO.getSubAppid());
+        request.setSubMchid(wechatMiniPayRequestInfoDO.getSubMchid());
+        request.setDescription(description);
+        request.setNotifyUrl(wechatMiniPayRequestInfoDO.getNotifyUrl());
+        request.setOutTradeNo(outTradeNo);
+        request.setAttach("{}");
 
         Payer payer = new Payer();
-        payer.setSpOpenid("omRZq10rC8JR5SysFqVj82CJDqVk"); // 必须传入用户的openid
+        payer.setSpOpenid(openId); // 必须传入用户的openid
         request.setPayer(payer);
         String requestPaymentAppid = request.getSubAppid() != null ? request.getSubAppid() : request.getSpAppid();
         // 4. 调用扩展方法,直接得到前端调起支付所需的参数
         PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request,requestPaymentAppid);
 
         // 5. 输出或返回给前端
-        System.out.println("package: " + response.getPackageVal());
-        System.out.println("nonceStr: " + response.getNonceStr());
-        System.out.println("timeStamp: " + response.getTimeStamp());
-        System.out.println("signType: " + response.getSignType());
-        System.out.println("paySign: " + response.getPaySign());
-        return CommonResult.success("ok");
+        JSONObject result = new JSONObject();
+        result.put("package",response.getPackageVal());
+        result.put("nonceStr",response.getNonceStr());
+        result.put("timeStamp",response.getTimeStamp());
+        result.put("signType",response.getSignType());
+        result.put("paySign",response.getPaySign());
+        result.put("outTradeNo",outTradeNo);
+        return CommonResult.success(result);
     }
     @PostMapping(value = "/callback", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE})
     @PermitAll
     @TenantIgnore
-    public CommonResult<String> weChatPayCallBack(){
-        System.out.println("wechat callback");
-        return CommonResult.success("callBackOk");
+    public String weChatPayCallBack(HttpServletRequest request){
+        try {
+            // 1. 读取请求体
+            String requestBody = getRequestBody(request);
+            // 2. 获取请求头
+            String wechatPaySerial = request.getHeader("Wechatpay-Serial");
+            String wechatpayNonce = request.getHeader("Wechatpay-Nonce");
+            String wechatTimestamp = request.getHeader("Wechatpay-Timestamp");
+            String wechatSignature = request.getHeader("Wechatpay-Signature");
+            // 3. 构建 RequestParam
+            com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder()
+                    .serialNumber(wechatPaySerial)
+                    .nonce(wechatpayNonce)
+                    .signature(wechatSignature)
+                    .timestamp(wechatTimestamp)
+                    .body(requestBody)
+                    .build();
+            // 4. 构建 RSAPublicKeyNotificationConfig
+            NotificationConfig config = new RSAPublicKeyNotificationConfig.Builder()
+                    .publicKey(publicKey)      // 微信支付公钥字符串
+                    .publicKeyId(publicKeyId)     // 公钥ID(必须)
+                    .apiV3Key(apiV3Key)                // APIv3密钥
+                    .build();
+            // 5. 初始化解析器
+            NotificationParser parser = new NotificationParser(config);
+            // 6. 验签并解密,直接转换为 Transaction 对象(微信支付订单对象)
+            Transaction transaction = parser.parse(requestParam, Transaction.class);
+            // 9. 获取订单关键信息
+            String outTradeNo = transaction.getOutTradeNo();   // 商户订单号
+            String transactionId = transaction.getTransactionId(); // 微信支付订单号
+            Transaction.TradeStateEnum tradeState = transaction.getTradeState(); // 支付状态
+            // 其他字段请参考 Transaction 类
+            log.info("支付回调成功: outTradeNo={}, transactionId={}, tradeState={}",
+                    outTradeNo, transactionId, tradeState);
+
+            // 9. 业务处理(幂等更新订单)
+            boolean success = processOrder(outTradeNo, transactionId, tradeState, transaction);
+            if (!success) {
+                return "FAIL";
+            }
+            // 10. 返回 SUCCESS
+            return "SUCCESS";
+
+        } catch (Exception e) {
+            log.error("回调处理异常", e);
+            return "FAIL";
+        }
+    }
+
+    /**
+     * 生成订单号格式:OUT_TRADE_NO_yyyyMMdd_HHmmssSSS + 两位随机数
+     * 例如:OUT_TRADE_NO_20250303_14353012345
+     */
+    private String generateOrderNo() {
+        LocalDateTime now = LocalDateTime.now();
+        String datePart = now.format(DATE_FORMATTER);
+        String timePart = now.format(TIME_FORMATTER); // 精确到毫秒(3位)
+        int randomSuffix = ThreadLocalRandom.current().nextInt(100); // 0-99 两位
+        return PREFIX + datePart + "_" + timePart + String.format("%02d", randomSuffix);
+    }
+
+    private String insertMiniOrder(WechatMiniOrderDO wechatMiniOrderDO){
+        if(CollectionUtils.isEmpty(wechatMiniOrderDO.getItems())){
+            throw exceptionCustomMsg(ErrorCodeConstants.COMMON_ERROR,"明细不能为空");
+        }
+        StringBuilder description = new StringBuilder();
+        wechatMiniOrderDO.setStatus(0);
+        wechatMiniOrderMapper.insert(wechatMiniOrderDO);
+        List<WechatMiniOrderItemDO> items = wechatMiniOrderDO.getItems();
+        for (WechatMiniOrderItemDO item : items) {
+            item.setOrderId(wechatMiniOrderDO.getId());
+            description.append(item.getGoodsName()).append(",数量:").append(item.getQuantity())
+                    .append(",单价:").append(item.getPrice())
+                    .append(",金额:").append(item.getAmount()).append("。");
+        }
+        wechatMiniOrderItemMapper.insertBatch(items);
+        return description.toString();
+    }
+
+    /**
+     * 从 HttpServletRequest 中读取请求体(原始字符串)
+     */
+    private String getRequestBody(HttpServletRequest request) throws IOException {
+        try (BufferedReader reader = request.getReader()) {
+            return reader.lines().collect(Collectors.joining(System.lineSeparator()));
+        }
+    }
+
+    private boolean processOrder(String outTradeNo, String transactionId, Transaction.TradeStateEnum tradeState, Transaction transaction) {
+        try {
+            if(tradeState.equals(Transaction.TradeStateEnum.SUCCESS)){
+                wechatMiniOrderMapper.update(new LambdaUpdateWrapper<WechatMiniOrderDO>()
+                        .eq(WechatMiniOrderDO::getOutTradeNo,outTradeNo)
+                        .set(WechatMiniOrderDO::getStatus,1));
+            }
+            return true; // 成功返回 true
+        } catch (Exception e) {
+            log.error("业务处理失败", e);
+            return false;
+        }
     }
 }

+ 0 - 167
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/pay/vo/WechatUnifiedOrderRequest.java

@@ -1,167 +0,0 @@
-package cn.iocoder.yudao.module.system.controller.admin.pay.vo;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import lombok.Data;
-
-import java.util.List;
-
-/**
- * 微信支付统一下单请求体(APIv3 全球接口)
- * 对应接口:POST /v3/global/transactions/jsapi
- * 文档参考:https://pay.weixin.qq.com/doc/global/v3/zh/api/jsapi/orders.html
- */
-@Data
-public class WechatUnifiedOrderRequest {
-
-    /** 服务商应用ID(必填) */
-    @JsonProperty("sp_appid")
-    private String spAppid;
-
-    /** 服务商商户号(必填) */
-    @JsonProperty("sp_mchid")
-    private String spMchid;
-
-    /** 子商户号(必填) */
-    @JsonProperty("sub_mchid")
-    private String subMchid;
-
-    /** 子商户应用ID(若传入sub_mchid,该字段必填) */
-    @JsonProperty("sub_appid")
-    private String subAppid;
-
-    /** 商户订单号(必填,商户系统内部唯一) */
-    @JsonProperty("out_trade_no")
-    private String outTradeNo;
-
-    /** 商户类别码(必填,如:1011 代表餐饮) */
-    @JsonProperty("merchant_category_code")
-    private String merchantCategoryCode;
-
-    /** 支付者信息(必填) */
-    private Payer payer;
-
-    /** 通知地址(必填,用于接收支付结果回调) */
-    @JsonProperty("notify_url")
-    private String notifyUrl;
-
-    /** 交易类型(必填,JSAPI 代表公众号/小程序支付) */
-    @JsonProperty("trade_type")
-    private String tradeType;
-
-    /** 订单金额信息(必填) */
-    private Amount amount;
-
-    /** 附加数据(选填,在查询API和支付通知中原样返回) */
-    private String attach;
-
-    /** 商品描述(必填) */
-    private String description;
-
-    /** 商品详情(选填) */
-    private Detail detail;
-
-    /** 场景信息(选填) */
-    @JsonProperty("scene_info")
-    private SceneInfo sceneInfo;
-
-    // ---------- 内部类 ----------
-
-    /**
-     * 支付者信息
-     */
-    @Data
-    public static class Payer {
-        /** 用户在子商户appid下的唯一标识(必填) */
-        @JsonProperty("sub_openid")
-        private String subOpenid;
-    }
-
-    /**
-     * 订单金额
-     */
-    @Data
-    public static class Amount {
-        /** 总金额(单位:分,必填) */
-        private int total;
-
-        /** 货币类型(符合ISO 4217的三位字母代码,如CNY、HKD,必填) */
-        private String currency;
-    }
-
-    /**
-     * 商品详情
-     */
-    @Data
-    public static class Detail {
-        /** 订单原价(单位:分,选填) */
-        @JsonProperty("cost_price")
-        private int costPrice;
-
-        /** 商品小票ID(选填) */
-        @JsonProperty("receipt_id")
-        private String receiptId;
-
-        /** 商品列表(选填) */
-        @JsonProperty("goods_detail")
-        private List<GoodsDetail> goodsDetail;
-    }
-
-    /**
-     * 单品信息
-     */
-    @Data
-    public static class GoodsDetail {
-        /** 商品编码(必填) */
-        @JsonProperty("goods_id")
-        private String goodsId;
-
-        /** 微信支付商品编码(选填) */
-        @JsonProperty("wxpay_goods_id")
-        private String wxpayGoodsId;
-
-        /** 商品名称(选填) */
-        @JsonProperty("goods_name")
-        private String goodsName;
-
-        /** 商品数量(必填) */
-        private int quantity;
-
-        /** 商品单价(单位:分,必填) */
-        private int price;
-    }
-
-    /**
-     * 场景信息
-     */
-    @Data
-    public static class SceneInfo {
-        /** 用户终端IP(必填) */
-        @JsonProperty("payer_client_ip")
-        private String payerClientIp;
-
-        /** 商户端设备IP(选填) */
-        @JsonProperty("device_ip")
-        private String deviceIp;
-
-        /** 商户端设备号(选填) */
-        @JsonProperty("device_id")
-        private String deviceId;
-
-        /** 操作员ID(选填) */
-        @JsonProperty("operator_id")
-        private String operatorId;
-
-        /** 门店信息(选填) */
-        @JsonProperty("store_info")
-        private StoreInfo storeInfo;
-    }
-
-    /**
-     * 门店信息
-     */
-    @Data
-    public static class StoreInfo {
-        /** 门店ID(选填) */
-        private String id;
-    }
-}

+ 7 - 21
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/biz/ElderlyConsumerVouchersDO.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.system.dal.dataobject.biz;
 
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseNoDeleteDO;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.KeySequence;
 import com.baomidou.mybatisplus.annotation.TableField;
@@ -24,7 +25,7 @@ import java.util.Date;
 @Builder
 @NoArgsConstructor
 @AllArgsConstructor
-public class ElderlyConsumerVouchersDO {
+public class ElderlyConsumerVouchersDO extends BaseNoDeleteDO {
 
     @TableId(value = "id", type = IdType.AUTO)
     private Long id;
@@ -35,6 +36,11 @@ public class ElderlyConsumerVouchersDO {
     private Long elderId;
 
     /**
+     * 账单id
+     */
+    private Long orderId;
+
+    /**
      * 长者姓名(联表字段)
      */
     @TableField(exist = false)
@@ -86,24 +92,4 @@ public class ElderlyConsumerVouchersDO {
      * 租户ID
      */
     private Long tenantId;
-
-    /**
-     * 创建时间
-     */
-    private Date createdTime;
-
-    /**
-     * 更新时间
-     */
-    private Date updateTime;
-
-    /**
-     * 创建人
-     */
-    private String creator;
-
-    /**
-     * 更新人
-     */
-    private String updater;
 }

+ 88 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/miniapp/MiniAppUserDO.java

@@ -0,0 +1,88 @@
+package cn.iocoder.yudao.module.system.dal.dataobject.miniapp;
+
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * 小程序用户 DO
+ */
+@TableName("user_v2")
+@KeySequence("user_v2_seq")
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class MiniAppUserDO {
+
+    /**
+     * 用户ID(主键)
+     */
+    @TableId
+    private Long id;
+
+    /**
+     * 微信小程序 OpenID
+     */
+    private String openId;
+
+    /**
+     * 公众号 OpenID(关注了公众号)
+     */
+    private String mpOpenId;
+
+    /**
+     * 微信开放平台 UnionID
+     */
+    private String unionId;
+
+    /**
+     * 家属姓名
+     */
+    private String name;
+
+    /**
+     * 手机号码(带国际区号)
+     */
+    private String phone;
+
+    /**
+     * 用户角色:RELATIVE/EMPLOYEE/VISITOR/BOSS/ORGADMIN/YKVERIFIER/NURSE
+     */
+    private String role;
+
+    /**
+     * 账号状态(1新用户未绑定机构 2已绑定机构 0冻结)
+     */
+    private Integer status;
+
+    /**
+     * employee 身份证号
+     */
+    private String idCard;
+
+    /**
+     * employee 所属机构 id
+     */
+    private Integer orgId;
+
+    /**
+     * 创建时间
+     */
+    @TableField("created_at")
+    private LocalDateTime createdAt;
+
+    /**
+     * 更新时间
+     */
+    @TableField("updated_at")
+    private LocalDateTime updatedAt;
+}
+

+ 71 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/pay/WechatMiniOrderDO.java

@@ -0,0 +1,71 @@
+package cn.iocoder.yudao.module.system.dal.dataobject.pay;
+
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 微信小程序支付订单 DO
+ */
+@TableName("wechat_mini_order")
+@KeySequence("wechat_mini_order_seq")
+@Data
+@ToString
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WechatMiniOrderDO {
+
+    /**
+     * id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 订单号
+     */
+    private String outTradeNo;
+    /**
+     * 电话
+     */
+    private String phone;
+    /**
+     * 总金额,分
+     */
+    private Integer totalAmount;
+    /**
+     * 状态,0:未支付,1:已支付
+     */
+    private Integer status;
+    /**
+     * 机构 id
+     */
+    private Long tenantId;
+    /**
+     * 备注
+     */
+    private String remarks;
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+    /**
+     * 修改时间
+     */
+    private LocalDateTime updateTime;
+    /**
+     * 明细
+     */
+    @TableField(exist = false)
+    private List<WechatMiniOrderItemDO> items;
+}
+

+ 54 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/pay/WechatMiniOrderItemDO.java

@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.module.system.dal.dataobject.pay;
+
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+/**
+ * 微信小程序支付订单明细 DO
+ */
+@TableName("wechat_mini_order_item")
+@KeySequence("wechat_mini_order_item_seq")
+@Data
+@ToString
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WechatMiniOrderItemDO {
+
+    /**
+     * id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 订单 id
+     */
+    private Long orderId;
+    /**
+     * 商品名称
+     */
+    private String goodsName;
+    /**
+     * 单价,分
+     */
+    private Integer price;
+    /**
+     * 数量
+     */
+    private Integer quantity;
+    /**
+     * 金额
+     */
+    private Long amount;
+    /**
+     * 机构 id
+     */
+    private Long tenantId;
+}
+

+ 56 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/pay/WechatMiniPayRequestInfoDO.java

@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.system.dal.dataobject.pay;
+
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * 微信小程序请求支付信息 DO
+ */
+@TableName("wechat_mini_pay_request_info")
+@KeySequence("wechat_mini_pay_request_info_seq")
+@Data
+@ToString
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WechatMiniPayRequestInfoDO {
+
+    private Long id;
+    /**
+     * 机构id
+     */
+    private Long tenantId;
+    /**
+     * 状态,0:禁用,1:启用
+     */
+    private Integer status;
+    /**
+     * 商户私钥字符串
+     */
+    private String privateKey;
+    /**
+     * 证书PEM字符串
+     */
+    private String certPem;
+    /**
+     * 主商户appid
+     */
+    private String spAppid;
+    /**
+     * 主商户商户号
+     */
+    private String spMchid;
+    /**
+     * 子商户appid
+     */
+    private String subAppid;
+    /**
+     * 子商户商户号
+     */
+    private String subMchid;
+    /**
+     * 回调地址
+     */
+    private String notifyUrl;
+}

+ 36 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/restaurant/CateringPlanItemDO.java

@@ -75,5 +75,41 @@ public class CateringPlanItemDO {
      */
     @Schema(description = "周日餐谱")
     private String sunday;
+    /**
+     * 周一可选
+     */
+    @Schema(description = "周一可选")
+    private String mondayExtra;
+    /**
+     * 周二可选
+     */
+    @Schema(description = "周二可选")
+    private String tuesdayExtra;
+    /**
+     * 周三可选
+     */
+    @Schema(description = "周三可选")
+    private String wednesdayExtra;
+    /**
+     * 周四可选
+     */
+    @Schema(description = "周四可选")
+    private String thursdayExtra;
+    /**
+     * 周五可选
+     */
+    @Schema(description = "周五可选")
+    private String fridayExtra;
+    /**
+     * 周六可选
+     */
+    @Schema(description = "周六可选")
+    private String saturdayExtra;
+    /**
+     * 周日可选
+     */
+    @Schema(description = "周日可选")
+    private String sundayExtra;
+
 
 }

+ 18 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/miniapp/MiniAppUserMapper.java

@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.system.dal.mysql.miniapp;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.system.dal.dataobject.miniapp.MiniAppUserDO;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface MiniAppUserMapper extends BaseMapperX<MiniAppUserDO> {
+
+    default MiniAppUserDO selectByOpenId(String openId) {
+        return selectOne(MiniAppUserDO::getOpenId, openId);
+    }
+
+    default MiniAppUserDO selectByPhone(String phone) {
+        return selectOne(MiniAppUserDO::getPhone, phone);
+    }
+}
+

+ 10 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/pay/WechatMiniOrderItemMapper.java

@@ -0,0 +1,10 @@
+package cn.iocoder.yudao.module.system.dal.mysql.pay;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.system.dal.dataobject.pay.WechatMiniOrderItemDO;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface WechatMiniOrderItemMapper extends BaseMapperX<WechatMiniOrderItemDO> {
+}
+

+ 10 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/pay/WechatMiniOrderMapper.java

@@ -0,0 +1,10 @@
+package cn.iocoder.yudao.module.system.dal.mysql.pay;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.system.dal.dataobject.pay.WechatMiniOrderDO;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface WechatMiniOrderMapper extends BaseMapperX<WechatMiniOrderDO> {
+}
+

+ 9 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/pay/WechatMiniPayRequestInfoMapper.java

@@ -0,0 +1,9 @@
+package cn.iocoder.yudao.module.system.dal.mysql.pay;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.system.dal.dataobject.pay.WechatMiniPayRequestInfoDO;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface WechatMiniPayRequestInfoMapper extends BaseMapperX<WechatMiniPayRequestInfoDO> {
+}

+ 9 - 4
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ElderlyConsumerVouchersServiceImpl.java

@@ -22,6 +22,7 @@ import javax.annotation.Resource;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.time.LocalDate;
+import java.time.YearMonth;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeParseException;
 import java.util.Date;
@@ -49,7 +50,6 @@ public class ElderlyConsumerVouchersServiceImpl implements ElderlyConsumerVouche
     @Override
     public Long create(ElderlyConsumerVouchersDO createReqVO) {
         validateBillingMonth(createReqVO.getBillingMonth());
-        createReqVO.setCreatedTime(new Date());
         elderlyConsumerVouchersMapper.insert(createReqVO);
         updateExpenseOrder(createReqVO);
         return createReqVO.getId();
@@ -89,21 +89,22 @@ public class ElderlyConsumerVouchersServiceImpl implements ElderlyConsumerVouche
         ExpenseOrderDO expenseOrder = expenseOrderMapper.selectOne(new LambdaQueryWrapperX<ExpenseOrderDO>()
                 .eq(ExpenseOrderDO::getElderId, createReqVO.getElderId())
                 .eq(ExpenseOrderDO::getIsShow, true)
+                .ne(ExpenseOrderDO::getPayStatus, 1)
                 .eq(ExpenseOrderDO::getBillingMonth, createReqVO.getBillingMonth())
-                .eq(ExpenseOrderDO::getType, 2));
+                .in(ExpenseOrderDO::getType, 1,2));
 
         if (expenseOrder == null) {
             return;
         }
-
+        YearMonth yearMonth = YearMonth.parse(createReqVO.getBillingMonth(), DateTimeFormatter.ofPattern("yyyy-MM"));
         validateExpenseOrderNotConfirmedAndNotLock(expenseOrder);
-
         ExpenseOrderItemDO orderItem = new ExpenseOrderItemDO();
         orderItem.setExpenseOrderId(expenseOrder.getId());
         orderItem.setSourceExpenseItemId(createReqVO.getId());
         orderItem.setExpenseSource(BusinessConstants.CONSUMER_VOUCHER);
         orderItem.setCount(1);
         orderItem.setItemName("消费券抵扣");
+        orderItem.setItemCategoryName("消费券");
         orderItem.setPrice(createReqVO.getAmount().negate());
         orderItem.setActualPrice(createReqVO.getAmount().negate());
         orderItem.setTotalAmount(createReqVO.getAmount().negate());
@@ -111,8 +112,11 @@ public class ElderlyConsumerVouchersServiceImpl implements ElderlyConsumerVouche
         orderItem.setRoundTwoDecimalAmount(orderItem.getTotalAmount().setScale(2, RoundingMode.HALF_UP));
         orderItem.setCreatedTime(new Date());
         orderItem.setCreatedBy(SecurityFrameworkUtils.getLoginUserNickname());
+        orderItem.setStartDate(yearMonth.atDay(1));
+        orderItem.setEndDate(yearMonth.atEndOfMonth());
         orderItem.setTenantId(createReqVO.getTenantId());
         orderItem.setPayStatus(0);
+        orderItem.setDescription(yearMonth+"消费券抵扣");
         expenseOrderItemMapper.insert(orderItem);
 
         BigDecimal currentAmount = expenseOrder.getActualAmount() != null ? expenseOrder.getActualAmount() : BigDecimal.ZERO;
@@ -121,6 +125,7 @@ public class ElderlyConsumerVouchersServiceImpl implements ElderlyConsumerVouche
 
         createReqVO.setStatus(1);
         createReqVO.setOrderNumber(expenseOrder.getBillOrderNumber());
+        createReqVO.setOrderId(expenseOrder.getId());
         elderlyConsumerVouchersMapper.updateById(createReqVO);
     }
 

+ 25 - 2
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ExpenseOrderServiceImpl.java

@@ -158,6 +158,9 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
     @Autowired
     private ElderlyTempOutMapper elderlyTempOutMapper;
 
+    @Autowired
+    private ElderlyConsumerVouchersMapper elderlyConsumerVouchersMapper;
+
     @Override
     public PageResult<ExpenseOrderDO> getExpenseBillPage(ExpenseBillPageReqVO pageReqVO) {
         Page<ExpenseOrderDO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
@@ -371,8 +374,7 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
                 List<ExpenseSubsidyDO> expenseSubsidyList = expenseSubsidyMapper.selectList(new LambdaQueryWrapperX<ExpenseSubsidyDO>()
                         .eq(ExpenseSubsidyDO::getDeductionBillMonth, expenseOrder.getBillingMonth())
                         .eq(ExpenseSubsidyDO::getElderId, expenseOrder.getElderId())
-                        .eq(ExpenseSubsidyDO::getStatus, BooleanEnum.FALSE.getValue())
-                );
+                        .eq(ExpenseSubsidyDO::getStatus, BooleanEnum.FALSE.getValue()));
                 if (CollectionUtil.isNotEmpty(expenseSubsidyList)) {
                     for (ExpenseSubsidyDO expenseSubsidyDO : expenseSubsidyList) {
                         expenseSubsidyDO.setStatus(BooleanEnum.TRUE.getValue());
@@ -386,6 +388,19 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
                     expenseSubsidyAccountMapper.updateById(expenseSubsidyAccountDO);
                 }
             }
+            if(item.getPayType().equals(BusinessConstants.CONSUMER_VOUCHER)){
+                // 查询对应的月份账消费券
+                List<ElderlyConsumerVouchersDO> consumerVouchersDOList = elderlyConsumerVouchersMapper.selectList(new LambdaQueryWrapperX<ElderlyConsumerVouchersDO>()
+                        .eq(ElderlyConsumerVouchersDO::getBillingMonth, expenseOrder.getBillingMonth())
+                        .eq(ElderlyConsumerVouchersDO::getElderId, expenseOrder.getElderId())
+                        .eq(ElderlyConsumerVouchersDO::getReturnStatus, BooleanEnum.FALSE.getValue()));
+                if (CollectionUtil.isNotEmpty(consumerVouchersDOList)) {
+                    for (ElderlyConsumerVouchersDO consumerVouchersDO : consumerVouchersDOList) {
+                        consumerVouchersDO.setReturnStatus(BooleanEnum.TRUE.getValue());
+                    }
+                    elderlyConsumerVouchersMapper.updateBatch(consumerVouchersDOList);
+                }
+            }
 
             //判断是否使用了账户会员卡进行支付
             if (item.getPayType().equals(BusinessConstants.MEMBER_CARD)) {
@@ -492,6 +507,14 @@ public class ExpenseOrderServiceImpl implements ExpenseOrderService {
                     expenseSubsidyMapper.updateById(expenseSubsidyDO);
                 }
             }
+            if (expenseOrderItem.getExpenseSource().equals(BusinessConstants.CONSUMER_VOUCHER)) {
+                //修改长期护理保险缴费状态
+                ElderlyConsumerVouchersDO consumerVouchersDO = elderlyConsumerVouchersMapper.selectById(expenseOrderItem.getSourceExpenseItemId());
+                if (consumerVouchersDO != null) {
+                    consumerVouchersDO.setReturnStatus(BooleanEnum.TRUE.getValue());
+                    elderlyConsumerVouchersMapper.updateById(consumerVouchersDO);
+                }
+            }
 
             //生成押金缴费记录
             ExpenseItemDO expenseItemDO = expenseItemMapper.selectById(expenseOrderItem.getSourceExpenseItemId());

+ 133 - 19
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/MaterialIoServiceImpl.java

@@ -263,7 +263,11 @@ public class MaterialIoServiceImpl implements MaterialIoService {
     private Long createInboundOrderWithPrefix(MaterialIoOrderSaveReqVO createReqVO, String prefixType) {
         // 1. 创建入库单主表
         MaterialInboundOrderDO order = BeanUtils.toBean(createReqVO, MaterialInboundOrderDO.class);
-        order.setOrderNo(orderNoGenerator.generate(prefixType, createReqVO.getOrderDate()));
+        if (StringUtils.isNotBlank(createReqVO.getOrderNo())) {
+            order.setOrderNo(createReqVO.getOrderNo().trim());
+        } else {
+            order.setOrderNo(orderNoGenerator.generate(prefixType, createReqVO.getOrderDate()));
+        }
         if (order.getStatus() == null) {
             order.setStatus(1); // 默认草稿
         }
@@ -2342,7 +2346,7 @@ public class MaterialIoServiceImpl implements MaterialIoService {
         for (MaterialInboundImportExcelVO row : rows) {
             rowNum++;
             if (StringUtils.isBlank(row.getOrderNo())) {
-                ImportUtil.addFailure(failures, rowNum, null, row.getMaterialId() == null ? null : String.valueOf(row.getMaterialId()), "单号不能为空");
+                ImportUtil.addFailure(failures, rowNum, null, null, "入库单号不能为空");
                 continue;
             }
             grouped.computeIfAbsent(row.getOrderNo().trim(), k -> new ArrayList<>()).add(row);
@@ -2350,7 +2354,10 @@ public class MaterialIoServiceImpl implements MaterialIoService {
 
         for (Map.Entry<String, List<MaterialInboundImportExcelVO>> entry : grouped.entrySet()) {
             try {
-                inbound(buildInboundReq(entry.getValue()));
+                if (existsInboundOrderNo(entry.getKey())) {
+                    throw new IllegalArgumentException("入库单号已存在,不允许重复导入");
+                }
+                inbound(buildInboundReq(entry.getKey(), entry.getValue()));
                 success++;
             } catch (Exception e) {
                 ImportUtil.addFailure(failures, null, null, entry.getKey(), e.getMessage(), e);
@@ -2371,7 +2378,7 @@ public class MaterialIoServiceImpl implements MaterialIoService {
         for (MaterialOutboundImportExcelVO row : rows) {
             rowNum++;
             if (StringUtils.isBlank(row.getOrderNo())) {
-                ImportUtil.addFailure(failures, rowNum, null, row.getMaterialId() == null ? null : String.valueOf(row.getMaterialId()), "单据号不能为空");
+                ImportUtil.addFailure(failures, rowNum, null, null, "单据号不能为空");
                 continue;
             }
             grouped.computeIfAbsent(row.getOrderNo().trim(), k -> new ArrayList<>()).add(row);
@@ -2379,6 +2386,9 @@ public class MaterialIoServiceImpl implements MaterialIoService {
 
         for (Map.Entry<String, List<MaterialOutboundImportExcelVO>> entry : grouped.entrySet()) {
             try {
+                if (existsOutboundOrderNo(entry.getKey())) {
+                    throw new IllegalArgumentException("出库单号已存在,不允许重复导入");
+                }
                 outbound(buildOutboundReq(entry.getValue()));
                 success++;
             } catch (Exception e) {
@@ -2388,13 +2398,14 @@ public class MaterialIoServiceImpl implements MaterialIoService {
         return ImportUtil.buildResult(success, failures);
     }
 
-    private MaterialIoOrderSaveReqVO buildInboundReq(List<MaterialInboundImportExcelVO> groupRows) {
+    private MaterialIoOrderSaveReqVO buildInboundReq(String orderNo, List<MaterialInboundImportExcelVO> groupRows) {
         MaterialInboundImportExcelVO head = groupRows.get(0);
         if (head.getOrderDate() == null) {
             throw new IllegalArgumentException("单据日期不能为空");
         }
         MaterialIoOrderSaveReqVO reqVO = new MaterialIoOrderSaveReqVO();
         reqVO.setBizType("IN");
+        reqVO.setOrderNo(orderNo);
         reqVO.setOrderDate(head.getOrderDate());
         reqVO.setRemark(head.getRemark());
         reqVO.setTenantId(TenantContextHolder.getTenantId());
@@ -2407,12 +2418,15 @@ public class MaterialIoServiceImpl implements MaterialIoService {
             if (!Objects.equals(StringUtils.trimToEmpty(head.getRemark()), StringUtils.trimToEmpty(row.getRemark()))) {
                 throw new IllegalArgumentException("同单号的备注必须一致");
             }
-            if (row.getMaterialId() == null || row.getQuantity() == null || row.getQuantity() <= 0) {
-                throw new IllegalArgumentException("入库明细物资ID与数量必须填写且数量大于0");
+            if (row.getQuantity() == null || row.getQuantity() <= 0) {
+                throw new IllegalArgumentException("入库明细数量必须填写且数量大于0");
             }
+            Long materialId = resolveMaterialId(row.getMaterialNumber(), null);
+            Long storeId = resolveStoreId(row.getRefInStoreNumber(), null);
+
             MaterialIoOrderItemSaveReqVO item = new MaterialIoOrderItemSaveReqVO();
-            item.setMaterialId(row.getMaterialId());
-            item.setRefInStoreId(row.getRefInStoreId());
+            item.setMaterialId(materialId);
+            item.setRefInStoreId(storeId);
             item.setQuantity(row.getQuantity());
             item.setInUnitPrice(row.getInUnitPrice());
             item.setAmount(row.getAmount());
@@ -2428,13 +2442,13 @@ public class MaterialIoServiceImpl implements MaterialIoService {
         if (head.getOrderDate() == null) {
             throw new IllegalArgumentException("单据日期不能为空");
         }
-        if (head.getOutDeptId() == null) {
-            throw new IllegalArgumentException("领用部门ID不能为空");
-        }
+
+        Long outDeptId = resolveDeptId(head.getOutDeptNumber(), head.getOutDeptName());
+
         MaterialIoOrderSaveReqVO reqVO = new MaterialIoOrderSaveReqVO();
         reqVO.setBizType("OUT");
         reqVO.setOrderDate(head.getOrderDate());
-        reqVO.setOutDeptId(head.getOutDeptId());
+        reqVO.setOutDeptId(outDeptId);
         reqVO.setOutUser(head.getOutUser());
         reqVO.setOutReason(head.getOutReason());
         reqVO.setRemark(head.getRemark());
@@ -2445,8 +2459,9 @@ public class MaterialIoServiceImpl implements MaterialIoService {
             if (!Objects.equals(head.getOrderDate(), row.getOrderDate())) {
                 throw new IllegalArgumentException("同单号的单据日期必须一致");
             }
-            if (!Objects.equals(head.getOutDeptId(), row.getOutDeptId())) {
-                throw new IllegalArgumentException("同单号的领用部门ID必须一致");
+            if (!Objects.equals(StringUtils.trimToEmpty(head.getOutDeptNumber()), StringUtils.trimToEmpty(row.getOutDeptNumber()))
+                    || !Objects.equals(StringUtils.trimToEmpty(head.getOutDeptName()), StringUtils.trimToEmpty(row.getOutDeptName()))) {
+                throw new IllegalArgumentException("同单号的领用部门必须一致");
             }
             if (!Objects.equals(StringUtils.trimToEmpty(head.getOutUser()), StringUtils.trimToEmpty(row.getOutUser()))) {
                 throw new IllegalArgumentException("同单号的领用人必须一致");
@@ -2457,12 +2472,16 @@ public class MaterialIoServiceImpl implements MaterialIoService {
             if (!Objects.equals(StringUtils.trimToEmpty(head.getRemark()), StringUtils.trimToEmpty(row.getRemark()))) {
                 throw new IllegalArgumentException("同单号的备注必须一致");
             }
-            if (row.getMaterialId() == null || row.getInboundItemId() == null || row.getQuantity() == null || row.getQuantity() <= 0) {
-                throw new IllegalArgumentException("出库明细物资ID、入库批次明细ID、数量必须填写且数量大于0");
+            if (row.getQuantity() == null || row.getQuantity() <= 0) {
+                throw new IllegalArgumentException("出库明细数量必须填写且数量大于0");
             }
+
+            Long materialId = resolveMaterialId(row.getMaterialNumber(), row.getMaterialName());
+            Long inboundItemId = resolveInboundItemId(row.getInboundOrderNo(), materialId);
+
             MaterialIoOrderItemSaveReqVO item = new MaterialIoOrderItemSaveReqVO();
-            item.setMaterialId(row.getMaterialId());
-            item.setInboundItemId(row.getInboundItemId());
+            item.setMaterialId(materialId);
+            item.setInboundItemId(inboundItemId);
             item.setQuantity(row.getQuantity());
             item.setSaleUnitPrice(row.getSaleUnitPrice());
             item.setAmount(row.getAmount());
@@ -2473,6 +2492,101 @@ public class MaterialIoServiceImpl implements MaterialIoService {
         return reqVO;
     }
 
+    private boolean existsInboundOrderNo(String orderNo) {
+        return inboundOrderMapper.selectCount(new LambdaQueryWrapperX<MaterialInboundOrderDO>()
+                .eq(MaterialInboundOrderDO::getOrderNo, orderNo)
+                .eq(MaterialInboundOrderDO::getTenantId, TenantContextHolder.getTenantId())) > 0;
+    }
+
+    private boolean existsOutboundOrderNo(String orderNo) {
+        return outboundOrderMapper.selectCount(new LambdaQueryWrapperX<MaterialOutboundOrderDO>()
+                .eq(MaterialOutboundOrderDO::getOrderNo, orderNo)
+                .eq(MaterialOutboundOrderDO::getTenantId, TenantContextHolder.getTenantId())) > 0;
+    }
+
+    private Long resolveMaterialId(String materialNumber, String materialName) {
+        LambdaQueryWrapperX<MaterialInfoDO> wrapper = new LambdaQueryWrapperX<>();
+        if (StringUtils.isNotBlank(materialNumber)) {
+            wrapper.eq(MaterialInfoDO::getMaterialNumber, materialNumber.trim());
+        } else if (StringUtils.isNotBlank(materialName)) {
+            wrapper.eq(MaterialInfoDO::getMaterialName, materialName.trim());
+        } else {
+            throw new IllegalArgumentException("物资编号和物资名称不能同时为空");
+        }
+        wrapper.eq(MaterialInfoDO::getTenantId, TenantContextHolder.getTenantId());
+        List<MaterialInfoDO> list = materialInfoMapper.selectList(wrapper);
+        if (list.isEmpty()) {
+            throw new IllegalArgumentException("未找到匹配的物资");
+        }
+        if (list.size() > 1) {
+            throw new IllegalArgumentException("匹配到多个物资,请优先填写唯一物资编号");
+        }
+        return list.get(0).getId();
+    }
+
+    private Long resolveStoreId(String storeNumber, String storeName) {
+        LambdaQueryWrapperX<StoreManageDO> wrapper = new LambdaQueryWrapperX<>();
+        if (StringUtils.isNotBlank(storeNumber)) {
+            wrapper.eq(StoreManageDO::getStoreNumber, storeNumber.trim());
+        } else if (StringUtils.isNotBlank(storeName)) {
+            wrapper.eq(StoreManageDO::getStoreName, storeName.trim());
+        } else {
+            throw new IllegalArgumentException("入库仓库编号和名称不能同时为空");
+        }
+        wrapper.eq(StoreManageDO::getTenantId, TenantContextHolder.getTenantId());
+        List<StoreManageDO> list = storeManageMapper.selectList(wrapper);
+        if (list.isEmpty()) {
+            throw new IllegalArgumentException("未找到匹配的仓库");
+        }
+        if (list.size() > 1) {
+            throw new IllegalArgumentException("匹配到多个仓库,请优先填写唯一仓库编号");
+        }
+        return list.get(0).getId();
+    }
+
+    private Long resolveDeptId(String deptNumber, String deptName) {
+        LambdaQueryWrapperX<DeptDO> wrapper = new LambdaQueryWrapperX<>();
+        if (StringUtils.isNotBlank(deptNumber)) {
+            if (!deptNumber.trim().matches("\\d+")) {
+                throw new IllegalArgumentException("领用部门编号必须为数字ID");
+            }
+            wrapper.eq(DeptDO::getId, Long.valueOf(deptNumber.trim()));
+        } else if (StringUtils.isNotBlank(deptName)) {
+            wrapper.eq(DeptDO::getName, deptName.trim());
+        } else {
+            throw new IllegalArgumentException("领用部门编号和名称不能同时为空");
+        }
+        wrapper.eq(DeptDO::getTenantId, TenantContextHolder.getTenantId());
+        List<DeptDO> list = deptMapper.selectList(wrapper);
+        if (list.isEmpty()) {
+            throw new IllegalArgumentException("未找到匹配的领用部门");
+        }
+        if (list.size() > 1) {
+            throw new IllegalArgumentException("匹配到多个领用部门,请优先填写唯一部门编号");
+        }
+        return list.get(0).getId();
+    }
+
+    private Long resolveInboundItemId(String inboundOrderNo, Long materialId) {
+        if (StringUtils.isBlank(inboundOrderNo)) {
+            throw new IllegalArgumentException("关联入库单号不能为空");
+        }
+        MaterialInboundOrderDO inboundOrder = inboundOrderMapper.selectOne(new LambdaQueryWrapperX<MaterialInboundOrderDO>()
+                .eq(MaterialInboundOrderDO::getOrderNo, inboundOrderNo.trim())
+                .eq(MaterialInboundOrderDO::getTenantId, TenantContextHolder.getTenantId()));
+        if (inboundOrder == null) {
+            throw new IllegalArgumentException("未找到关联入库单号: " + inboundOrderNo);
+        }
+        List<MaterialInboundOrderItemDO> items = inboundOrderItemMapper.selectList(new LambdaQueryWrapperX<MaterialInboundOrderItemDO>()
+                .eq(MaterialInboundOrderItemDO::getInboundOrderId, inboundOrder.getId())
+                .eq(MaterialInboundOrderItemDO::getMaterialId, materialId)
+                .orderByDesc(MaterialInboundOrderItemDO::getId));
+        if (items.isEmpty()) {
+            throw new IllegalArgumentException("关联入库单中未找到该物资对应批次");
+        }
+        return items.get(0).getId();
+    }
+
     /**
      * 批量加载物资信息
      */

+ 19 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/miniapp/MiniAppUserService.java

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.system.service.miniapp;
+
+import cn.iocoder.yudao.module.system.dal.dataobject.miniapp.MiniAppUserDO;
+
+/**
+ * 小程序用户 Service
+ */
+public interface MiniAppUserService {
+
+    /**
+     * 根据手机号获取小程序用户信息
+     *
+     * @param phone 手机号
+     * @return 小程序用户信息
+     */
+    MiniAppUserDO getByPhone(String phone);
+
+}
+

+ 25 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/miniapp/MiniAppUserServiceImpl.java

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.system.service.miniapp;
+
+import cn.iocoder.yudao.module.system.dal.dataobject.miniapp.MiniAppUserDO;
+import cn.iocoder.yudao.module.system.dal.mysql.miniapp.MiniAppUserMapper;
+import com.baomidou.dynamic.datasource.annotation.DS;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * 小程序用户 Service 实现类
+ */
+@Service
+@DS("miniapp")
+public class MiniAppUserServiceImpl implements MiniAppUserService {
+
+    @Resource
+    private MiniAppUserMapper miniAppUserMapper;
+
+    @Override
+    public MiniAppUserDO getByPhone(String phone) {
+        return miniAppUserMapper.selectByPhone(phone);
+    }
+}
+

+ 4 - 4
yudao-server/src/main/resources/application-dev.yaml

@@ -46,11 +46,11 @@ spring:
           url: jdbc:mysql://rm-wz9essqqs1wa914b4ko.mysql.rds.aliyuncs.com:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
           username: rdsdev
           password: Yndev@2025
-        slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改
+        miniapp: # 小程序家属端数据库
           lazy: true # 开启懒加载,保证启动速度
-          url: jdbc:mysql://rm-wz9essqqs1wa914b4ko.mysql.rds.aliyuncs.com:3306/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
-          username: rdsdev
-          password: Yndev@2025
+          url: jdbc:mysql://rm-wz9essqqs1wa914b4ko.mysql.rds.aliyuncs.com:3306/yanglao-jiashu?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true # MySQL Connector/J 8.X 连接的示例
+          username: rdsadmin
+          password: Rds@2025
 
   # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
   redis:

+ 17 - 1
yudao-server/src/main/resources/application.yaml

@@ -317,4 +317,20 @@ wechat:
     app-secret: ca7e095bb686187c2894995c782f583d
     templateId: nBzy7Ht9OY5nsmEoVCzJB3BkBB7wZcrK16IuCDnHIRo
   miniapp:
-    app-id: wx0fe6b44ff9e5d4d6
+    app-id: wx0fe6b44ff9e5d4d6
+    pay: #微信支付配置
+      public-key: |
+        -----BEGIN PUBLIC KEY-----
+        MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuh82JjfQ/r0+mz8W9ZAr
+        Uw5nLSSzUKxvepSnWny0a7ccZFB+j8q9pZWq7gmfyOmsC6uq8gmzPDnOD+xrBfj7
+        t8R3x/VU7tpmGtdNecQFTaJ6NrausM82sMVdf9XOpQvERgVtfIO5U1q3jqSfTyNk
+        MchXhQMoWa3RXDl7EO0okLIKoNgA1o4AWZZaVyiJ0BjF/URwk6O0eg+g2PqDldFr
+        RxQIHLsaFnFsDJx5bNia9Jb48g+nNpoKtW1njsPDn/ckTOvnZxdkbkwIaQ2NDli1
+        ehsaDK6ACReD/A6nIlDQB50duKhVNzx10MZwikD2OWAPUnY6rIE9cqWwKUH4okWJ
+        BwIDAQAB
+        -----END PUBLIC KEY-----
+      # 公钥ID(微信支付平台提供的公钥ID,通常是一串数字)
+      public-key-id: "PUB_KEY_ID_0111058353662026030200381966000601"
+      # APIv3密钥(32字节字符串)
+      api-v3-key: "W2sE4rF6tY8uI0oP1aQ2wS3dF4gH5jK6"
+