package com.gree.mall.manager.logic.goods;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.db.sql.Order;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gree.mall.manager.bean.admin.AdminUserCom;
import com.gree.mall.manager.bean.goods.GoodsCodeAccVO;
import com.gree.mall.manager.bean.goods.GoodsSaleLedgerVO;
import com.gree.mall.manager.bean.goods.GoodsStockVO;
import com.gree.mall.manager.bean.order.SendOrderBody;
import com.gree.mall.manager.bean.websit.WorkerSettlementLineVO;
import com.gree.mall.manager.commonmapper.JxMapper;
import com.gree.mall.manager.constant.Constant;
import com.gree.mall.manager.enums.CodeAccStatusEnum;
import com.gree.mall.manager.enums.CodeAccTypeEnum;
import com.gree.mall.manager.enums.IsYesNoEnum;
import com.gree.mall.manager.enums.material.DirectFlagEnum;
import com.gree.mall.manager.enums.material.GoodsMaterialStockAccBillTypeEnum;
import com.gree.mall.manager.enums.material.GoodsMaterialTypeEnum;
import com.gree.mall.manager.exception.RemoteServiceException;
import com.gree.mall.manager.logic.common.CommonLogic;
import com.gree.mall.manager.plus.entity.*;
import com.gree.mall.manager.plus.service.*;
import com.gree.mall.manager.utils.StringUtil;
import com.gree.mall.manager.utils.excel.ExcelUtils;
import com.gree.mall.manager.zfire.bean.ZfireParamBean;
import com.gree.mall.manager.zfire.util.FieldUtils;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.implementation.bytecode.Throw;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;

@Slf4j
@Service
public class JxGoodsLogic {

    @Autowired
    JxMapper jxMapper;

    @Autowired
    CommonLogic commonLogic;

    @Autowired
    RedisLockRegistry redisLockRegistry;

    @Autowired
    GoodsPurchaseItemService goodsPurchaseItemService;

    @Autowired
    GoodsPurchaseCodeService goodsPurchaseCodeService;

    @Autowired
    GoodsMaterialService goodsMaterialService;

    @Autowired
    GoodsPurchaseService goodsPurchaseService;

    @Autowired
    GoodsCodeService goodsCodeService;

    @Autowired
    GoodsCodeAccService goodsCodeAccService;

    @Autowired
    GoodsMaterialAccService goodsMaterialAccService;

    @Autowired
    OrderDetailService orderDetailService;

    @Autowired
    GoodsMaterialItemService goodsMaterialItemService;

    @Autowired
    GoodsMaterialStockAccLogic goodsMaterialStockAccLogic;

    @Autowired
    OrderDetailCodeService orderDetailCodeService;

    @Autowired
    OrderRefundCodeService orderRefundCodeService;

    @Autowired
    OrderInfoService orderInfoService;

    @Autowired
    GoodsPurchaseRetService goodsPurchaseRetService;

    @Autowired
    GoodsPurchaseRetItemService goodsPurchaseRetItemService;

    @Autowired
    GoodsPurchaseRetCodeService goodsPurchaseRetCodeService;

    @Autowired
    GoodsSaleLedgerService goodsSaleLedgerService;

    @Autowired
    OrderRefundService orderRefundService;

    @Autowired
    OrderShareService orderShareService;

    @Autowired
    GoodsMaterialStorageService goodsMaterialStorageService;

    @Autowired
    OrderDeliveryService orderDeliveryService;

    @Autowired
    StorageService storageService;

    public IPage<GoodsStockVO> pageStock(ZfireParamBean zfireParamBean) {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        List<String> companyWechatIds = adminUser.getCompanyWechatIds();

        //1.组装查询条件
        ZfireParamBean zfireParam = FieldUtils.supplyParam(zfireParamBean, GoodsStockVO.class, adminUser);
        IPage<GoodsStockVO> stock = jxMapper.pageStock(new Page(zfireParamBean.getPageNum(),
                        zfireParamBean.getPageSize()),
                zfireParam, companyWechatIds);

        return stock;

    }

    public IPage<GoodsCodeAccVO> pageCode(ZfireParamBean zfireParamBean) {

        AdminUserCom adminUser = commonLogic.getAdminUser();
        List<String> companyWechatIds = adminUser.getCompanyWechatIds();

        //1.组装查询条件
        ZfireParamBean zfireParam = FieldUtils.supplyParam(zfireParamBean, GoodsCodeAccVO.class, adminUser);
        IPage<GoodsCodeAccVO> goodsCodeAccVOIPage = jxMapper.pageCode(new Page(zfireParamBean.getPageNum(),
                        zfireParamBean.getPageSize()),
                zfireParam);

        return goodsCodeAccVOIPage;
    }

    public IPage<GoodsSaleLedgerVO> pageSale(ZfireParamBean zfireParamBean) {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        List<String> companyWechatIds = adminUser.getCompanyWechatIds();

        //1.组装查询条件
        ZfireParamBean zfireParam = FieldUtils.supplyParam(zfireParamBean, GoodsSaleLedgerVO.class, adminUser);
        IPage<GoodsSaleLedgerVO> goodsSaleLedgerVOIPage = jxMapper.pageSale(new Page(zfireParamBean.getPageNum(),
                        zfireParamBean.getPageSize()),
                zfireParam);

        return goodsSaleLedgerVOIPage;
    }

