Browse Source

增加零售订单功能

FengChaoYu 1 tuần trước cách đây
mục cha
commit
a050c94d90

+ 21 - 0
mall-server-api/src/main/java/com/gree/mall/manager/bean/supply/order/RetailOrderAdd.java

@@ -0,0 +1,21 @@
+package com.gree.mall.manager.bean.supply.order;
+
+import com.gree.mall.manager.plus.entity.RetailOrder;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@ApiModel
+public class RetailOrderAdd extends RetailOrder {
+
+    @NotNull(message = "产品信息不能为空")
+    @ApiModelProperty(value="产品信息",required = true)
+    private List<RetailOrderItemBean> retailOrderItemList;
+
+}

+ 18 - 0
mall-server-api/src/main/java/com/gree/mall/manager/bean/supply/order/RetailOrderBean.java

@@ -0,0 +1,18 @@
+package com.gree.mall.manager.bean.supply.order;
+
+import com.gree.mall.manager.plus.entity.RetailOrder;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@ApiModel
+public class RetailOrderBean extends RetailOrder {
+
+    @ApiModelProperty("产品信息")
+    private List<RetailOrderItemBean> retailOrderItemList;
+}

+ 28 - 0
mall-server-api/src/main/java/com/gree/mall/manager/bean/supply/order/RetailOrderItemBean.java

@@ -0,0 +1,28 @@
+package com.gree.mall.manager.bean.supply.order;
+
+import com.gree.mall.manager.bean.supply.funds.CustomerWalletBean;
+import com.gree.mall.manager.plus.entity.RetailOrderItem;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@ApiModel
+public class RetailOrderItemBean extends RetailOrderItem {
+
+    @ApiModelProperty("退订数量")
+    private Integer tdQty;
+
+    @ApiModelProperty("现金钱包")
+    List<CustomerWalletBean> wallets = new ArrayList<>();
+    @ApiModelProperty("返利钱包")
+    List<CustomerWalletBean> rebateWallets = new ArrayList<>();
+    @ApiModelProperty("当前可用返利金额")
+    private BigDecimal curRebateAmount;
+}

+ 24 - 0
mall-server-api/src/main/java/com/gree/mall/manager/bean/supply/order/RetailOrderRefundBean.java

@@ -0,0 +1,24 @@
+package com.gree.mall.manager.bean.supply.order;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * 退订
+ */
+@ApiModel
+@Data
+public class RetailOrderRefundBean {
+
+    @ApiModelProperty("表头单号")
+    private String id;
+
+    @NotNull(message = "产品信息不能为空")
+    @ApiModelProperty(value="产品信息",required = true)
+    private List<RetailOrderItemBean> retailOrderItemList;
+
+}

+ 87 - 0
mall-server-api/src/main/java/com/gree/mall/manager/bean/supply/order/RetailOrderVO.java

@@ -0,0 +1,87 @@
+package com.gree.mall.manager.bean.supply.order;
+
+import com.gree.mall.manager.annotation.ZfireField;
+import com.gree.mall.manager.enums.ExamineStatusEnum;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@ApiModel
+@ZfireField(tbName = "a")
+public class RetailOrderVO {
+
+
+    @ApiModelProperty(value = "订单号")
+    private String id;
+
+    @ZfireField(hide = true)
+    @ApiModelProperty(value = "商户id")
+    private String companyWechatId;
+
+    @ApiModelProperty(value = "商户名称")
+    private String companyName;
+
+    @ApiModelProperty(value = "单据状态")
+    private ExamineStatusEnum examineStatus;
+
+    @ApiModelProperty(value = "审核备注")
+    private String examineRemark;
+
+    @ZfireField(hide = true)
+    @ApiModelProperty(value = "类型:1=普通零售单  2=政策零售单")
+    private Integer type;
+
+    @ApiModelProperty(value = "单据日期")
+    private Date theTime;
+
+    @ZfireField(hide = true)
+    @ApiModelProperty(value = "销售政策id")
+    private String policyId;
+
+    @ApiModelProperty(value = "销售政策编号")
+    private String policyCode;
+
+    @ApiModelProperty(value = "销售政策名称")
+    private String policyTitle;
+
+    @ApiModelProperty(value = "销售政策备注")
+    private String policyRemark;
+
+    @ApiModelProperty(value = "总金额")
+    private BigDecimal totalAmount;
+
+    @ApiModelProperty(value = "总数量")
+    private Integer totalQty;
+
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+    @ApiModelProperty(value = "创建人")
+    private String createBy;
+
+    @ApiModelProperty(value = "创建时间")
+    private Date createTime;
+
+    @ApiModelProperty(value = "修改人")
+    private String updateBy;
+
+    @ApiModelProperty(value = "修改时间")
+    private Date updateTime;
+
+    @ApiModelProperty(value = "提交人")
+    private String submitBy;
+
+    @ApiModelProperty(value = "提交时间")
+    private Date submitTime;
+
+    @ApiModelProperty(value = "审核人")
+    private String examineBy;
+
+    @ApiModelProperty(value = "审核时间")
+    private Date examineTime;
+
+}

+ 9 - 0
mall-server-api/src/main/java/com/gree/mall/manager/commonmapper/CommonMapper.java

@@ -30,6 +30,7 @@ import com.gree.mall.manager.bean.supply.funds.AdminCompanyRebateAccVO;
 import com.gree.mall.manager.bean.supply.funds.AdminCompanyWalletAccVO;
 import com.gree.mall.manager.bean.supply.funds.RebateVO;
 import com.gree.mall.manager.bean.supply.funds.ReceiptVO;
+import com.gree.mall.manager.bean.supply.order.RetailOrderVO;
 import com.gree.mall.manager.bean.supply.policy.PolicyVO;
 import com.gree.mall.manager.bean.supply.sales.config.*;
 import com.gree.mall.manager.bean.supply.sales.price.ProductPriceUpdateVO;
@@ -793,4 +794,12 @@ public interface CommonMapper {
      * @return
      */
     IPage<PolicyVO> policyList(Page page, @Param("ex") ZfireParamBean zfireParamBean);
+
+    /**
+     * 销售政策列表
+     * @param page
+     * @param zfireParamBean
+     * @return
+     */
+    IPage<RetailOrderVO> retailOrderList(Page page, @Param("ex") ZfireParamBean zfireParamBean);
 }

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

@@ -70,6 +70,8 @@ public class Constant {
 
         public final static String LOCK_COMPANY_WALLET = "zfire:overseas:company:wallet:";
 
+        public final static String LOCK_RETAIL = "zfire:overseas:company:retail:";
+
     }
 
 

+ 189 - 0
mall-server-api/src/main/java/com/gree/mall/manager/controller/supply/order/RetailOrderController.java

