Bladeren bron

线上新件返还

FengChaoYu 8 maanden geleden
bovenliggende
commit
bac8289cb7
24 gewijzigde bestanden met toevoegingen van 1176 en 23 verwijderingen
  1. 14 0
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/bean/inf/ValidGroup.java
  2. 144 0
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/bean/material/parts/NewRefundManageBean.java
  3. 65 0
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/bean/material/parts/NewRefundManageItemBean.java
  4. 16 0
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/bean/material/parts/NewRefundManageRecordBean.java
  5. 124 0
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/bean/material/parts/PartsRefundRecordDTO.java
  6. 48 0
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/bean/material/parts/SalesItemRecordDTO.java
  7. 22 3
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/bean/material/stock/WorkerStockDTO.java
  8. 23 0
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/commonmapper/MaterialMapper.java
  9. 2 0
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/constant/Constant.java
  10. 1 2
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/controller/material/WorkerStockController.java
  11. 82 0
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/controller/material/parts/NewRefundController.java
  12. 21 0
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/enums/material/DirectFlagEnum.java
  13. 5 1
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/enums/material/PartsAttrEnum.java
  14. 27 0
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/enums/material/PartsOrderFlagEnum.java
  15. 21 0
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/enums/material/PartsPushFlagEnum.java
  16. 25 0
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/enums/material/PartsRefTypeEnum.java
  17. 22 0
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/enums/material/PartsRefundModeEnum.java
  18. 23 0
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/enums/material/PartsRefundStateEnum.java
  19. 22 0
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/logic/common/CommonLogic.java
  20. 219 0
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/logic/material/parts/NewRefundManageLogic.java
  21. 114 2
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/logic/material/stock/WorkerStockLogic.java
  22. 4 4
      mall-miniapp-service/src/main/java/com/gree/mall/miniapp/logic/order/PayOrderLogic.java
  23. 121 0
      mall-miniapp-service/src/main/resources/mapper/MaterialMapper.xml
  24. 11 11
      mall-server-api/src/main/java/com/gree/mall/manager/constant/Constant.java

+ 14 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/bean/inf/ValidGroup.java

@@ -0,0 +1,14 @@
+package com.gree.mall.miniapp.bean.inf;
+
+/**
+ * 校验分组
+ */
+public interface ValidGroup {
+    interface Add {
+
+    }
+
+    interface Edit {
+
+    }
+}

+ 144 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/bean/material/parts/NewRefundManageBean.java

@@ -0,0 +1,144 @@
+package com.gree.mall.miniapp.bean.material.parts;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.gree.mall.miniapp.bean.inf.ValidGroup;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import javax.validation.constraints.*;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+@Data
+@ApiModel
+@Accessors(chain = true)
+@JsonIgnoreProperties(value = {"createBy", "createTime", "updateBy", "updateTime", "submitBy"
+        , "submitTime", "examineBy", "examineTime", "refundedBy", "refundedTime"}, allowGetters = true)
+public class NewRefundManageBean {
+
+    private String companyWechatId;
+    private String companyWechatName;
+
+    @ApiModelProperty("申请单号")
+    @Null(groups = ValidGroup.Add.class, message = "申请单号必须为空")
+    @NotNull(groups = ValidGroup.Edit.class, message = "申请单号不能为空")
+    private String applyNo;
+
+    @ApiModelProperty("销售单号")
+    @NotBlank(groups = {ValidGroup.Add.class, ValidGroup.Edit.class}, message = "销售单id不能空")
+    private String salesId;
+
+    @ApiModelProperty(value = "申请类别", required = true)
+    @NotBlank(groups = {ValidGroup.Add.class, ValidGroup.Edit.class}, message = "申请类别不能空")
+    private String applyCategory;
+
+    @ApiModelProperty(value = "申请类别")
+    private String applyCategoryName;
+
+    @ApiModelProperty(value = "申请类型", required = true)
+    @NotBlank(groups = {ValidGroup.Add.class, ValidGroup.Edit.class}, message = "申请类型不能空")
+    @Pattern(regexp = "^NEW|LOST|BUG$", message = "申请类型错误")
+    private String applyType;
+
+    @ApiModelProperty(value = "申请类型")
+    private String applyTypeName;
+
+    @ApiModelProperty(value = "返还方式", required = true)
+    @NotBlank(groups = {ValidGroup.Add.class, ValidGroup.Edit.class}, message = "返还方式不能空")
+    private String refundMode;
+
+    @ApiModelProperty(value = "返还方式")
+    private String refundModeName;
+
+    @ApiModelProperty("快递单号")
+    private String expressNo;
+
+    @ApiModelProperty("收货地址")
+    private String receiveAddress;
+
+    @ApiModelProperty(value = "接收网点编号", required = true)
+    @NotBlank(groups = {ValidGroup.Add.class, ValidGroup.Edit.class}, message = "接收网点编号不能空")
+    private String receiveWebsitId;
+
+    @ApiModelProperty("接收网点名称")
+    private String receiveWebsitName;
+
+    @ApiModelProperty("接收配件网点编号")
+    private String receivePartsWebsitId;
+
+    @ApiModelProperty("网点地址")
+    private String websitAddress;
+
+    @ApiModelProperty(value = "师傅身份证", required = true)
+    @NotBlank(groups = {ValidGroup.Add.class, ValidGroup.Edit.class}, message = "师傅身份证不能空")
+    private String identity;
+
+    @ApiModelProperty(value = "师傅编号", required = true)
+    @NotBlank(groups = {ValidGroup.Add.class, ValidGroup.Edit.class}, message = "师傅编号不能空")
+    private String workerId;
+
+    @ApiModelProperty(value = "师傅名称", required = true)
+    @NotBlank(groups = {ValidGroup.Add.class, ValidGroup.Edit.class}, message = "师傅名称不能空")
+    private String workerName;
+
+    @ApiModelProperty("退款金额")
+    private BigDecimal refundAmount;
+
+    @ApiModelProperty("退款方式")
+    private String refundAmountMode;
+
+    @ApiModelProperty("退款方式")
+    private String refundAmountModeName;
+
+    @ApiModelProperty("备注")
+    private String remark;
+
+    @ApiModelProperty("审批备注")
+    private String examineRemark;
+
+    @ApiModelProperty("单据状态")
+    private String flag;
+
+    @ApiModelProperty("单据状态")
+    private String flagName;
+
+    @ApiModelProperty("创建人")
+    private String createBy;
+
+    @ApiModelProperty("创建时间")
+    private Date createTime;
+
+    @ApiModelProperty("更新人")
+    private String updateBy;
+
+    @ApiModelProperty("更新时间")
+    private Date updateTime;
+
+    @ApiModelProperty("提交人")
+    private String submitBy;
+
+    @ApiModelProperty("提交时间")
+    private Date submitTime;
+
+    @ApiModelProperty("审核人")
+    private String examineBy;
+
+    @ApiModelProperty("审核时间")
+    private Date examineTime;
+
+    @ApiModelProperty("确认返还人")
+    private String refundedBy;
+
+    @ApiModelProperty("确认返还时间")
+    private Date refundedTime;
+
+    @ApiModelProperty("申请明细")
+    @NotEmpty(groups = {ValidGroup.Add.class, ValidGroup.Edit.class}, message = "申请明细不能空")
+    private List<NewRefundManageItemBean> newRefundManageItemBeanList;
+
+    @ApiModelProperty("记录")
+    private List<NewRefundManageRecordBean> partsNewRefundManageRecordList;
+}

+ 65 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/bean/material/parts/NewRefundManageItemBean.java

