Browse Source

开发商品下单的接口

jinshihui 13 hours ago
parent
commit
f7ec014294
19 changed files with 1010 additions and 66 deletions
  1. 44 0
      nightFragrance-admin/src/main/java/com/ylx/web/controller/massage/ProductOrderController.java
  2. 3 0
      nightFragrance-common/src/main/java/com/ylx/common/core/domain/model/WxLoginUser.java
  3. 10 15
      nightFragrance-framework/src/main/java/com/ylx/framework/config/SecurityConfig.java
  4. 24 45
      nightFragrance-framework/src/main/java/com/ylx/framework/web/service/PermissionService.java
  5. 1 0
      nightFragrance-framework/src/main/java/com/ylx/framework/web/service/WxTokenService.java
  6. 120 0
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/AfterSaleOrder.java
  7. 63 0
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/ProductOrderAddress.java
  8. 153 0
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/ProductOrderInfo.java
  9. 118 0
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/ProductOrderItem.java
  10. 108 0
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/ProductOrderPayment.java
  11. 103 0
      nightFragrance-massage/src/main/java/com/ylx/massage/domain/dto/ProductOrderCreateRequest.java
  12. 12 0
      nightFragrance-massage/src/main/java/com/ylx/massage/mapper/ProductOrderInfoMapper.java
  13. 12 0
      nightFragrance-massage/src/main/java/com/ylx/massage/mapper/ProductOrderItemMapper.java
  14. 19 0
      nightFragrance-massage/src/main/java/com/ylx/massage/service/IProductOrderInfoService.java
  15. 10 0
      nightFragrance-massage/src/main/java/com/ylx/massage/service/IProductOrderItemService.java
  16. 178 0
      nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/ProductOrderInfoServiceImpl.java
  17. 14 0
      nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/ProductOrderItemServiceImpl.java
  18. 1 0
      nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/TOrderServiceImpl.java
  19. 17 6
      nightFragrance-massage/src/main/java/com/ylx/massage/utils/OrderNumberGenerator.java

+ 44 - 0
nightFragrance-admin/src/main/java/com/ylx/web/controller/massage/ProductOrderController.java

@@ -0,0 +1,44 @@
+package com.ylx.web.controller.massage;
+
+import com.alibaba.fastjson.JSON;
+import com.ylx.common.core.controller.BaseController;
+import com.ylx.common.core.domain.R;
+import com.ylx.massage.domain.dto.ProductOrderCreateRequest;
+import com.ylx.massage.service.IProductOrderInfoService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+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;
+
+/**
+ * 商品订单控制器
+ */
+@Slf4j
+@RestController
+@RequestMapping("/product/order")
+public class ProductOrderController extends BaseController {
+
+    @Autowired
+    private IProductOrderInfoService productOrderInfoService;
+
+    /**
+     * 创建商品订单
+     *
+     * @param request 订单创建请求
+     * @return R<String> 订单编号
+     */
+    @PostMapping("/create")
+    public R<String> createProductOrder(@RequestBody ProductOrderCreateRequest request) {
+        try {
+            log.info("创建商品订单,请求参数:{}", JSON.toJSONString(request));
+            String orderNo = productOrderInfoService.createProductOrder(request);
+            log.info("商品订单创建成功,订单编号:{}", orderNo);
+            return R.ok(orderNo);
+        } catch (Exception e) {
+            log.error("商品订单创建失败:{}", e.getMessage(), e);
+            return R.fail(e.getMessage());
+        }
+    }
+}

+ 3 - 0
nightFragrance-common/src/main/java/com/ylx/common/core/domain/model/WxLoginUser.java

@@ -9,6 +9,9 @@ import org.springframework.security.core.userdetails.UserDetails;
 import java.math.BigDecimal;
 import java.util.Collection;
 