@@ -0,0 +1,189 @@
+package com.gree.mall.manager.controller.supply.order;
+
+import cn.hutool.core.lang.TypeReference;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.gree.mall.manager.annotation.ZfireList;
+import com.gree.mall.manager.bean.supply.order.RetailOrderAdd;
+import com.gree.mall.manager.bean.supply.order.RetailOrderBean;
+import com.gree.mall.manager.bean.supply.order.RetailOrderRefundBean;
+import com.gree.mall.manager.bean.supply.order.RetailOrderVO;
+import com.gree.mall.manager.constant.Constant;
+import com.gree.mall.manager.helper.ResponseHelper;
+import com.gree.mall.manager.logic.supply.order.RetailOrderLogic;
+import com.gree.mall.manager.zfire.bean.ZfireParamBean;
+import com.gree.mall.manager.zfire.util.FieldUtils;
+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.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.stream.Collectors;
+
+@Slf4j
+@RestController
+@Api(value = "零售订单API", tags = {"零售订单API"})
+@RequestMapping(value = "/supply/retail", produces = "application/json; charset=utf-8")
+public class RetailOrderController {
+
+    @Resource
+    RetailOrderLogic retailOrderLogic;
+    @Resource
+    RedisLockRegistry redisLockRegistry;
+
+    @ZfireList
+    @PostMapping("/list")
+    @ApiOperation(value = "列表")
+    public ResponseHelper<IPage<RetailOrderVO>> list(
+            @RequestBody ZfireParamBean zfireParamBean
+    ) {
+        IPage<RetailOrderVO> page = retailOrderLogic.list(zfireParamBean);
+        return ResponseHelper.success(page, new TypeReference<RetailOrderVO>() {
+        });
+    }
+
+    @PostMapping("/list/export")
+    @ApiOperation(value = "导出")
+    public void listExport(@RequestBody ZfireParamBean zfireParamBean, HttpServletRequest request, HttpServletResponse response) throws Exception {
+        //2.查询要导出的内容
+        IPage<RetailOrderVO> page = retailOrderLogic.list(zfireParamBean);
+        //3.导出
+        FieldUtils.exportData(page.getRecords(), zfireParamBean.getExportFields(), request, response);
+    }
+
+    @PostMapping("/detail")
+    @ApiOperation("获取详情")
+    public ResponseHelper<RetailOrderBean> detail(
+            @ApiParam(value = "订单id") @RequestParam(required = false) String id
+    ) {
+        RetailOrderBean detail = retailOrderLogic.detail(id);
+        return ResponseHelper.success(detail);
+    }
+
+    @PostMapping("/add")
+    @ApiOperation("新增")
+    public ResponseHelper add(
+            @RequestBody RetailOrderAdd retailOrderAdd) throws Exception {
+        retailOrderLogic.add(retailOrderAdd);
+        return ResponseHelper.success();
+    }
+
+
+    @PostMapping("/update")
+    @ApiOperation("修改")
+    public ResponseHelper update(
+            @RequestBody RetailOrderAdd retailOrderAdd) throws Exception {
+
+        Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.LOCK_RETAIL + retailOrderAdd.getId());
+        if (!obtain.tryLock(5, TimeUnit.SECONDS)) {
+            return ResponseHelper.error("系统繁忙,请稍后再试");
+        }
+        try {
+            retailOrderLogic.update(retailOrderAdd);
+        } finally {
+            obtain.unlock();
+        }
+        return ResponseHelper.success();
+    }
+
+    @PostMapping("/delete")
+    @ApiOperation("删除")
+    public ResponseHelper delete(
+            @RequestParam String id) throws Exception {
+        Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.LOCK_RETAIL + id);
+        if (!obtain.tryLock(5, TimeUnit.SECONDS)) {
+            return ResponseHelper.error("系统繁忙,请稍后再试");
+        }
+        try {
+            retailOrderLogic.delete(id);
+        } finally {
+            obtain.unlock();
+        }
+        return ResponseHelper.success();
+    }
+
+    @PostMapping("/refund")
+    @ApiOperation("退订")
+    public ResponseHelper refund(
+            @RequestBody RetailOrderRefundBean retailOrderRefundBean) throws Exception {
+        Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.LOCK_RETAIL + retailOrderRefundBean.getId());
+        if (!obtain.tryLock(5, TimeUnit.SECONDS)) {
+            return ResponseHelper.error("系统繁忙,请稍后再试");
+        }
+        try {
+            retailOrderLogic.refund(retailOrderRefundBean);
+        } finally {
+            obtain.unlock();
+        }
+        return ResponseHelper.success();
+    }
+
+
+    @PostMapping("/submit")
+    @ApiOperation("提审")
+    public ResponseHelper submit(
+            @ApiParam(value = "id") @RequestParam(required = false) String id
+    ) throws Exception {
+        Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.LOCK_RETAIL + id);
+        if (!obtain.tryLock(5, TimeUnit.SECONDS)) {
+            return ResponseHelper.error("系统繁忙,请稍后再试");
+        }
+        try {
+            retailOrderLogic.submit(id);
+        } finally {
+            obtain.unlock();
+        }
+        return ResponseHelper.success();
+    }
+
+
+    @PostMapping("/submit/cancel")
+    @ApiOperation("撤回")
+    public ResponseHelper submitCancel(
+            @ApiParam(value = "id") @RequestParam(required = false) String id
+    ) throws Exception {
+        Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.LOCK_RETAIL + id);
+        if (!obtain.tryLock(5, TimeUnit.SECONDS)) {
+            return ResponseHelper.error("系统繁忙,请稍后再试");
+        }
+        try {
+            retailOrderLogic.submitCancel(id);
+        } finally {
+            obtain.unlock();
+        }
+        return ResponseHelper.success();
+    }
+
+    @PostMapping("/examine")
+    @ApiOperation("审核与批量审核")
+    public ResponseHelper examine(
+            @ApiParam(value = "id", required = true) @RequestParam(required = true) List<String> id,
+            @ApiParam(value = "审核结果 OK=通过 FAIL=不通过", required = false) @RequestParam(required = false) String examineStatus,
+            @ApiParam(value = "审核备注", required = false) @RequestParam(required = false) String examineRemark,
+            @ApiParam(value = "表头备注", required = false) @RequestParam(required = false) String remark,
+            @ApiParam(value = "文件编号", required = false) @RequestParam(required = false) String fileNo
+    ) throws Exception {
+
+        id = id.stream().distinct().collect(Collectors.toList());
+
+        for (String idd : id) {
+            Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.LOCK_RETAIL + idd);
+            if (!obtain.tryLock(5, TimeUnit.SECONDS)) {
+                return ResponseHelper.error("系统繁忙,请稍后再试");
+            }
+            try {
+                retailOrderLogic.examine(idd, examineStatus, examineRemark, remark, fileNo);
+            } finally {
+                obtain.unlock();
+            }
+        }
+        return ResponseHelper.success();
+    }
+}

+ 2 - 0
mall-server-api/src/main/java/com/gree/mall/manager/enums/supply/BalanceBillTypeEnum.java

@@ -14,6 +14,8 @@ public enum BalanceBillTypeEnum implements BaseEnum {
 
     RECEIPT_BILL("RECEIPT_BILL","收款单"),
     REBATE_BILL("REBATE_BILL","返利单"),
+    POLICY_ORDER("POLICY_ORDER","销售政策单"),
+    RETAIL_ORDER("RETAIL_ORDER","其他零售单"),
             ;
 
     @EnumValue

+ 17 - 0
mall-server-api/src/main/java/com/gree/mall/manager/logic/supply/funds/CompanyWalletBalanceLogic.java

@@ -157,4 +157,21 @@ public class CompanyWalletBalanceLogic {
                 .eq(AdminCompanyWalletBalance::getCompanyWechatId, adminCompanyId)
                 .list();
     }
+
+    /**
+     * 删除对应单据三级账记录
+     */
+    public void removeBalanceAccRecordByBillId(String companyId, String billId, String billType) {
+        adminCompanyWalletAccService.lambdaUpdate()
+                .eq(AdminCompanyWalletAcc::getCompanyWechatId, companyId)
+                .eq(AdminCompanyWalletAcc::getBillId, billId)
+                .eq(AdminCompanyWalletAcc::getBillType, billType)
+                .remove();
+
+        adminCompanyRebateAccService.lambdaUpdate()
+                .eq(AdminCompanyRebateAcc::getCompanyWechatId, companyId)
+                .eq(AdminCompanyRebateAcc::getBillId, billId)
+                .eq(AdminCompanyRebateAcc::getBillType, billType)
+                .remove();
+    }
 }

+ 69 - 1
mall-server-api/src/main/java/com/gree/mall/manager/logic/supply/funds/CompanyWalletLogic.java

@@ -2,11 +2,11 @@ package com.gree.mall.manager.logic.supply.funds;
 
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.date.DateUtil;
-import com.aliyuncs.utils.StringUtils;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.gree.mall.manager.bean.admin.AdminUserCom;
 import com.gree.mall.manager.bean.supply.funds.CompanyWalletBalanceDTO;
 import com.gree.mall.manager.bean.supply.funds.CustomerWalletBean;
