baolei 7 сар өмнө
parent
commit
a741f0f597
31 өөрчлөгдсөн 1213 нэмэгдсэн , 0 устгасан
  1. 33 0
      08.src/Xingxi/xingxi-common/src/main/java/com/xingxi/common/enums/EInventoryBillType.java
  2. 38 0
      08.src/Xingxi/xingxi-common/src/main/java/com/xingxi/common/enums/EOrderDetailStatus.java
  3. 36 0
      08.src/Xingxi/xingxi-common/src/main/java/com/xingxi/common/enums/EOrderStatus.java
  4. 6 0
      08.src/Xingxi/xingxi-miniprogram-api/pom.xml
  5. 109 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/configuration/AttachRequestIdRequestFilter.java
  6. 53 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/configuration/WXMessageEndpoint.java
  7. 36 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/configuration/WxMpConfiguration.java
  8. 16 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/configuration/WxMpProperties.java
  9. 64 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/configuration/WxSubscribeMessageConsumer.java
  10. 37 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/controller/OrderApiController.java
  11. 26 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/controller/WxLogoutApiController.java
  12. 18 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/data/domain/OrderDTO.java
  13. 20 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/data/domain/OrderDetailDTO.java
  14. 18 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/data/mapper/WxApiProdInventoryMapper.java
  15. 24 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/model/OrderCreateRequest.java
  16. 11 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/model/OrderCreateResponse.java
  17. 15 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/model/OrderItemDTO.java
  18. 14 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/model/OrderQueryRequest.java
  19. 12 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/model/OrderQueryResponse.java
  20. 4 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/model/WxLogoutRequest.java
  21. 4 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/model/WxLogoutResponse.java
  22. 11 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/CacheService.java
  23. 15 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/OrderServiceI.java
  24. 42 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/WXPayServiceI.java
  25. 8 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/WxmaUserServiceI.java
  26. 34 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/impl/GuavaCacheServiceImpl.java
  27. 28 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/impl/MySqlDBCacheServiceImpl.java
  28. 363 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/impl/OrderApiServiceImpl.java
  29. 45 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/impl/WxaMediaCheckWxMaMessageHandlerImpl.java
  30. 35 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/impl/WxmaUserServiceImpl.java
  31. 38 0
      08.src/Xingxi/xingxi-miniprogram-api/src/main/resources/META-INF/sqlmap/WxApiProdInventoryMapper.xml

+ 33 - 0
08.src/Xingxi/xingxi-common/src/main/java/com/xingxi/common/enums/EInventoryBillType.java

@@ -0,0 +1,33 @@
+package com.xingxi.common.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @program: xingxi
+ * @description: 库存流水分类
+ * @author: bao
+ * @create: 2025-04-21
+ */
+@AllArgsConstructor
+@Getter
+public enum EInventoryBillType {
+
+    STOCKIN("stockin", "入库"),
+    STOCKOUT("stockout", "出库"),
+    LOCK("lock", "锁库"),
+    UNLOCK("unlock", "解锁");
+
+    private String val;
+    private String desc;
+
+    /** 解析 */
+    public static EInventoryBillType parseByVal(String val) {
+        for(EInventoryBillType type : EInventoryBillType.values()) {
+            if(type.getVal().equalsIgnoreCase(val)) {
+                return type;
+            }
+        }
+        return EInventoryBillType.STOCKIN;
+    }
+}

+ 38 - 0
08.src/Xingxi/xingxi-common/src/main/java/com/xingxi/common/enums/EOrderDetailStatus.java

@@ -0,0 +1,38 @@
+package com.xingxi.common.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @program: xingxi
+ * @description: 审核状态
+ * @author: bao
+ * @create: 2025-04-21
+ */
+@AllArgsConstructor
+@Getter
+public enum EOrderDetailStatus {
+    SAVED("SAVED", "已保存"),
+    ORDERED("ORDERED", "已下单"),
+    PAYED("PAYED", "已支付"),
+    CANCELLED("CANCELLED", "已取消"),
+    REJECTED("REJECTED", "已驳回"),
+    APPROVED("APPROVED", "已审核"),
+    DELIVERED("DELIVERED", "已发货"),
+    RECEIVED("RECEIVED", "已收货"),
+    FINISHED("FINISHED", "已完成"),
+    AFTERSALES("AFTERSALES", "售后中");
+
+    private String val;
+    private String desc;
+
+    /** 解析 */
+    public static EOrderDetailStatus parseByVal(String val) {
+        for(EOrderDetailStatus type : EOrderDetailStatus.values()) {
+            if(type.getVal().equalsIgnoreCase(val)) {
+                return type;
+            }
+        }
+        return EOrderDetailStatus.ORDERED;
+    }
+}

+ 36 - 0
08.src/Xingxi/xingxi-common/src/main/java/com/xingxi/common/enums/EOrderStatus.java

@@ -0,0 +1,36 @@
+package com.xingxi.common.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @program: xingxi
+ * @description: 审核状态
+ * @author: bao
+ * @create: 2025-04-21
+ */
+@AllArgsConstructor
+@Getter
+public enum EOrderStatus {
+    SAVED("SAVED", "已保存"),
+    ORDERED("ORDERED", "已下单"),
+    PAYED("PAYED", "已支付"),
+    CANCELLED("CANCELLED", "已取消"),
+    DELIVERED("DELIVERED", "已发货"),
+    RECEIVED("RECEIVED", "已收货"),
+    SETTLED("SETTLED", "已结算"),
+    FINISHED("FINISHED", "已完成");
+
+    private String val;
+    private String desc;
+
+    /** 解析 */
+    public static EOrderStatus parseByVal(String val) {
+        for(EOrderStatus type : EOrderStatus.values()) {
+            if(type.getVal().equalsIgnoreCase(val)) {
+                return type;
+            }
+        }
+        return EOrderStatus.ORDERED;
+    }
+}