    /**
     * id 采购入库单id
     */
    public void addStock(String id) throws InterruptedException {

        GoodsPurchase goodsPurchase = goodsPurchaseService.getById(id);

        List<GoodsPurchaseItem> list = goodsPurchaseItemService.lambdaQuery().eq(GoodsPurchaseItem::getGoodsPurchaseId, id).list();

        //添加条码台账和条码库存记录
        List<GoodsPurchaseCode> codeList = goodsPurchaseCodeService.lambdaQuery().eq(GoodsPurchaseCode::getGoodsPurchaseId, id).list();

        this.addCodeAcc(codeList, list, goodsPurchase);

        for (GoodsPurchaseItem goodsPurchaseItem : list) {
            Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.LOCK_WALLET + goodsPurchaseItem.getGoodsMaterialId());
            if (!obtain.tryLock(10, TimeUnit.SECONDS)) {
                throw new RemoteServiceException("库存已冻结:" + goodsPurchaseItem.getGoodsMaterialId());
            }
            try {
                //添加库存
                this.addMaterialNum(goodsPurchaseItem.getGoodsMaterialId(), goodsPurchaseItem.getInsideQty(), goodsPurchaseItem.getOutQty(),
                        goodsPurchaseItem.getPartsQty(), goodsPurchaseItem.getQty(), id, goodsPurchaseItem.getPrice(),goodsPurchase.getStorageId(),goodsPurchase.getStorageName());

                goodsMaterialStockAccLogic.add(goodsPurchaseItem.getGoodsMaterialId(), goodsPurchaseItem.getPrice(), goodsPurchaseItem.getQty(),
                        DirectFlagEnum.ADD, goodsPurchaseItem.getGoodsPurchaseId(), GoodsMaterialStockAccBillTypeEnum.B,goodsPurchase.getStorageId(),goodsPurchase.getStorageName());

                //变化成本价
                this.changeCost(goodsPurchaseItem.getGoodsMaterialId(), goodsPurchaseItem);
            } finally {
                //事务提交释放锁
                this.unlockAfterTransaction(obtain);
            }
        }

    }

    /**
     * 更新计算成本价
     * goodsMaterialId 商品物料id
     */
    private void changeCost(String goodsMaterialId, GoodsPurchaseItem goodsPurchaseItem) {

        GoodsMaterial goodsMaterial = goodsMaterialService.getById(goodsMaterialId);

        List<GoodsMaterialAcc> list = goodsMaterialAccService.lambdaQuery().eq(GoodsMaterialAcc::getGoodsMaterialId, goodsMaterialId)
                .gt(GoodsMaterialAcc::getStockQty, 0).list();


        List<GoodsMaterialStorage> goodsMaterialStorages = goodsMaterialStorageService.lambdaQuery()
                .eq(GoodsMaterialStorage::getGoodsMaterialId, goodsMaterial.getId()).list();

        Integer integer = goodsMaterialStorages.stream().map(GoodsMaterialStorage::getStockQty).reduce(Integer::sum).orElse(0);

        if (integer.equals(0)) {

            BigDecimal multiply = goodsPurchaseItem.getPrice();

            goodsMaterial.setCostAmount(multiply);

            goodsMaterialStorageService.lambdaUpdate().eq(GoodsMaterialStorage::getGoodsMaterialId,goodsMaterial.getId())
                    .set(GoodsMaterialStorage::getCostAmount,multiply).update();

        } else {


            Integer qty = integer- goodsPurchaseItem.getQty();

            BigDecimal amount = goodsMaterial.getCostAmount().multiply(Convert.toBigDecimal(qty));

            BigDecimal multiply = goodsPurchaseItem.getPrice().multiply(Convert.toBigDecimal(goodsPurchaseItem.getQty()));

            BigDecimal allPrice = amount.add(multiply);

            BigDecimal bigDecimal = allPrice.divide(Convert.toBigDecimal(integer), 2, RoundingMode.HALF_UP);

            goodsMaterial.setCostAmount(bigDecimal);


            goodsMaterialStorageService.lambdaUpdate().eq(GoodsMaterialStorage::getGoodsMaterialId,goodsMaterial.getId())
                    .set(GoodsMaterialStorage::getCostAmount,bigDecimal).update();
        }

        goodsMaterial.updateById();
    }

    /**
     * 采购入库单变更台账
     * codeList 采购入库单条码
     * list 采购入库单物料
     * goodsPurchase 采购入库订单
     */
    private void addCodeAcc(List<GoodsPurchaseCode> codeList, List<GoodsPurchaseItem> list, GoodsPurchase goodsPurchase) {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        List<GoodsCodeAcc> goodsCodeAccs = new ArrayList<>();
        List<GoodsCode> goodsCodes = new ArrayList<>();

        List<String> materialId = list.stream().map(GoodsPurchaseItem::getGoodsMaterialId).collect(Collectors.toList());

        List<GoodsMaterial> goodsMaterialList = goodsMaterialService.lambdaQuery().in(GoodsMaterial::getId, materialId).list();


        for (GoodsPurchaseCode goodsPurchaseCode : codeList) {
            GoodsPurchaseItem goodsPurchaseItem = list.stream().filter(item -> item.getGoodsPurchaseId().equals(goodsPurchaseCode.getGoodsPurchaseId())).collect(Collectors.toList()).get(0);
            GoodsMaterial goodsMaterial = goodsMaterialList.stream().filter(item ->
                    item.getId().equals(goodsPurchaseItem.getGoodsMaterialId())).collect(Collectors.toList()).get(0);

            List<GoodsCode> goodsCodeList = goodsCodeService.lambdaQuery().eq(GoodsCode::getMaterialCode, goodsPurchaseCode.getCode())
                    .eq(GoodsCode::getCompanyWechatId,adminUser.getCompanyWechatId())
                    .eq(GoodsCode::getUniqueCode, IsYesNoEnum.NO.getKey())
                    .eq(GoodsCode::getGoodsMaterialId, goodsMaterial.getId())
                    .list();


            GoodsCodeAcc goodsCodeAcc = new GoodsCodeAcc();
            goodsCodeAcc.setCompanyWechatId(goodsPurchase.getCompanyWechatId())
                    .setCompanyWechatName(goodsPurchase.getCompanyWechatName())
                    .setBrandId(goodsMaterial.getBrandId())
                    .setBrandName(goodsMaterial.getBrandName())
                    .setMainId(goodsMaterial.getMainId())
                    .setMainName(goodsMaterial.getMainName())
                    .setSmallId(goodsMaterial.getSmallId())
                    .setSmallName(goodsMaterial.getSmallName())
                    .setGoodsMaterialId(goodsMaterial.getId())
                    .setGoodsMaterialName(goodsMaterial.getGoodsName())
                    .setSpecsName(goodsMaterial.getSpecsName())
                    .setUnit(goodsMaterial.getUnit())
                    .setQty(goodsPurchaseCode.getCodeQty())
                    .setStockQty(goodsPurchaseCode.getCodeQty())
                    .setVenderId(goodsPurchase.getVenderId())
                    .setVenderName(goodsPurchase.getVenderName())
                    .setMaterialName(goodsPurchaseCode.getGoodsMaterialItemName())
                    .setMaterialCode(goodsPurchaseCode.getCode())
                    .setStatus(CodeAccStatusEnum.GIVE.getKey())
                    .setOrderType(CodeAccTypeEnum.PUR.getKey())
                    .setOrderId(goodsPurchaseCode.getGoodsPurchaseId())
                    .setStorageId(goodsPurchase.getStorageId())
                    .setStorageName(goodsPurchase.getStorageName())
                    .setGoodsMaterialItemType(goodsPurchaseCode.getGoodsMaterialItemType());



            GoodsCode goodsCode = new GoodsCode();

            if(!CollectionUtils.isEmpty(goodsCodeList) && goodsPurchaseCode.getUniqueCode().equals(IsYesNoEnum.NO.getKey())){

                goodsCodeAcc.setStockQty(goodsCodeList.get(0).getStockQty()+goodsPurchaseCode.getCodeQty());

                goodsCode.setGoodsCodeId(goodsCodeList.get(0).getGoodsCodeId());
                goodsCode.setStockQty(goodsCodeList.get(0).getStockQty()+goodsPurchaseCode.getCodeQty());
            }



            goodsCode.setCompanyWechatId(goodsPurchase.getCompanyWechatId())
                    .setCompanyWechatName(goodsPurchase.getCompanyWechatName())
                    .setBrandId(goodsMaterial.getBrandId())
                    .setBrandName(goodsMaterial.getBrandName())
                    .setMainId(goodsMaterial.getMainId())
                    .setMainName(goodsMaterial.getMainName())
                    .setSmallId(goodsMaterial.getSmallId())
                    .setSmallName(goodsMaterial.getSmallName())
                    .setGoodsMaterialId(goodsMaterial.getId())
                    .setGoodsMaterialName(goodsMaterial.getGoodsName())
                    .setSpecsName(goodsMaterial.getSpecsName())
                    .setStockQty(goodsPurchaseCode.getCodeQty())
                    .setVenderId(goodsPurchase.getVenderId())
                    .setVenderName(goodsPurchase.getVenderName())
                    .setMaterialName(goodsPurchaseCode.getGoodsMaterialItemName())
                    .setMaterialCode(goodsPurchaseCode.getCode())
                    .setOrderId(goodsPurchaseCode.getGoodsPurchaseId())
                    .setUniqueCode(goodsPurchaseCode.getUniqueCode())
                    .setGoodsMaterialItemId(goodsPurchaseCode.getGoodsMaterialItemId())
                    .setGoodsMaterialItemType(goodsPurchaseCode.getGoodsMaterialItemType());


            goodsCodes.add(goodsCode);

            goodsCodeAccs.add(goodsCodeAcc);

        }

        goodsCodeAccService.saveBatch(goodsCodeAccs);
        goodsCodeService.saveOrUpdateBatch(goodsCodes);

    }

    /**
     * 销售订单台账
     * codeList 发货条码
     */
    public void subCodeAcc(List<OrderDetailCode> codeList, OrderInfo orderInfo,String storageId,String storageName) throws InterruptedException {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        List<GoodsCodeAcc> goodsCodeAccs = new ArrayList<>();

        Storage storage = storageService.getById(storageId);


        List<String> materialId = codeList.stream().map(OrderDetailCode::getGoodsMaterialId).collect(Collectors.toList());

        List<GoodsMaterial> goodsMaterialList = goodsMaterialService.lambdaQuery().in(GoodsMaterial::getId, materialId).list();


        for (OrderDetailCode orderDetailCode : codeList) {
            GoodsMaterial goodsMaterial = goodsMaterialList.stream().filter(item -> item.getId().equals(orderDetailCode.getGoodsMaterialId()))
                    .collect(Collectors.toList()).get(0);

            GoodsCode goodsCode = goodsCodeService.lambdaQuery().eq(GoodsCode::getMaterialCode, orderDetailCode.getMaterialCode())
                    .eq(GoodsCode::getCompanyWechatId,adminUser.getCompanyWechatId())
                    .gt(GoodsCode::getStockQty, 0).last("limit 1").one();

            if (goodsCode == null)
                throw new RemoteServiceException("没有此条码库存" + orderDetailCode.getMaterialCode());

            GoodsPurchase goodsPurchase = goodsPurchaseService.getById(goodsCode.getOrderId());

            GoodsCodeAcc goodsCodeAcc = new GoodsCodeAcc();
            goodsCodeAcc.setCompanyWechatId(goodsMaterial.getCompanyWechatId())
                    .setCompanyWechatName(goodsMaterial.getCompanyWechatName())
                    .setBrandId(goodsMaterial.getBrandId())
                    .setBrandName(goodsMaterial.getBrandName())
                    .setMainId(goodsMaterial.getMainId())
                    .setMainName(goodsMaterial.getMainName())
                    .setSmallId(goodsMaterial.getSmallId())
                    .setSmallName(goodsMaterial.getSmallName())
                    .setGoodsMaterialId(goodsMaterial.getId())
                    .setGoodsMaterialName(goodsMaterial.getGoodsName())
                    .setSpecsName(goodsMaterial.getSpecsName())
                    .setUnit(goodsMaterial.getUnit())
                    .setQty(orderDetailCode.getStockQty())
                    .setStockQty(goodsCode.getStockQty() - orderDetailCode.getStockQty())

                    .setMaterialName(orderDetailCode.getMaterialName())
                    .setMaterialCode(orderDetailCode.getMaterialCode())
                    .setStatus(CodeAccStatusEnum.OUT.getKey())
                    .setOrderType(CodeAccTypeEnum.SALE.getKey())
                    .setOrderId(orderDetailCode.getOrderId())
                    .setUserMobile(orderInfo.getPhone())
                    .setUserName(orderInfo.getUserName())
                    .setStorageId(storageId)
                    .setStorageName(storage.getStorageName())
                    .setGoodsMaterialItemType(orderDetailCode.getGoodsMaterialItemType());

            if (goodsPurchase != null){
                goodsCodeAcc.setVenderId(goodsPurchase.getVenderId());
                goodsCodeAcc.setVenderName(goodsPurchase.getVenderName());
            }

            goodsCodeAccs.add(goodsCodeAcc);

            //减去条码库存 减去批次库存

            Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.LOCK_WALLET + goodsCode.getGoodsCodeId());
            if (!obtain.tryLock(10, TimeUnit.SECONDS)) {
                throw new RemoteServiceException("库存已冻结:" + goodsCode.getMaterialName() + ",请稍后重试");
            }
            try {

                GoodsCode goodsCodeUp = new GoodsCode();
                goodsCodeUp.setGoodsCodeId(goodsCode.getGoodsCodeId());

                goodsCodeUp.setStockQty(goodsCode.getStockQty() - orderDetailCode.getStockQty());
                goodsCodeUp.updateById();

            } finally {
                //事务提交释放锁
                this.unlockAfterTransaction(obtain);
            }
        }

        goodsCodeAccService.saveBatch(goodsCodeAccs);

    }


    /**
     * 销售维权台账
     * codeList  退款条码
     */
    public void addCodeAcc(List<OrderRefundCode> codeList) throws InterruptedException {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        List<GoodsCodeAcc> goodsCodeAccs = new ArrayList<>();


        List<String> materialId = codeList.stream().map(OrderRefundCode::getGoodsMaterialId).collect(Collectors.toList());

        List<GoodsMaterial> goodsMaterialList = goodsMaterialService.lambdaQuery().in(GoodsMaterial::getId, materialId).list();


        for (OrderRefundCode orderDetailCode : codeList) {
            GoodsMaterial goodsMaterial = goodsMaterialList.stream().filter(item -> item.getId().equals(orderDetailCode.getGoodsMaterialId())).collect(Collectors.toList()).get(0);
            GoodsCode goodsCode = goodsCodeService.lambdaQuery()
                    .eq(GoodsCode::getMaterialCode, orderDetailCode.getMaterialCode())
                    .eq(GoodsCode::getCompanyWechatId,adminUser.getCompanyWechatId())

                    .last("limit 1").one();

            GoodsPurchase goodsPurchase = goodsPurchaseService.getById(goodsCode.getOrderId());

            GoodsCodeAcc goodsCodeAcc = new GoodsCodeAcc();
            goodsCodeAcc.setCompanyWechatId(goodsMaterial.getCompanyWechatId())
                    .setCompanyWechatName(goodsMaterial.getCompanyWechatName())
                    .setBrandId(goodsMaterial.getBrandId())
                    .setBrandName(goodsMaterial.getBrandName())
                    .setMainId(goodsMaterial.getMainId())
                    .setMainName(goodsMaterial.getMainName())
                    .setSmallId(goodsMaterial.getSmallId())
                    .setSmallName(goodsMaterial.getSmallName())
                    .setGoodsMaterialId(goodsMaterial.getId())
                    .setGoodsMaterialName(goodsMaterial.getGoodsName())
                    .setSpecsName(goodsMaterial.getSpecsName())
                    .setUnit(goodsMaterial.getUnit())
                    .setQty(orderDetailCode.getStockQty())
                    .setStockQty(goodsCode.getStockQty() + orderDetailCode.getStockQty())
                    .setMaterialName(orderDetailCode.getMaterialName())
                    .setMaterialCode(orderDetailCode.getMaterialCode())
                    .setStatus(CodeAccStatusEnum.GIVE.getKey())
                    .setOrderType(CodeAccTypeEnum.SALE_REFUND.getKey())
                    .setOrderId(orderDetailCode.getOrderId())
                    .setGoodsMaterialItemType(orderDetailCode.getGoodsMaterialItemType());


            if (goodsPurchase != null){
                goodsCodeAcc.setVenderId(goodsPurchase.getVenderId());
                goodsCodeAcc.setVenderName(goodsPurchase.getVenderName());
            }

            goodsCodeAccs.add(goodsCodeAcc);

            //加回条码库存

            Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.LOCK_WALLET + goodsCode.getGoodsCodeId());
            if (!obtain.tryLock(10, TimeUnit.SECONDS)) {
                throw new RemoteServiceException("库存已冻结:" + goodsCode.getGoodsCodeId());
            }
            try {

                GoodsCode goodsCodeUp = new GoodsCode();
                goodsCodeUp.setGoodsCodeId(goodsCode.getGoodsCodeId());


                goodsCodeUp.setStockQty(goodsCode.getStockQty() + orderDetailCode.getStockQty());

                if (goodsCode.getUniqueCode().equals(IsYesNoEnum.YES.getKey())) {
                    if (!goodsCodeUp.getStockQty().equals(1)) {
                        throw new RemoteServiceException("退货条码有库存" + orderDetailCode.getMaterialCode());
                    }
                }

                goodsCodeUp.updateById();

            } finally {
                //事务提交释放锁
                this.unlockAfterTransaction(obtain);
            }
        }

        goodsCodeAccService.saveBatch(goodsCodeAccs);

    }


    private void addMaterialNum(String goodsMaterialId, Integer insideQty, Integer outQty, Integer partsQty, Integer qty, String id, BigDecimal price,String storageId,String storageName) {

        GoodsMaterialStorage goodsMaterialStorage = goodsMaterialStorageService.lambdaQuery().eq(GoodsMaterialStorage::getGoodsMaterialId, goodsMaterialId)
                .eq(GoodsMaterialStorage::getStorageId, storageId).last("limit 1").one();

        GoodsMaterial goodsMaterial = goodsMaterialService.getById(goodsMaterialId);

        if (goodsMaterialStorage == null) {
            GoodsMaterialStorage goodsMaterialStoragein = BeanUtil.toBean(goodsMaterial, GoodsMaterialStorage.class);
            goodsMaterialStoragein.setId(null);
            goodsMaterialStoragein.setGoodsMaterialId(goodsMaterialId);
            goodsMaterialStoragein.setStorageId(storageId);
            goodsMaterialStoragein.setStorageName(storageName);
            goodsMaterialStoragein.setInsideQty(insideQty);
            goodsMaterialStoragein.setOutQty(outQty);
            goodsMaterialStoragein.setPartsQty(partsQty);
            goodsMaterialStoragein.setStockQty(qty);
            goodsMaterialStoragein.setAmount(price);
            goodsMaterialStoragein.insert();
        }else {
            goodsMaterialStorage.setInsideQty(goodsMaterial.getInsideQty() + insideQty);
            goodsMaterialStorage.setOutQty(goodsMaterial.getOutQty() + outQty);
            goodsMaterialStorage.setPartsQty(goodsMaterial.getPartsQty() + partsQty);
            goodsMaterialStorage.setStockQty(goodsMaterialStorage.getStockQty() + qty);
            goodsMaterialStorage.setAmount(price);
            goodsMaterialStorage.updateById();
        }

        //添加批次库存
        GoodsMaterialAcc goodsMaterialAcc = new GoodsMaterialAcc();
        goodsMaterialAcc.setGoodsMaterialId(goodsMaterialId);
        goodsMaterialAcc.setOrderId(id);
        goodsMaterialAcc.setStockQty(qty);
        goodsMaterialAcc.setPrice(price);
        goodsMaterialAcc.insert();

    }

    /**
     * 事务结束后释放锁
     */
    private void unlockAfterTransaction(Lock obtain) {
        //事务结束后释放锁
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCompletion(int status) {

                obtain.unlock();
            }
        });
    }


    /**
     * 减少库存数量
     * goodsMaterialId  物料id
     * num   减少数量
     * puOrderId   采购单 可以为空
     */
    public void subMaterialStock(String goodsMaterialId, Integer num, String puOrderId,String storageId) throws InterruptedException {

        Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.LOCK_WALLET + goodsMaterialId);

       // GoodsMaterial goodsMaterial = goodsMaterialService.getById(goodsMaterialId);

        GoodsMaterialStorage goodsMaterialStorage = goodsMaterialStorageService.lambdaQuery().eq(GoodsMaterialStorage::getGoodsMaterialId, goodsMaterialId)
                .eq(GoodsMaterialStorage::getStorageId, storageId).last("limit 1").one();

        if (goodsMaterialStorage == null)
            throw new RemoteServiceException("没有库存");

        if (!obtain.tryLock(10, TimeUnit.SECONDS)) {
            throw new RemoteServiceException("库存已冻结:" + goodsMaterialStorage.getGoodsName() + ",请稍后重试。");
        }
        try {


            List<GoodsMaterialItem> goodsMaterialItems = goodsMaterialItemService.lambdaQuery().eq(GoodsMaterialItem::getGoodsMaterialId, goodsMaterialId).list();

            for (GoodsMaterialItem goodsMaterialItem : goodsMaterialItems) {
                if (goodsMaterialItem.getType().equals(GoodsMaterialTypeEnum.INSIDE.getKey()))
                    goodsMaterialStorage.setInsideQty(goodsMaterialStorage.getInsideQty() - (goodsMaterialItem.getQty() * num));
                else if (goodsMaterialItem.getType().equals(GoodsMaterialTypeEnum.OUT.getKey()))
                    goodsMaterialStorage.setOutQty(goodsMaterialStorage.getOutQty() - (goodsMaterialItem.getQty() * num));
                else
                    goodsMaterialStorage.setPartsQty(goodsMaterialStorage.getPartsQty() - (goodsMaterialItem.getQty() * num));
            }

            //减少库存
            goodsMaterialStorage.setStockQty(goodsMaterialStorage.getStockQty() - num);

            //减少批次库存
            if (StringUtil.isEmpty(puOrderId)) {
                List<GoodsMaterialAcc> list = goodsMaterialAccService.lambdaQuery().eq(GoodsMaterialAcc::getGoodsMaterialId, goodsMaterialId).orderByAsc(GoodsMaterialAcc::getCreateTime)
                        .gt(GoodsMaterialAcc::getStockQty, 0).list();

                for (GoodsMaterialAcc goodsMaterialAcc : list) {
                    if ((goodsMaterialAcc.getStockQty() - num) < 0) {
                        num = num - goodsMaterialAcc.getStockQty();
                        goodsMaterialAcc.setStockQty(0);
                        goodsMaterialAcc.updateById();
                    } else {
                        goodsMaterialAcc.setStockQty(goodsMaterialAcc.getStockQty() - num);
                        goodsMaterialAcc.updateById();
                        break;
                    }
                }
            } else {
                List<GoodsMaterialAcc> list = goodsMaterialAccService.lambdaQuery().eq(GoodsMaterialAcc::getOrderId, puOrderId)
                        .eq(GoodsMaterialAcc::getGoodsMaterialId, goodsMaterialId)
                        .orderByAsc(GoodsMaterialAcc::getCreateTime)
                        .gt(GoodsMaterialAcc::getStockQty, 0).list();

                for (GoodsMaterialAcc goodsMaterialAcc : list) {
                    if ((goodsMaterialAcc.getStockQty() - num) < 0) {
                        num = num - goodsMaterialAcc.getStockQty();
                        goodsMaterialAcc.setStockQty(0);
                        goodsMaterialAcc.updateById();
                    } else {
                        goodsMaterialAcc.setStockQty(goodsMaterialAcc.getStockQty() - num);
                        goodsMaterialAcc.updateById();

                        break;
                    }
                }
            }


            if (goodsMaterialStorage.getStockQty() < 0)
                throw new RemoteServiceException("库存不够扣除:" + goodsMaterialStorage.getGoodsName());
            goodsMaterialStorage.updateById();
        } finally {
            //事务提交释放锁
            this.unlockAfterTransaction(obtain);
        }

    }


    /**
     * 增加库存数量
     * goodsMaterialId  物料id
     * num   减少数量
     */
    public void addMaterialStock(String goodsMaterialId, Integer num,String storageId,String befStorageId) throws InterruptedException {
        Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.LOCK_WALLET + goodsMaterialId);
        if (!obtain.tryLock(10, TimeUnit.SECONDS)) {
            throw new RemoteServiceException("库存已冻结:" + goodsMaterialId);
        }
        try {
            GoodsMaterial goodsMaterial = goodsMaterialService.getById(goodsMaterialId);

            GoodsMaterialStorage goodsMaterialStorage = goodsMaterialStorageService.lambdaQuery().eq(GoodsMaterialStorage::getGoodsMaterialId, goodsMaterialId)
                    .eq(GoodsMaterialStorage::getStorageId, storageId).last("limit 1").one();

            Storage storage = storageService.getById(storageId);

            if (goodsMaterialStorage == null){

                GoodsMaterialStorage goodsMaterialStorageUp = goodsMaterialStorageService.lambdaQuery().eq(GoodsMaterialStorage::getGoodsMaterialId, goodsMaterialId)
                        .eq(GoodsMaterialStorage::getStorageId, befStorageId).last("limit 1").one();

                if (goodsMaterialStorageUp == null)
                    throw new RemoteServiceException("库存为空");

                goodsMaterialStorage = goodsMaterialStorageUp;

                goodsMaterialStorage.setId(null);
                goodsMaterialStorage.setGoodsMaterialId(goodsMaterialId);
                goodsMaterialStorage.setStorageId(storageId);
                goodsMaterialStorage.setStorageName(storage.getStorageName());
                goodsMaterialStorage.setInsideQty(0);
                goodsMaterialStorage.setOutQty(0);
                goodsMaterialStorage.setPartsQty(0);
                goodsMaterialStorage.setStockQty(0);

                goodsMaterialStorage.insert();
            }


            List<GoodsMaterialItem> goodsMaterialItems = goodsMaterialItemService.lambdaQuery().eq(GoodsMaterialItem::getGoodsMaterialId, goodsMaterialId).list();

            for (GoodsMaterialItem goodsMaterialItem : goodsMaterialItems) {
                if (goodsMaterialItem.getType().equals(GoodsMaterialTypeEnum.INSIDE.getKey()))
                    goodsMaterialStorage.setInsideQty(goodsMaterialStorage.getInsideQty() + (goodsMaterialItem.getQty() * num));
                else if (goodsMaterialItem.getType().equals(GoodsMaterialTypeEnum.OUT.getKey()))
                    goodsMaterialStorage.setOutQty(goodsMaterialStorage.getOutQty() + (goodsMaterialItem.getQty() * num));
                else
                    goodsMaterialStorage.setPartsQty(goodsMaterialStorage.getPartsQty() + (goodsMaterialItem.getQty() * num));
            }
            //增加批次库存
            List<GoodsMaterialAcc> list = goodsMaterialAccService.lambdaQuery().eq(GoodsMaterialAcc::getGoodsMaterialId, goodsMaterialId)
                    .orderByAsc(GoodsMaterialAcc::getCreateTime)
                    .gt(GoodsMaterialAcc::getStockQty, 0).list();

            if (CollectionUtils.isEmpty(list)) {
                list = goodsMaterialAccService.lambdaQuery().eq(GoodsMaterialAcc::getGoodsMaterialId, goodsMaterialId)
                        .orderByAsc(GoodsMaterialAcc::getCreateTime)
                        .list();
            }


            for (GoodsMaterialAcc goodsMaterialAcc : list) {

                goodsMaterialAcc.setStockQty(goodsMaterialAcc.getStockQty() + num);
                goodsMaterialAcc.updateById();
                break;
            }


            //增加库存todo
            goodsMaterialStorage.setStockQty(goodsMaterialStorage.getStockQty() + num);
            goodsMaterialStorage.updateById();
        } finally {
            //事务提交释放锁
            this.unlockAfterTransaction(obtain);
        }
    }

    @Transactional
    public void importData(MultipartFile file, String orderDetailId) throws IOException {
        AdminUserCom adminUser = commonLogic.getAdminUser();

        List<Object> objects = ExcelUtils.importExcel(file);


        // List<GoodsCode> goodsCodes = goodsCodeService.lambdaQuery().in(GoodsCode::getMaterialCode, orderDetailCodes.stream().map(OrderDetailCode::getMaterialCode).collect(Collectors.toList())).list();

        for (int i = 0; i < objects.size(); i++) {
            List<Object> row = (List<Object>) objects.get(i);
            List<GoodsCode> collect = goodsCodeService.lambdaQuery().in(GoodsCode::getMaterialCode, row.get(0))
                    .in(GoodsCode::getCompanyWechatId,adminUser.getCompanyWechatId())
                    .list();


            if (CollectionUtils.isEmpty(collect))
                throw new RemoteServiceException(row.get(0) + "该条码无库存");

            GoodsCode goodsCode = collect.get(0);


            OrderDetail orderDetail = orderDetailService.getById(orderDetailId);

            if (!orderDetail.getGoodsMaterialId().equals(goodsCode.getGoodsMaterialId()))
                throw new RemoteServiceException("非对应机型条码");


            OrderDetailCode orderDetailCodeSave = BeanUtil.toBean(goodsCode, OrderDetailCode.class);
            orderDetailCodeSave.setGiveOrderId(goodsCode.getOrderId());
            orderDetailCodeSave.setOrderId(orderDetail.getOrderId());
            orderDetailCodeSave.setOrderDetailId(orderDetail.getOrderDetailId());
            orderDetailCodeSave.setGoodsMaterialItemId(goodsCode.getGoodsMaterialItemId());

            if (orderDetailCodeSave.getUniqueCode().equals(IsYesNoEnum.YES.getKey()))
                orderDetailCodeSave.setStockQty(1);

            if (goodsCode.getStockQty() < orderDetailCodeSave.getStockQty()) {
                throw new RemoteServiceException("库存不足" + orderDetailCodeSave.getMaterialCode());
            }

            orderDetailCodeSave.setStockQty(Convert.toInt(row.get(1)));

            if (orderDetailCodeService.lambdaQuery().eq(OrderDetailCode::getMaterialCode, orderDetailCodeSave.getMaterialCode())
                    .eq(OrderDetailCode::getOrderDetailId, orderDetail.getOrderDetailId())
                    .count() > 0) {
                throw new RemoteServiceException("存在重复条码" + orderDetailCodeSave.getMaterialCode());
            }

            orderDetailCodeSave.insert();
            this.upOrderDetailCode(orderDetail);

        }


    }

    @Transactional
    public void importRefund(MultipartFile file, String orderDetailId) throws IOException {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        List<Object> objects = ExcelUtils.importExcel(file);

        List<OrderRefundCode> orderDetailCodeSaves = new ArrayList<>();

        // List<GoodsCode> goodsCodes = goodsCodeService.lambdaQuery().in(GoodsCode::getMaterialCode, orderDetailCodes.stream().map(OrderDetailCode::getMaterialCode).collect(Collectors.toList())).list();

        for (int i = 0; i < objects.size(); i++) {
            List<Object> row = (List<Object>) objects.get(i);
            List<GoodsCode> collect = goodsCodeService.lambdaQuery().in(GoodsCode::getMaterialCode, row.get(0))
                    .in(GoodsCode::getCompanyWechatId,adminUser.getCompanyWechatId())
                    .list();


            if (CollectionUtils.isEmpty(collect))
                throw new RemoteServiceException(row.get(0) + "该条码无库存");

            GoodsCode goodsCode = collect.get(0);

            OrderDetail orderDetail = orderDetailService.getById(orderDetailId);


            OrderRefundCode orderDetailCodeSave = BeanUtil.toBean(goodsCode, OrderRefundCode.class);
            orderDetailCodeSave.setGiveOrderId(goodsCode.getOrderId());
            orderDetailCodeSave.setOrderId(orderDetail.getOrderId());
            orderDetailCodeSave.setOrderDetailId(orderDetail.getOrderDetailId());
            orderDetailCodeSave.setGoodsMaterialItemId(goodsCode.getGoodsMaterialItemId());
            if (orderDetailCodeSave.getUniqueCode().equals(IsYesNoEnum.YES.getKey()))
                orderDetailCodeSave.setStockQty(1);

            orderDetailCodeSave.setStockQty(Convert.toInt(row.get(1)));


            if (orderRefundCodeService.lambdaQuery().eq(OrderRefundCode::getMaterialCode, orderDetailCodeSave.getMaterialCode())
                    .eq(OrderRefundCode::getOrderId, orderDetail.getOrderId())
                    .count() > 0) {
                throw new RemoteServiceException("存在重复条码" + orderDetailCodeSave.getMaterialCode());
            }

            orderDetailCodeSave.insert();
            this.upOrderDetailCode(orderDetail);

        }


    }

    public List<OrderDetailCode> detail(String orderId) {
        List<OrderDetailCode> list = orderDetailCodeService.lambdaQuery().eq(OrderDetailCode::getOrderId, orderId).list();
        return list;

    }

    @Transactional(rollbackFor = Exception.class)
    public void save(List<OrderDetailCode> orderDetailCodes) {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        for (OrderDetailCode orderDetailCode : orderDetailCodes) {

            GoodsCode goodsCode = goodsCodeService.lambdaQuery().eq(GoodsCode::getMaterialCode, orderDetailCode.getMaterialCode())
                    .eq(GoodsCode::getCompanyWechatId,adminUser.getCompanyWechatId())
                    .one();
            OrderDetail orderDetail = orderDetailService.getById(orderDetailCode.getOrderDetailId());

            if (goodsCode == null)
                throw new RemoteServiceException("无该条码库存");

            if (!orderDetail.getGoodsMaterialId().equals(goodsCode.getGoodsMaterialId()))
                throw new RemoteServiceException("非对应机型条码");

            orderDetailCode.setGoodsMaterialItemId(goodsCode.getGoodsMaterialItemId());
            orderDetailCode.setOrderDetailId(orderDetail.getOrderDetailId());

            if (orderDetailCode.getUniqueCode().equals(IsYesNoEnum.YES.getKey()))
                orderDetailCode.setStockQty(1);

            if (goodsCode.getStockQty() < orderDetailCode.getStockQty()) {
                throw new RemoteServiceException("库存不足" + orderDetailCode.getMaterialCode());
            }

            if (!StringUtil.isEmpty(orderDetailCode.getOrderDetailCodeId()))
                orderDetailCode.updateById();
            else {

                if (orderDetailCodeService.lambdaQuery().eq(OrderDetailCode::getMaterialCode, orderDetailCode.getMaterialCode())
                        .eq(OrderDetailCode::getOrderDetailId, orderDetailCode.getOrderDetailId())
                        .count() > 0) {
                    throw new RemoteServiceException("存在重复条码" + orderDetailCode.getMaterialCode());
                }

                orderDetailCode.insert();
            }


            this.upOrderDetailCode(orderDetail);


        }

    }


    //更新订单明细条码导入数量
    public void upOrderDetailCode(OrderDetail orderDetail) {

        orderDetail.setInsideCodeQty(
                orderDetailCodeService.lambdaQuery().eq(OrderDetailCode::getOrderDetailId, orderDetail.getOrderDetailId())
                        .eq(OrderDetailCode::getGoodsMaterialItemType, GoodsMaterialTypeEnum.INSIDE.getKey()).list().stream()
                        .map(OrderDetailCode::getStockQty).reduce(Integer::sum).orElse(0)
        );
        orderDetail.setOutCodeQty(
                orderDetailCodeService.lambdaQuery().eq(OrderDetailCode::getOrderDetailId, orderDetail.getOrderDetailId())
                        .eq(OrderDetailCode::getGoodsMaterialItemType, GoodsMaterialTypeEnum.OUT.getKey()).list().stream()
                        .map(OrderDetailCode::getStockQty).reduce(Integer::sum).orElse(0)
        );
        orderDetail.setPartsCodeQty(
                orderDetailCodeService.lambdaQuery().eq(OrderDetailCode::getOrderDetailId, orderDetail.getOrderDetailId())
                        .eq(OrderDetailCode::getGoodsMaterialItemType, GoodsMaterialTypeEnum.PARTS.getKey()).list().stream()
                        .map(OrderDetailCode::getStockQty).reduce(Integer::sum).orElse(0)
        );


        orderDetail.setRefundInsideCodeQty(
                orderRefundCodeService.lambdaQuery().eq(OrderRefundCode::getOrderDetailId, orderDetail.getOrderDetailId())
                        .eq(OrderRefundCode::getGoodsMaterialItemType, GoodsMaterialTypeEnum.INSIDE.getKey()).list().stream()
                        .map(OrderRefundCode::getStockQty).reduce(Integer::sum).orElse(0)
        );
        orderDetail.setRefundOutCodeQty(
                orderRefundCodeService.lambdaQuery().eq(OrderRefundCode::getOrderDetailId, orderDetail.getOrderDetailId())
                        .eq(OrderRefundCode::getGoodsMaterialItemType, GoodsMaterialTypeEnum.OUT.getKey()).list().stream()
                        .map(OrderRefundCode::getStockQty).reduce(Integer::sum).orElse(0)
        );
        orderDetail.setRefundPartsCodeQty(
                orderRefundCodeService.lambdaQuery().eq(OrderRefundCode::getOrderDetailId, orderDetail.getOrderDetailId())
                        .eq(OrderRefundCode::getGoodsMaterialItemType, GoodsMaterialTypeEnum.PARTS.getKey()).list().stream()
                        .map(OrderRefundCode::getStockQty).reduce(Integer::sum).orElse(0)
        );

        orderDetail.updateById();


    }

    @Transactional(rollbackFor = Exception.class)
    public void saveRefund(List<OrderRefundCode> orderDetailCodes) {
        AdminUserCom adminUser = commonLogic.getAdminUser();

        for (OrderRefundCode orderDetailCode : orderDetailCodes) {

            OrderDetail orderDetailServiceById = orderDetailService.getById(orderDetailCode.getOrderDetailId());

            GoodsCode goodsCode = goodsCodeService.lambdaQuery().eq(GoodsCode::getMaterialCode, orderDetailCode.getMaterialCode())
                    .eq(GoodsCode::getCompanyWechatId,adminUser.getCompanyWechatId())
                    .one();

            if (goodsCode == null)
                throw new RemoteServiceException("无该条码库存");

            orderDetailCode.setGoodsMaterialItemId(goodsCode.getGoodsMaterialItemId());

            orderDetailCode.setOrderId(orderDetailServiceById.getOrderId());

            if (orderDetailCode.getUniqueCode().equals(IsYesNoEnum.YES.getKey()))
                orderDetailCode.setStockQty(1);


            if (!StringUtil.isEmpty(orderDetailCode.getOrderDetailCodeId()))
                orderDetailCode.updateById();
            else {

                if (orderRefundCodeService.lambdaQuery().eq(OrderRefundCode::getMaterialCode, orderDetailCode.getMaterialCode())
                        .eq(OrderRefundCode::getOrderDetailId, orderDetailCode.getOrderDetailId())
                        .count() > 0) {
                    throw new RemoteServiceException("存在重复条码" + orderDetailCode.getMaterialCode());
                }
                orderDetailCode.insert();

            }


            OrderDetail orderDetail = orderDetailService.getById(orderDetailCode.getOrderDetailId());

            this.upOrderDetailCode(orderDetail);


        }
    }

    public List<OrderRefundCode> detailRefund(String orderId) {
        OrderRefund orderRefund = orderRefundService.getById(orderId);
        List<OrderRefundCode> list = orderRefundCodeService.lambdaQuery().eq(OrderRefundCode::getOrderId, orderRefund.getOrderId()).list();
        return list;
    }

    public void remove(String orderDetailCodeId) {
        OrderDetailCode orderDetailCode = orderDetailCodeService.getById(orderDetailCodeId);

        OrderDetail orderDetail = orderDetailService.getById(orderDetailCode.getOrderDetailId());


        orderDetail.updateById();
        orderDetailCodeService.removeById(orderDetailCodeId);
        this.upOrderDetailCode(orderDetail);
    }

    public void removeRefund(String orderDetailCodeId) {
        OrderRefundCode orderDetailCode = orderRefundCodeService.getById(orderDetailCodeId);

        OrderDetail orderDetail = orderDetailService.getById(orderDetailCode.getOrderDetailId());


        orderRefundCodeService.removeById(orderDetailCodeId);
        this.upOrderDetailCode(orderDetail);
    }

    @Transactional(rollbackFor = Exception.class)
    public void addGoodsSaleLedger(String orderId,String deId) {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        OrderInfo orderInfo = orderInfoService.getById(orderId);

        OrderShare orderShare = orderShareService.lambdaQuery().eq(OrderShare::getOrderId, orderId).one();

        OrderDelivery orderDelivery = orderDeliveryService.getById(deId);

        List<OrderDetail> orderDetails = orderDetailService.lambdaQuery().eq(OrderDetail::getOrderId, orderId).list();

        List<GoodsSaleLedger> goodsSaleLedgers = new ArrayList<>();

        for (OrderDetail orderDetail : orderDetails) {

            if (orderDetail.getIsVr() || StringUtil.isEmpty(orderDetail.getGoodsMaterialId()))
                continue;

            GoodsMaterial goodsMaterial = goodsMaterialService.getById(orderDetail.getGoodsMaterialId());
            GoodsSaleLedger goodsSaleLedger = new GoodsSaleLedger();
            BeanUtil.copyProperties(goodsMaterial, goodsSaleLedger);
            goodsSaleLedger.setCompanyWechatId(orderInfo.getCompanyWechatId());
            goodsSaleLedger.setCompanyWechatName(orderInfo.getCompanyWechatName());
            goodsSaleLedger.setGoodsMaterialId(goodsMaterial.getId());
            goodsSaleLedger.setGoodsMaterialName(goodsMaterial.getGoodsName());
            goodsSaleLedger.setWorkerId(orderInfo.getWorkerId());
            goodsSaleLedger.setWorkerName(orderInfo.getWorkerName());
            goodsSaleLedger.setWorkerPhone(orderInfo.getWorkerPhone());
            goodsSaleLedger.setCostPrice(goodsMaterial.getCostAmount());
            goodsSaleLedger.setOrderDetailId(orderDetail.getOrderDetailId());
            goodsSaleLedger.setFreight(orderInfo.getFreight());
            goodsSaleLedger.setQty(orderDetail.getNum());
            goodsSaleLedger.setSaleTime(orderInfo.getPayTime());
            goodsSaleLedger.setSaleAmount(orderDetail.getTotalPrice());
            goodsSaleLedger.setCommisAmount(orderDetail.getShareAmount());
            goodsSaleLedger.setRecePhone(orderInfo.getRecePhone());
            goodsSaleLedger.setReceUserName(orderInfo.getReceUserName());
            goodsSaleLedger.setSendGoodsTime(new Date());
            goodsSaleLedger.setSendName(adminUser.getNickName());
            goodsSaleLedger.setStorageId(orderDelivery.getStorageStockId());
            goodsSaleLedger.setStorageName(orderDelivery.getStorageStockName());
            goodsSaleLedger.setDeliveryId(orderDelivery.getDeliveryId());
            goodsSaleLedger.setOrderId(orderId);
            if (orderShare != null)
                goodsSaleLedger.setOrderShareId(orderShare.getOrderShareId());

            goodsSaleLedgers.add(goodsSaleLedger);
        }

        goodsSaleLedgerService.saveBatch(goodsSaleLedgers);
    }

    public void subGoodsSaleLedger(String orderId) {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        OrderRefund orderRefund = orderRefundService.getById(orderId);
        List<OrderDetail> orderDetails = orderDetailService.lambdaQuery().eq(OrderDetail::getOrderId, orderRefund.getOrderId()).list();
        for (OrderDetail orderDetail : orderDetails) {
            if (orderDetail.getRefund() && orderDetail.getRefundNum() > 0) {
                GoodsMaterial goodsMaterial = goodsMaterialService.getById(orderDetail.getGoodsMaterialId());
                List<GoodsSaleLedger> list = goodsSaleLedgerService.lambdaQuery()
                        .eq(GoodsSaleLedger::getOrderDetailId, orderDetail.getOrderDetailId()).list();

                for (GoodsSaleLedger goodsSaleLedger : list) {
                    goodsSaleLedger.setRefundOrderId(orderRefund.getOrderRefundId());
                    goodsSaleLedger.setRefundName(adminUser.getNickName());
                    goodsSaleLedger.setRefundTime(orderRefund.getExamineTime());
                    goodsSaleLedger.setRefundNum(goodsSaleLedger.getQty());
                    goodsSaleLedger.setRefundAmount(goodsSaleLedger.getSaleAmount());
                    goodsSaleLedger.updateById();
                }

            }


        }

    }

    public void refundStockQty(String id) throws InterruptedException {

        GoodsPurchaseRet goodsPurchaseRet = goodsPurchaseRetService.getById(id);

        List<GoodsPurchaseRetItem> list = goodsPurchaseRetItemService.lambdaQuery().eq(GoodsPurchaseRetItem::getGoodsPurchaseRetId, id).list();

        //添加条码台账和条码库存记录
        List<GoodsPurchaseRetCode> codeList = goodsPurchaseRetCodeService.lambdaQuery().eq(GoodsPurchaseRetCode::getGoodsPurchaseRetId, id).list();

        this.subRefundCodeAcc(codeList, list, goodsPurchaseRet);

        for (GoodsPurchaseRetItem goodsPurchaseRetItem : list) {
            Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.LOCK_WALLET + goodsPurchaseRetItem.getGoodsMaterialId());
            if (!obtain.tryLock(10, TimeUnit.SECONDS)) {
                throw new RemoteServiceException("库存已冻结:" + goodsPurchaseRetItem.getGoodsMaterialName());
            }
            try {
                //添加库存

                this.subMaterialStock(goodsPurchaseRetItem.getGoodsMaterialId(), goodsPurchaseRetItem.getRetQty(), goodsPurchaseRet.getGoodsPurchaseId(),goodsPurchaseRet.getStorageId());

                goodsMaterialStockAccLogic.add(goodsPurchaseRetItem.getGoodsMaterialId(), goodsPurchaseRetItem.getPrice(), goodsPurchaseRetItem.getRetQty(),
                        DirectFlagEnum.SUB, goodsPurchaseRetItem.getGoodsPurchaseRetId(), GoodsMaterialStockAccBillTypeEnum.C,goodsPurchaseRet.getStorageId(),goodsPurchaseRet.getStorageName());

                //变化成本价
                this.changeRefundCost(goodsPurchaseRetItem.getGoodsMaterialId(), goodsPurchaseRetItem);
            } finally {
                //事务提交释放锁
                this.unlockAfterTransaction(obtain);
            }
        }

    }

    private void changeRefundCost(String goodsMaterialId, GoodsPurchaseRetItem goodsPurchaseRetItem) {
        //todo
   /*     GoodsMaterial goodsMaterial = goodsMaterialService.getById(goodsMaterialId);


        Integer qty = goodsMaterial.getStockQty() + goodsPurchaseRetItem.getRetQty();
        BigDecimal amount = goodsMaterial.getCostAmount().multiply(Convert.toBigDecimal(qty));

        BigDecimal multiply = goodsPurchaseRetItem.getPrice().multiply(Convert.toBigDecimal(goodsPurchaseRetItem.getRetQty()));

        BigDecimal allPrice = amount.subtract(multiply);

        BigDecimal bigDecimal = !goodsMaterial.getStockQty().equals(0)?
                allPrice.divide(Convert.toBigDecimal(goodsMaterial.getStockQty()), 2, RoundingMode.HALF_UP):new BigDecimal("0");

        goodsMaterial.setCostAmount(bigDecimal);


        goodsMaterial.updateById();*/
    }

    private void subRefundCodeAcc
            (List<GoodsPurchaseRetCode> codeList, List<GoodsPurchaseRetItem> list, GoodsPurchaseRet
                    goodsPurchaseRet) throws
            InterruptedException {
        List<GoodsCodeAcc> goodsCodeAccs = new ArrayList<>();


        List<String> materialId = list.stream().map(GoodsPurchaseRetItem::getGoodsMaterialId).collect(Collectors.toList());

        List<GoodsMaterial> goodsMaterialList = goodsMaterialService.lambdaQuery().in(GoodsMaterial::getId, materialId).list();


        for (GoodsPurchaseRetCode goodsPurchaseCode : codeList) {
            GoodsPurchaseRetItem goodsPurchaseItem = list.stream().filter(item -> item.getGoodsPurchaseRetId().equals(goodsPurchaseCode.getGoodsPurchaseRetId())).collect(Collectors.toList()).get(0);
            GoodsMaterial goodsMaterial = goodsMaterialList.stream().filter(item -> item.getId().equals(goodsPurchaseItem.getGoodsMaterialId())).collect(Collectors.toList()).get(0);


            //减去条码库存

            GoodsCode goodsCode = goodsCodeService.lambdaQuery().eq(GoodsCode::getMaterialCode, goodsPurchaseCode.getCode())
                    .eq(GoodsCode::getOrderId, goodsPurchaseRet.getGoodsPurchaseId())
                    .gt(GoodsCode::getStockQty, 0).last("limit 1").one();

            GoodsCodeAcc goodsCodeAcc = new GoodsCodeAcc();
            goodsCodeAcc.setCompanyWechatId(goodsPurchaseRet.getCompanyWechatId())
                    .setCompanyWechatName(goodsPurchaseRet.getCompanyWechatName())
                    .setBrandId(goodsMaterial.getBrandId())
                    .setBrandName(goodsMaterial.getBrandName())
                    .setMainId(goodsMaterial.getMainId())
                    .setMainName(goodsMaterial.getMainName())
                    .setSmallId(goodsMaterial.getSmallId())
                    .setSmallName(goodsMaterial.getSmallName())
                    .setGoodsMaterialId(goodsMaterial.getId())
                    .setGoodsMaterialName(goodsMaterial.getGoodsName())
                    .setSpecsName(goodsMaterial.getSpecsName())
                    .setUnit(goodsMaterial.getUnit())
                    .setQty(goodsPurchaseCode.getCodeQty())
                    .setStockQty(goodsCode.getStockQty() - goodsPurchaseCode.getCodeQty())
                    .setVenderId(goodsPurchaseRet.getVenderId())
                    .setVenderName(goodsPurchaseRet.getVenderName())
                    .setMaterialName(goodsPurchaseCode.getGoodsMaterialItemName())
                    .setMaterialCode(goodsPurchaseCode.getCode())
                    .setStatus(CodeAccStatusEnum.OUT.getKey())
                    .setOrderType(CodeAccTypeEnum.OUT.getKey())
                    .setOrderId(goodsPurchaseCode.getGoodsPurchaseRetId())
                    .setStorageName(goodsPurchaseRet.getStorageName())
                    .setStorageId(goodsPurchaseRet.getStorageId())
                    .setGoodsMaterialItemType(goodsPurchaseCode.getGoodsMaterialItemType());

            goodsCodeAccs.add(goodsCodeAcc);


            Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.LOCK_WALLET + goodsCode.getGoodsCodeId());
            if (!obtain.tryLock(10, TimeUnit.SECONDS)) {
                throw new RemoteServiceException("库存已冻结:" + goodsCode.getMaterialName() + ",请稍后重试");
            }
            try {

                GoodsCode goodsCodeUp = new GoodsCode();
                goodsCodeUp.setGoodsCodeId(goodsCode.getGoodsCodeId());

                goodsCodeUp.setStockQty(goodsCode.getStockQty() - goodsPurchaseCode.getCodeQty());
                goodsCodeUp.updateById();

            } finally {
                //事务提交释放锁
                this.unlockAfterTransaction(obtain);
            }


        }

        goodsCodeAccService.saveBatch(goodsCodeAccs);


    }

    @Transactional(rollbackFor = Exception.class)
    public void importCode(MultipartFile file) throws IOException {

        AdminUserCom adminUser = commonLogic.getAdminUser();

        List<Object> objects = ExcelUtils.importExcel(file);

        List<GoodsMaterial> goodsMaterialList = goodsMaterialService.lambdaQuery()
                .eq(GoodsMaterial::getCompanyWechatId, adminUser.getAdminCompanyWechat().getCompanyWechatId()).list();

        List<GoodsMaterialItem> goodsMaterialItemList = goodsMaterialItemService.lambdaQuery().in(GoodsMaterialItem::getGoodsMaterialId,
                goodsMaterialList.stream().map(GoodsMaterial::getId).collect(Collectors.toList())).list();

        List<GoodsCode> goodsCodes = new ArrayList<>();
        List<GoodsCodeAcc> goodsCodeAccs = new ArrayList<>();

        for (int i = 0; i < objects.size(); i++) {
            List<Object> row = (List<Object>) objects.get(i);

            if (goodsCodeService.lambdaQuery().eq(GoodsCode::getMaterialCode, Convert.toStr(row.get(8)))
                    .eq(GoodsCode::getCompanyWechatId,adminUser.getCompanyWechatId())
                    .eq(GoodsCode::getUniqueCode,IsYesNoEnum.YES.getKey())
                    .count() > 0)
                throw new RemoteServiceException("条码已经导入" + row.get(8));


            List<GoodsMaterial> goodsMaterials = goodsMaterialList.stream().filter(item -> item.getSpecsName().equals(row.get(0))
                    && item.getBrandName().equals(row.get(1))
                    && item.getMainName().equals(row.get(2))
                    && item.getSmallName().equals(row.get(3))
            ).collect(Collectors.toList());

            if (CollectionUtils.isEmpty(goodsMaterials))
                throw new RemoteServiceException("没有该物料" + row.get(0));

            GoodsMaterial goodsMaterial = goodsMaterials.get(0);


            List<GoodsMaterialItem> goodsMaterialItems = goodsMaterialItemList.stream().filter(item -> item.getName().equals(row.get(5))
                            && item.getType().equals(
                    row.get(4).equals(GoodsMaterialTypeEnum.INSIDE.getRemark()) ? GoodsMaterialTypeEnum.INSIDE.getKey() :
                            row.get(4).equals(GoodsMaterialTypeEnum.OUT.getRemark()) ? GoodsMaterialTypeEnum.OUT.getKey() :
                                    GoodsMaterialTypeEnum.PARTS.getKey()
                    )
                            && item.getGoodsMaterialId().equals(goodsMaterial.getId())

            ).collect(Collectors.toList());

            if (CollectionUtils.isEmpty(goodsMaterialItems))
                throw new RemoteServiceException("没有该物料" + row.get(5));

            GoodsMaterialItem goodsMaterialItem = goodsMaterialItems.get(0);





            GoodsCode goodsCode = new GoodsCode();
            BeanUtil.copyProperties(goodsMaterial, goodsCode);
            goodsCode.setStockQty(Convert.toInt(row.get(7)));

            List<GoodsCode> goodsCodeList = goodsCodeService.lambdaQuery().eq(GoodsCode::getMaterialCode, Convert.toStr(row.get(8)))
                    .eq(GoodsCode::getUniqueCode, IsYesNoEnum.NO.getKey())
                    .eq(GoodsCode::getCompanyWechatId,adminUser.getCompanyWechatId())
                    .eq(GoodsCode::getGoodsMaterialId, goodsMaterial.getId())
                    .list();



            if(!CollectionUtils.isEmpty(goodsCodeList) && goodsMaterialItem.getUniqueCode().equals(IsYesNoEnum.NO.getKey())){
                goodsCode.setGoodsCodeId(goodsCodeList.get(0).getGoodsCodeId());
                goodsCode.setStockQty(goodsCodeList.get(0).getStockQty()+Convert.toInt(row.get(7)));
            }

            goodsCode.setGoodsMaterialId(goodsMaterialItem.getGoodsMaterialId());
            goodsCode.setGoodsMaterialName(goodsMaterial.getGoodsName());


            goodsCode.setMaterialName(goodsMaterialItem.getName());

            goodsCode.setUniqueCode(goodsMaterialItem.getUniqueCode());
            goodsCode.setGoodsMaterialItemType(goodsMaterialItem.getType());
            goodsCode.setGoodsMaterialItemId(goodsMaterialItem.getId());
            goodsCode.setMaterialCode(Convert.toStr(row.get(8)));

            if (goodsCode.getUniqueCode().equals(IsYesNoEnum.YES.getKey()))
                goodsCode.setStockQty(1);

            goodsCodes.add(goodsCode);

            GoodsCodeAcc goodsCodeAcc = new GoodsCodeAcc();
            goodsCodeAcc.setCompanyWechatId(adminUser.getCompanyWechatId())
                    .setCompanyWechatName(adminUser.getCompanyName())
                    .setBrandId(goodsMaterial.getBrandId())
                    .setBrandName(goodsMaterial.getBrandName())
                    .setMainId(goodsMaterial.getMainId())
                    .setMainName(goodsMaterial.getMainName())
                    .setSmallId(goodsMaterial.getSmallId())
                    .setSmallName(goodsMaterial.getSmallName())
                    .setGoodsMaterialId(goodsMaterial.getId())
                    .setGoodsMaterialName(goodsMaterial.getGoodsName())
                    .setSpecsName(goodsMaterial.getSpecsName())
                    .setUnit(goodsMaterial.getUnit())

                    .setQty(Convert.toInt(row.get(7)))

                    .setStockQty(goodsCode.getStockQty())

                    .setMaterialName(goodsCode.getMaterialName())
                    .setMaterialCode(goodsCode.getMaterialCode())
                    .setStatus(CodeAccStatusEnum.GIVE.getKey())
                    .setOrderType(CodeAccTypeEnum.INIT.getKey())
                    .setGoodsMaterialItemType(goodsCode.getGoodsMaterialItemType());

            if(!CollectionUtils.isEmpty(goodsCodeList) && goodsMaterialItem.getUniqueCode().equals(IsYesNoEnum.NO.getKey())){

                goodsCodeAcc.setStockQty(goodsCodeList.get(0).getStockQty()+Convert.toInt(row.get(7)));
            }

            goodsCodeAccs.add(goodsCodeAcc);


        }

        goodsCodeService.saveOrUpdateBatch(goodsCodes);
        goodsCodeAccService.saveBatch(goodsCodeAccs);
    }

    public void addCodeAccOffline(List<OrderOfflineItemCode> codeList,String storaId) throws InterruptedException {
        AdminUserCom adminUser = commonLogic.getAdminUser();
        List<GoodsCodeAcc> goodsCodeAccs = new ArrayList<>();


        Storage storage = storageService.getById(storaId);
        List<String> materialId = codeList.stream().map(OrderOfflineItemCode::getGoodsMaterialId).collect(Collectors.toList());

        List<GoodsMaterial> goodsMaterialList = goodsMaterialService.lambdaQuery().in(GoodsMaterial::getId, materialId).list();


        for (OrderOfflineItemCode orderDetailCode : codeList) {
            GoodsMaterial goodsMaterial = goodsMaterialList.stream().filter(item -> item.getId().equals(orderDetailCode.getGoodsMaterialId())).collect(Collectors.toList()).get(0);
            GoodsCode goodsCode = goodsCodeService.lambdaQuery()
                    .eq(GoodsCode::getMaterialCode, orderDetailCode.getMaterialCode())
                    .eq(GoodsCode::getCompanyWechatId,adminUser.getCompanyWechatId())

                    .last("limit 1").one();

            GoodsPurchase goodsPurchase = goodsPurchaseService.getById(goodsCode.getOrderId());

            GoodsCodeAcc goodsCodeAcc = new GoodsCodeAcc();
            goodsCodeAcc.setCompanyWechatId(goodsMaterial.getCompanyWechatId())
                    .setCompanyWechatName(goodsMaterial.getCompanyWechatName())
                    .setBrandId(goodsMaterial.getBrandId())
                    .setBrandName(goodsMaterial.getBrandName())
                    .setMainId(goodsMaterial.getMainId())
                    .setMainName(goodsMaterial.getMainName())
                    .setSmallId(goodsMaterial.getSmallId())
                    .setSmallName(goodsMaterial.getSmallName())
                    .setGoodsMaterialId(goodsMaterial.getId())
                    .setGoodsMaterialName(goodsMaterial.getGoodsName())
                    .setSpecsName(goodsMaterial.getSpecsName())
                    .setUnit(goodsMaterial.getUnit())
                    .setQty(orderDetailCode.getStockQty())
                    .setStockQty(goodsCode.getStockQty() + orderDetailCode.getStockQty())
                    .setMaterialName(orderDetailCode.getMaterialName())
                    .setMaterialCode(orderDetailCode.getMaterialCode())
                    .setStatus(CodeAccStatusEnum.GIVE.getKey())
                    .setOrderType(CodeAccTypeEnum.SALE_REFUND.getKey())
                    .setOrderId(orderDetailCode.getOrderId())
                    .setStorageName(storage.getStorageName())
                    .setStorageId(storage.getStorageId())
                    .setGoodsMaterialItemType(orderDetailCode.getGoodsMaterialItemType());


            if (goodsPurchase != null){
                goodsCodeAcc.setVenderId(goodsPurchase.getVenderId());
                goodsCodeAcc.setVenderName(goodsPurchase.getVenderName());
            }

            goodsCodeAccs.add(goodsCodeAcc);

            //加回条码库存

            Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.LOCK_WALLET + goodsCode.getGoodsCodeId());
            if (!obtain.tryLock(10, TimeUnit.SECONDS)) {
                throw new RemoteServiceException("库存已冻结:" + goodsCode.getGoodsCodeId());
            }
            try {

                GoodsCode goodsCodeUp = new GoodsCode();
                goodsCodeUp.setGoodsCodeId(goodsCode.getGoodsCodeId());


                goodsCodeUp.setStockQty(goodsCode.getStockQty() + orderDetailCode.getStockQty());

                if (goodsCode.getUniqueCode().equals(IsYesNoEnum.YES.getKey())) {
                    if (!goodsCodeUp.getStockQty().equals(1)) {
                        throw new RemoteServiceException("退货条码有库存" + orderDetailCode.getMaterialCode());
                    }
                }

                goodsCodeUp.updateById();

            } finally {
                //事务提交释放锁
                this.unlockAfterTransaction(obtain);
            }
        }

        goodsCodeAccService.saveBatch(goodsCodeAccs);
    }
}