+/**
+ * 微信登录用户信息
+ */
 @Data
 public class WxLoginUser implements UserDetails {
 

+ 10 - 15
nightFragrance-framework/src/main/java/com/ylx/framework/config/SecurityConfig.java

@@ -26,8 +26,7 @@ import com.ylx.framework.security.handle.LogoutSuccessHandlerImpl;
  * @author ylx
  */
 @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
-public class SecurityConfig extends WebSecurityConfigurerAdapter
-{
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
     /**
      * 自定义用户认证逻辑
      */
@@ -72,8 +71,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
      */
     @Bean
     @Override
-    public AuthenticationManager authenticationManagerBean() throws Exception
-    {
+    public AuthenticationManager authenticationManagerBean() throws Exception {
         return super.authenticationManagerBean();
     }
 
@@ -93,8 +91,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
      * authenticated       |   用户登录后可访问
      */
     @Override
-    protected void configure(HttpSecurity httpSecurity) throws Exception
-    {
+    protected void configure(HttpSecurity httpSecurity) throws Exception {
         // 注解标记允许匿名访问的url
         ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests();
         permitAllUrl.getUrls().forEach(url -> registry.antMatchers(url).permitAll());
@@ -111,13 +108,13 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                 // 过滤请求
                 .authorizeRequests()
                 // 对于登录login 注册register 验证码captchaImage 允许匿名访问
-                .antMatchers("/login", "/register", "/captchaImage","/wx/login",
+                .antMatchers("/login", "/register", "/captchaImage", "/wx/login",
                         "/api/lbt/v1/getAll", "/api/js/v1/select", "/api/xiangmu/v1/wx/getAll", "/api/order/v1/getStatus",
-                        "/api/xiangmu/v1/getByid", "/api/xiangmu/v1/highlights","/api/js/v1/wx/getByid","/api/js/v1/wx/select","/api/js/v1/wx/add", "/api/recharge/v1/test",
-                        "/wx/pay/payNotify","/wx/pay/refundNotify","/weChat/getAccessToken","/weChat/getCode","/weChat/verifyToken","/sq/getAccessToken",
-                        "/area/select","/system/dept/list","/api/xiangmu/v1/wx/recommend","/product/category/create").permitAll()
+                        "/api/xiangmu/v1/getByid", "/api/xiangmu/v1/highlights", "/api/js/v1/wx/getByid", "/api/js/v1/wx/select", "/api/js/v1/wx/add", "/api/recharge/v1/test",
+                        "/wx/pay/payNotify", "/wx/pay/refundNotify", "/weChat/getAccessToken", "/weChat/getCode", "/weChat/verifyToken", "/sq/getAccessToken",
+                        "/area/select", "/system/dept/list", "/api/xiangmu/v1/wx/recommend", "/product/category/create").permitAll()
                 // 静态资源,可匿名访问
-                .antMatchers(HttpMethod.GET, "/", "/*.txt","/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
+                .antMatchers(HttpMethod.GET, "/", "/*.txt", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                 .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
                 // 除上面外的所有请求全部需要鉴权认证
                 .anyRequest().authenticated()
@@ -136,8 +133,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
      * 强散列哈希加密实现
      */
     @Bean
-    public BCryptPasswordEncoder bCryptPasswordEncoder()
-    {
+    public BCryptPasswordEncoder bCryptPasswordEncoder() {
         return new BCryptPasswordEncoder();
     }
 
@@ -145,8 +141,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
      * 身份认证接口
      */
     @Override
-    protected void configure(AuthenticationManagerBuilder auth) throws Exception
-    {
+    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
         auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
     }
 }

+ 24 - 45
nightFragrance-framework/src/main/java/com/ylx/framework/web/service/PermissionService.java

@@ -1,6 +1,7 @@
 package com.ylx.framework.web.service;
 
 import java.util.Set;
+
 import org.springframework.stereotype.Service;
 import org.springframework.util.CollectionUtils;
 import com.ylx.common.constant.Constants;
@@ -16,23 +17,19 @@ import com.ylx.framework.security.context.PermissionContextHolder;
  * @author ylx
  */
 @Service("ss")
-public class PermissionService
-{
+public class PermissionService {
     /**
      * 验证用户是否具备某权限
      *
      * @param permission 权限字符串
      * @return 用户是否具备某权限
      */
-    public boolean hasPermi(String permission)
-    {
-        if (StringUtils.isEmpty(permission))
-        {
+    public boolean hasPermi(String permission) {
+        if (StringUtils.isEmpty(permission)) {
             return false;
         }
         LoginUser loginUser = SecurityUtils.getLoginUser();
-        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
-        {
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) {
             return false;
         }
         PermissionContextHolder.setContext(permission);
@@ -45,8 +42,7 @@ public class PermissionService
      * @param permission 权限字符串
      * @return 用户是否不具备某权限
      */
-    public boolean lacksPermi(String permission)
-    {
+    public boolean lacksPermi(String permission) {
         return hasPermi(permission) != true;
     }
 
@@ -56,23 +52,18 @@ public class PermissionService
      * @param permissions 以 PERMISSION_DELIMETER 为分隔符的权限列表
      * @return 用户是否具有以下任意一个权限
      */
-    public boolean hasAnyPermi(String permissions)
-    {
-        if (StringUtils.isEmpty(permissions))
-        {
+    public boolean hasAnyPermi(String permissions) {
+        if (StringUtils.isEmpty(permissions)) {
             return false;
         }
         LoginUser loginUser = SecurityUtils.getLoginUser();
-        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
-        {
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) {
             return false;
         }
         PermissionContextHolder.setContext(permissions);
         Set<String> authorities = loginUser.getPermissions();
-        for (String permission : permissions.split(Constants.PERMISSION_DELIMETER))
-        {
-            if (permission != null && hasPermissions(authorities, permission))
-            {
+        for (String permission : permissions.split(Constants.PERMISSION_DELIMETER)) {
+            if (permission != null && hasPermissions(authorities, permission)) {
                 return true;
             }
         }
@@ -85,22 +76,17 @@ public class PermissionService
      * @param role 角色字符串
      * @return 用户是否具备某角色
      */
-    public boolean hasRole(String role)
-    {
-        if (StringUtils.isEmpty(role))
-        {
+    public boolean hasRole(String role) {
+        if (StringUtils.isEmpty(role)) {
             return false;
         }
         LoginUser loginUser = SecurityUtils.getLoginUser();
-        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
-        {
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles())) {
             return false;
         }
-        for (SysRole sysRole : loginUser.getUser().getRoles())
-        {
+        for (SysRole sysRole : loginUser.getUser().getRoles()) {
             String roleKey = sysRole.getRoleKey();
-            if (Constants.SUPER_ADMIN.equals(roleKey) || roleKey.equals(StringUtils.trim(role)))
-            {
+            if (Constants.SUPER_ADMIN.equals(roleKey) || roleKey.equals(StringUtils.trim(role))) {
                 return true;
             }
         }
@@ -113,8 +99,7 @@ public class PermissionService
      * @param role 角色名称
      * @return 用户是否不具备某角色
      */
-    public boolean lacksRole(String role)
-    {
+    public boolean lacksRole(String role) {
         return hasRole(role) != true;
     }
 
@@ -124,21 +109,16 @@ public class PermissionService
      * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表
      * @return 用户是否具有以下任意一个角色
      */
-    public boolean hasAnyRoles(String roles)
-    {
-        if (StringUtils.isEmpty(roles))
-        {
+    public boolean hasAnyRoles(String roles) {
+        if (StringUtils.isEmpty(roles)) {
             return false;
         }
         LoginUser loginUser = SecurityUtils.getLoginUser();
-        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
-        {
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles())) {
             return false;
         }
-        for (String role : roles.split(Constants.ROLE_DELIMETER))
-        {
-            if (hasRole(role))
-            {
+        for (String role : roles.split(Constants.ROLE_DELIMETER)) {
+            if (hasRole(role)) {
                 return true;
             }
         }
@@ -149,11 +129,10 @@ public class PermissionService
      * 判断是否包含权限
      *
      * @param permissions 权限列表
-     * @param permission 权限字符串
+     * @param permission  权限字符串
      * @return 用户是否具备某权限
      */
-    private boolean hasPermissions(Set<String> permissions, String permission)
-    {
+    private boolean hasPermissions(Set<String> permissions, String permission) {
         return permissions.contains(Constants.ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
     }
 }

+ 1 - 0
nightFragrance-framework/src/main/java/com/ylx/framework/web/service/WxTokenService.java

@@ -204,6 +204,7 @@ public class WxTokenService {
      */
     public String getToken(HttpServletRequest request) {
         String token = request.getHeader(header);
+        log.info("token的值: {}", token);
         if (StringUtils.isNotEmpty(token) && token.startsWith(wx_prefix)) {
             token = token.replace(wx_prefix, "");
             return token;

+ 120 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/AfterSaleOrder.java

@@ -0,0 +1,120 @@
+package com.ylx.massage.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+@Data
+@TableName("after_sale_order")
+public class AfterSaleOrder implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.ASSIGN_ID)
+    private Long id;
+
+    /** 售后单号(唯一) */
+    private String afterSaleNo;
+
+    /** 原订单ID */
+    private Long orderId;
+
+    /** 原订单编号 */
+    private String orderNo;
+
+    /** 用户ID */
+    private Long userId;
+
+    /**
+     * 收货状态
+     * 1未收货 2已收货
+     */
+    private Integer receiptStatus;
+
+    /**
+     * 售后类型
+     * 1退货 2换货
+     */
+    private Integer afterSaleType;
+
+    /**
+     * 售后状态
+     * 0待审核 1审核通过 2审核拒绝 3待买家退货 4待商家收货 5退款处理中 6售后完成
+     */
+    private Integer afterSaleStatus;
+
+    /** 申请原因 */
+    private Integer applyReason;
+
+    /** 问题描述 */
+    private String applyDesc;
+
+    /** 凭证图片URL,多个逗号分隔(最多3张) */
+    private String applyImages;
+
+    /** 申请退款金额(分) */
+    private Integer applyAmount;
+
+    /** 实际退款金额(分) */
+    private Integer actualRefundAmount;
+
+    /**
+     * 退款方式
+     * 1原路退回 2退至余额
+     */
+    private Integer refundType;
+
+    /** 审核人ID */
+    private Long auditUserId;
+
+    /** 审核时间 */
+    private LocalDateTime auditTime;
+
+    /** 审核备注(拒绝原因等) */
+    private String auditRemark;
+
+    /**
+     * 拒绝原因
+     * 1超过售后期限 2不符合售后条件 3凭证不足 4其他
+     */
+    private Integer rejectReason;
+
+    /** 退款完成时间 */
+    private LocalDateTime refundTime;
+
+    /** 退款流水号(第三方) */
+    private String refundNo;
+
+    /** 换货新订单ID */
+    private Long exchangeOrderId;
+
+    /** 换货新订单编号 */
+    private String exchangeOrderNo;
+
+    /** 售后申请过期时间 */
+    private LocalDateTime expireTime;
+
+    /** 售后完成时间 */
+    private LocalDateTime finishTime;
+
+    /** 备注 */
+    private String remark;
+
+    /** 是否删除 0否 1是 */
+    @TableLogic
+    private Integer isDeleted;
+
+    /**
+     * 创建时间
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+}

+ 63 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/ProductOrderAddress.java

@@ -0,0 +1,63 @@
+package com.ylx.massage.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 订单收货地址实体类
+ */
+@Data
+@TableName("product_order_address")
+public class ProductOrderAddress implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.ASSIGN_ID)
+    private Long id;
+
+    /** 用户openID */
+    private String openId;
+
+    /** 收货人姓名 */
+    private String receiverName;
+
+    /** 收货人手机号 */
+    private String receiverPhone;
+
+
+    /** 省份名称 */
+    private String provinceName;
+
+
+    /** 城市名称 */
+    private String cityName;
+
+
+    /** 区县名称 */
+    private String districtName;
+
+    /** 详细地址 */
+    private String detailAddress;
+
+    /** 完整地址(省+市+区+详细) */
+    private String fullAddress;
+
+    /** 是否删除 0否 1是 */
+    @TableLogic
+    private Integer isDelete;
+
+    /**
+     * 创建时间
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+}

+ 153 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/ProductOrderInfo.java

@@ -0,0 +1,153 @@
+package com.ylx.massage.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 商品订单信息
+ */
+@Data
+@TableName("product_order_info")
+public class ProductOrderInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(type = IdType.ASSIGN_ID)
+    private Long id;
+
+    /**
+     * 订单编号(雪花算法/业务规则生成)
+     */
+    @TableField("order_no")
+    private String orderNo;
+
+    /**
+     * 用户openId
+     */
+    @TableField("open_id")
+    private String openId;
+
+    /**
+     * 订单状态
+     * 0待付款 1待发货 2已发货 3待收货 4已收货 5换货待审核 6换货中 7退货待审核
+     */
+    private Integer orderStatus;
+
+    /**
+     * 支付状态
+     * 0未支付 1已支付 2支付失败 3已退款
+     */
+    private Integer payStatus;
+
+    /**
+     * 支付方式
+     * 1微信 2余额
+     */
+    private Integer payType;
+
+    /**
+     * 支付时间
+     */
+    private LocalDateTime payTime;
+
+    /**
+     * 支付超时时间(默认下单后15分钟)
+     */
+    private LocalDateTime payExpireTime;
+
+    /**
+     * 商品总金额(分)
+     */
+    private Integer totalAmount;
+
+    /**
+     * 优惠金额(分)
+     */
+    private Integer discountAmount;
+
+    /**
+     * 运费(分)
+     */
+    private Integer freightAmount;
+
+    /**
+     * 实付金额(分)= total_amount - discount_amount + freight_amount
+     */
+    private Integer payAmount;
+
+    /**
+     * 使用的优惠券ID
+     */
+    private Long couponId;
+
+    /**
+     * 优惠券抵扣金额(分)
+     */
+    private Integer couponAmount;
+
+    /**
+     * 使用积分数量
+     */
+    private Integer pointsUsed;
+
+    /**
+     * 地址ID
+     */
+    private Long addressId;
+
+    /**
+     * 配送方式
+     * 1快递 2自提
+     */
+    @TableField("delivery_type")
+    private Integer deliveryType;
+
+    /**
+     * 快递公司
+     */
+    private String logisticsCompany;
+
+    /**
+     * 快递单号
+     */
+    private String logisticsNo;
+
+    /**
+     * 发货时间
+     */
+    private LocalDateTime deliveryTime;
+
+    /**
+     * 确认收货时间
+     */
+    private LocalDateTime receiveTime;
+
+    /**
+     * 买家备注
+     */
+    private String buyerRemark;
+
+
+    /**
+     * 是否删除 0否 1是
+     */
+    @TableLogic
+    private Integer isDeleted;
+
+    /**
+     * 创建时间
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+}

+ 118 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/ProductOrderItem.java

@@ -0,0 +1,118 @@
+package com.ylx.massage.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 订单商品明细实体类
+ */
+@Data
+@TableName("product_order_item")
+public class ProductOrderItem implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(type = IdType.ASSIGN_ID)
+    private Long id;
+
+    /**
+     * 订单ID
+     */
+    @TableField
+    private Long orderId;
+
+    /**
+     * 订单编号(冗余,方便查询)
+     */
+    @TableField
+    private String orderNo;
+
+    /**
+     * 商品ID
+     */
+    @TableField
+    private Long productId;
+
+    /**
+     * 商品名称
+     */
+    @TableField
+    private String productName;
+
+    /**
+     * 商品SKU ID
+     */
+    @TableField
+    private Long skuId;
+
+    /**
+     * SKU规格信息快照 JSON,如{"颜色":"红色","尺寸":"XL"}
+     */
+    @TableField
+    private String skuSpec;
+
+    /**
+     * SKU图片
+     */
+    @TableField
+    private String skuImage;
+
+    /**
+     * 下单时单价(分)
+     */
+    @TableField
+    private Integer price;
+
+    /**
+     * 购买数量
+     */
+    @TableField
+    private Integer quantity;
+
+    /**
+     * 总金额(分)= price × quantity
+     */
+    @TableField
+    private Integer totalAmount;
+
+    /**
+     * 优惠金额(分)
+     */
+    @TableField
+    private Integer discountAmount;
+
+    /**
+     * 实付金额(分)
+     */
+    @TableField
+    private Integer actualAmount;
+
+    /**
+     * 退款状态 (0无退款 1退款中 2已退款 3退款失败)
+     */
+    @TableField
+    private Integer refundStatus;
+
+    /**
+     * 退款金额(分)
+     */
+    @TableField
+    private Integer refundAmount;
+
+    /**
+     * 创建时间
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+}

+ 108 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/ProductOrderPayment.java

@@ -0,0 +1,108 @@
+package com.ylx.massage.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 订单支付记录实体类
+ */
+@Data
+@TableName("product_order_payment")
+public class ProductOrderPayment implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(type = IdType.ASSIGN_ID)
+    private Long id;
+
+    /**
+     * 订单ID
+     */
+    @TableField
+    private String orderId;
+
+    /**
+     * 订单号
+     */
+    @TableField
+    private String orderNo;
+
+    /**
+     * 支付流水号
+     */
+    @TableField(value = "payment_no")
+    private String paymentNo;
+
+    /**
+     * 第三方支付流水号
+     */
+    @TableField(value = "third_payment_no")
+    private String thirdPaymentNo;
+
+    /**
+     * 支付类型 (1-微信支付, 2-余额)
+     */
+    @TableField(value = "pay_type")
+    private Integer payType;
+
+    /**
+     * 支付金额 (单位: 分)
+     */
+    @TableField(value = "pay_amount")
+    private BigDecimal payAmount;
+
+    /**
+     * 支付状态(0待支付 1支付成功 2支付失败
+     */
+    @TableField(value = "pay_status")
+    private String payStatus;
+
+    /**
+     * 支付完成时间
+     */
+    @TableField(value = "pay_time")
+    private LocalDateTime payTime;
+
+    /**
+     * 回调通知时间
+     */
+    @TableField(value = "notify_time")
+    private LocalDateTime notifyTime;
+
+    /**
+     * 回调通知内容
+     */
+    @TableField(value = "notify_content")
+    private String notifyContent;
+
+    /**
+     * 支付过期时间
+     */
+    @TableField(value = "expire_time")
+    private LocalDateTime expireTime;
+
+
+    /**
+     * 备注
+     */
+    @TableField
+    private String remark;
+
+    /**
+     * 创建时间
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+}

+ 103 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/domain/dto/ProductOrderCreateRequest.java

@@ -0,0 +1,103 @@
+package com.ylx.massage.domain.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 商品订单创建请求DTO
+ */
+@Data
+public class ProductOrderCreateRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 用户ID
+     */
+    private String openId;
+
+    /**
+     * 地址ID
+     */
+    private Long addressId;
+
+    /**
+     * 商品ID
+     */
+    private Long productId;
+
+    /**
+     * 商品名称
+     */
+    private String name;
+
+    /**
+     * 商品主图URL
+     */
+    private String productMainImage;
+
+    /**
+     * 选中的SKU ID
+     */
+    private Long skuId;
+
+    /**
+     * SKU列表(规格组合明细)
+     */
+    private List<SpecNameValue> specNameValueList;
+
+    /**
+     * 购买数量
+     */
+    private Integer quantity;
+
+    /**
+     * 支付方式:1微信支付 2账户余额
+     */
+    private Integer payType;
+
+    /**
+     * 运费(分)
+     */
+    private Integer freightAmount;
+
+    /**
+     * 总金额(分)
+     */
+    private Integer totalAmount;
+
+    /**
+     * 支付金额(分)
+     */
+    private Integer payAmount;
+
+    /**
+     * 使用的积分
+     */
+    private Integer pointsUsed;
+
+    /**
+     * 买家备注信息
+     */
+    private String buyerRemark;
+
+    /**
+     * SKU规格名称值对象
+     */
+    @Data
+    public static class SpecNameValue implements Serializable {
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * 规格名称
+         */
+        private String specName;
+
+        /**
+         * 规格值
+         */
+        private String specValue;
+    }
+}

+ 12 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/mapper/ProductOrderInfoMapper.java

@@ -0,0 +1,12 @@
+package com.ylx.massage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ylx.massage.domain.ProductOrderInfo;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 商品订单信息Mapper接口
+ */
+@Mapper
+public interface ProductOrderInfoMapper extends BaseMapper<ProductOrderInfo> {
+}

+ 12 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/mapper/ProductOrderItemMapper.java

@@ -0,0 +1,12 @@
+package com.ylx.massage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ylx.massage.domain.ProductOrderItem;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 商品订单明细Mapper接口
+ */
+@Mapper
+public interface ProductOrderItemMapper extends BaseMapper<ProductOrderItem> {
+}

+ 19 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/service/IProductOrderInfoService.java

@@ -0,0 +1,19 @@
+package com.ylx.massage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ylx.massage.domain.ProductOrderInfo;
+import com.ylx.massage.domain.dto.ProductOrderCreateRequest;
+
+/**
+ * 商品订单信息Service接口
+ */
+public interface IProductOrderInfoService extends IService<ProductOrderInfo> {
+
+    /**
+     * 创建商品订单
+     *
+     * @param request 订单创建请求
+     * @return 订单编号
+     */
+    String createProductOrder(ProductOrderCreateRequest request);
+}

+ 10 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/service/IProductOrderItemService.java

@@ -0,0 +1,10 @@
+package com.ylx.massage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ylx.massage.domain.ProductOrderItem;
+
+/**
+ * 商品订单明细Service接口
+ */
+public interface IProductOrderItemService extends IService<ProductOrderItem> {
+}

+ 178 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/ProductOrderInfoServiceImpl.java

@@ -0,0 +1,178 @@
+package com.ylx.massage.service.impl;
+
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ylx.common.exception.ServiceException;
+import com.ylx.massage.domain.Product;
+import com.ylx.massage.domain.ProductOrderInfo;
+import com.ylx.massage.domain.ProductOrderItem;
+import com.ylx.massage.domain.dto.ProductOrderCreateRequest;
+import com.ylx.massage.mapper.ProductMapper;
+import com.ylx.massage.mapper.ProductOrderInfoMapper;
+import com.ylx.massage.mapper.ProductOrderItemMapper;
+import com.ylx.massage.service.IProductOrderInfoService;
+import com.ylx.massage.utils.OrderNumberGenerator;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+
+/**
+ * 商品订单信息Service实现类
+ */
+@Service
+@Slf4j
+public class ProductOrderInfoServiceImpl extends ServiceImpl<ProductOrderInfoMapper, ProductOrderInfo> implements IProductOrderInfoService {
+
+    @Autowired
+    private ProductOrderInfoMapper productOrderInfoMapper;
+
+    @Autowired
+    private ProductOrderItemMapper productOrderItemMapper;
+
+    @Autowired
+    private OrderNumberGenerator orderNumberGenerator;
+
+    @Autowired
+    private ProductMapper productMapper;
+
+
+
+    /**
+     * 创建商品订单
+     *
+     * @param request 订单创建请求
+     * @return String 订单编号
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public String createProductOrder(ProductOrderCreateRequest request) {
+        // 1. 参数校验
+        validateRequest(request);
+
+        // 2. 生成订单编号
+        String orderNo = orderNumberGenerator.generateNextOrderNumber(OrderNumberGenerator.KEY_PREFIX_PRODUCTORDER);
+        log.info("创建商品订单,订单编号:{}", orderNo);
+
+        // 3. 构建订单主表信息
+        ProductOrderInfo orderInfo = buildOrderInfo(request, orderNo);
+
+        // 4. 保存订单主表
+        int insertResult = productOrderInfoMapper.insert(orderInfo);
+        if (insertResult <= 0) {
+            throw new ServiceException("订单创建失败");
+        }
+        log.info("订单主表保存成功,订单编号:{}", orderNo);
+
+        // 5. 构建订单商品明细
+        ProductOrderItem orderItem = buildOrderItem(request, orderInfo);
+
+        // 6. 保存订单商品明细
+        int itemInsertResult = productOrderItemMapper.insert(orderItem);
+        if (itemInsertResult <= 0) {
+            throw new ServiceException("订单商品明细创建失败");
+        }
+        log.info("订单商品明细保存成功,订单编号:{}", orderNo);
+        return orderNo;
+    }
+
+    /**
+     * 参数校验
+     *
+     * @param request 订单创建请求
+     */
+    private void validateRequest(ProductOrderCreateRequest request) {
+        if (request == null) {
+            throw new ServiceException("订单请求不能为空");
+        }
+        if (request.getOpenId() == null || request.getOpenId().trim().isEmpty()) {
+            throw new ServiceException("用户ID不能为空");
+        }
+        if (request.getAddressId() == null) {
+            throw new ServiceException("地址ID不能为空");
+        }
+        if (request.getProductId() == null) {
+            throw new ServiceException("商品ID不能为空");
+        }
+        // 根据商品ID查询商品信息
+        Product product = productMapper.selectById(request.getProductId());
+        if (product == null) {
+            throw new ServiceException("商品不存在");
+        }
+
+        if (request.getSkuId() == null) {
+            throw new ServiceException("SKU ID不能为空");
+        }
+        if (request.getQuantity() == null || request.getQuantity() <= 0) {
+            throw new ServiceException("购买数量必须大于0");
+        }
+        if (request.getPayType() == null || (request.getPayType() != 1 && request.getPayType() != 2)) {
+            throw new ServiceException("支付方式不正确");
+        }
+        if (request.getTotalAmount() == null || request.getTotalAmount() < 0) {
+            throw new ServiceException("总金额不能为空");
+        }
+        if (request.getPayAmount() == null || request.getPayAmount() < 0) {
+            throw new ServiceException("支付金额不能为空");
+        }
+    }
+
+    /**
+     * 构建订单主表信息
+     *
+     * @param request 订单创建请求
+     * @param orderNo 订单编号
+     * @return ProductOrderInfo 订单主表信息
+     */
+    private ProductOrderInfo buildOrderInfo(ProductOrderCreateRequest request, String orderNo) {
+        ProductOrderInfo orderInfo = new ProductOrderInfo();
+        orderInfo.setOrderNo(orderNo);
+        orderInfo.setOpenId(request.getOpenId());
+        orderInfo.setOrderStatus(0); // 待付款
+        orderInfo.setPayStatus(0); // 未支付
+        orderInfo.setPayType(request.getPayType());
+        orderInfo.setTotalAmount(request.getTotalAmount());
+        orderInfo.setDiscountAmount(0); // 优惠金额暂无
+        orderInfo.setFreightAmount(request.getFreightAmount() != null ? request.getFreightAmount() : 0);
+        orderInfo.setPayAmount(request.getPayAmount());
+        orderInfo.setPointsUsed(request.getPointsUsed() != null ? request.getPointsUsed() : 0);
+        orderInfo.setAddressId(request.getAddressId());
+        // 快递
+        orderInfo.setDeliveryType(1);
+        orderInfo.setBuyerRemark(request.getBuyerRemark());
+        // 支付超时时间15分钟
+        orderInfo.setPayExpireTime(LocalDateTime.now().plusMinutes(15));
+        return orderInfo;
+    }
+
+    /**
+     * 构建订单商品明细
+     *
+     * @param request 订单创建请求
+     * @param orderInfo 订单主表信息
+     * @return ProductOrderItem 订单商品明细
+     */
+    private ProductOrderItem buildOrderItem(ProductOrderCreateRequest request, ProductOrderInfo orderInfo) {
+        ProductOrderItem orderItem = new ProductOrderItem();
+        orderItem.setOrderId(orderInfo.getId());
+        orderItem.setOrderNo(orderInfo.getOrderNo());
+        orderItem.setProductId(request.getProductId());
+        orderItem.setProductName(request.getName());
+        orderItem.setSkuId(request.getSkuId());
+        // 将SKU规格信息转为JSON
+        if (request.getSpecNameValueList() != null && !request.getSpecNameValueList().isEmpty()) {
+            orderItem.setSkuSpec(JSONUtil.toJsonStr(request.getSpecNameValueList()));
+        }
+        orderItem.setSkuImage(request.getProductMainImage());
+        // 单价 = 总金额 / 数量
+        orderItem.setPrice(request.getTotalAmount() / request.getQuantity());
+        orderItem.setQuantity(request.getQuantity());
+        orderItem.setTotalAmount(request.getTotalAmount());
+        orderItem.setDiscountAmount(0); // 优惠金额暂无
+        orderItem.setActualAmount(request.getPayAmount());
+        orderItem.setRefundStatus(0); // 无退款
+        return orderItem;
+    }
+}

+ 14 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/ProductOrderItemServiceImpl.java

@@ -0,0 +1,14 @@
+package com.ylx.massage.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ylx.massage.domain.ProductOrderItem;
+import com.ylx.massage.mapper.ProductOrderItemMapper;
+import com.ylx.massage.service.IProductOrderItemService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 商品订单明细Service实现类
+ */
+@Service
+public class ProductOrderItemServiceImpl extends ServiceImpl<ProductOrderItemMapper, ProductOrderItem> implements IProductOrderItemService {
+}

+ 1 - 0
nightFragrance-massage/src/main/java/com/ylx/massage/service/impl/TOrderServiceImpl.java

@@ -51,6 +51,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
 
     @Resource
     private WechatAccountConfig wxPayProperties;
+
     @Resource
     private LocationUtil locationUtil;
 

+ 17 - 6
nightFragrance-massage/src/main/java/com/ylx/massage/utils/OrderNumberGenerator.java

@@ -1,5 +1,7 @@
 package com.ylx.massage.utils;
+
 import com.ylx.common.constant.MassageConstants;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import org.springframework.data.redis.core.script.DefaultRedisScript;
 import org.springframework.stereotype.Component;
@@ -9,6 +11,7 @@ import java.time.format.DateTimeFormatter;
 import java.util.Collections;
 
 @Component
+@Slf4j
 public class OrderNumberGenerator {
 
     //订单单号前缀
@@ -20,6 +23,8 @@ public class OrderNumberGenerator {
 
     public static final String KEY_PREFIX_REFUND = "REFUND";
 
+    public static final String KEY_PREFIX_PRODUCTORDER = "PRODUCT";
+
     private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
 
     private final StringRedisTemplate stringRedisTemplate;
@@ -45,8 +50,14 @@ public class OrderNumberGenerator {
     }
 
 
-
+    /**
+     * 使用Lua脚本原子性递增Redis键值
+     *
+     * @param key Redis键名
+     * @return Long递增后的键值
+     */
     public Long incrementByScript(String key) {
+        log.info("key的值:{}", key);
         if (key == null || key.trim().isEmpty()) {
             throw new IllegalArgumentException("Key cannot be null or empty");
         }
@@ -57,7 +68,8 @@ public class OrderNumberGenerator {
 
         try {
             Long execute = stringRedisTemplate.execute(redisScript, Collections.singletonList(key));
-            stringRedisTemplate.expireAt(key,LocalDateTime.of(LocalDate.now(), LocalTime.MAX).atZone(ZoneId.systemDefault()).toInstant());
+            log.info("递增后的键值:{}", execute);
+            stringRedisTemplate.expireAt(key, LocalDateTime.of(LocalDate.now(), LocalTime.MAX).atZone(ZoneId.systemDefault()).toInstant());
             return execute;
         } catch (Exception e) {
             // 根据业务需求,这里可以选择抛出运行时异常或者返回特定的错误码
@@ -73,12 +85,11 @@ public class OrderNumberGenerator {
 
         Instant instant = todayStart.atZone(ZoneId.systemDefault()).toInstant();
 
-        System.out.println("当前时间,当天的开始时间(日期+时分秒):"+ todayStart.format(dtf));
-        System.out.println("当前时间,当天的结束时间(日期+时分秒):"+ todayEnd.format(dtf));
-        System.out.println("当前的时间(只有日期)"+LocalDate.now());
+        System.out.println("当前时间,当天的开始时间(日期+时分秒):" + todayStart.format(dtf));
+        System.out.println("当前时间,当天的结束时间(日期+时分秒):" + todayEnd.format(dtf));
+        System.out.println("当前的时间(只有日期)" + LocalDate.now());
         System.out.println(instant);
     }
 
 
-
 }