+ 6 - 0
08.src/Xingxi/xingxi-miniprogram-api/pom.xml

@@ -134,6 +134,12 @@
             <artifactId>thumbnailator</artifactId>
             <version>0.4.16</version>
         </dependency>
+        <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>weixin-java-pay</artifactId>
+            <version>4.5.6.B</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 
     <build>

+ 109 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/configuration/AttachRequestIdRequestFilter.java

@@ -0,0 +1,109 @@
+package com.xingxi.api.configuration;
+
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.config.WxMaConfig;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.xingxi.api.common.ResponseDTO;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcher;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+@Slf4j
+@Component
+@Order(Ordered.HIGHEST_PRECEDENCE)
+@RequiredArgsConstructor
+class AttachRequestIdRequestFilter extends OncePerRequestFilter {
+
+    private final RequestMatcher requestMatcher = new AntPathRequestMatcher("/api/store/**");
+    private final ObjectMapper objectMapper;
+    private final WxMaService maService;
+
+    @Value("${spring.application.request.referers}")
+    private String[] referers;
+
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
+        String uuid = UUID.randomUUID().toString();
+
+
+        if (requestMatcher.matches(request)) {
+
+            String userAgent = request.getHeader("User-Agent");
+            if (!(userAgent != null && userAgent.contains("MicroMessenger"))) {
+                log.debug("User-Agent[" + userAgent + "],请使用微信浏览器");
+                responseFail(uuid, response);
+                return;
+            }
+
+            String referer = request.getHeader("Referer");
+            if (!((referer != null && verifyReferer(referer)) || othersReferer(referer))) {
+                log.debug("Referer[" + referer + "]错误,请求不是来自微信服务器");
+                responseFail(uuid, response);
+                return;
+            }
+
+        }
+
+        ContentCachingRequestWrapper cachingRequestWrapper = new ContentCachingRequestWrapper(request);
+        String requestIdKey = "X-REQUEST-ID";
+
+        try {
+            cachingRequestWrapper.setAttribute(requestIdKey, uuid);
+            MDC.put(requestIdKey, uuid);
+            filterChain.doFilter(cachingRequestWrapper, response);
+        } finally {
+            MDC.remove(requestIdKey);
+        }
+
+
+    }
+
+
+    private void responseFail(String requestId, HttpServletResponse response) {
+        ResponseDTO<Void> responseDTO = new ResponseDTO<>(500);
+        responseDTO.setRequestId(requestId);
+        responseDTO.setMessage("拒绝访问");
+        response.setStatus(500);
+        response.setCharacterEncoding("utf-8");
+        try {
+            response.getWriter().write(objectMapper.writeValueAsString(responseDTO));
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    private boolean othersReferer(String referer){
+        return Arrays.stream(referers).anyMatch(referer::contains);
+    }
+
+    private boolean verifyReferer(String referer) {
+        WxMaConfig wxMaConfig = maService.getWxMaConfig();
+        String appid = wxMaConfig.getAppid();
+        String regEx = String.format("^https://servicewechat.com/%s/([a-zA-Z0-9.]{1,}|devtools)/page-frame.html$", appid);
+        Pattern pattern = Pattern.compile(regEx);
+        Matcher matcher = pattern.matcher(referer);
+        return matcher.matches();
+    }
+
+
+}

+ 53 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/configuration/WXMessageEndpoint.java

@@ -0,0 +1,53 @@
+package com.xingxi.api.configuration;
+
+
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.WxMaMessage;
+import cn.binarywang.wx.miniapp.config.WxMaConfig;
+import cn.binarywang.wx.miniapp.message.WxMaMessageHandler;
+import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
+import cn.binarywang.wx.miniapp.message.WxMaXmlOutMessage;
+import lombok.RequiredArgsConstructor;
+import me.chanjar.weixin.common.api.WxConsts;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+
+@RestController
+@RequestMapping("/wx/message")
+@RequiredArgsConstructor
+public class WXMessageEndpoint {
+    private final WxMaService wxMaService;
+    private final WxMaMessageHandler wxMaMessageHandler;
+
+
+    @PostMapping
+    public String message(HttpServletRequest request, HttpServletResponse response) {
+        WxMaMessageRouter router = new WxMaMessageRouter(wxMaService);
+        router.rule()
+                .msgType(WxConsts.XmlMsgType.EVENT)
+                .event("wxa_media_check")
+                .handler(wxMaMessageHandler)
+                .end();
+
+        WxMaConfig wxMaConfig = wxMaService.getWxMaConfig();
+
+        try {
+            WxMaMessage wxMaMessage = WxMaMessage.fromEncryptedJson(request.getInputStream(), wxMaConfig);
+            WxMaXmlOutMessage route = router.route(wxMaMessage);
+        } catch (IOException e) {
+            e.printStackTrace();
+
+            return "fail";
+        }
+
+        return "success";
+
+    }
+
+}

+ 36 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/configuration/WxMpConfiguration.java

@@ -0,0 +1,36 @@
+package com.xingxi.api.configuration;
+
+import com.google.common.collect.Maps;
+import lombok.AllArgsConstructor;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
+import me.chanjar.weixin.mp.config.WxMpConfigStorage;
+import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Map;
+
+@AllArgsConstructor
+@Configuration
+@EnableConfigurationProperties(WxMpProperties.class)
+public class WxMpConfiguration {
+
+    private final WxMpProperties properties;
+
+    @Bean
+    public WxMpService wxMpService() {
+
+        WxMpService service = new WxMpServiceImpl();
+        WxMpDefaultConfigImpl wxMpDefaultConfig = new WxMpDefaultConfigImpl();
+        wxMpDefaultConfig.setAppId(properties.getAppId());
+        wxMpDefaultConfig.setSecret(properties.getSecret());
+
+        Map<String, WxMpConfigStorage> configMap = Maps.newHashMap();
+        configMap.put(properties.getAppId(),wxMpDefaultConfig);
+        service.setMultiConfigStorages(configMap);
+
+        return service;
+    }
+}

+ 16 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/configuration/WxMpProperties.java

@@ -0,0 +1,16 @@
+package com.xingxi.api.configuration;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@Data
+//@ConfigurationProperties(prefix = "spring.application.biandan.unifiedpay.wxpay")
+@ConfigurationProperties(prefix = "wx.mp")
+public class WxMpProperties {
+
+    // 微信公众号appid.
+    private String appId;
+
+    // 证书序列号
+    private String secret;
+}

+ 64 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/configuration/WxSubscribeMessageConsumer.java

@@ -0,0 +1,64 @@
+package com.xingxi.api.configuration;
+
+import cn.binarywang.wx.miniapp.api.WxMaMsgService;
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
+import com.alibaba.fastjson.JSON;
+import com.google.common.collect.Lists;
+import com.rabbitmq.client.Channel;
+import com.xingxi.common.mq.bo.wxmessage.WxSubscribeMessageBO;
+import com.xingxi.common.mq.constant.WxSubscribeMessageMqKey;
+import com.xingxi.common.mq.core.AbstractRabbitConsumer;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.core.Binding;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.beans.BeanUtils;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+class WxSubscribeMessageConsumer extends AbstractRabbitConsumer {
+    private final WxMaService wxMaService;
+
+    @Bean
+    @Override
+    protected List<Binding> getBindingList() {
+        return Lists.newArrayList(
+                this.bind(WxSubscribeMessageMqKey.EDIT_EXCHANGE,
+                        WxSubscribeMessageMqKey.EDIT_QUEUE_FOR_WXSUBSCRIBEMESSAGE_PUBLISH,
+                        WxSubscribeMessageMqKey.EDIT_ROUTE_FOR_WXSUBSCRIBEMESSAGE_PUBLISH));
+    }
+
+
+    @RabbitListener(queues = WxSubscribeMessageMqKey.EDIT_QUEUE_FOR_WXSUBSCRIBEMESSAGE_PUBLISH)
+    @Override
+    public void onMessage(Message message, Channel channel) throws Exception {
+        this.convertMessage(message, channel);
+    }
+
+
+    @Override
+    public boolean execute(String body, Channel channel, Message message) throws Exception {
+        log.debug("发布微信订阅消息[{}]", body);
+        WxSubscribeMessageBO wxSubscribeMessageBO = JSON.parseObject(body, WxSubscribeMessageBO.class);
+        WxMaSubscribeMessage subscribeMessage = new WxMaSubscribeMessage();
+        BeanUtils.copyProperties(wxSubscribeMessageBO, subscribeMessage);
+
+        try {
+            WxMaMsgService msgService = wxMaService.getMsgService();
+            msgService.sendSubscribeMsg(subscribeMessage);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+
+}

+ 37 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/controller/OrderApiController.java

@@ -0,0 +1,37 @@
+package com.xingxi.api.controller;
+
+import com.xingxi.api.common.BaseApiController;
+import com.xingxi.api.model.OrderCreateRequest;
+import com.xingxi.api.model.OrderCreateResponse;
+import com.xingxi.api.model.OrderQueryRequest;
+import com.xingxi.api.model.OrderQueryResponse;
+import com.xingxi.api.service.OrderServiceI;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+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.RestController;
+
+import javax.validation.Valid;
+
+@Slf4j
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/api/store/order")
+public class OrderApiController extends BaseApiController {
+
+    private final OrderServiceI orderServiceI;
+
+    @PostMapping("/orders")
+    public OrderQueryResponse getOrderList(@Valid @RequestBody OrderQueryRequest request) {
+
+        return orderServiceI.list(getUserContext(), request);
+    }
+
+    @PostMapping("/create")
+    public OrderCreateResponse create(@Valid @RequestBody OrderCreateRequest request){
+        return orderServiceI.create(getUserContext(), request);
+    }
+
+}

+ 26 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/controller/WxLogoutApiController.java

@@ -0,0 +1,26 @@
+package com.xingxi.api.controller;
+
+import com.xingxi.api.common.BaseApiController;
+import com.xingxi.api.model.WxLogoutRequest;
+import com.xingxi.api.model.WxLogoutResponse;
+import com.xingxi.api.service.WxmaUserServiceI;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@Slf4j
+@RestController
+@RequestMapping("/api/store/wxlogout")
+@RequiredArgsConstructor
+public class WxLogoutApiController extends BaseApiController {
+    private final WxmaUserServiceI wxmaUserServiceI;
+
+    @PostMapping
+    public WxLogoutResponse logout(WxLogoutRequest request){
+        wxmaUserServiceI.userExit(getUserContext(), request);
+        return new WxLogoutResponse();
+    }
+}

+ 18 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/data/domain/OrderDTO.java

@@ -0,0 +1,18 @@
+package com.xingxi.api.data.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.xingxi.business.Order.domain.Order;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+@JsonIgnoreProperties("params")
+public class OrderDTO extends Order {
+
+    private List<OrderDetailDTO> orderDetailDTOS;
+
+
+}

+ 20 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/data/domain/OrderDetailDTO.java

@@ -0,0 +1,20 @@
+package com.xingxi.api.data.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.xingxi.business.Order.domain.OrderDeliveryExpr;
+import com.xingxi.business.Order.domain.OrderDetail;
+import com.xingxi.master.product.domain.ProdPic;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Setter
+@Getter
+@JsonIgnoreProperties("params")
+public class OrderDetailDTO extends OrderDetail {
+
+    private List<ProdPic> imageDTOS;
+    private List<OrderDeliveryExpr> orderDetailExprs;
+
+}

+ 18 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/data/mapper/WxApiProdInventoryMapper.java

@@ -0,0 +1,18 @@
+package com.xingxi.api.data.mapper;
+
+import com.xingxi.business.ProdInventory.domain.ProdInventory;
+import com.xingxi.business.ProdInventory.mapper.ProdInventoryBillMapper;
+import com.xingxi.business.ProdInventory.mapper.ProdInventoryMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+@Mapper
+public interface WxApiProdInventoryMapper extends ProdInventoryMapper, ProdInventoryBillMapper {
+
+    ProdInventory selectProdInventoryLock(@Param("prodId") Long prodId, @Param("prodAttrId") Long prodAttrId, @Param("mercId") Long mercId);
+
+    int updateSubtractProdStock(ProdInventory prodStock);
+
+    int updatePlusProdStock(ProdInventory prodStock);
+
+}

+ 24 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/model/OrderCreateRequest.java

@@ -0,0 +1,24 @@
+package com.xingxi.api.model;
+
+import com.xingxi.business.UserAddress.domain.UserAddress;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+@Getter
+@Setter
+public class OrderCreateRequest {
+
+    @Deprecated
+    private String userAddressId;
+
+    @NotNull
+    private UserAddress userAddress;
+
+    private List<OrderItemDTO> orderItemDTOS;
+
+    private String remark;
+
+}

+ 11 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/model/OrderCreateResponse.java

@@ -0,0 +1,11 @@
+package com.xingxi.api.model;
+
+
+import com.xingxi.business.Order.domain.Order;
+import lombok.Value;
+
+@Value
+public class OrderCreateResponse {
+    Order createdOrder;
+//    OrderPaySignDTO orderPaySignDTO;
+}

+ 15 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/model/OrderItemDTO.java

@@ -0,0 +1,15 @@
+package com.xingxi.api.model;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class OrderItemDTO {
+
+    private Long cartsId;
+
+    private Long mercProdId;
+
+    private Integer count;
+}

+ 14 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/model/OrderQueryRequest.java

@@ -0,0 +1,14 @@
+package com.xingxi.api.model;
+
+import com.xingxi.api.common.PageDTO;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@ToString
+public class OrderQueryRequest extends PageDTO {
+
+    private String status;
+}

+ 12 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/model/OrderQueryResponse.java

@@ -0,0 +1,12 @@
+package com.xingxi.api.model;
+
+import com.xingxi.api.data.domain.OrderDTO;
+import lombok.Value;
+
+import java.util.List;
+
+@Value
+public class OrderQueryResponse {
+
+    List<OrderDTO> orderDTOS;
+}

+ 4 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/model/WxLogoutRequest.java

@@ -0,0 +1,4 @@
+package com.xingxi.api.model;
+
+public class WxLogoutRequest {
+}

+ 4 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/model/WxLogoutResponse.java

@@ -0,0 +1,4 @@
+package com.xingxi.api.model;
+
+public class WxLogoutResponse {
+}

+ 11 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/CacheService.java

@@ -0,0 +1,11 @@
+package com.xingxi.api.service;
+
+public interface CacheService {
+    //存
+    void setCache(String key, Object value);
+    //取
+    Object getCache(String key);
+
+    // 删除该key关联的缓存
+    void invalidate(String key);
+}

+ 15 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/OrderServiceI.java

@@ -0,0 +1,15 @@
+package com.xingxi.api.service;
+
+import com.xingxi.api.common.UserContext;
+import com.xingxi.api.model.OrderCreateRequest;
+import com.xingxi.api.model.OrderCreateResponse;
+import com.xingxi.api.model.OrderQueryRequest;
+import com.xingxi.api.model.OrderQueryResponse;
+
+public interface OrderServiceI {
+
+    OrderQueryResponse list(UserContext userContext, OrderQueryRequest request);
+
+    OrderCreateResponse create(UserContext userContext, OrderCreateRequest request);
+
+}

+ 42 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/WXPayServiceI.java

@@ -0,0 +1,42 @@
+package com.xingxi.api.service;
+
+import com.xingxi.api.common.UserContext;
+import com.xingxi.business.Order.domain.Order;
+import com.xingxi.common.utils.DateUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import java.text.ParseException;
+import java.util.Calendar;
+import java.util.Date;
+
+public interface WXPayServiceI {
+    String expTimeFormat = "yyyy-MM-dd'T'HH:mm:ss+08:00";
+
+    Object unifiedOrder(Long callWXPayMercId, UserContext userContext, Order order) throws Exception;
+
+    Object continue2pay(Long callWXPayMercId, UserContext userContext, String prepayId) throws Exception;
+
+    void callback(Long callWXPayMercId, HttpServletRequest request) throws Exception;
+
+
+    default Date parseDate(String dateString){
+        try {
+            return DateUtils.parseDate(dateString, expTimeFormat);
+        } catch (ParseException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    default Date getCurrentDate(){
+        Calendar instance = Calendar.getInstance();
+        instance.set(Calendar.MILLISECOND, 0);
+        return instance.getTime();
+    }
+
+
+    default String timeExpire(){
+        return DateUtils.parseDateToStr(
+                expTimeFormat, DateUtils.addMinutes(getCurrentDate(), 10));
+    }
+
+}

+ 8 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/WxmaUserServiceI.java

@@ -0,0 +1,8 @@
+package com.xingxi.api.service;
+
+import com.xingxi.api.common.UserContext;
+import com.xingxi.api.model.WxLogoutRequest;
+
+public interface WxmaUserServiceI {
+    void userExit(UserContext userContext, WxLogoutRequest request);
+}

+ 34 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/impl/GuavaCacheServiceImpl.java

@@ -0,0 +1,34 @@
+package com.xingxi.api.service.impl;
+
+import com.google.common.cache.Cache;
+import com.xingxi.api.service.CacheService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+class GuavaCacheServiceImpl implements CacheService {
+    private final Cache<String, Object> cache;
+
+    GuavaCacheServiceImpl(@Qualifier("WxaMediaCheckGuavaCache") final Cache<String, Object> cache) {
+        this.cache = cache;
+    }
+
+
+    @Override
+    public void setCache(String key, Object value) {
+        cache.put(key, value);
+
+    }
+
+    @Override
+    public Object getCache(String key) {
+        return cache.getIfPresent(key);
+    }
+
+    @Override
+    public void invalidate(String key) {
+        cache.invalidate(key);
+    }
+}

+ 28 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/impl/MySqlDBCacheServiceImpl.java

@@ -0,0 +1,28 @@
+package com.xingxi.api.service.impl;
+
+import com.xingxi.api.service.CacheService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+
+@Slf4j
+@RequiredArgsConstructor
+class MySqlDBCacheServiceImpl implements CacheService {
+
+
+
+    @Override
+    public void setCache(String key, Object value) {
+
+    }
+
+    @Override
+    public Object getCache(String key) {
+        return null;
+    }
+
+    @Override
+    public void invalidate(String key) {
+
+    }
+}

+ 363 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/impl/OrderApiServiceImpl.java

@@ -0,0 +1,363 @@
+package com.xingxi.api.service.impl;
+
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
+import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
+import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.pagehelper.Page;
+import com.github.pagehelper.PageHelper;
+import com.xingxi.api.common.ApiException;
+import com.xingxi.api.common.UserContext;
+import com.xingxi.api.data.domain.OrderDTO;
+import com.xingxi.api.data.domain.OrderDetailDTO;
+import com.xingxi.api.data.mapper.WxApiProdInventoryMapper;
+import com.xingxi.api.model.*;
+import com.xingxi.api.service.OrderServiceI;
+import com.xingxi.business.Order.domain.Order;
+import com.xingxi.business.Order.domain.OrderDeliveryExpr;
+import com.xingxi.business.Order.domain.OrderDetail;
+import com.xingxi.business.Order.mapper.OrderDeliveryExprMapper;
+import com.xingxi.business.Order.mapper.OrderDetailMapper;
+import com.xingxi.business.Order.mapper.OrderMapper;
+import com.xingxi.business.PaymentInfo.domain.PaymentInfo;
+import com.xingxi.business.PaymentInfo.mapper.PaymentInfoMapper;
+import com.xingxi.business.ProdInventory.domain.ProdInventory;
+import com.xingxi.business.ProdInventory.domain.ProdInventoryBill;
+import com.xingxi.business.ProdInventory.mapper.ProdInventoryBillMapper;
+import com.xingxi.business.UserAddress.domain.UserAddress;
+import com.xingxi.common.core.domain.entity.SysUser;
+import com.xingxi.common.enums.EDelFlag;
+import com.xingxi.common.enums.EInventoryBillType;
+import com.xingxi.common.enums.EOrderDetailStatus;
+import com.xingxi.common.enums.EOrderStatus;
+import com.xingxi.common.exception.BusinessException;
+import com.xingxi.common.mq.bo.order.OrderBO;
+import com.xingxi.common.mq.publisher.order.OrderCreatedMqPublisher;
+import com.xingxi.common.utils.DateUtils;
+import com.xingxi.common.utils.PageUtils;
+import com.xingxi.common.utils.StringUtils;
+import com.xingxi.common.utils.bean.BeanUtils;
+import com.xingxi.common.utils.uuid.IdUtils;
+import com.xingxi.master.merchant.domain.MerchantProd;
+import com.xingxi.master.merchant.mapper.MerchantProdMapper;
+import com.xingxi.master.product.domain.Prod;
+import com.xingxi.master.product.domain.ProdAttrPrice;
+import com.xingxi.master.product.domain.ProdPic;
+import com.xingxi.master.product.domain.ProdVendor;
+import com.xingxi.master.product.mapper.*;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+@Slf4j
+@RequiredArgsConstructor
+@Service("OrderServiceI")
+class OrderApiServiceImpl implements OrderServiceI {
+
+    @Autowired
+    private OrderMapper orderMapper;
+    @Autowired
+    private OrderDetailMapper orderDetailMapper;
+    @Autowired
+    private ProdPicMapper prodPicMapper;
+    @Autowired
+    private OrderDeliveryExprMapper orderDeliveryExprMapper;
+    @Autowired
+    private MerchantProdMapper merchantProdMapper;
+    @Autowired
+    private ProdMapper prodMapper;
+    @Autowired
+    private ProdAttrMapper prodAttrMapper;
+    @Autowired
+    private ProdAttrPriceMapper prodAttrPriceMapper;
+    @Autowired
+    private ProdVendorMapper prodVendorMapper;
+    @Autowired
+    private ProdInventoryBillMapper prodInventoryBillMapper;
+    @Autowired
+    private WxApiProdInventoryMapper wxApiProdInventoryMapper;
+
+    private final OrderCreatedMqPublisher createdMqPublisher;
+
+    @Autowired
+    private WxPayService wxPayService;
+
+    @Value("${wx.pay.domain}")
+    private String domain;
+    @Value("${wx.pay.notifyUrl}")
+    private String notifyUrl;
+    private WxPayConfig config;
+
+    @Autowired
+    private PaymentInfoMapper paymentInfoMapper;
+
+    @Override
+    public OrderQueryResponse list(UserContext userContext, OrderQueryRequest request) {
+
+        SysUser currentUser = userContext.getCurrentUser();
+        Long userId = currentUser.getUserId();
+        Integer pageNum = request.getPageNum();
+        Integer pageSize = request.getPageSize();
+        String status = request.getStatus();
+
+        Order condOrder = new Order();
+        condOrder.setBuyerId(userId);
+        condOrder.setOrderStatus(status);
+        condOrder.setDelFlag(EDelFlag.NO.getVal());
+
+        PageUtils.startPage();
+        Page<OrderDTO> orderList  = PageHelper.startPage(pageNum, pageSize)
+                .doSelectPage(() -> orderMapper.selectOrderList(condOrder));
+
+        if (!orderList.isEmpty()) {
+            for (OrderDTO order : orderList) {
+                OrderDetail condOderDetail = new OrderDetail();
+                condOderDetail.setOrderId(order.getOrderId());
+                List<OrderDetail> orderDetailList = orderDetailMapper.selectOrderDetailList(condOderDetail);
+                List<OrderDetailDTO> odDtoList = new ArrayList<>();
+                for (OrderDetail orderDetail : orderDetailList) {
+                    OrderDetailDTO odDto = new OrderDetailDTO();
+                    BeanUtils.copyBeanProp(odDto, orderDetail);
+
+                    ProdPic condPic = new ProdPic();
+                    condPic.setProdId(orderDetail.getProdId());
+                    condPic.setDelFlag(EDelFlag.NO.getVal());
+                    odDto.setImageDTOS(prodPicMapper.selectProdPicList(condPic));
+
+                    OrderDeliveryExpr condExp = new OrderDeliveryExpr();
+                    condExp.setOrderDetailId(orderDetail.getOrderDetailId());
+                    odDto.setOrderDetailExprs(orderDeliveryExprMapper.selectOrderDeliveryExprList(condExp));
+
+                    odDtoList.add(odDto);
+                }
+
+                order.setOrderDetailDTOS(odDtoList);
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public OrderCreateResponse create(UserContext userContext, OrderCreateRequest request) {
+
+        Date orderTime = DateUtils.getNowDate();
+
+        // C端用户信息
+        SysUser currentUser = userContext.getCurrentUser();
+        Long userId = currentUser.getUserId();
+
+        // 订单信息
+        List<OrderItemDTO> orderItemDTOS = request.getOrderItemDTOS();
+        UserAddress userAddressDTO = request.getUserAddress();
+
+        String orderNo = IdUtils.snowFlake();
+        String orderStatus = EOrderStatus.ORDERED.getVal();
+
+        Order order = new Order();
+
+        order.setOrderNo(orderNo);
+        order.setOrderTime(DateUtils.getNowDate());
+        order.setOrderStatus(orderStatus);
+        order.setBuyerId(userId);
+
+        order.setRecProv(request.getUserAddress().getProvince());
+        order.setRecCity(request.getUserAddress().getCity());
+        order.setRecDistrict(request.getUserAddress().getDistrict());
+        order.setRecAddress(request.getUserAddress().getAddress());
+        order.setRecName(request.getUserAddress().getRecipient());
+        order.setRecMobile(request.getUserAddress().getMobile());
+        order.setRemark(request.getRemark());
+        order.setDelFlag(EDelFlag.NO.getVal());
+        order.setCreateUser(userId.toString());
+        order.setCreateTime(orderTime);
+        order.setUpdateUser(userId.toString());
+        order.setUpdateTime(orderTime);
+
+        int cnt = orderMapper.insertOrder(order);
+        if (cnt <= 0) {
+            log.debug("创建订单失败");
+            throw new BusinessException("创建订单失败");
+        }
+
+        Integer prodQty = 0;
+        BigDecimal prodAmt = BigDecimal.ZERO;
+
+        List<OrderDetail> orderDetailItems = new ArrayList<>();
+        for (OrderItemDTO orderItemDTO : orderItemDTOS) {
+            MerchantProd merchantProd = merchantProdMapper.selectMerchantProdByMercProdId(orderItemDTO.getMercProdId());
+            Prod prod = prodMapper.selectProdById(merchantProd.getProdId());
+            order.setSellerId(merchantProd.getMercId());
+
+            ProdVendor condPv = new ProdVendor();
+            condPv.setDelFlag(EDelFlag.NO.getVal());
+            condPv.setProdId(merchantProd.getProdId());
+            condPv.setProdAttrId(merchantProd.getProdAttrId());
+
+            List<ProdVendor> prodVendorList = prodVendorMapper.selectProdVendorList(condPv);
+            if (prodVendorList.isEmpty()) {
+                log.error("商户商品[" + orderItemDTO.getMercProdId() + "]无供应商");
+                throw new BusinessException("未查询到商品的供应商");
+            }
+
+            OrderDetail orderDetail = new OrderDetail();
+            orderDetail.setOrderId(order.getOrderId());
+            orderDetail.setOrderDetailStatus(EOrderDetailStatus.ORDERED.getVal());
+            orderDetail.setProdId(merchantProd.getProdId());
+            orderDetail.setProdName(prod.getProdName());
+            orderDetail.setProdAttrId(merchantProd.getProdAttrId());
+            orderDetail.setProdAttrName(prodAttrMapper.selectProdAttrByProdAttrId(merchantProd.getProdAttrId()).getAttrName());
+            orderDetail.setVendorId(prodVendorList.get(0).getVendorId());
+            orderDetail.setQuantity(orderItemDTO.getCount());
+
+            ProdAttrPrice condPrice = new ProdAttrPrice();
+            condPrice.setDelFlag(EDelFlag.NO.getVal());
+            condPrice.setProdId(merchantProd.getProdId());
+            condPrice.setProdAttrId(merchantProd.getProdAttrId());
+            condPrice.setSellerId(merchantProd.getMercId());
+            List<ProdAttrPrice> prodAttrPriceList = prodAttrPriceMapper.selectProdAttrPriceList(condPrice);
+            if (StringUtils.isEmpty(prodAttrPriceList)) {
+                log.error("商户商品[{}]无价格", orderItemDTO.getMercProdId());
+                throw new BusinessException("未查询到商品的价格");
+            }
+
+            orderDetail.setPrice(prodAttrPriceList.get(0).getPrice());
+            orderDetail.setOrderAmount(orderDetail.getPrice().multiply(new BigDecimal(orderDetail.getQuantity())));
+            orderDetail.setPayAmount(orderDetail.getOrderAmount());
+            orderDetail.setDelFlag(EDelFlag.NO.getVal());
+            orderDetail.setCreateUser(userId.toString());
+            orderDetail.setCreateTime(orderTime);
+            orderDetail.setUpdateUser(userId.toString());
+            orderDetail.setUpdateTime(orderTime);
+
+            orderDetailItems.add(orderDetail);
+
+            prodQty = prodQty + orderDetail.getQuantity();
+            prodAmt = prodAmt.add(orderDetail.getOrderAmount());
+
+            // 锁库
+            ProdInventory prodInventory = wxApiProdInventoryMapper.selectProdInventoryLock(orderDetail.getProdId(), orderDetail.getProdAttrId(), merchantProd.getMercId());
+            if (!(prodInventory != null && prodInventory.getAvailQty() > 0)) {
+                log.error("商品[{}]库存不足", prod.getProdName());
+                throw new BusinessException("商品[" + prod.getProdName() + "]库存不足");
+            }
+
+            prodInventory.setAvailQty(orderDetail.getQuantity());
+            prodInventory.setUpdateTime(orderTime);
+            prodInventory.setUpdateUser(userId.toString());
+            cnt = wxApiProdInventoryMapper.updateSubtractProdStock(prodInventory);
+            if (cnt <= 0) {
+                log.error("扣减库存[{}]失败", prodInventory.getProdInventoryId());
+                throw new ApiException("prod.stock.out.error");
+            }
+
+            ProdInventoryBill inventoryBill = new ProdInventoryBill();
+            inventoryBill.setBillTime(orderTime);
+            inventoryBill.setBillType(EInventoryBillType.LOCK.getVal());
+            inventoryBill.setQuantity(orderItemDTO.getCount());
+            inventoryBill.setInventoryId(prodInventory.getProdInventoryId());
+            inventoryBill.setOrderId(order.getOrderId());
+            inventoryBill.setOrderNo(orderNo);
+            inventoryBill.setDelFlag(EDelFlag.NO.getVal());
+            inventoryBill.setCreateUser(userId.toString());
+            inventoryBill.setCreateTime(orderTime);
+            inventoryBill.setUpdateUser(userId.toString());
+            inventoryBill.setUpdateTime(orderTime);
+
+            cnt = prodInventoryBillMapper.insertProdInventoryBill(inventoryBill);
+            if (cnt <= 0) {
+                log.error("创建订单失败");
+                throw new BusinessException("创建订单失败");
+            }
+        }
+
+        orderDetailMapper.batchInsertOrderDetail(orderDetailItems);
+        order.setOrderAmount(prodAmt);
+        order.setProdQuantity(prodQty);
+        orderMapper.updateOrder(order);
+
+        orderCreatedEvent(order);
+
+        config = wxPayService.getConfig();
+
+        WxPayUnifiedOrderV3Result.JsapiResult result = callWxpay(order,currentUser.getWxOpenId(),order.getOrderAmount().intValue(),currentUser.getLoginIp());
+
+        return null;
+    }
+
+    private void orderCreatedEvent(Order message){
+        OrderBO sendOrder = new OrderBO();
+        sendOrder.setOrderId(message.getOrderId());
+        sendOrder.setOrderNo(message.getOrderNo());
+        createdMqPublisher.sendMessage(sendOrder);
+    }
+
+    private WxPayUnifiedOrderV3Result.JsapiResult callWxpay(Order order, String openid, int amount, String ip) {
+        WxPayUnifiedOrderV3Result.JsapiResult rtn = new WxPayUnifiedOrderV3Result.JsapiResult();
+
+        Date now = DateUtils.getNowDate();
+        WxPayUnifiedOrderV3Request.Payer payer = new WxPayUnifiedOrderV3Request.Payer();
+        payer.setOpenid(openid);
+
+        WxPayUnifiedOrderV3Request.Amount payAmount = new WxPayUnifiedOrderV3Request.Amount();
+        payAmount.setTotal(amount); // 分
+        payAmount.setCurrency("CNY");
+
+        WxPayUnifiedOrderV3Request wxrequest = new WxPayUnifiedOrderV3Request();
+        //过期时间,15分钟
+        wxrequest.setTimeExpire(DateUtils.parseDateToStr(DateUtils.RFC3339, DateUtils.addMinutes(now,15))); // 示例值:2018-06-08T10:34:56+08:00
+
+        wxrequest.setDescription("谷鹿鹿Q");
+        wxrequest.setOutTradeNo(order.getOrderNo());
+        wxrequest.setAppid(config.getAppId());
+        wxrequest.setMchid(config.getMchId());
+        wxrequest.setNotifyUrl(notifyUrl);
+        wxrequest.setPayer(payer);
+        wxrequest.setAmount(payAmount);
+
+        log.info(wxrequest.toString());
+
+        WxPayUnifiedOrderV3Request.SceneInfo sceneInfo = new WxPayUnifiedOrderV3Request.SceneInfo();
+        sceneInfo.setPayerClientIp(ip);
+        wxrequest.setSceneInfo(sceneInfo);
+
+        try {
+
+            rtn = wxPayService.createOrderV3(TradeTypeEnum.JSAPI, wxrequest);
+
+            PaymentInfo paymentInfo = new PaymentInfo();
+
+            paymentInfo.setOrderId(order.getOrderId());
+            paymentInfo.setOrderNo(order.getOrderNo());
+            paymentInfo.setPayTime(now);
+            paymentInfo.setSellerId(order.getSellerId());
+            paymentInfo.setDescription("谷鹿鹿Q");
+            paymentInfo.setOutTradeNo(order.getOrderNo());
+            paymentInfo.setNotifyUrl(notifyUrl);
+            paymentInfo.setAmountTotal(new BigDecimal(amount));
+            paymentInfo.setPayerOpenid(openid);
+            paymentInfo.setPrepayId(rtn.getPackageValue());
+            paymentInfo.setDelFlag(EDelFlag.NO.getVal());
+            paymentInfo.setCreateTime(now);
+            paymentInfo.setUpdateTime(now);
+            paymentInfo.setCreateUser(openid);
+            paymentInfo.setUpdateUser(openid);
+            paymentInfoMapper.insertPaymentInfo(paymentInfo);
+
+            return rtn;
+        } catch (WxPayException e) {
+            log.error(e.getMessage());
+            throw new RuntimeException("创建支付失败");
+        }
+    }
+}

+ 45 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/impl/WxaMediaCheckWxMaMessageHandlerImpl.java

@@ -0,0 +1,45 @@
+package com.xingxi.api.service.impl;
+
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.WxMaMessage;
+import cn.binarywang.wx.miniapp.message.WxMaMessageHandler;
+import cn.binarywang.wx.miniapp.message.WxMaXmlOutMessage;
+import com.xingxi.api.service.CacheService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import lombok.var;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.session.WxSessionManager;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+
+@Slf4j
+@Component("WXA_MEDIA_CHECK")
+@RequiredArgsConstructor
+public class WxaMediaCheckWxMaMessageHandlerImpl implements WxMaMessageHandler {
+    private final CacheService cacheService;
+
+    @Override
+    public WxMaXmlOutMessage handle(WxMaMessage message, Map<String, Object> context, WxMaService service, WxSessionManager sessionManager) throws WxErrorException {
+        String traceId = message.getTraceId();
+        // 如果检测内容违规,此订单看情况处理是否要退款
+        Object orderNo = cacheService.getCache(traceId);
+        if(orderNo != null){
+            var traceIds = (List<String>) cacheService.getCache((String) orderNo);
+            if (traceIds != null && !traceIds.isEmpty()) {
+                for (String id : traceIds) {
+                    cacheService.invalidate(id);
+                }
+                cacheService.invalidate((String) orderNo);
+            }
+
+        }
+
+        return null;
+    }
+
+
+}

+ 35 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/java/com/xingxi/api/service/impl/WxmaUserServiceImpl.java

@@ -0,0 +1,35 @@
+package com.xingxi.api.service.impl;
+
+import com.xingxi.api.common.UserContext;
+import com.xingxi.api.model.WxLogoutRequest;
+import com.xingxi.api.service.WxmaUserServiceI;
+import com.xingxi.common.core.domain.entity.SysUser;
+import com.xingxi.system.mapper.SysUserMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+
+@Service
+@Slf4j
+@RequiredArgsConstructor
+class WxmaUserServiceImpl implements WxmaUserServiceI {
+    private final SysUserMapper sysUserMapper;
+
+    @Override
+    public void userExit(UserContext userContext, WxLogoutRequest request) {
+        SysUser currentUser = userContext.getCurrentUser();
+        Long userId = currentUser.getUserId();
+        SysUser sysUser = new SysUser();
+        sysUser.setUserId(userId);
+        sysUser.setLoginDate(new Date());
+        sysUser.setUpdateTime(sysUser.getLoginDate());
+        sysUser.setUpdateUser(userId + "");
+        sysUserMapper.updateUser(sysUser);
+    }
+
+
+
+
+}

+ 38 - 0
08.src/Xingxi/xingxi-miniprogram-api/src/main/resources/META-INF/sqlmap/WxApiProdInventoryMapper.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.xingxi.api.data.mapper.WxApiProdInventoryMapper">
+
+    <select id="selectProdInventoryLock" resultType="ProdInventory">
+        SELECT tpi.*
+        FROM t_prod_inventory tpi
+        WHERE tpi.delFlag = '0'
+          AND tpi.mercId = #{mercId}
+          AND tpi.prodId = #{prodId}
+          AND tpi.prodAttrId = #{prodAttrId}
+        LIMIT 1
+        FOR UPDATE
+    </select>
+
+    <update id="updateSubtractProdStock" parameterType="ProdInventory">
+        update t_prod_inventory
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="availQty != null">availQty = availQty - #{availQty},</if>
+            <if test="updateUser != null and updateUser != ''">updateUser = #{updateUser},</if>
+            <if test="updateTime != null">updateTime = #{updateTime},</if>
+        </trim>
+        where prodInventoryId = #{prodInventoryId} and availQty - #{availQty} >= 0
+    </update>
+
+    <update id="updatePlusProdStock" parameterType="ProdInventory">
+        update t_prod_inventory
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="availQty != null">availQty = availQty + #{availQty},</if>
+            <if test="updateUser != null and updateUser != ''">updateUser = #{updateUser},</if>
+            <if test="updateTime != null">updateTime = #{updateTime},</if>
+        </trim>
+        where prodInventoryId = #{prodInventoryId}
+    </update>
+
+</mapper>