+import com.gree.mall.manager.bean.supply.order.RetailOrderItemBean;
 import com.gree.mall.manager.enums.ExamineStatusEnum;
 import com.gree.mall.manager.enums.material.DirectFlagEnum;
 import com.gree.mall.manager.enums.supply.BalanceBillTypeEnum;
@@ -24,11 +24,13 @@ import com.gree.mall.manager.plus.service.ReceiptService;
 import com.gree.mall.manager.plus.service.SalesTypeService;
 import lombok.RequiredArgsConstructor;
 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.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -164,6 +166,71 @@ public class CompanyWalletLogic {
                 .update();
     }
 
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
+    public void handleRetailOrderCompanyWallet(List<RetailOrderItemBean> rebateList, DirectFlagEnum directFlag, boolean isRemoveRecord) {
+        try {
+            final List<RetailOrderItemBean> cList = rebateList.stream().filter(v -> StringUtils.isNotBlank(v.getCustomerWalletId())).collect(Collectors.toList());
+            final List<RetailOrderItemBean> rList = rebateList.stream().filter(v -> StringUtils.isNotBlank(v.getCustomerWalletId2())).collect(Collectors.toList());
+
+            List<CompanyWalletBalanceDTO> dtoList = new ArrayList<>();
+            if (CollectionUtil.isNotEmpty(cList)) {
+                for (RetailOrderItemBean itemBean : cList) {
+                    StringBuilder sb = new StringBuilder();
+                    if (StringUtils.isNotBlank(itemBean.getRemark())) {
+                        sb.append(itemBean.getRemark()).append("; ");
+                    }
+                    sb.append(itemBean.getGoodsMaterialName()).append(" ").append(itemBean.getSpecsName());
+                    dtoList.add(new CompanyWalletBalanceDTO()
+                            .setDirectFlag(directFlag.getKey())
+                            .setCompanyWechatId(itemBean.getCompanyWechatId())
+                            .setCompanyName(itemBean.getCompanyName())
+                            .setTheTime(itemBean.getCreateTime())
+                            .setChangeAmount(itemBean.getPayAmount())
+                            .setBillId(itemBean.getId())
+                            .setBillType(StringUtils.isNotBlank(itemBean.getPolicyId()) ? BalanceBillTypeEnum.POLICY_ORDER.getKey() : BalanceBillTypeEnum.RETAIL_ORDER.getKey())
+                            .setWalletId(itemBean.getWalletId1())
+                            .setWalletType(BalanceTypeEnum.W.getKey())
+                            .setRemark(sb.toString())
+                    );
+                }
+            }
+
+            if (CollectionUtil.isNotEmpty(rList)) {
+                for (RetailOrderItemBean itemBean : rList) {
+                    if (itemBean.getPayRebateAmount().compareTo(BigDecimal.ZERO) > 0) {
+                        StringBuilder sb = new StringBuilder();
+                        if (StringUtils.isNotBlank(itemBean.getRemark())) {
+                            sb.append(itemBean.getRemark()).append("; ");
+                        }
+                        sb.append(itemBean.getGoodsMaterialName()).append(" ").append(itemBean.getSpecsName());
+                        dtoList.add(new CompanyWalletBalanceDTO()
+                                .setDirectFlag(directFlag.getKey())
+                                .setCompanyWechatId(itemBean.getCompanyWechatId())
+                                .setCompanyName(itemBean.getCompanyName())
+                                .setTheTime(itemBean.getCreateTime())
+                                .setChangeAmount(itemBean.getPayRebateAmount())
+                                .setBillId(itemBean.getId())
+                                .setBillType(StringUtils.isNotBlank(itemBean.getPolicyId()) ? BalanceBillTypeEnum.POLICY_ORDER.getKey() : BalanceBillTypeEnum.RETAIL_ORDER.getKey())
+                                .setWalletId(itemBean.getWalletId2())
+                                .setWalletType(BalanceTypeEnum.R.getKey())
+                                .setRemark(sb.toString())
+                        );
+                    }
+                }
+            }
+
+            if (CollectionUtil.isNotEmpty(dtoList)) {
+                companyWalletBalanceLogic.handleCompanyWalletBalance(dtoList);
+                if (isRemoveRecord) {
+                    companyWalletBalanceLogic.removeBalanceAccRecordByBillId(dtoList.get(0).getCompanyWechatId(), dtoList.get(0).getBillId(), dtoList.get(0).getBillType());
+                }
+            }
+
+        } catch (Exception e) {
+            throw new RemoteServiceException(e.getMessage());
+        }
+    }
+
     /**
      * 查询商户所有钱包
      * @param adminCompanyId
@@ -227,4 +294,5 @@ public class CompanyWalletLogic {
 
         return customerWalletBeanList;
     }
+
 }

+ 800 - 0
mall-server-api/src/main/java/com/gree/mall/manager/logic/supply/order/RetailOrderLogic.java

@@ -0,0 +1,800 @@
+package com.gree.mall.manager.logic.supply.order;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.gree.mall.manager.bean.admin.AdminUserCom;
+import com.gree.mall.manager.bean.supply.funds.CustomerWalletBean;
+import com.gree.mall.manager.bean.supply.order.*;
+import com.gree.mall.manager.commonmapper.CommonMapper;
+import com.gree.mall.manager.enums.ExamineStatusEnum;
+import com.gree.mall.manager.enums.material.DirectFlagEnum;
+import com.gree.mall.manager.enums.material.StateEnum;
+import com.gree.mall.manager.enums.supply.BalanceTypeEnum;
+import com.gree.mall.manager.exception.RemoteServiceException;
+import com.gree.mall.manager.logic.common.CommonLogic;
+import com.gree.mall.manager.logic.supply.funds.CompanyWalletLogic;
+import com.gree.mall.manager.logic.supply.policy.PolicyLogic;
+import com.gree.mall.manager.plus.entity.*;
+import com.gree.mall.manager.plus.service.*;
+import com.gree.mall.manager.utils.CommonUtils;
+import com.gree.mall.manager.zfire.bean.ZfireParamBean;
+import com.gree.mall.manager.zfire.util.FieldUtils;
+import lombok.RequiredArgsConstructor;
+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 java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class RetailOrderLogic {
+
+    private final CommonLogic commonLogic;
+    private final CommonMapper commonMapper;
+    private final RetailOrderService retailOrderService;
+    private final RetailOrderItemService retailOrderItemService;
+    private final CompanyWalletLogic companyWalletLogic;
+    private final PolicyLogic policyLogic;
+    private final PolicyWalletRelaService policyWalletRelaService;
+    private final ProductPriceService productPriceService;
+    private final PolicyCustomerService policyCustomerService;
+    private final SalesTypeService salesTypeService;
+    private final GoodsMaterialService goodsMaterialService;
+    private final WalletService walletService;
+    private final RebateTypeService rebateTypeService;
+    private final RefundOrderItemService refundOrderItemService;
+
+    public IPage<RetailOrderVO> list(ZfireParamBean zfireParamBean) {
+        AdminUserCom adminUser = commonLogic.getAdminUser();
+        FieldUtils.supplyParam(zfireParamBean, RetailOrderVO.class, adminUser);
+
+        return commonMapper.retailOrderList(new Page(zfireParamBean.getPageNum(), zfireParamBean.getPageSize()), zfireParamBean);
+    }
+
+    public RetailOrderBean detail(String id) {
+        RetailOrder retailOrder = retailOrderService.getById(id);
+        RetailOrderBean retailOrderBean = new RetailOrderBean();
+        BeanUtils.copyProperties(retailOrder, retailOrderBean);
+
+        //明细
+        List<RetailOrderItem> list = retailOrderItemService.lambdaQuery().eq(RetailOrderItem::getRetailOrderId, id).list();
+
+        List<CustomerWalletBean> customerWalletBeans = companyWalletLogic.queryWalletByAdminCompanyId(retailOrder.getCompanyWechatId());
+        //所有钱包的map  key = walletId
+        Map<String, CustomerWalletBean> customerWalletMap = customerWalletBeans.stream()
+                .collect(Collectors.toMap(CustomerWalletBean::getWalletId, v -> v));
+
+        //所有钱包的map  key = customerWalletId
+        Map<String, CustomerWalletBean> customerWalletIdMap = customerWalletBeans.stream()
+                .collect(Collectors.toMap(CustomerWalletBean::getId, v -> v));
+
+        List<RetailOrderItemBean> newList = new ArrayList<>();
+        for (RetailOrderItem retailOrderItem : list) {
+            RetailOrderItemBean bean = new RetailOrderItemBean();
+            BeanUtils.copyProperties(retailOrderItem, bean);
+
+            if (retailOrder.getType() == 2) {
+                PolicyMaterial policyMaterial = policyLogic.getPolicyMaterial(bean.getPolicyId(), bean.getGoodsMaterialId(), bean.getSalesTypeId());
+                //现金钱包
+                if (policyMaterial != null) {
+                    List<CustomerWalletBean> customerWallets = this.supplyWallet2(policyMaterial.getId(), customerWalletMap, BalanceTypeEnum.W.getKey());
+                    bean.setWallets(customerWallets);
+
+                    //返利钱包
+                    List<CustomerWalletBean> customerWallets2 = this.supplyWallet2(policyMaterial.getId(), customerWalletMap, BalanceTypeEnum.R.getKey());
+                    bean.getRebateWallets().addAll(customerWallets2);
+                }
+
+            } else {
+
+                List<CustomerWalletBean> customerWallets = this.supplyWallet1(bean.getProductPriceId(), customerWalletMap, BalanceTypeEnum.W.getKey());
+                bean.getWallets().addAll(customerWallets);
+
+                //返利钱包
+                List<CustomerWalletBean> customerWallets2 = this.supplyWallet1(bean.getProductPriceId(), customerWalletMap, BalanceTypeEnum.R.getKey());
+                bean.getRebateWallets().addAll(customerWallets2);
+            }
+
+            if (CollectionUtils.isEmpty(bean.getWallets())) {
+                CustomerWalletBean customerWalletBean1 = customerWalletIdMap.get(bean.getCustomerWalletId());
+                if (customerWalletBean1 != null) {
+                    bean.getWallets().add(customerWalletBean1);
+                }
+                CustomerWalletBean customerWalletBean2 = customerWalletIdMap.get(bean.getCustomerWalletId2());
+                if (customerWalletBean2 != null) {
+                    bean.getRebateWallets().add(customerWalletBean2);
+                }
+            }
+
+            //当前可用返利金额
+            if (CollectionUtil.isNotEmpty(bean.getRebateWallets())) {
+                List<CustomerWalletBean> curRebate = bean.getRebateWallets().stream()
+                        .filter(v -> Objects.nonNull(v)
+                                && StringUtils.isNotEmpty(retailOrderItem.getCustomerWalletId2())
+                                && v.getId().equals(retailOrderItem.getCustomerWalletId2()))
+                        .collect(Collectors.toList());
+                if (curRebate.size() > 0) {
+                    bean.setCurRebateAmount(curRebate.get(0).getBalance());
+                }
+            }
+
+            newList.add(bean);
+        }
+
+        retailOrderBean.setRetailOrderItemList(newList);
+        return retailOrderBean;
+    }
+
+    //零售单补充钱包数据
+    public List<CustomerWalletBean> supplyWallet1(String productPriceId, Map<String, CustomerWalletBean> customerWalletMap, String type) {
+
+        ProductPrice productPrice = productPriceService.lambdaQuery()
+                .eq(ProductPrice::getId, productPriceId)
+                .one();
+        List<CustomerWalletBean> list = new ArrayList<>();
+
+        List<String> priceWallets = type.equals(BalanceTypeEnum.W.getKey()) ? StrUtil.split(productPrice.getWalletId(), ",") : StrUtil.split(productPrice.getRebateTypeId(), ",");
+        if (CollectionUtil.isNotEmpty(priceWallets)) {
+            for (String walletId : priceWallets) {
+                CustomerWalletBean customerWalletBean = customerWalletMap.get(walletId);
+                if (Objects.nonNull(customerWalletBean) && customerWalletBean.getType().equals(type)) {
+                    list.add(customerWalletBean);
+                }
+            }
+        }
+        return list;
+    }
+
+    //销售政策单补充钱包数据,销售政策的返利钱包是直接根据销售类型来匹配的
+    public List<CustomerWalletBean> supplyWallet2(String policyMaterialId, Map<String, CustomerWalletBean> customerWalletMap, String type) {
+        List<PolicyWalletRela> policyWalletRelas = policyWalletRelaService.lambdaQuery()
+                .eq(PolicyWalletRela::getPolicyMaterialId, policyMaterialId)
+                .list();
+        List<CustomerWalletBean> list = new ArrayList<>();
+        for (PolicyWalletRela wallet : policyWalletRelas) {
+            CustomerWalletBean customerWalletBean = customerWalletMap.get(wallet.getWalletId());
+            if (customerWalletBean != null && customerWalletBean.getType().equals(type)) {
+                list.add(customerWalletBean);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * 新增零售订单信息
+     *
+     * @param retailOrderAdd
+     */
+    @Transactional
+    public void add(RetailOrderAdd retailOrderAdd) throws Exception {
+
+        AdminUserCom adminUser = commonLogic.getAdminUser();
+        String policyId = retailOrderAdd.getPolicyId();
+        Policy policy = null;
+        if (adminUser.getType() == 2) {
+            throw new RemoteServiceException("非商户不可下单");
+        }
+        if (CollectionUtils.isEmpty(retailOrderAdd.getRetailOrderItemList())) {
+            throw new RemoteServiceException("请选择机型");
+        }
+
+        RetailOrder retailOrder = new RetailOrder();
+        String idPrefix = "1";
+        if (retailOrderAdd.getType() == 2) {
+            idPrefix = "2";
+
+            policy = this.checkPolicy(policyId, adminUser, adminUser.getCompanyWechatId());
+        }
+        retailOrder.setId(commonLogic.generateNo(idPrefix, "retailOrder", 13));
+        retailOrder.setCompanyWechatId(adminUser.getCompanyWechatId());
+        retailOrder.setCompanyName(adminUser.getCompanyName());
+        retailOrder.setRemark(retailOrderAdd.getRemark());
+        retailOrder.setTheTime(new Date());
+        retailOrder.setType(retailOrderAdd.getType());
+
+        if (Objects.nonNull(policy)) {
+            retailOrder.setPolicyId(policyId);
+            retailOrder.setPolicyCode(policy.getCode());
+            retailOrder.setPolicyTitle(policy.getTitle());
+            retailOrder.setPolicyRemark(policy.getRemark());
+        }
+
+        //处理明细
+        retailOrderAdd.getRetailOrderItemList().forEach(v -> v.setId(null));
+        this.addRetailOrderItem(retailOrder, retailOrderAdd.getRetailOrderItemList(), policy, true);
+        //此处新增一定要在item下
+        retailOrder.insert();
+
+        submit(retailOrder.getId());
+    }
+
+    private Policy checkPolicy(String policyId, AdminUserCom adminUser, String customerId) {
+        Policy policy = policyLogic.detail(policyId);
+        if (policy == null) {
+            return null;
+        }
+        if (StringUtils.isEmpty(customerId)) {
+            customerId = adminUser.getCompanyWechatId();
+        }
+
+        //检查经销商是否可以下单
+        Integer count = policyCustomerService.lambdaQuery()
+                .eq(PolicyCustomer::getPolicyId, policy.getId())
+                .eq(PolicyCustomer::getCompanyWechatId, customerId).count();
+        if (count == 0) {
+            throw new RemoteServiceException("非本销售政策适用商户对象");
+        }
+
+        return policy;
+    }
+
+    /**
+     * 新增零售单明细
+     *
+     * @param retailOrder
+     * @param retailOrderItemList 如果是配提政策,前端传表体的policyMaterialId  其实是policy_condition_material的id,需注意
+     */
+    public void addRetailOrderItem(RetailOrder retailOrder, List<RetailOrderItemBean> retailOrderItemList, Policy policy, Boolean add) throws InterruptedException {
+        String retailOrderId = retailOrder.getId();
+        Integer type = retailOrder.getType();
+
+        if (CollectionUtils.isEmpty(retailOrderItemList)) {
+            return;
+        }
+
+        if (!add && !StringUtils.equals(retailOrder.getExamineStatus(), ExamineStatusEnum.SAVE.toString())) {
+            throw new RemoteServiceException("非保存状态不可编辑");
+        }
+        //判断是否购买了同机型并同销售类型的机型
+        Map<String, RetailOrderItemBean> checkProduct = new HashMap<>();
+        for (RetailOrderItemBean retailOrderItemBean : retailOrderItemList) {
+            if (checkProduct.containsKey(retailOrderItemBean.getGoodsMaterialId() + retailOrderItemBean.getSalesTypeId())) {
+                throw new RemoteServiceException("请勿重复选择同型号同销售类型的产品");
+            }
+            checkProduct.put(retailOrderItemBean.getGoodsMaterialId() + retailOrderItemBean.getSalesTypeId(), retailOrderItemBean);
+        }
+        //先清空机型
+        retailOrderItemService.lambdaUpdate()
+                .eq(RetailOrderItem::getRetailOrderId, retailOrderId)
+                .remove();
+
+        //销售政策 type=1 普通零售单 type =2 销售政策单
+        if (type == 2) {
+            retailOrder.setPolicyId(retailOrder.getPolicyCode());
+        }
+        //查询钱包名称
+        List<CustomerWalletBean> customerWalletBeans = companyWalletLogic.queryWalletByAdminCompanyId(retailOrder.getCompanyWechatId());
+        Map<String, CustomerWalletBean> companyWalletMap = customerWalletBeans.stream()
+                .collect(Collectors.toMap(CustomerWalletBean::getId, v -> v));
+
+        // 获取所有定义钱包
+        final List<Wallet> walletList = walletService.list();
+        final Map<String, Wallet> walletMap = walletList.stream().collect(Collectors.toMap(Wallet::getId, Function.identity()));
+
+        // 获取所有返利类型
+        final List<RebateType> rebateTypeList = rebateTypeService.list();
+        final Map<String, RebateType> rebateTypeMap = rebateTypeList.stream().collect(Collectors.toMap(RebateType::getId, Function.identity()));
+
+        //新增明细
+        for (RetailOrderItemBean retailOrderItem : retailOrderItemList) {
+            SalesType saleType = salesTypeService.getById(retailOrderItem.getSalesTypeId());
+            String policyId = retailOrderItem.getPolicyId();
+            //单价
+            BigDecimal price;
+            //折扣价
+            BigDecimal discAmount = BigDecimal.valueOf(0);
+            String materialId;
+
+            if (type == 2) {
+                //销售政策
+                PolicyMaterial policyMaterial = policyLogic.getPolicyMaterial(policyId, retailOrderItem.getGoodsMaterialId(), retailOrderItem.getSalesTypeId());
+                if (Objects.isNull(policyMaterial) || !policyMaterial.getStatus()) {
+                    throw new RemoteServiceException("机型型号【" + retailOrderItem.getSpecsName() + "】在当前政策中无效,请联系相关人员");
+                }
+
+                price = policyMaterial.getPrice();
+                materialId = policyMaterial.getGoodsMaterialId();
+                //这里覆盖下前端传错的参数
+                retailOrderItem.setPolicyMaterialId(policyMaterial.getId());
+                //补充下政策订单需要的参数
+                retailOrderItem.setOrgPrice(policyMaterial.getOrgPrice());
+            } else {
+                if (!add && StringUtils.isNotEmpty(retailOrderItem.getId())) {
+                    //零售单可以改单价,所以直接使用前端传的价格
+                    price = retailOrderItem.getPrice();
+                    //折扣价
+                    discAmount = retailOrderItem.getDiscAmount();
+                    materialId = retailOrderItem.getGoodsMaterialId();
+                } else {
+                    //零售
+                    String productPriceId = retailOrderItem.getProductPriceId();
+                    ProductPrice productPrice = productPriceService.getById(productPriceId);
+                    if (productPrice == null) {
+                        throw new RemoteServiceException("机型型号【" + retailOrderItem.getSpecsName() + "】价格表失效,请联系相关人员");
+                    }
+                    //单价
+                    price = productPrice.getPrice();
+                    materialId = productPrice.getGoodsMaterialId();
+                }
+
+            }
+
+
+            if (retailOrderItem.getQty() <= 0) {
+                throw new RemoteServiceException("数量必须大于等于1");
+            }
+
+            //现金钱包
+            CustomerWalletBean amountCustomerWallet = companyWalletMap.get(retailOrderItem.getCustomerWalletId());
+            //返利钱包
+            CustomerWalletBean rebateCustomerWallet = companyWalletMap.get(retailOrderItem.getCustomerWalletId2());
+
+            // 定义的现金钱包
+            final Wallet wallet = walletMap.get(amountCustomerWallet.getWalletId());
+
+            //数量
+            BigDecimal qty = BigDecimal.valueOf(retailOrderItem.getQty());
+            //总价
+            BigDecimal totalAmount = price.multiply(qty);
+            //总折扣价格
+            BigDecimal totalDiscAmount = discAmount.multiply(qty);
+            //实际支付价格
+            BigDecimal payAmount = totalAmount.subtract(totalDiscAmount);
+            //总返利价格
+            BigDecimal totalRebateAmount = new BigDecimal(0);
+            if (Objects.nonNull(rebateCustomerWallet)) {
+                BigDecimal rebateRate = CommonUtils.getRebateRate(rebateCustomerWallet, retailOrderItem.getSalesTypeId());
+                retailOrderItem.setRebateRate(rebateRate);
+                totalRebateAmount = retailOrderItem.getRebateRate().multiply(payAmount);
+            }
+            //实际返利金额
+            BigDecimal payRebateAmount = totalRebateAmount;
+            if (rebateCustomerWallet != null) {
+                boolean subRebateAmountBol = rebateCustomerWallet.getBalance().doubleValue() < totalRebateAmount.doubleValue();
+                if (subRebateAmountBol) {
+                    payRebateAmount = rebateCustomerWallet.getBalance().doubleValue() > 0 ? rebateCustomerWallet.getBalance() : BigDecimal.valueOf(0);
+                    //扣减当前返利钱包的钱,防止每次对比都是和原金额对比
+                    rebateCustomerWallet.setBalance(BigDecimal.valueOf(0));
+                } else {
+                    //扣减当前返利钱包的钱,防止每次对比都是和原金额对比
+                    rebateCustomerWallet.setBalance(rebateCustomerWallet.getBalance().subtract(totalRebateAmount));
+                }
+
+                companyWalletMap.put(retailOrderItem.getCustomerWalletId2(), rebateCustomerWallet);
+            }
+            //实际支付价格
+            payAmount = payAmount.subtract(payRebateAmount);
+
+            GoodsMaterial goodsMaterial = goodsMaterialService.getById(materialId);
+
+            //检测钱包的合法性
+            this.checkWallet(retailOrderItem, amountCustomerWallet, rebateCustomerWallet, type);
+
+            retailOrderItem.setId(null);
+            retailOrderItem.setFileNo(retailOrder.getFileNo());
+            retailOrderItem.setCompanyWechatId(retailOrder.getCompanyWechatId());
+            retailOrderItem.setCompanyName(retailOrder.getCompanyName());
+            retailOrderItem.setIsUseRebate(StringUtils.isNotEmpty(retailOrderItem.getCustomerWalletId2()));
+            retailOrderItem.setRetailOrderId(retailOrderId);
+            retailOrderItem.setCustomerWalletName(amountCustomerWallet.getName());
+            retailOrderItem.setCustomerWalletCode(wallet.getCode());
+            retailOrderItem.setWalletId1(amountCustomerWallet.getWalletId());
+            if (Objects.nonNull(rebateCustomerWallet)) {
+                final RebateType rebateType = rebateTypeMap.get(rebateCustomerWallet.getWalletId());
+
+                retailOrderItem.setCustomerWalletName2(rebateCustomerWallet.getName());
+                retailOrderItem.setCustomerWalletCode2(rebateType.getCode());
+                retailOrderItem.setWalletId2(rebateCustomerWallet.getWalletId());
+            }
+            if (goodsMaterial != null) {
+                retailOrderItem.setFactoryNo(goodsMaterial.getFactoryNo());
+                retailOrderItem.setMainId(goodsMaterial.getMainId());
+                retailOrderItem.setMainName(goodsMaterial.getMainName());
+                retailOrderItem.setSmallId(goodsMaterial.getSmallId());
+                retailOrderItem.setSmallName(goodsMaterial.getSmallName());
+                retailOrderItem.setGoodsMaterialName(goodsMaterial.getGoodsName());
+                retailOrderItem.setSeriesName(goodsMaterial.getSeriesName());
+                retailOrderItem.setSpecsName(goodsMaterial.getSpecsName());
+                retailOrderItem.setUnit(goodsMaterial.getUnit());
+            }
+
+            retailOrderItem.setSalesTypeCode(saleType.getCode());
+            retailOrderItem.setPrice(price);
+            retailOrderItem.setTotalAmount(totalAmount);
+            retailOrderItem.setRebateAmount(totalRebateAmount.doubleValue() < 0 ? BigDecimal.valueOf(0) : totalRebateAmount);
+            retailOrderItem.setPayAmount(payAmount.doubleValue() < 0 ? BigDecimal.valueOf(0) : payAmount);
+            retailOrderItem.setPayRebateAmount(payRebateAmount);
+            retailOrderItem.setSingleRebateAmount(payRebateAmount.divide(qty, 6, RoundingMode.HALF_UP));
+            retailOrderItem.setTotalDiscAmount(totalDiscAmount);
+            retailOrderItem.setDiscAmount(discAmount);
+            retailOrderItem.setSinglePayPrice(retailOrderItem.getPayAmount().divide(qty, 6, RoundingMode.HALF_UP));
+            retailOrderItem.setRefundableQty(retailOrderItem.getQty());
+            retailOrderItem.setOldPayAmount(retailOrderItem.getPayAmount());
+            retailOrderItem.setOldQty(retailOrderItem.getQty());
+        }
+
+        Integer totalQty = 0;
+        BigDecimal totalAmount = new BigDecimal(0);
+        for (RetailOrderItem retailOrderItem : retailOrderItemList) {
+            totalQty += retailOrderItem.getQty();
+            totalAmount = totalAmount.add(retailOrderItem.getTotalAmount());
+            //新增
+            retailOrderItem.insert();
+        }
+        retailOrder.setTotalAmount(totalAmount);
+        retailOrder.setTotalQty(totalQty);
+    }
+
+    /**
+     * 检测政策单下单时钱包的合法性
+     *
+     * @param retailOrderItem
+     * @param amountCustomerWallet 现金钱包
+     * @param rebateCustomerWallet 返利钱包(可能为空)
+     * @param type                 1=零售  2=政策
+     */
+    public void checkWallet(RetailOrderItemBean retailOrderItem, CustomerWalletBean amountCustomerWallet, CustomerWalletBean rebateCustomerWallet, Integer type) {
+        if (amountCustomerWallet == null) {
+            log.info("【请选择现金钱包】:{}", JSONObject.toJSONString(retailOrderItem));
+            throw new RemoteServiceException("请选择现金钱包");
+        }
+
+        //其他零售机
+        if (type == 1 && StringUtils.isNotEmpty(retailOrderItem.getProductPriceId())) {
+            ProductPrice productPrice = productPriceService.getById(retailOrderItem.getProductPriceId());
+            // 分隔逗号钱包
+            List<String> priceWalletIds = StrUtil.split(productPrice.getWalletId(), ",");
+            List<String> priceRebateIds = StrUtil.split(productPrice.getRebateTypeId(), ",");
+            List<String> walletIds = new ArrayList<>();
+            walletIds.addAll(priceWalletIds);
+            walletIds.addAll(priceRebateIds);
+            if (!walletIds.contains(amountCustomerWallet.getWalletId())) {
+                throw new RemoteServiceException(retailOrderItem.getSpecsName() + "的现金钱包【" + amountCustomerWallet.getName() + "】不能使用");
+            }
+            if (Objects.nonNull(rebateCustomerWallet) && !walletIds.contains(rebateCustomerWallet.getWalletId())) {
+                throw new RemoteServiceException(retailOrderItem.getSpecsName() + "返利钱包【" + rebateCustomerWallet.getName() + "】不能使用");
+            }
+        } else if (type == 2) {
+            //如果是配提政策,前端传的policyMaterialId其实是政策条件机型的id(policyConditionMaterialId)
+            List<PolicyWalletRela> policyWalletRelas = policyWalletRelaService
+                    .lambdaQuery().eq(PolicyWalletRela::getPolicyId, retailOrderItem.getPolicyId())
+                    .eq(PolicyWalletRela::getPolicyMaterialId, retailOrderItem.getPolicyMaterialId())
+                    .list();
+            List<String> walletIds = policyWalletRelas.stream().map(PolicyWalletRela::getWalletId).collect(Collectors.toList());
+            if (!walletIds.contains(amountCustomerWallet.getWalletId())) {
+                throw new RemoteServiceException(retailOrderItem.getSpecsName() + "现金钱包【" + amountCustomerWallet.getName() + "】不能使用");
+            }
+            if (rebateCustomerWallet != null && !walletIds.contains(rebateCustomerWallet.getWalletId())) {
+                throw new RemoteServiceException(retailOrderItem.getSpecsName() + "返利钱包【" + rebateCustomerWallet.getName() + "】不能使用");
+            }
+        }
+    }
+
+    /**
+     * 提审
+     *
+     * @param id
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void submit(String id) throws Exception {
+        AdminUserCom adminUser = commonLogic.getAdminUser();
+        //零售单表头
+        RetailOrder retailOrder = retailOrderService.getById(id);
+        if (!retailOrder.getExamineStatus().equals(ExamineStatusEnum.SAVE.toString())) {
+            throw new RemoteServiceException("请勿重复提审");
+        }
+        if (retailOrder.getType() == 2) {
+            Policy policy = policyLogic.detail(retailOrder.getPolicyId());
+            if (Objects.isNull(policy)
+                    || policy.getStatus().equals(StateEnum.OFF.getKey())
+                    || policy.getEndTime().getTime() < new Date().getTime()
+                    || policy.getStartTime().getTime() > new Date().getTime()) {
+                throw new RemoteServiceException("政策已失效,无法提审");
+            }
+        }
+        //零售单表体
+        List<RetailOrderItem> list = retailOrderItemService.lambdaQuery()
+                .eq(RetailOrderItem::getRetailOrderId, id)
+                .list();
+
+        //重新刷新次要计算的金额
+        List<RetailOrderItemBean> beanList = new ArrayList<>();
+        for (RetailOrderItem retailOrderItem : list) {
+            RetailOrderItemBean bean = new RetailOrderItemBean();
+            BeanUtils.copyProperties(retailOrderItem, bean);
+            beanList.add(bean);
+        }
+        RetailOrderAdd retailOrderAdd = new RetailOrderAdd();
+        BeanUtils.copyProperties(retailOrder, retailOrderAdd);
+        retailOrderAdd.setRetailOrderItemList(beanList);
+        this.update(retailOrderAdd);
+
+        //提审扣钱
+        companyWalletLogic.handleRetailOrderCompanyWallet(beanList, DirectFlagEnum.SUB, false);
+
+        retailOrder.setTheTime(new Date());
+        retailOrder.setExamineStatus(ExamineStatusEnum.WAIT.toString());
+        retailOrder.updateById();
+    }
+
+    /**
+     * 编辑零售订单信息
+     */
+    @Transactional
+    public void update(RetailOrderAdd retailOrderAdd) throws InterruptedException {
+
+        AdminUserCom adminUser = commonLogic.getAdminUser();
+        RetailOrder retailOrder = retailOrderService.getById(retailOrderAdd.getId());
+        Policy policy = null;
+        String policyId = retailOrderAdd.getPolicyId();
+        if(retailOrderAdd.getType() != null && retailOrderAdd.getType() == 2){
+            policy = this.checkPolicy(policyId,adminUser,retailOrder.getCompanyWechatId());
+        }
+
+        retailOrder.setId(retailOrderAdd.getId());
+        retailOrder.setRemark(retailOrderAdd.getRemark());
+
+        retailOrder.setFileNo(retailOrderAdd.getFileNo());
+        if(CollectionUtils.isNotEmpty(retailOrderAdd.getRetailOrderItemList())) {
+            //处理明细
+            this.addRetailOrderItem(retailOrder, retailOrderAdd.getRetailOrderItemList(),policy,false);
+        }
+
+        if(Objects.nonNull(policy)){
+            retailOrder.setPolicyId(policyId);
+            retailOrder.setPolicyCode(policy.getCode());
+            retailOrder.setPolicyTitle(policy.getTitle());
+            retailOrder.setPolicyRemark(policy.getRemark());
+        }
+
+        retailOrder.updateById();
+    }
+
+
+
+    /**
+     * 撤回提审
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void submitCancel(String id) throws Exception {
+        RetailOrder retailOrder = retailOrderService.getById(id);
+        if(!retailOrder.getExamineStatus().equals(ExamineStatusEnum.WAIT.toString())){
+            throw new RemoteServiceException("无法撤回提审");
+        }
+        retailOrder.setExamineStatus(ExamineStatusEnum.SAVE.toString());
+        retailOrder.updateById();
+
+        //不通过,直接退钱
+        //全退
+        this.refundAll(retailOrder, true);
+    }
+
+    /**
+     * 退订
+     * @param retailOrderRefundBean 退订的商品明细
+     * @return
+     * @throws Exception
+     */
+    @Transactional
+    public List<Map<String, Object>> refund(RetailOrderRefundBean retailOrderRefundBean) throws Exception {
+        List<RetailOrderItemBean> retailOrderItemList = retailOrderRefundBean.getRetailOrderItemList();
+        RetailOrder retailOrder = retailOrderService.getById(retailOrderRefundBean.getId());
+        if(!retailOrder.getExamineStatus().equals(ExamineStatusEnum.OK.toString())){
+            throw new RemoteServiceException("非审核通过订单不可退订");
+        }
+        AdminUserCom adminUser = commonLogic.getAdminUser();
+        if (adminUser.getType() != 2) {
+            throw new RemoteServiceException("暂无权限操作");
+        }
+        List<Map<String, Object>> resultMap = new ArrayList<>();
+
+        List<RetailOrderItem> execRecords = new ArrayList<>();
+        List<RetailOrderItem> updateItems = new ArrayList<>();
+        for(RetailOrderItemBean retailOrderItem : retailOrderItemList) {
+            RetailOrderItem item = retailOrderItemService.getById(retailOrderItem.getId());
+
+            //退订数量
+            int tdQty = (retailOrderItem.getTdQty() == null ? 0 : retailOrderItem.getTdQty());
+            //订单明细的退订
+            Map<String, Object> paramsMap = this.refundItem(item,tdQty);
+            resultMap.add(paramsMap);
+
+            if (tdQty > 0 && Objects.nonNull(paramsMap.get("execRecord")))
+                execRecords.add((RetailOrderItem) paramsMap.get("execRecord"));
+
+            if (tdQty > 0 && Objects.nonNull(paramsMap.get("updateItem")))
+                updateItems.add((RetailOrderItem) paramsMap.get("updateItem"));
+        }
+
+        if (CollectionUtil.isNotEmpty(execRecords)) {
+            //钱包金额的退订
+            this.refundAmount(execRecords);
+            // 更新订单明细
+            retailOrderItemService.saveOrUpdateBatch(updateItems);
+            // 插入退订记录
+            this.insertRefundOrderRecord(retailOrder, execRecords, adminUser);
+        }
+
+        return resultMap;
+    }
+
+    private void refundAll(RetailOrder retailOrder, boolean isRemoveRecord) throws Exception {
+        //退钱
+        List<RetailOrderItemBean> retailOrderItemBeans = new ArrayList<>();
+        List<RetailOrderItem> retailOrderItemList = retailOrderItemService.lambdaQuery().eq(RetailOrderItem::getRetailOrderId, retailOrder.getId()).list();
+
+        for(RetailOrderItem item : retailOrderItemList){
+            if(item.getRefundableQty().intValue() != item.getOldQty().intValue()){
+                throw new RemoteServiceException("检测到订单数量与订单原数量有变动,不可弃审");
+            }
+            RetailOrderItemBean retailOrderItemBean = new RetailOrderItemBean();
+            BeanUtils.copyProperties(item, retailOrderItemBean);
+            retailOrderItemBeans.add(retailOrderItemBean);
+        }
+
+        companyWalletLogic.handleRetailOrderCompanyWallet(retailOrderItemBeans, DirectFlagEnum.ADD, isRemoveRecord);
+    }
+
+    /**
+     * 订单明细退订处理(不处理钱包的钱,只处理明细数量和订单里的钱)
+     * @param retailOrderItem 订单明细
+     * @param itemTdQty 退订明细数量
+     * @return 退订现金金额
+     */
+    public Map<String, Object> refundItem(RetailOrderItem retailOrderItem, Integer itemTdQty){
+        RetailOrderItem item = retailOrderItemService.getById(retailOrderItem.getId());
+        //退订数量
+        int tdQty = (itemTdQty == null ? 0 : itemTdQty);
+
+        //退订金额
+        BigDecimal tdAmount = retailOrderItem.getSinglePayPrice().multiply(BigDecimal.valueOf(tdQty));
+        if(item.getQty() == tdQty){
+            tdAmount = retailOrderItem.getPayAmount();
+        }
+        //退订的实际返利金额
+        BigDecimal tdPayRebateAmount = retailOrderItem.getSingleRebateAmount().multiply(BigDecimal.valueOf(tdQty));
+        if(item.getQty() == tdQty){
+            tdPayRebateAmount = retailOrderItem.getPayRebateAmount();
+        }
+        //退订折扣金额
+        BigDecimal tdDiscAmount = retailOrderItem.getDiscAmount().multiply(BigDecimal.valueOf(tdQty));
+        if(item.getQty() == tdQty){
+            tdDiscAmount = retailOrderItem.getTotalDiscAmount();
+        }
+        //剩余金额
+        BigDecimal balanceNewPrice = retailOrderItem.getPayAmount().subtract(tdAmount);
+        //剩余返利金额
+        BigDecimal balanceRebateAmount = retailOrderItem.getPayRebateAmount().subtract(tdPayRebateAmount);
+        //剩余折扣金额
+        BigDecimal balanceDiscAmount = retailOrderItem.getTotalDiscAmount().subtract(tdDiscAmount);
+
+        if(tdQty < 0){
+            throw new RemoteServiceException("退订数量不可为负数");
+        }
+        if(tdQty > item.getRefundableQty()){
+            throw new RemoteServiceException("机型:" + item.getSpecsName() + "退订数量不可大于可退数量");
+        }
+        //处理数量
+        retailOrderItem.setRefundableQty(item.getRefundableQty() - tdQty);
+        retailOrderItem.setRetiredQty(item.getRetiredQty() + tdQty);
+        retailOrderItem.setQty(retailOrderItem.getQty() - tdQty);
+
+        //处理金额
+        retailOrderItem.setPayAmount(balanceNewPrice.doubleValue() < 0 ? BigDecimal.valueOf(0) : balanceNewPrice);
+        retailOrderItem.setPayRebateAmount(balanceRebateAmount.doubleValue() < 0 ? BigDecimal.valueOf(0) : balanceRebateAmount);
+        retailOrderItem.setTotalDiscAmount(balanceDiscAmount.doubleValue() < 0 ? BigDecimal.valueOf(0) : balanceDiscAmount);
+        retailOrderItem.setTotalAmount(retailOrderItem.getPrice().multiply(BigDecimal.valueOf(retailOrderItem.getQty())));
+
+        Map<String, Object> paramsMap = new HashMap<>();
+        if (tdQty > 0) {
+            RetailOrderItem execRecord = new RetailOrderItem();
+            BeanUtils.copyProperties(item, execRecord);
+            execRecord.setQty(tdQty)
+                    .setTotalAmount(item.getPrice().multiply(BigDecimal.valueOf(tdQty)))
+                    .setTotalDiscAmount(tdDiscAmount)
+                    .setPayRebateAmount(tdPayRebateAmount)
+                    .setPayAmount(tdAmount);
+
+            paramsMap.put("execRecord", execRecord);
+            paramsMap.put("updateItem", retailOrderItem);
+        }
+
+        return paramsMap;
+    }
+
+    private void refundAmount(List<RetailOrderItem> retailOrderItemList) {
+        List<RetailOrderItemBean> retailOrderItemBeans = new ArrayList<>();
+        for (RetailOrderItem item : retailOrderItemList) {
+            RetailOrderItemBean bean = new RetailOrderItemBean();
+            BeanUtils.copyProperties(item, bean);
+            retailOrderItemBeans.add(bean);
+        }
+
+        companyWalletLogic.handleRetailOrderCompanyWallet(retailOrderItemBeans, DirectFlagEnum.ADD, false);
+    }
+
+    private void insertRefundOrderRecord(RetailOrder retailOrder, List<RetailOrderItem> execRecords, AdminUserCom adminUser) {
+        RefundOrder refundOrder = new RefundOrder();
+        refundOrder.setRefundOrderType(retailOrder.getType().toString());
+        refundOrder.setRefOrderDate(retailOrder.getTheTime());
+        refundOrder.setRefOrderId(retailOrder.getId());
+        refundOrder.setPolicyId(retailOrder.getPolicyId());
+        refundOrder.setPolicyCode(retailOrder.getPolicyCode());
+        refundOrder.setPolicyTitle(retailOrder.getPolicyTitle());
+        refundOrder.setPolicyRemark(retailOrder.getPolicyRemark());
+        refundOrder.setFileNo(retailOrder.getFileNo());
+        refundOrder.setRefOrderRemark(retailOrder.getRemark());
+        refundOrder.setRefundBy(adminUser.getNickName());
+        refundOrder.setRefundTime(DateUtil.date());
+        refundOrder.setCompanyWechatId(retailOrder.getCompanyWechatId());
+        refundOrder.setCompanyName(retailOrder.getCompanyName());
+        refundOrder.insert();
+
+        List<RefundOrderItem> refundOrderItems = new ArrayList<>();
+        for (RetailOrderItem execRecord : execRecords) {
+            RefundOrderItem refundOrderItem = new RefundOrderItem();
+            BeanUtils.copyProperties(execRecord, refundOrderItem);
+            refundOrderItem.setRefundOrderItemId(null)
+                    .setRefundOrderId(refundOrder.getRefundOrderId())
+                    .setRetailOrderId(refundOrder.getRefOrderId());
+
+            refundOrderItems.add(refundOrderItem);
+        }
+
+        refundOrderItemService.saveBatch(refundOrderItems);
+    }
+
+    public void examine(String id, String examineStatus, String examineRemark, String remark, String fileNo) throws Exception {
+        AdminUserCom adminUser = commonLogic.getAdminUser();
+        RetailOrder retailOrder = retailOrderService.getById(id);
+        if(!retailOrder.getExamineStatus().equals(ExamineStatusEnum.WAIT.toString())){
+            throw new RemoteServiceException("非待审核单据不可审核");
+        }
+        if(adminUser.getType() != 2){
+            throw new RemoteServiceException("暂无权限操作");
+        }
+        //驳回直接变回保存状态
+        retailOrder.setRemark(remark);
+        retailOrder.setExamineStatus(examineStatus.equals(ExamineStatusEnum.FAIL.getKey())?ExamineStatusEnum.SAVE.getKey():examineStatus);
+        retailOrder.setExamineRemark(examineRemark);
+        retailOrder.setExamineBy(adminUser.getNickName());
+        retailOrder.setExamineTime(new Date());
+        retailOrder.setFileNo(fileNo);
+
+        List<RetailOrderItem> retailOrderItems = retailOrderItemService.lambdaQuery()
+                .eq(RetailOrderItem::getRetailOrderId, id).list();
+
+        //审核通过
+        if(StringUtils.equals(examineStatus,ExamineStatusEnum.OK.toString())){
+
+        }else if(StringUtils.equals(examineStatus,ExamineStatusEnum.FAIL.toString())){
+            //全退
+            this.refundAll(retailOrder, false);
+        }
+        retailOrder.updateById();
+        retailOrderItemService.saveOrUpdateBatch(retailOrderItems);
+    }
+
+    @Transactional
+    public void delete(String id){
+        RetailOrder retailOrder = retailOrderService.getById(id);
+        if(!retailOrder.getExamineStatus().equals(ExamineStatusEnum.SAVE.toString())){
+            throw new RemoteServiceException("非保存状态不可删除");
+        }
+        retailOrder.deleteById();
+        retailOrderItemService.lambdaUpdate().eq(RetailOrderItem::getRetailOrderId,id).remove();
+    }
+}