@@ -0,0 +1,65 @@
+package com.gree.mall.miniapp.bean.material.parts;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.gree.mall.miniapp.bean.inf.ValidGroup;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Null;
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@ApiModel
+@JsonIgnoreProperties(value = {"id"}, allowGetters = true)
+public class NewRefundManageItemBean {
+
+    private static final long serialVersionUID = 1L;
+
+    @Null(groups = {ValidGroup.Add.class}, message = "id必须为空")
+    private String id;
+
+    @ApiModelProperty("申请单号")
+    private String applyNo;
+
+    @ApiModelProperty("销售单id")
+    private String salesId;
+
+    @ApiModelProperty("配件编码")
+    @NotBlank(groups = {ValidGroup.Add.class, ValidGroup.Edit.class}, message = "配件编码不能空")
+    private String partsNumber;
+
+    @ApiModelProperty("配件名称")
+    @NotBlank(groups = {ValidGroup.Add.class, ValidGroup.Edit.class}, message = "配件名称不能空")
+    private String partsName;
+
+    @ApiModelProperty("物料组名称")
+    @NotBlank(groups = {ValidGroup.Add.class, ValidGroup.Edit.class}, message = "物料组名称不能空")
+    private String materialGroupName;
+
+    @ApiModelProperty("单位名称")
+    @NotBlank(groups = {ValidGroup.Add.class, ValidGroup.Edit.class}, message = "单位名称不能空")
+    private String goodsStockUnit;
+
+    @ApiModelProperty("数量")
+    @NotNull(groups = {ValidGroup.Add.class, ValidGroup.Edit.class}, message = "数量不能空")
+    private BigDecimal qty;
+
+    @ApiModelProperty("备注")
+    private String remark;
+
+    @ApiModelProperty("图片地址")
+    private String image;
+
+    @ApiModelProperty("自编码")
+    private String customNo;
+
+    @ApiModelProperty("创建时间")
+    private Date createTime;
+
+    @ApiModelProperty("库存数量")
+    private BigDecimal stockQty = new BigDecimal("0");
+}

+ 16 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/bean/material/parts/NewRefundManageRecordBean.java

@@ -0,0 +1,16 @@
+package com.gree.mall.miniapp.bean.material.parts;
+
+import com.gree.mall.miniapp.plus.entity.WebsitPartsNewRefundManageRecord;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@ApiModel
+public class NewRefundManageRecordBean extends WebsitPartsNewRefundManageRecord {
+
+    @ApiModelProperty("新件返还明细id")
+    private String refundStateName;
+}

+ 124 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/bean/material/parts/PartsRefundRecordDTO.java

@@ -0,0 +1,124 @@
+package com.gree.mall.miniapp.bean.material.parts;
+
+import cn.hutool.core.date.DateUtil;
+import com.gree.mall.miniapp.enums.material.PartsRefTypeEnum;
+import com.gree.mall.miniapp.plus.entity.WebsitPartsSalesItem;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+public class PartsRefundRecordDTO {
+
+    @ApiModelProperty("返还明细id")
+    private String itemId;
+
+    @ApiModelProperty("申请单号")
+    private String applyNo;
+
+    @ApiModelProperty("销售单id")
+    private String salesId;
+
+    @ApiModelProperty("销售单明细id")
+    private String salesItemId;
+
+    @ApiModelProperty("配件编码")
+    private String partsNumber;
+
+    @ApiModelProperty("配件名称")
+    private String partsName;
+
+    @ApiModelProperty("销售价")
+    private BigDecimal salesPrice;
+
+    @ApiModelProperty("市场价")
+    private BigDecimal marketPrice;
+
+    @ApiModelProperty("优惠价2")
+    private BigDecimal secondPrice;
+
+    @ApiModelProperty("数量")
+    private BigDecimal qty;
+
+    @ApiModelProperty("总金额")
+    private BigDecimal totalAmount;
+
+    @ApiModelProperty("退款方式 WX=微信 CASH=现金")
+    private String refundAmountMode;
+
+    @ApiModelProperty("退款金额")
+    private BigDecimal refundAmount;
+
+    @ApiModelProperty("维修标识 INNER=保内 OUTSIDE=保外")
+    private String repairFlag;
+
+    @ApiModelProperty("工单编号")
+    private String workOrderNo;
+
+    @ApiModelProperty("总部工单派工id")
+    private String pgId;
+
+    @ApiModelProperty("用户名称")
+    private String customerName;
+
+    @ApiModelProperty("用户电话")
+    private String customerTel;
+
+    @ApiModelProperty("是否备用件 false=否 true=是")
+    private Boolean isBackup;
+
+    @ApiModelProperty("创建时间")
+    private Date createTime;
+
+
+    public void injectData(SalesItemRecordDTO itemRecordDTO, WebsitPartsSalesItem salesOrderItem, BigDecimal qty, String refType) {
+        this.itemId = itemRecordDTO.getItemId();
+        this.applyNo = itemRecordDTO.getApplyNo();
+        this.salesId = salesOrderItem.getSalesId();
+        this.salesItemId = salesOrderItem.getId();
+        this.partsNumber = salesOrderItem.getPartsNumber();
+        this.partsName = salesOrderItem.getPartsName();
+        this.salesPrice = salesOrderItem.getSalesPrice();
+        this.marketPrice = salesOrderItem.getMarketPrice();
+        this.secondPrice = salesOrderItem.getSecondPrice();
+        this.qty = qty;
+        this.totalAmount = salesOrderItem.getSalesPrice().multiply(qty);
+        this.repairFlag = itemRecordDTO.getRepairFlag();
+        this.workOrderNo = itemRecordDTO.getWorkOrderNo();
+        this.pgId = itemRecordDTO.getPgId();
+        this.customerName = itemRecordDTO.getCustomerName();
+        this.customerTel = itemRecordDTO.getCustomerTel();
+        this.isBackup = itemRecordDTO.getIsBackup();
+        this.createTime = DateUtil.date();
+        this.refundAmountMode = salesOrderItem.getRefundAmountMode();
+        if (refType.equals(PartsRefTypeEnum.OLD_REFUND.getKey()) || refType.equals(PartsRefTypeEnum.NEW_REFUND.getKey())) {
+            // 旧件返还保内或新件返还 全额退还
+            this.refundAmount = salesOrderItem.getSalesPrice().multiply(qty);
+        } else if (refType.equals(PartsRefTypeEnum.OUTSIDE_TO_SALES.getKey())) {
+            // 保外新件转销售的市场价-优惠价2的差价退还(旧计算方式)
+//            this.refundAmount = salesOrderItem.getMarketPrice().subtract(salesOrderItem.getSecondPrice()).multiply(qty);
+            // 销售价-优惠价2*1.2倍  返还差价
+            this.refundAmount = BigDecimal.ZERO;
+            if (salesOrderItem.getSecondPrice().compareTo(BigDecimal.ZERO) > 0) {
+                this.refundAmount = this.computeDiffAmount(salesOrderItem.getSalesPrice(), salesOrderItem.getSecondPrice(), qty);
+            }
+
+        }
+
+        if (refType.equals(PartsRefTypeEnum.NEW_REFUND.toString())) {
+            // 销售明细新件数量增加
+            salesOrderItem.setNewRefundQty(salesOrderItem.getNewRefundQty().add(qty));
+        } else {
+            // 销售明细旧件数量增加
+            salesOrderItem.setOldRefundQty(salesOrderItem.getOldRefundQty().add(qty));
+        }
+        // 销售明细数量减少
+        salesOrderItem.setQty(salesOrderItem.getQty().subtract(qty));
+    }
+
+    public BigDecimal computeDiffAmount(BigDecimal salesPrice, BigDecimal secondPrice, BigDecimal qty) {
+        return salesPrice.subtract(secondPrice.multiply(BigDecimal.valueOf(1.2))).multiply(qty);
+    }
+}

+ 48 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/bean/material/parts/SalesItemRecordDTO.java

