package com.gree.mall.miniapp.logic.material.stock;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
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.*;
import com.gree.mall.miniapp.bean.user.CurrentCompanyWechat;
import com.gree.mall.miniapp.commonmapper.MaterialMapper;
import com.gree.mall.miniapp.commonmapper.stock.MaterialGoodsStockCMapper;
import com.gree.mall.miniapp.constant.Constant;
import com.gree.mall.miniapp.enums.material.PartsPushFlagEnum;
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.plus.entity.*;
import com.gree.mall.miniapp.plus.service.*;
import com.gree.mall.miniapp.utils.ValidateUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.validation.ValidationException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * 师傅的辅材库存
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class MaterialGoodsStockLogic {

    private final CommonLogic commonLogic;
    private final WorkerStockService workerStockService;
    private final WorkerStockAccService workerStockAccService;
    private final WebsitPartsSalesItemService websitPartsSalesItemService;
    private final MaterialGoodsStockCMapper materialGoodsStockCMapper;
    private final WebsitPartsRetService websitPartsRetService;
    private final WebsitNormRecordService websitNormRecordService;
    private final WebsitGoodsService websitGoodsService;
    private final RedisLockRegistry redisLockRegistry;
    private final MaterialMapper materialMapper;
    private final WebsitStockService websitStockService;
    private final WebsitStockAccService websitStockAccService;

    /**
     * 我的库存分类
     *
     * @param webistId
     * @param goodsType
     * @return
     */
    public List<WebsitGoodsCategory> websitGoodsCategoryList(String webistId, String goodsType) {
        CurrentCompanyWechat currentCompanyWechat = commonLogic.getCurrentCompanyWechat();
        List<WebsitGoodsCategory> websitGoodsCategories = materialGoodsStockCMapper.queryWebsitGoodsCategoryList(webistId, currentCompanyWechat.getUser().getWorkerNumber(), goodsType);
        return websitGoodsCategories;
    }

    /**
     * 我的库存列表
     *
     * @param websitId
     * @param goodsType
     * @param pageNum
     * @param pageSize
     * @return
     */
    public IPage<WorkerStockBean> workerStockList(String websitId, String goodsType, String categoryId, Integer pageNum, Integer pageSize) {
        CurrentCompanyWechat currentCompanyWechat = commonLogic.getCurrentCompanyWechat();
        IPage<WorkerStockBean> workerStockBeanIPage = materialGoodsStockCMapper
                .queryWorkerStockList(new Page(pageNum, pageSize), websitId, currentCompanyWechat.getUser().getWorkerNumber(), goodsType, categoryId);

        return workerStockBeanIPage;
    }

    /**
     * 我的辅材配件库存详情
     */
    public WorkerStock detail(String id) {
        WorkerStock workerStock = workerStockService.getById(id);
        WorkerStockDetailBean workerStockDetailBean = BeanUtil.copyProperties(workerStock, WorkerStockDetailBean.class);
        String unit = Optional.ofNullable(websitGoodsService.getById(workerStock.getGoodsId()))
                .map(WebsitGoods::getGoodsStockUnit)
                .orElse("");
        workerStockDetailBean.setUnit(unit);
        return workerStockDetailBean;
    }


    /**
     * 我的库存明细
     */
    public IPage<WorkerStockAccBean> workerStockAccList(String websitId, String websitGoodsId, String month, String directFlag, Integer pageNum, Integer pageSize) {
        String startTime = null;
        String endTime = null;
        if (StringUtils.isNotBlank(month)) {
            startTime = month + "-01";
            endTime = DateUtil.offsetMonth(DateUtil.parseDate(startTime), 1).toDateStr();
        }
        CurrentCompanyWechat currentCompanyWechat = commonLogic.getCurrentCompanyWechat();
        Page page = workerStockAccService.lambdaQuery()
                .eq(StringUtils.isNotBlank(websitId), WorkerStockAcc::getWebsitId, websitId)
                .eq(StringUtils.isNotBlank(directFlag), WorkerStockAcc::getDirectFlag, directFlag)
                .eq(WorkerStockAcc::getWorkerId, currentCompanyWechat.getUser().getWorkerNumber())
                .eq(WorkerStockAcc::getGoodsId, websitGoodsId)
                .between(startTime != null && endTime != null, WorkerStockAcc::getOperTime, startTime, endTime)
                .orderByDesc(WorkerStockAcc::getOperTime).page(new Page<>(pageNum, pageSize));

        List<WorkerStockAccBean> workerStockAccBeans = BeanUtil.copyToList(page.getRecords(), WorkerStockAccBean.class);
        for (WorkerStockAccBean workerStockAccBean : workerStockAccBeans) {
            WebsitGoods websitGoods = websitGoodsService.getById(workerStockAccBean.getGoodsId());
            if (websitGoods != null) {
                workerStockAccBean.setUnit(websitGoods.getGoodsStockUnit());
            }
        }
        page.setRecords(workerStockAccBeans);
        return page;
    }


    public MyDataCountBean myDataCount() {
        CurrentCompanyWechat wechat = commonLogic.getCurrentCompanyWechat();
        MyDataCountBean bean = new MyDataCountBean();
        String curDate = DateUtil.formatDate(DateUtil.date());
        Integer newRefundCount = websitPartsRetService.lambdaQuery()
                .eq(WebsitPartsRet::getType, "NEW")
                .eq(WebsitPartsRet::getFlag, "SUBMIT")
                .eq(WebsitPartsRet::getWorkerId, wechat.getUser().getWorkerNumber())
                .eq(WebsitPartsRet::getCompanyWechatId, wechat.getCurrentCompanyWechatId())
                .count();
        Integer oldRefundCount = websitPartsRetService.lambdaQuery()
                .eq(WebsitPartsRet::getType, "OLD")
                .eq(WebsitPartsRet::getFlag, "SUBMIT")
                .eq(WebsitPartsRet::getWorkerId, wechat.getUser().getWorkerNumber())
                .eq(WebsitPartsRet::getCompanyWechatId, wechat.getCurrentCompanyWechatId())
                .count();
        Integer materialSalesCount = websitNormRecordService.query()
                .select("DISTINCT ref_order")
                .eq("goods_type", "M")
                .eq("worker_id", wechat.getUser().getWorkerNumber())
                .between("create_time", curDate + " 00:00:00", curDate + " 23:59:59")
                .count();
        List<WebsitNormRecord> normRecords1 = websitNormRecordService.lambdaQuery()
                .eq(WebsitNormRecord::getGoodsType, "M")
                .eq(WebsitNormRecord::getWorkerId, wechat.getUser().getWorkerNumber())
                .between(WebsitNormRecord::getCreateTime, curDate + " 00:00:00", curDate + " 23:59:59")
                .list();
        Integer partsSalesCount = websitNormRecordService.query()
                .select("DISTINCT ref_order")
                .eq("goods_type", "P")
                .eq("worker_id", wechat.getUser().getWorkerNumber())
                .between("create_time", curDate + " 00:00:00", curDate + " 23:59:59")
                .count();
        List<WebsitNormRecord> normRecords2 = websitNormRecordService.lambdaQuery()
                .eq(WebsitNormRecord::getGoodsType, "P")
                .eq(WebsitNormRecord::getWorkerId, wechat.getUser().getWorkerNumber())
                .between(WebsitNormRecord::getCreateTime, curDate + " 00:00:00", curDate + " 23:59:59")
                .list();

        double materialSalesAmount = normRecords1.stream().mapToDouble(v -> v.getUseQty().multiply(v.getNormAmount()).doubleValue()).sum();
        double partsSalesAmount = normRecords2.stream().mapToDouble(v -> v.getUseQty().multiply(v.getNormAmount()).doubleValue()).sum();
        bean.setNewRefundCount(newRefundCount);
        bean.setOldRefundCount(oldRefundCount);
        bean.setMaterialSalesCount(materialSalesCount);
        bean.setMaterialSalesAmount(BigDecimal.valueOf(materialSalesAmount).setScale(2, BigDecimal.ROUND_HALF_UP));
        bean.setPartsSalesCount(partsSalesCount);
        bean.setPartsSalesAmount(BigDecimal.valueOf(partsSalesAmount).setScale(2, BigDecimal.ROUND_HALF_UP));
        return bean;
    }

    /**
     * 单个网点库存处理
     * @param stockList
     * @throws Exception
     */
    public void handleWebsitStock(List<WebsitStockDTO> stockList) throws Exception {
        if(!TransactionSynchronizationManager.isSynchronizationActive()) {
            throw new RemoteServiceException("请先开启事务");
        }
//        System.out.println("程序入口：" + DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss.SSS"));
        if (CollectionUtil.isEmpty(stockList)) {
            return;
        }
//        System.out.println("检查传入的参数入口：" + DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss.SSS"));
        // 检查传入的参数
        for (int i = 0; i < stockList.size(); i++) {
            WebsitStockDTO websitStockDTO = stockList.get(i);
            try {
                ValidateUtil.validate(websitStockDTO);
                if (websitStockDTO.getChangeQty().compareTo(BigDecimal.ZERO) <= 0) {
                    throw new RuntimeException("变动数量不能少于0");
                }
            } catch (ValidationException ve) {
                throw new RemoteServiceException("执行数据第" + (i+1) + "行" + ve.getMessage());
            }
        }
//        System.out.println("检查传入的参数出口：" + DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss.SSS"));
        // 锁定网点库存
//        System.out.println("锁定网点库存入口：" + DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss.SSS"));
        WebsitStockDTO websitStockDTO = stockList.get(0);
        Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.MATERIAL_STOCK_LOCK +
                websitStockDTO.getCompanyWechatId() + ":" +
                websitStockDTO.getWebsitId() + ":" +
                websitStockDTO.getGoodsType() + ":" +
                websitStockDTO.getStorageId());
        if(!obtain.tryLock(10, TimeUnit.SECONDS)){
            throw new RemoteServiceException("库存已冻结:" + websitStockDTO.getWebsitName());
        }
//        System.out.println("锁定网点库存出口：" + DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss.SSS"));
        // 处理网点库存
        try{
            this.saveWebsitStock(websitStockDTO, stockList);

        } finally {
            this.txCallUnlock(obtain);
//            System.out.println("程序出口：" + DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss.SSS"));
        }
    }

    private void saveWebsitStock(WebsitStockDTO websitStockDTO, List<WebsitStockDTO> stockList) {
        //        System.out.println("处理网点库存入口：" + DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss.SSS"));
        // 查询存在的配件库存
        List<WebsitStock> existWebsitStockList = materialGoodsStockCMapper.queryExistWebsitStockList(websitStockDTO.getCompanyWechatId(),
                websitStockDTO.getWebsitId(), websitStockDTO.getStorageId(), stockList);

//        System.out.println("计算库存入口：" + DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss.SSS"));
        // 全部商品库存
        Map<String, WebsitStock> existShopStockMap = this.createNotExistStock(stockList, existWebsitStockList);
        // 计算商品库存
//        List<PartsShopStock> shopStockList = new ArrayList<>();
        List<WebsitStockAcc> shopStockAccList = new ArrayList<>();
        this.computeWebsitStock(stockList, existShopStockMap, null, shopStockAccList);

        if (CollectionUtil.isEmpty(shopStockAccList)) {
            throw new RemoteServiceException("商品库存处理失败");
        }
//        System.out.println("计算商品库存出口：" + DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss.SSS"));
//        System.out.println("保存商品库存入口：" + DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss.SSS"));
//        partsShopStockService.saveOrUpdateBatch(shopStockList);
        websitStockService.saveOrUpdateBatch(existShopStockMap.values());
//        System.out.println("保存商品库存出口：" + DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss.SSS"));
//        System.out.println("保存商品库存三级帐入口：" + DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss.SSS"));
        websitStockAccService.saveBatch(shopStockAccList);
//        System.out.println("保存商品库存三级帐出口：" + DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss.SSS"));
    }

    private Map<String, WebsitStock> createNotExistStock(List<WebsitStockDTO> stockList, List<WebsitStock> existWebsitStockList) {
        // 已存在的配件库存转成Map
        Map<String, WebsitStock> existStockMap = existWebsitStockList.stream()
                .collect(Collectors.toMap(WebsitStock::getGoodsId, Function.identity()));

        // 找出不存在的配件库存并存入新配件库存List
        for (WebsitStockDTO websitStockDTO : stockList) {
            WebsitStock shopStock = existStockMap.get(websitStockDTO.getGoodsId());
            if (Objects.isNull(shopStock)) {
                shopStock = websitStockDTO.createPartsStock();
                existStockMap.put(websitStockDTO.getGoodsId(), shopStock);
            }
        }
        return existStockMap;
    }

    private void computeWebsitStock(List<WebsitStockDTO> stockList, Map<String, WebsitStock> existShopStockMap, Object o, List<WebsitStockAcc> shopStockAccList) {
        for (WebsitStockDTO shopStockDTO : stockList) {
            WebsitStock shopStock = existShopStockMap.get(shopStockDTO.getGoodsId());
            WebsitStockAcc shopStockAcc = new WebsitStockAcc();
            shopStockDTO.computeWebsitStock(shopStock, shopStockAcc);
            shopStockAccList.add(shopStockAcc);
        }
    }

    /**
     * 单个师傅库存处理
     *
     * @param stockList
     * @throws Exception
     */
    public void handleWorkerStock(List<WorkerStockDTO> stockList) throws Exception {
        if (!TransactionSynchronizationManager.isSynchronizationActive()) {
            throw new RemoteServiceException("请先开启事务");
        }
        if (CollectionUtil.isEmpty(stockList)) {
            return;
        }
        // 检查传入的参数
        for (int i = 0; i < stockList.size(); i++) {
            WorkerStockDTO workerStockDTO = stockList.get(i);
            try {
                ValidateUtil.validate(workerStockDTO);
                if (workerStockDTO.getChangeQty().compareTo(BigDecimal.ZERO) <= 0) {
                    throw new RuntimeException("变动数量不能少于0");
                }
            } catch (ValidationException ve) {
                throw new RemoteServiceException("第" + (i + 1) + "行" + ve.getMessage());
            }
        }
        // 锁定师傅配件库存
        WorkerStockDTO workerStockDTO = stockList.get(0);
        Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.MATERIAL_STOCK_LOCK +
                workerStockDTO.getCompanyWechatId() + ":" +
                workerStockDTO.getWorkerId() + ":" +
                workerStockDTO.getGoodsType());
        if (!obtain.tryLock(10, TimeUnit.SECONDS)) {
            throw new RemoteServiceException("库存已冻结:" + workerStockDTO.getWorkerName());
        }
        // 处理师傅库存
        try {
            this.saveWorkerStock(workerStockDTO, stockList);
        } finally {
            this.txCallUnlockWorker(obtain);
        }
    }

    private void saveWorkerStock(WorkerStockDTO workerStockDTO, List<WorkerStockDTO> stockList) throws Exception {
        // 查询存在的商品库存
        List<WorkerStock> existWorkerStockList = materialGoodsStockCMapper.queryExistWorkerStockList(workerStockDTO.getCompanyWechatId()
                , workerStockDTO.getWorkerId(), stockList);
        // 全部商品库存
        Map<String, WorkerStock> existWorkerStockMap = this.createNotExistWorkerStock(workerStockDTO.getGoodsType(), stockList, existWorkerStockList);
        // 计算商品库存
        List<WorkerStockAcc> workerStockAccList = new ArrayList<>();
        this.computeWorkerStock(stockList, existWorkerStockMap, null, workerStockAccList);

        if (CollectionUtil.isEmpty(workerStockAccList)) {
            throw new RemoteServiceException("师傅配件库存处理失败");
        }

        workerStockService.saveOrUpdateBatch(existWorkerStockMap.values());
        workerStockAccService.saveBatch(workerStockAccList);
    }

    private void computeWorkerStock(List<WorkerStockDTO> stockList, Map<String, WorkerStock> existWorkerStockMap,
                                    List<WorkerStock> workerStockList, List<WorkerStockAcc> workerStockAccList) throws Exception {
        for (WorkerStockDTO workerStockDTO : stockList) {
            WorkerStock workerStock = existWorkerStockMap.get(workerStockDTO.getGoodsId());
            if (workerStockDTO.getGoodsType().equals(WebsitGoodsTypeEnum.P.toString())) {
                workerStock = existWorkerStockMap.get(workerStockDTO.getCompanyWechatId() + workerStockDTO.getWebsitId() + workerStockDTO.getPartsWebsitId() +  workerStockDTO.getGoodsId());
            }
            WorkerStockAcc workerStockAcc = new WorkerStockAcc();
            workerStockDTO.computeWorkerStock(workerStock, workerStockAcc);
            workerStockAccList.add(workerStockAcc);
        }
    }

    private Map<String, WorkerStock> createNotExistWorkerStock(String goodsType, List<WorkerStockDTO> stockList, List<WorkerStock> existWorkerStockList) {
        // 已存在的商品库存转成Map
        Map<String, WorkerStock> existShopStockMap;

        if (goodsType.equals(WebsitGoodsTypeEnum.M.toString())) {
            existShopStockMap = existWorkerStockList.stream()
                    .collect(Collectors.toMap(WorkerStock::getGoodsId, Function.identity()));
        } else {
            existShopStockMap = existWorkerStockList.stream()
                    .collect(Collectors.toMap(o -> o.getCompanyWechatId() + o.getWebsitId() + o.getPartsWebsitId() +  o.getGoodsId(), Function.identity()));
        }

        // 找出不存在的商品库存并存入新商品库存List
        for (WorkerStockDTO workerStockDTO : stockList) {
            WorkerStock workerStock = existShopStockMap.get(workerStockDTO.getGoodsId());
            if (goodsType.equals(WebsitGoodsTypeEnum.P.toString())) {
                workerStock = existShopStockMap.get(workerStockDTO.getCompanyWechatId() + workerStockDTO.getWebsitId() + workerStockDTO.getPartsWebsitId() +  workerStockDTO.getGoodsId());
            }

            if (Objects.isNull(workerStock)) {
                workerStock = workerStockDTO.createWorkerStock();
                if (goodsType.equals(WebsitGoodsTypeEnum.M.toString())) {
                    existShopStockMap.put(workerStockDTO.getGoodsId(), workerStock);
                } else {
                    existShopStockMap.put(workerStockDTO.getCompanyWechatId() + workerStockDTO.getWebsitId() + workerStockDTO.getPartsWebsitId() +  workerStockDTO.getGoodsId(), workerStock);
                }
            }
        }
        return existShopStockMap;
    }

    public void txCallUnlockWorker(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();
        }
    }

    /**
     * 处理网点销售单明细数量 新件
     * @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.handleWebsitSales(websitId, partsWebsitId, identity, salesItemRecordDTOList, refType);
    }

    private List<PartsRefundRecordDTO> handleWebsitSales(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);
        }
    }

    private void txCallUnlock(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();
        }
    }

    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();
        }
    }

    /**
     * 处理网点销售单明细数量 旧件
     * @param manage
     * @param items
     * @param refType
     */
    public List<PartsRefundRecordDTO> handleOldRefundWebsitSales(String receiveWebsitId, String receivePartsWebsitId,
                                                                 String identity, WebsitPartsOldRefundManage manage,
                                                                 List<WebsitPartsOldRefundManageItem> items, String refType)
            throws Exception {
        List<SalesItemRecordDTO> salesItemRecordDTOList = new ArrayList<>();
        for (WebsitPartsOldRefundManageItem partsOldRefundManageItem : items) {
            SalesItemRecordDTO salesItemRecordDTO = new SalesItemRecordDTO();
            salesItemRecordDTO.setItemId(partsOldRefundManageItem.getId());
            salesItemRecordDTO.setApplyNo(partsOldRefundManageItem.getApplyNo());
            salesItemRecordDTO.setPartsNumber(partsOldRefundManageItem.getNewPartsNumber());
            salesItemRecordDTO.setPartsName(partsOldRefundManageItem.getNewPartsName());
            salesItemRecordDTO.setQty(partsOldRefundManageItem.getQty());
            salesItemRecordDTO.setRepairFlag(manage.getRepairFlag());
            salesItemRecordDTO.setWorkOrderNo(manage.getWorkOrderNo());
            salesItemRecordDTO.setPgId(manage.getPgId());
            salesItemRecordDTO.setCustomerName(manage.getCustomerName());
            salesItemRecordDTO.setCustomerTel(manage.getCustomerTel());
            salesItemRecordDTO.setIsBackup(partsOldRefundManageItem.getIsBackup());
            salesItemRecordDTOList.add(salesItemRecordDTO);
        }
        return this.handleWebsitSales(receiveWebsitId, receivePartsWebsitId, identity, salesItemRecordDTOList, refType);
    }
}