+ 22 - 4
mall-server-api/src/main/java/com/gree/mall/manager/utils/CommonUtils.java

@@ -1,10 +1,14 @@
 package com.gree.mall.manager.utils;
 
 
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.gree.mall.manager.bean.admin.AdminWebsitBean;
+import com.gree.mall.manager.bean.supply.funds.CustomerWalletBean;
 import com.gree.mall.manager.commonmapper.WebsitMapper;
 import com.gree.mall.manager.constant.DailyConstant;
+import com.gree.mall.manager.exception.RemoteServiceException;
 import com.gree.mall.manager.plus.entity.AdminUser;
+import com.gree.mall.manager.plus.entity.RebateTypeUseRate;
 import com.gree.mall.manager.plus.service.AdminUserService;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
@@ -18,14 +22,13 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.lang.reflect.Field;
+import java.math.BigDecimal;
 import java.net.URL;
 import java.net.URLConnection;
 import java.net.URLEncoder;
 import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+import java.util.stream.Collectors;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
@@ -440,4 +443,19 @@ public class CommonUtils {
     public static String getCurDateFileName(String name, String fileSuffix) {
         return name + DateUtils.formatDate1(new Date()) + "." + fileSuffix;
     }
+
+    /**
+     * 根据销售类型获取返利比例
+     */
+    public static BigDecimal getRebateRate(CustomerWalletBean rebateCustomerWallet, String saleTypeId){
+        if(Objects.nonNull(rebateCustomerWallet)) {
+            List<RebateTypeUseRate> rebateTypeUseRates = rebateCustomerWallet.getWalletRaleTypes().stream()
+                    .filter(v -> v.getSalesTypeId().equals(saleTypeId)).collect(Collectors.toList());
+            if(CollectionUtils.isEmpty(rebateTypeUseRates)){
+                throw new RemoteServiceException("返利钱包不符合销售类型");
+            }
+            return rebateTypeUseRates.get(0).getRebateRate();
+        }
+        return BigDecimal.valueOf(0);
+    }
 }

+ 11 - 0
mall-server-api/src/main/resources/mapper/CommonMapper.xml

@@ -1475,4 +1475,15 @@
         ${ex.orderBy}
     </select>
 
+    <select id="retailOrderList" resultType="com.gree.mall.manager.bean.supply.order.RetailOrderVO">
+        SELECT
+        ${ex.selected}
+        FROM retail_order a
+        ${ex.query}
+        <if test="ex.orderBy == null or ex.orderBy ==''">
+            ORDER BY a.create_time DESC
+        </if>
+        ${ex.orderBy}
+    </select>
+
 </mapper>