@@ -0,0 +1,48 @@
+package com.gree.mall.miniapp.bean.material.parts;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Data
+public class SalesItemRecordDTO {
+
+    @ApiModelProperty("明细id")
+    private String itemId;
+
+    @ApiModelProperty("申请单号")
+    private String applyNo;
+
+    @ApiModelProperty("配件编码")
+    private String partsNumber;
+
+    @ApiModelProperty("配件名称")
+    private String partsName;
+
+    @ApiModelProperty("数量")
+    private BigDecimal qty;
+
+    @ApiModelProperty("销售单id")
+    private String salesId;
+
+    @ApiModelProperty("维修标识 INNER=保内 OUTSIDE=保外")
+    private String repairFlag;
+
+    @ApiModelProperty("工单编号")
+    private String workOrderNo;
+
+    @ApiModelProperty("总部工单派工id")
+    private String pgId;
+
+    @ApiModelProperty("用户名称")
+    private String customerName;
+
+    @ApiModelProperty("用户电话")
+    private String customerTel;
+
+    @ApiModelProperty("是否备用件 false=否 true=是")
+    private Boolean isBackup;
+
+
+}

+ 22 - 3
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/bean/material/stock/WorkerStockDTO.java

@@ -53,6 +53,9 @@ public class WorkerStockDTO {
     @NotBlank(message = "销售网点名称不能空")
     private String websitName;
 
+    @ApiModelProperty("配件网点编号")
+    private String partsWebsitId;
+
     @ApiModelProperty("商品类型")
     @NotNull(message = "商品类型不能空")
     private String goodsType;
@@ -70,10 +73,10 @@ public class WorkerStockDTO {
     private String goodsName;
 
     @ApiModelProperty("单位id")
-    private String unitId;
+    private String goodsStockUnit;
 
-    @ApiModelProperty("单位名称")
-    private String unitName;
+    @ApiModelProperty("物料组名称")
+    private String materialGroupName;
 
     @ApiModelProperty("发生单价")
     private BigDecimal price;
@@ -142,6 +145,14 @@ public class WorkerStockDTO {
             qty = workerStock.getQty();
         } else if (this.partsAttr.equals(PartsAttrEnum.OLD.toString())) {
             qty = workerStock.getOldQty();
+        } else if (this.partsAttr.equals(PartsAttrEnum.TEMP_NEW.toString())) {
+            qty = workerStock.getTempNewQty();
+        } else if (this.partsAttr.equals(PartsAttrEnum.TEMP_OLD.toString())) {
+            qty = workerStock.getTempOldQty();
+        } else if (this.partsAttr.equals(PartsAttrEnum.WAY.toString())) {
+            qty = workerStock.getWayQty();
+        } else if (this.partsAttr.equals(PartsAttrEnum.CHANGE_NEW.toString())) {
+            qty = workerStock.getChangeSalesQty();
         } else {
             throw new RemoteServiceException("配件库存属性不匹配:" + this.partsAttr);
         }
@@ -164,6 +175,14 @@ public class WorkerStockDTO {
             workerStock.setQty(closeQty);
         } else if (this.partsAttr.equals(PartsAttrEnum.OLD.toString())) {
             workerStock.setOldQty(closeQty);
+        } else if (this.partsAttr.equals(PartsAttrEnum.TEMP_NEW.toString())) {
+            workerStock.setTempNewQty(closeQty);
+        } else if (this.partsAttr.equals(PartsAttrEnum.TEMP_OLD.toString())) {
+            workerStock.setTempOldQty(closeQty);
+        } else if (this.partsAttr.equals(PartsAttrEnum.WAY.toString())) {
+            workerStock.setWayQty(closeQty);
+        } else if (this.partsAttr.equals(PartsAttrEnum.CHANGE_NEW.toString())) {
+            workerStock.setChangeSalesQty(closeQty);
         }
         workerStock.setOperBy(this.operateBy)
                 .setOperTime(this.operateTime);

+ 23 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/commonmapper/MaterialMapper.java

@@ -4,7 +4,10 @@ import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.gree.mall.miniapp.bean.material.*;
+import com.gree.mall.miniapp.bean.material.parts.NewRefundManageBean;
+import com.gree.mall.miniapp.bean.material.parts.SalesItemRecordDTO;
 import com.gree.mall.miniapp.bean.material.stock.WorkerNormStockBean;
+import com.gree.mall.miniapp.plus.entity.WebsitPartsSalesItem;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
@@ -100,4 +103,24 @@ public interface MaterialMapper {
      * @return
      */
     List<WorkerNormStockBean> queryWorkerStockQty(@Param("goodsId") String goodsId, @Param("workerId") String workerId);
+
+    @InterceptorIgnore(tenantLine = "1", blockAttack = "1", illegalSql = "1")
+    IPage<NewRefundManageBean> appList(IPage page,
+                                       @Param("applyNo") String applyNo,
+                                       @Param("flag") String flag,
+                                       @Param("identity") String identity,
+                                       @Param("partsNumber") String partsNumber);
+
+    /**
+     * 带锁的查询
+     * @param websitId
+     * @param salesId
+     * @param partsWebsitId
+     * @param identity
+     * @param pushFlag
+     * @param records
+     * @return
+     */
+    List<WebsitPartsSalesItem> querySalesPushFlagItem(String websitId, String salesId, String partsWebsitId,
+                                                      String identity, String pushFlag, List<SalesItemRecordDTO> records);
 }

+ 2 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/constant/Constant.java

@@ -57,6 +57,8 @@ public class Constant {
 
         // 查询通联支付订单信息
         public final static String QUERY_ALLINPAY_ORDER = "jsm:sxb:lock:a:query:order:";
+        public static final String PARTS_SALES = "jsm:sxb:lock:parts:sales:";
+        public static final String WRITE_SALES_ITEM = "jsm:sxb:parts:write:sales:item:";
     }
 
     //礼品卡支持的市

+ 1 - 2
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/controller/material/WorkerStockController.java

@@ -6,10 +6,9 @@ import com.gree.mall.miniapp.bean.material.stock.WorkerStockAccBean;
 import com.gree.mall.miniapp.bean.material.stock.WorkerStockBean;
 import com.gree.mall.miniapp.exception.RemoteServiceException;
 import com.gree.mall.miniapp.helper.ResponseHelper;
-import com.gree.mall.miniapp.logic.material.WorkerStockLogic;
+import com.gree.mall.miniapp.logic.material.stock.WorkerStockLogic;
 import com.gree.mall.miniapp.plus.entity.WebsitGoodsCategory;
 import com.gree.mall.miniapp.plus.entity.WorkerStock;
-import com.gree.mall.miniapp.plus.entity.WorkerStockAcc;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;

+ 82 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/controller/material/parts/NewRefundController.java

@@ -0,0 +1,82 @@
+package com.gree.mall.miniapp.controller.material.parts;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.gree.mall.miniapp.bean.inf.ValidGroup;
+import com.gree.mall.miniapp.bean.material.parts.NewRefundManageBean;
+import com.gree.mall.miniapp.bean.material.parts.NewRefundManageItemBean;
+import com.gree.mall.miniapp.constant.Constant;
+import com.gree.mall.miniapp.exception.RemoteServiceException;
+import com.gree.mall.miniapp.helper.ResponseHelper;
+import com.gree.mall.miniapp.logic.material.parts.NewRefundManageLogic;
+import com.gree.mall.miniapp.utils.ValidateUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.integration.redis.util.RedisLockRegistry;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.ValidationException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+
+@Slf4j
+@RestController
+@Api(value = "新件返还管理", tags ={"新件返还管理"} )
+@RequestMapping(value = "/app/worker/new-refund", produces = "application/json; charset=utf-8")
+public class NewRefundController {
+
+    @Resource
+    NewRefundManageLogic newRefundManageLogic;
+    @Resource
+    RedisLockRegistry redisLockRegistry;
+
+    @GetMapping("/list")
+    @ApiOperation(value = "新件返还管理列表")
+    public ResponseHelper<IPage<NewRefundManageBean>> appList(
+            @ApiParam(value = "申请单号") @RequestParam(required = false) String applyNo,
+            @ApiParam(value = "单据状态 SAVE=保存 SUBMIT=提交 AGREE=通过 REJECT=驳回 REFUNDED=已返还") @RequestParam(required = false) String flag,
+            @ApiParam(value = "师傅身份证", required = true) @RequestParam String identity,
+            @ApiParam(value = "配件编码") @RequestParam(required = false) String partsNumber,
+            @ApiParam(value = "页号",required = true) @RequestParam Integer pageNo,
+            @ApiParam(value = "页大小",required = true) @RequestParam Integer pageSize
+    ) throws RemoteServiceException {
+        return ResponseHelper.success(newRefundManageLogic.appList(applyNo, flag, identity, partsNumber, pageNo, pageSize));
+    }
+
+    @GetMapping("/detail")
+    @ApiOperation(value = "新件返还管理详情")
+    public ResponseHelper<NewRefundManageBean> detail(
+            @ApiParam(value = "申请单号",required = true) @RequestParam String applyNo
+    ) throws RemoteServiceException {
+        return ResponseHelper.success(newRefundManageLogic.detail(applyNo));
+    }
+
+    @PostMapping("/add")
+    @ApiOperation(value = "新件返还申请")
+    public ResponseHelper add(
+            @RequestBody NewRefundManageBean newRefundManageBean
+    ) throws Exception {
+        Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.PARTS_SALES + newRefundManageBean.getSalesId());
+        if (!obtain.tryLock(5, TimeUnit.SECONDS)) {
+            throw new RemoteServiceException("销售单冻结中");
+        }
+        try {
+            // 校验
+            ValidateUtil.validate(newRefundManageBean, ValidGroup.Add.class);
+            for (NewRefundManageItemBean itemBean : newRefundManageBean.getNewRefundManageItemBeanList()) {
+                try {
+                    ValidateUtil.validate(itemBean, ValidGroup.Add.class);
+                } catch (ValidationException e) {
+                    throw new RemoteServiceException("“" +itemBean.getPartsName() + "”出错原因:" + e.getMessage());
+                }
+            }
+            newRefundManageLogic.add(newRefundManageBean);
+        } finally {
+            obtain.unlock();
+        }
+
+        return ResponseHelper.success();
+    }
+}

+ 21 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/enums/material/DirectFlagEnum.java

@@ -0,0 +1,21 @@
+package com.gree.mall.miniapp.enums.material;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.fasterxml.jackson.annotation.JsonValue;
+import com.gree.mall.miniapp.enums.base.BaseEnum;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
+public enum DirectFlagEnum implements BaseEnum {
+    ADD("ADD","增加"),
+    SUB("SUB","减少");
+
+    @EnumValue
+    @JsonValue
+    private final String key;
+
+    private final String remark;
+}

+ 5 - 1
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/enums/material/PartsAttrEnum.java

@@ -6,7 +6,11 @@ import lombok.Getter;
 public enum PartsAttrEnum {
 
     NEW("新件"),
-    OLD("旧件"),;
+    OLD("旧件"),
+    WAY("在途"),
+    TEMP_NEW("临占新件"),
+    TEMP_OLD("临占旧件"),
+    CHANGE_NEW("转销售新件"),;
 
     PartsAttrEnum(String name) {
         this.name = name;

+ 27 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/enums/material/PartsOrderFlagEnum.java

@@ -0,0 +1,27 @@
+package com.gree.mall.miniapp.enums.material;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.fasterxml.jackson.annotation.JsonValue;
+import com.gree.mall.miniapp.enums.base.BaseEnum;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
+public enum PartsOrderFlagEnum implements BaseEnum {
+    SAVE("SAVE","保存"),
+    SUBMIT("SUBMIT","提交"),
+    AGREE("AGREE","通过"),
+    REJECT("REJECT","驳回"),
+    REFUNDED("REFUNDED","已返还"),
+    NOTREFUND("NOTREFUND","未返还"),
+    WAIT_REVIEW("WAIT_REVIEW", "待复核"),
+    REVIEWED("REVIEWED", "已复核"),
+    ;
+
+    @EnumValue
+    @JsonValue
+    private final String key;
+    private final String remark;
+}

+ 21 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/enums/material/PartsPushFlagEnum.java

@@ -0,0 +1,21 @@
+package com.gree.mall.miniapp.enums.material;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.fasterxml.jackson.annotation.JsonValue;
+import com.gree.mall.miniapp.enums.base.BaseEnum;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
+public enum PartsPushFlagEnum implements BaseEnum {
+    SALES("SALES","销售"),
+    TRANS("TRANS","转销售"),
+    END("END","完结"),;
+
+    @EnumValue
+    @JsonValue
+    private final String key;
+    private final String remark;
+}

+ 25 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/enums/material/PartsRefTypeEnum.java

@@ -0,0 +1,25 @@
+package com.gree.mall.miniapp.enums.material;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.fasterxml.jackson.annotation.JsonValue;
+import com.gree.mall.miniapp.enums.base.BaseEnum;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
+public enum PartsRefTypeEnum implements BaseEnum {
+    SALES("SALES","销售"),
+    CHANGE_SALES("CHANGE_SALES","新件转销售"),
+    NEW_REFUND("NEW_REFUND","新件返还"),
+    OLD_REFUND("OLD_REFUND","旧件返还"),
+    OUTSIDE_TO_SALES("OUTSIDE_TO_SALES","保外新件转销售"),
+
+    ;
+
+    @EnumValue
+    @JsonValue
+    private final String key;
+    private final String remark;
+}

+ 22 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/enums/material/PartsRefundModeEnum.java

@@ -0,0 +1,22 @@
+package com.gree.mall.miniapp.enums.material;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.fasterxml.jackson.annotation.JsonValue;
+import com.gree.mall.miniapp.enums.base.BaseEnum;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
+public enum PartsRefundModeEnum implements BaseEnum {
+    EXPRESS("EXPRESS","快递"),
+    SELF("SELF","网点自还"),
+    ;
+
+    @EnumValue
+    @JsonValue
+    private final String key;
+
+    private final String remark;
+}

+ 23 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/enums/material/PartsRefundStateEnum.java

@@ -0,0 +1,23 @@
+package com.gree.mall.miniapp.enums.material;
+
+import com.baomidou.mybatisplus.annotation.EnumValue;
+import com.fasterxml.jackson.annotation.JsonValue;
+import com.gree.mall.miniapp.enums.base.BaseEnum;
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
+public enum PartsRefundStateEnum implements BaseEnum {
+    OK("OK","成功"),
+    FAIL("FAIL","失败"),
+    WAIT("WAIT","等待"),
+    ;
+
+    @EnumValue
+    @JsonValue
+    private final String key;
+
+    private final String remark;
+}

+ 22 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/logic/common/CommonLogic.java

@@ -316,6 +316,28 @@ public class CommonLogic {
         return list;
     }
 
+    /**
+     * 生成辅材编号
+     * @param companyId 商户编号
+     * @param start 前缀
+     * @param orderType 订单类型
+     * @param length 一般13 位
+     * @return
+     */
+    public String generateMaterialNo(String companyId, String start, String orderType, int length) {
+        String dayFmt = DateUtil.format(new Date(), "yyyyMMdd");
+        String tNumKey = Constant.RedisPrefix.ORDER_NUM + dayFmt + orderType + companyId;
+        StringBuilder number = new StringBuilder();
+        number.append(start);
+        number.append(dayFmt);
+        int ramainLen = length - number.toString().length();
+        //自增 填充位数
+        Object value = redisUtil.incr(tNumKey, 1);
+        redisUtil.expire(tNumKey, 24 * 60 * 60);
+        number.append(String.format("%0" + ramainLen + "d", Integer.parseInt(value.toString())));
+        return number.toString();
+    }
+
     public String getInfToken() throws RemoteServiceException {
         Object token = redisUtil.get(Constant.RedisPrefix.INF_TOKEN);
 

+ 219 - 0
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/logic/material/parts/NewRefundManageLogic.java

@@ -0,0 +1,219 @@
+package com.gree.mall.miniapp.logic.material.parts;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateUtil;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.gree.mall.miniapp.bean.material.parts.NewRefundManageBean;
+import com.gree.mall.miniapp.bean.material.parts.NewRefundManageItemBean;
+import com.gree.mall.miniapp.bean.material.parts.PartsRefundRecordDTO;
+import com.gree.mall.miniapp.bean.material.stock.WorkerStockDTO;
+import com.gree.mall.miniapp.bean.user.CurrentCompanyWechat;
+import com.gree.mall.miniapp.commonmapper.MaterialMapper;
+import com.gree.mall.miniapp.enums.PayTypeEnum;
+import com.gree.mall.miniapp.enums.admin.AdminWebsitTypeEnum;
+import com.gree.mall.miniapp.enums.material.*;
+import com.gree.mall.miniapp.exception.RemoteServiceException;
+import com.gree.mall.miniapp.logic.common.CommonLogic;
+import com.gree.mall.miniapp.logic.material.stock.WorkerStockLogic;
+import com.gree.mall.miniapp.plus.entity.*;
+import com.gree.mall.miniapp.plus.service.AdminWebsitService;
+import com.gree.mall.miniapp.plus.service.WebsitPartsNewRefundManageItemService;
+import com.gree.mall.miniapp.plus.service.WebsitPartsNewRefundManageRecordService;
+import com.gree.mall.miniapp.plus.service.WebsitPartsSalesItemService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+@Service
+@Slf4j
+public class NewRefundManageLogic {
+
+    @Resource
+    CommonLogic commonLogic;
+    @Resource
+    MaterialMapper materialMapper;
+    @Resource
+    AdminWebsitService adminWebsitService;
+    @Resource
+    WebsitPartsSalesItemService websitPartsSalesItemService;
+    @Resource
+    WebsitPartsNewRefundManageItemService websitPartsNewRefundManageItemService;
+    @Resource
+    WebsitPartsNewRefundManageRecordService websitPartsNewRefundManageRecordService;
+    @Resource
+    WorkerStockLogic workerStockLogic;
+
+    public IPage<NewRefundManageBean> appList(String applyNo, String flag, String identity, String partsNumber, Integer pageNo, Integer pageSize) {
+        IPage<NewRefundManageBean> page = materialMapper.appList(new Page(pageNo, pageSize), applyNo, flag, identity, partsNumber);
+        return page;
+    }
+
+    public NewRefundManageBean detail(String applyNo) {
+        IPage<NewRefundManageBean> page = materialMapper.appList(new Page(1, -1), applyNo, null, null, null);
+        if (CollectionUtil.isEmpty(page.getRecords())) {
+            throw new RemoteServiceException("单据不存在");
+        }
+        NewRefundManageBean newRefundManageBean = page.getRecords().get(0);
+        return newRefundManageBean;
+    }
+
+    @Transactional
+    public void add(NewRefundManageBean newRefundManageBean) throws Exception {
+        final CurrentCompanyWechat wechat = commonLogic.getCurrentCompanyWechat();
+        newRefundManageBean.setCompanyWechatId(wechat.getCompanyWechatId())
+                .setCompanyWechatName(wechat.getCompanyName());
+        // 查询接收网点
+        AdminWebsit websit = adminWebsitService.lambdaQuery()
+                .eq(AdminWebsit::getCompanyWechatId, newRefundManageBean.getCompanyWechatId())
+                .eq(AdminWebsit::getWebsitId, newRefundManageBean.getReceiveWebsitId())
+                .eq(AdminWebsit::getStatus, Boolean.TRUE)
+                .eq(AdminWebsit::getType, AdminWebsitTypeEnum.C.getKey())
+                .one();
+        if (Objects.isNull(websit)) {
+            throw new RemoteServiceException("接收网点不存在");
+        }
+        // 查询师傅在接收网点的库存
+        List<WebsitPartsSalesItem> salesOrderItems = websitPartsSalesItemService.lambdaQuery()
+                .eq(WebsitPartsSalesItem::getSalesId, newRefundManageBean.getSalesId())
+                .list();
+        Map<String, WebsitPartsSalesItem> workerStockMap = salesOrderItems.stream()
+                .collect(Collectors.toMap(WebsitPartsSalesItem::getPartsNumber, Function.identity()));
+        for (NewRefundManageItemBean itemBean : newRefundManageBean.getNewRefundManageItemBeanList()) {
+            WebsitPartsSalesItem workerStock = workerStockMap.get(itemBean.getPartsNumber());
+            if (Objects.isNull(workerStock)) {
+                throw new RemoteServiceException("“" + itemBean.getPartsName() + "”配件未找到记录");
+            }
+            if (itemBean.getQty().compareTo(workerStock.getQty()) > 0) {
+                throw new RemoteServiceException("“" + workerStock.getPartsName() + "”归还新件数量不能大于销售单剩余数量");
+            }
+            if (itemBean.getQty().compareTo(BigDecimal.ZERO) < 1) {
+                throw new RemoteServiceException("“" + workerStock.getPartsName() + "”归还新件数量必须大于0");
+            }
+        }
+        String sheetId = commonLogic.generateMaterialNo(newRefundManageBean.getCompanyWechatId(), "XH", PartsRefTypeEnum.NEW_REFUND.getKey(), 13);
+        newRefundManageBean.setApplyNo(sheetId);
+        newRefundManageBean.setReceiveWebsitName(websit.getName());
+        newRefundManageBean.setReceivePartsWebsitId(websit.getPartsWebsitId());
+        newRefundManageBean.setWebsitAddress(websit.getAddress());
+        newRefundManageBean.setCreateTime(DateUtil.date());
+        newRefundManageBean.setUpdateTime(DateUtil.date());
+        newRefundManageBean.setSubmitBy(newRefundManageBean.getWorkerName());
+        newRefundManageBean.setSubmitTime(DateUtil.date());
+        newRefundManageBean.setFlag(PartsOrderFlagEnum.SUBMIT.getKey());
+
+        // 保存主表和明细
+        WebsitPartsNewRefundManage partsNewRefundManage = new WebsitPartsNewRefundManage();
+        BeanUtils.copyProperties(newRefundManageBean, partsNewRefundManage);
+        List<WebsitPartsNewRefundManageItem> partsNewRefundManageItems = new ArrayList<>();
+        for (NewRefundManageItemBean itemBean : newRefundManageBean.getNewRefundManageItemBeanList()) {
+            WebsitPartsNewRefundManageItem partsNewRefundManageItem = new WebsitPartsNewRefundManageItem();
+            itemBean.setId(IdWorker.getIdStr());
+            itemBean.setApplyNo(sheetId);
+            BeanUtils.copyProperties(itemBean, partsNewRefundManageItem);
+            partsNewRefundManageItem.setSalesId(newRefundManageBean.getSalesId());
+            partsNewRefundManageItems.add(partsNewRefundManageItem);
+        }
+        partsNewRefundManage.insert();
+        websitPartsNewRefundManageItemService.saveBatch(partsNewRefundManageItems);
+        // 提交 暂扣师傅新件库存 增加师傅临占新件库存
+        List<WorkerStockDTO> workerStockDTOList = this.createWorkerStockDTO(partsNewRefundManage, partsNewRefundManageItems,
+                partsNewRefundManage.getWorkerName(), partsNewRefundManage.getUpdateTime(), PartsAttrEnum.NEW.toString(), PartsAttrEnum.TEMP_NEW.toString());
+        workerStockLogic.handleWorkerStock(workerStockDTOList);
+
+        // 查找销售单并减掉相应数量
+        List<PartsRefundRecordDTO> partsRefundRecordDTOList = workerStockLogic.handleNewRefundWebsitPartsSales(partsNewRefundManage.getReceiveWebsitId(), partsNewRefundManage.getReceivePartsWebsitId(),
+                partsNewRefundManage.getIdentity(), partsNewRefundManageItems, PartsRefTypeEnum.NEW_REFUND.getKey());
+        List<WebsitPartsNewRefundManageRecord> partsNewRefundManageRecordList = new ArrayList<>();
+        BigDecimal refundAmount = BigDecimal.ZERO;
+        for (PartsRefundRecordDTO partsRefundRecordDTO : partsRefundRecordDTOList) {
+            WebsitPartsNewRefundManageRecord refundManageRecord = new WebsitPartsNewRefundManageRecord();
+            BeanUtils.copyProperties(partsRefundRecordDTO, refundManageRecord);
+            if (refundManageRecord.getRefundAmountMode().equals(PayTypeEnum.CASH.getKey())) {
+                refundManageRecord.setRefundState(PartsRefundStateEnum.OK.getKey());
+            }
+            refundAmount = refundAmount.add(refundManageRecord.getRefundAmount());
+            partsNewRefundManageRecordList.add(refundManageRecord);
+        }
+
+        // 更新新件返还主表退款金额
+        partsNewRefundManage.setRefundAmount(refundAmount)
+                .updateById();
+        // 保存新件返还销售明细记录
+        websitPartsNewRefundManageRecordService.saveBatch(partsNewRefundManageRecordList);
+    }
+
+    private List<WorkerStockDTO> createWorkerStockDTO(WebsitPartsNewRefundManage partsNewRefundManage,
+                                                      List<WebsitPartsNewRefundManageItem> partsNewRefundManageItems,
+                                                      String operateBy, Date operateTime, String partsAttr1,
+                                                      String partsAttr2) {
+        List<WorkerStockDTO> workerStockDTOList = new ArrayList<>();
+
+        for (WebsitPartsNewRefundManageItem refundManageItem : partsNewRefundManageItems) {
+            // 新件
+            if (StringUtils.isNotBlank(partsAttr1)) {
+                WorkerStockDTO workerStockDTO = new WorkerStockDTO();
+                workerStockDTO.setCompanyWechatId(partsNewRefundManage.getCompanyWechatId());
+                workerStockDTO.setCompanyWechatName(partsNewRefundManage.getCompanyWechatName());
+                workerStockDTO.setIdentity(partsNewRefundManage.getIdentity());
+                workerStockDTO.setWorkerId(partsNewRefundManage.getWorkerId());
+                workerStockDTO.setWorkerName(partsNewRefundManage.getWorkerName());
+                workerStockDTO.setWebsitId(partsNewRefundManage.getReceiveWebsitId());
+                workerStockDTO.setWebsitName(partsNewRefundManage.getReceiveWebsitName());
+                workerStockDTO.setPartsWebsitId(partsNewRefundManage.getReceivePartsWebsitId());
+                workerStockDTO.setSdate(DateUtil.date());
+                workerStockDTO.setGoodsId(refundManageItem.getPartsNumber());
+                workerStockDTO.setGoodsName(refundManageItem.getPartsName());
+                workerStockDTO.setMaterialGroupName(refundManageItem.getMaterialGroupName());
+                workerStockDTO.setGoodsStockUnit(refundManageItem.getGoodsStockUnit());
+                workerStockDTO.setPrice(BigDecimal.ZERO);
+                workerStockDTO.setRef(partsNewRefundManage.getApplyNo());
+                workerStockDTO.setRefType(PartsRefTypeEnum.NEW_REFUND.toString());
+                workerStockDTO.setPartsAttr(partsAttr1);
+                workerStockDTO.setChangeQty(refundManageItem.getQty());
+                workerStockDTO.setDirectFlag(DirectFlagEnum.SUB.getKey());
+                workerStockDTO.setRemark(refundManageItem.getRemark());
+                workerStockDTO.setOperateBy(operateBy);
+                workerStockDTO.setOperateTime(operateTime);
+
+                workerStockDTOList.add(workerStockDTO);
+            }
+            if (StringUtils.isNotBlank(partsAttr2)) {
+                WorkerStockDTO workerStockDTO = new WorkerStockDTO();
+                workerStockDTO.setIdentity(partsNewRefundManage.getIdentity());
+                workerStockDTO.setWorkerId(partsNewRefundManage.getWorkerId());
+                workerStockDTO.setWorkerName(partsNewRefundManage.getWorkerName());
+                workerStockDTO.setWebsitId(partsNewRefundManage.getReceiveWebsitId());
+                workerStockDTO.setWebsitName(partsNewRefundManage.getReceiveWebsitName());
+                workerStockDTO.setPartsWebsitId(partsNewRefundManage.getReceivePartsWebsitId());
+                workerStockDTO.setSdate(DateUtil.date());
+                workerStockDTO.setGoodsId(refundManageItem.getPartsNumber());
+                workerStockDTO.setGoodsName(refundManageItem.getPartsName());
+                workerStockDTO.setMaterialGroupName(refundManageItem.getMaterialGroupName());
+                workerStockDTO.setGoodsStockUnit(refundManageItem.getGoodsStockUnit());
+                workerStockDTO.setPrice(BigDecimal.ZERO);
+                workerStockDTO.setRef(partsNewRefundManage.getApplyNo());
+                workerStockDTO.setRefType(PartsRefTypeEnum.NEW_REFUND.getKey());
+                workerStockDTO.setPartsAttr(partsAttr2);
+                workerStockDTO.setChangeQty(refundManageItem.getQty());
+                workerStockDTO.setDirectFlag(DirectFlagEnum.ADD.getKey());
+                workerStockDTO.setRemark(refundManageItem.getRemark());
+                workerStockDTO.setOperateBy(operateBy);
+                workerStockDTO.setOperateTime(operateTime);
+
+                workerStockDTOList.add(workerStockDTO);
+            }
+        }
+
+        return workerStockDTOList;
+    }
+}

+ 114 - 2
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/logic/material/WorkerStockLogic.java → mall-miniapp-service/src/main/java/com/gree/mall/miniapp/logic/material/stock/WorkerStockLogic.java

@@ -1,4 +1,4 @@
-package com.gree.mall.miniapp.logic.material;
+package com.gree.mall.miniapp.logic.material.stock;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollectionUtil;
@@ -6,13 +6,17 @@ import cn.hutool.core.date.DateUtil;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.gree.mall.miniapp.bean.material.MyDataCountBean;
+import com.gree.mall.miniapp.bean.material.parts.PartsRefundRecordDTO;
+import com.gree.mall.miniapp.bean.material.parts.SalesItemRecordDTO;
 import com.gree.mall.miniapp.bean.material.stock.WorkerStockAccBean;
 import com.gree.mall.miniapp.bean.material.stock.WorkerStockBean;
 import com.gree.mall.miniapp.bean.material.stock.WorkerStockDTO;
 import com.gree.mall.miniapp.bean.material.stock.WorkerStockDetailBean;
 import com.gree.mall.miniapp.bean.user.CurrentCompanyWechat;
+import com.gree.mall.miniapp.commonmapper.MaterialMapper;
 import com.gree.mall.miniapp.commonmapper.stock.WorkerStockCMapper;
 import com.gree.mall.miniapp.constant.Constant;
+import com.gree.mall.miniapp.enums.material.PartsPushFlagEnum;
 import com.gree.mall.miniapp.exception.RemoteServiceException;
 import com.gree.mall.miniapp.logic.common.CommonLogic;
 import com.gree.mall.miniapp.plus.entity.*;
@@ -46,12 +50,13 @@ public class WorkerStockLogic {
     private final CommonLogic commonLogic;
     private final WorkerStockService workerStockService;
     private final WorkerStockAccService workerStockAccService;
-    private final WebsitGoodsCategoryService websitGoodsCategoryService;
+    private final WebsitPartsSalesItemService websitPartsSalesItemService;
     private final WorkerStockCMapper workerStockCMapper;
     private final WebsitPartsRetService websitPartsRetService;
     private final WebsitNormRecordService websitNormRecordService;
     private final WebsitGoodsService websitGoodsService;
     private final RedisLockRegistry redisLockRegistry;
+    private final MaterialMapper materialMapper;
 
     /**
      * 我的库存分类
@@ -286,4 +291,111 @@ public class WorkerStockLogic {
             obtain.unlock();
         }
     }
+
+    /**
+     * 处理网点销售单明细数量 新件
+     * @param partsNewRefundManageItems
+     * @param refType
+     */
+    public List<PartsRefundRecordDTO> handleNewRefundWebsitPartsSales(String websitId,
+                                                                      String partsWebsitId,
+                                                                      String identity,
+                                                                      List<WebsitPartsNewRefundManageItem> partsNewRefundManageItems,
+                                                                      String refType) throws Exception {
+        List<SalesItemRecordDTO> salesItemRecordDTOList = new ArrayList<>();
+        for (WebsitPartsNewRefundManageItem partsNewRefundManageItem : partsNewRefundManageItems) {
+            SalesItemRecordDTO salesItemRecordDTO = new SalesItemRecordDTO();
+            salesItemRecordDTO.setItemId(partsNewRefundManageItem.getId());
+            salesItemRecordDTO.setApplyNo(partsNewRefundManageItem.getApplyNo());
+            salesItemRecordDTO.setPartsNumber(partsNewRefundManageItem.getPartsNumber());
+            salesItemRecordDTO.setPartsName(partsNewRefundManageItem.getPartsName());
+            salesItemRecordDTO.setQty(partsNewRefundManageItem.getQty());
+            salesItemRecordDTO.setSalesId(partsNewRefundManageItem.getSalesId());
+            salesItemRecordDTOList.add(salesItemRecordDTO);
+        }
+        return this.handleShopSales(websitId, partsWebsitId, identity, salesItemRecordDTOList, refType);
+    }
+
+    private List<PartsRefundRecordDTO> handleShopSales(String websitId, String partsWebsitId, String identity,
+                                                       List<SalesItemRecordDTO> salesItemRecordDTOList, String refType
+    ) throws Exception {
+        // 锁定销售单明细
+        String lockName = websitId + "|" + partsWebsitId + "|" + identity;
+        Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.WRITE_SALES_ITEM + lockName);
+        if(!obtain.tryLock(10, TimeUnit.SECONDS)){
+            throw new RemoteServiceException("销售明细已冻结:" + lockName);
+        }
+        // 处理销售单明细
+        try{
+            String salesId = Optional.ofNullable(salesItemRecordDTOList.get(0)).orElse(new SalesItemRecordDTO()).getSalesId();
+
+            List<PartsRefundRecordDTO> partsRefundRecordDTOList = new ArrayList<>();
+            // 查询未转销售的明细
+            List<WebsitPartsSalesItem> salesOrderItems = materialMapper.querySalesPushFlagItem(websitId, salesId
+                    , partsWebsitId, identity, PartsPushFlagEnum.SALES.getKey(), salesItemRecordDTOList);
+
+            // 遍历返还明细
+            for (SalesItemRecordDTO itemRecordDTO : salesItemRecordDTOList) {
+                BigDecimal realSubQty = itemRecordDTO.getQty();
+                // 遍历未转销售的明细
+                for (WebsitPartsSalesItem salesOrderItem : salesOrderItems) {
+                    // 返还明细配件编码=未转销售的明细编码
+                    if (salesOrderItem.getPartsNumber().equals(itemRecordDTO.getPartsNumber())) {
+                        if (salesOrderItem.getQty().compareTo(BigDecimal.ZERO) <= 0) {
+                            // 销售明细数量少于等于0跳出本次循环
+                            continue;
+                        }
+
+                        log.info("未转销售的明细{}", salesOrderItem.getQty());
+
+                        PartsRefundRecordDTO partsRefundRecordDTO = new PartsRefundRecordDTO();
+
+                        if (realSubQty.compareTo(salesOrderItem.getQty()) <= 0) {
+                            // 如果返还明细数量少于等于未转销售的明细数量 注值并结束循环
+                            partsRefundRecordDTO.injectData(itemRecordDTO, salesOrderItem, realSubQty, refType);
+                            partsRefundRecordDTOList.add(partsRefundRecordDTO);
+                            realSubQty = BigDecimal.ZERO;
+                            break;
+                        } else {
+                            // 如果返还明细数量大于未转销售的明细数量 注值
+                            partsRefundRecordDTO.injectData(itemRecordDTO, salesOrderItem, salesOrderItem.getQty(), refType);
+                            realSubQty = realSubQty.subtract(salesOrderItem.getQty());
+                        }
+                    }
+                }
+                if (realSubQty.compareTo(BigDecimal.ZERO) != 0) {
+                    throw new RemoteServiceException(itemRecordDTO.getPartsNumber() + "|" + itemRecordDTO.getPartsName() + "销售明细不够扣,处理失败");
+                }
+            }
+            // 更新销售明细数据
+            websitPartsSalesItemService.saveOrUpdateBatch(salesOrderItems);
+
+            return partsRefundRecordDTOList;
+
+        } finally {
+            this.txCallUnlockSalesItem(obtain);
+        }
+    }
+
+    public void txCallUnlockSalesItem(Lock obtain){
+        //事务提交完成后才释放锁,此方法禁止执行mysql相关操作,否则将导致重大问题。
+        if (TransactionSynchronizationManager.isActualTransactionActive()) {
+            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
+                @Override
+                public void afterCompletion(int status) {
+
+                    if(TransactionSynchronization.STATUS_COMMITTED == status){
+                        log.info("=========【销售单明细】======事务提交==============");
+                    }else if(TransactionSynchronization.STATUS_ROLLED_BACK == status){
+                        log.info("========【销售单明细】=========事务回滚============");
+                    }
+
+                    obtain.unlock();
+                }
+            });
+        } else {
+            log.info("【销售单明细】====没有事务===释放锁");
+            obtain.unlock();
+        }
+    }
 }

+ 4 - 4
mall-miniapp-service/src/main/java/com/gree/mall/miniapp/logic/order/PayOrderLogic.java

@@ -22,7 +22,7 @@ import com.gree.mall.miniapp.enums.material.WebsitGoodsTypeEnum;
 import com.gree.mall.miniapp.exception.RemoteServiceException;
 import com.gree.mall.miniapp.logic.common.CommonLogic;
 import com.gree.mall.miniapp.logic.common.outside.WechatLogic;
-import com.gree.mall.miniapp.logic.material.WorkerStockLogic;
+import com.gree.mall.miniapp.logic.material.stock.WorkerStockLogic;
 import com.gree.mall.miniapp.plus.entity.*;
 import com.gree.mall.miniapp.plus.service.*;
 import com.gree.mall.miniapp.utils.DateUtils;
@@ -455,7 +455,7 @@ public class PayOrderLogic {
                         workerStockDTO.setGoodsName(item.getGoodsName());
                         workerStockDTO.setGoodsType("P");
                         workerStockDTO.setPrice(item.getGoodsAmount());
-                        workerStockDTO.setUnitName(item.getUnit());
+                        workerStockDTO.setGoodsStockUnit(item.getUnit());
                         workerStockDTO.setRef(workerOrder.getOrderId());
                         workerStockDTO.setRefType("配件销售");
                         workerStockDTO.setPartsAttr(PartsAttrEnum.NEW.toString());
@@ -484,7 +484,7 @@ public class PayOrderLogic {
                         oldWorkerStockDTO.setGoodsName(item.getGoodsName());
                         oldWorkerStockDTO.setGoodsType("P");
                         oldWorkerStockDTO.setPrice(item.getGoodsAmount());
-                        oldWorkerStockDTO.setUnitName(item.getUnit());
+                        oldWorkerStockDTO.setGoodsStockUnit(item.getUnit());
                         oldWorkerStockDTO.setRef(workerOrder.getOrderId());
                         oldWorkerStockDTO.setRefType("配件销售");
                         oldWorkerStockDTO.setPartsAttr(PartsAttrEnum.OLD.toString());
@@ -587,7 +587,7 @@ public class PayOrderLogic {
             workerStockDTO.setGoodsName(bean.getGoodsName());
             workerStockDTO.setGoodsType(WebsitGoodsTypeEnum.M.toString());
             workerStockDTO.setPrice(bean.getNormPrice());
-            workerStockDTO.setUnitName(bean.getSalesUnit());
+            workerStockDTO.setGoodsStockUnit(bean.getSalesUnit());
             workerStockDTO.setRef(workerOrder.getOrderId());
             workerStockDTO.setRefType("辅材销售");
             workerStockDTO.setPartsAttr(PartsAttrEnum.NEW.toString());

+ 121 - 0
mall-miniapp-service/src/main/resources/mapper/MaterialMapper.xml

@@ -174,4 +174,125 @@
         WHERE
             a.norm_id = #{goodsId}
     </select>
+
+    <select id="appList" resultType="com.gree.mall.miniapp.bean.material.parts.NewRefundManageBean">
+        SELECT
+            a.company_wechat_id,
+            a.company_wechat_name
+            a.apply_no,
+            a.sales_id,
+            a.apply_category,
+            CASE a.apply_category WHEN 'HOME' THEN '家用空调'
+            WHEN 'TRADE' THEN '商用空调'
+            WHEN 'ELEC' THEN '生活电器(小家电)'
+            ELSE '' END AS applyCategoryName,
+            a.apply_type,
+            CASE a.apply_type WHEN 'NEW' THEN '新件返还'
+            WHEN 'LOST' THEN '破损返还'
+            WHEN 'BUG' THEN '故障返还'
+            ELSE '' END AS applyTypeName,
+            a.refund_mode,
+            CASE a.refund_mode WHEN 'EXPRESS' THEN '快递'
+            WHEN 'SELF' THEN '网点自还'
+            ELSE '' END AS refundModeName,
+            a.express_no,
+            a.receive_address,
+            a.receive_websit_id,
+            a.receive_websit_name,
+            a.receive_parts_websit_id,
+            a.websit_Address,
+            a.identity,
+            a.worker_id,
+            a.worker_name,
+            a.refund_amount,
+            a.refund_amount_mode,
+            IF(refund_amount_mode = 'CASH', '现金', '微信') AS refundAmountModeName,
+            a.remark,
+            a.examine_remark,
+            a.flag,
+            CASE a.flag WHEN 'SAVE' THEN '保存'
+            WHEN 'SUBMIT' THEN '待审批'
+            WHEN 'AGREE' THEN '待返还'
+            WHEN 'REJECT' THEN '驳回'
+            WHEN 'REFUNDED' THEN '已返还'
+            ELSE '' END AS flagName,
+            a.create_by,
+            a.create_time,
+            a.update_by,
+            a.update_time,
+            a.submit_by,
+            a.submit_time,
+            a.examine_by,
+            a.examine_time,
+            a.refunded_by,
+            a.refunded_time
+        FROM
+            websit_parts_new_refund_manage a
+            LEFT JOIN websit_parts_new_refund_manage_item b ON a.apply_no = b.apply_no
+        <where>
+            <if test="applyNo != null and applyNo != ''">
+                AND a.apply_no = #{applyNo}
+            </if>
+            <if test="flag != null and flag != ''">
+                AND a.flag = #{flag}
+            </if>
+            <if test="identity != null and identity != ''">
+                AND a.identity = #{identity}
+            </if>
+            <if test="partsNumber != null and partsNumber != ''">
+                AND b.parts_number = #{partsNumber}
+            </if>
+        </where>
+        GROUP BY a.apply_no, a.create_time
+        ORDER BY a.create_time DESC
+    </select>
+
+    <select id="querySalesPushFlagItem" resultType="com.gree.mall.miniapp.plus.entity.WebsitPartsSalesItem">
+        SELECT
+            id,
+            identity,
+            websit_id,
+            parts_websit_id,
+            parts_id,
+            parts_number,
+            parts_name,
+            material_group_name,
+            goods_stock_unit,
+            sales_id,
+            sales_price,
+            market_price,
+            second_price,
+            qty,
+            examine_qty,
+            new_refund_qty,
+            old_refund_qty,
+            total_amount,
+            refund_amount_mode,
+            push_flag,
+            create_by,
+            create_time,
+            update_by,
+            update_time,
+            examine_time
+        FROM
+            websit_parts_sales_item
+        WHERE
+        identity = #{identity}
+        AND websit_id = #{websitId}
+        AND parts_websit_id = #{partsWebsitId}
+        <if test="pushFlag != null and pushFlag != ''">
+            AND push_flag = #{pushFlag}
+        </if>
+        <if test="salesId != null and salesId != ''">
+            AND sales_id = #{salesId}
+        </if>
+        AND parts_number IN
+        <foreach item="item" index="index" collection="records" open="(" separator=","
+                 close=")">
+            #{item.partsNumber}
+        </foreach>
+        ORDER BY
+            examine_time
+        FOR UPDATE
+    </select>
 </mapper>

+ 11 - 11
mall-server-api/src/main/java/com/gree/mall/manager/constant/Constant.java

@@ -76,19 +76,19 @@ public class Constant {
         public final static String INF_TOKEN = "jsm:sxb:token:inf";
 
         //维修日结汇总
-        public final static String LOCK_DAILY_BANKACCOUNT = "jsm:SETTLE:LOCK:BANKACCOUNT:";
-        public final static String LOCK_DAILY_SUMMARY = "jsm:SETTLE:LOCK:DAILY:SUMMARY";
-        public final static String BALANCE_SEL_MOBILE_SMS = "jsm:SETTLE:BALANCE:SMS";
-        public final static String ISSUE_SAL_MOBILE_SMS = "jsm:SETTLE:ISSUE:SMS";
-        public final static String LOCK_SUMMARY_ISSUE = "jsm:SETTLE:lock:issue:summary";
+        public final static String LOCK_DAILY_BANKACCOUNT = "jsm:sxb:SETTLE:LOCK:BANKACCOUNT:";
+        public final static String LOCK_DAILY_SUMMARY = "jsm:sxb:SETTLE:LOCK:DAILY:SUMMARY";
+        public final static String BALANCE_SEL_MOBILE_SMS = "jsm:sxb:SETTLE:BALANCE:SMS";
+        public final static String ISSUE_SAL_MOBILE_SMS = "jsm:sxb:SETTLE:ISSUE:SMS";
+        public final static String LOCK_SUMMARY_ISSUE = "jsm:sxb:SETTLE:lock:issue:summary";
         public static final String LOCK_MATERIAL_PURCHASE = "jsm:sxb:material:purchase:";
 
-        public final static String NEW_IN = "jsm:parts:new:in:";
-        public static final String OLD_OUT = "jsm:parts:old:out:";
-        public static final String NEW_REFUND = "jsm:parts:new:refund:";
-        public static final String PARTS_SALES = "jsm:lock:parts:sales:";
-        public static final String WRITE_SALES_ITEM = "jsm:parts:write:sales:item:";
-        public static final String NEW_CHANGE = "jsm:parts:change:sales:";
+        public final static String NEW_IN = "jsm:sxb:parts:new:in:";
+        public static final String OLD_OUT = "jsm:sxb:parts:old:out:";
+        public static final String NEW_REFUND = "jsm:sxb:parts:new:refund:";
+        public static final String PARTS_SALES = "jsm:sxb:lock:parts:sales:";
+        public static final String WRITE_SALES_ITEM = "jsm:sxb:parts:write:sales:item:";
+        public static final String NEW_CHANGE = "jsm:sxb:parts:change:sales:";
     }
     public class ChatMessage {
         public final static String MSG_TYPE_DOC = "docmsg";