package cn.iocoder.yudao.module.stockOperate.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.common.*;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.base.service.RepairRecordsService;
import cn.iocoder.yudao.module.base.service.RepairWorkerService;
import cn.iocoder.yudao.module.company.entity.Company;
import cn.iocoder.yudao.module.company.service.CompanyService;
import cn.iocoder.yudao.module.project.entity.RepairWares;
import cn.iocoder.yudao.module.project.service.RepairWaresService;
import cn.iocoder.yudao.module.stockOperate.entity.DlRepairSo;
import cn.iocoder.yudao.module.stockOperate.entity.DlRepairSoi;
import cn.iocoder.yudao.module.stockOperate.mapper.DlRepairSoMapper;
import cn.iocoder.yudao.module.stockOperate.service.DlRepairSoService;
import cn.iocoder.yudao.module.stockOperate.service.DlRepairSoiService;
import cn.iocoder.yudao.module.stockOperate.vo.DlRepairSoReqVO;
import cn.iocoder.yudao.module.stockOperate.vo.DlRepairSoRespVO;
import cn.iocoder.yudao.module.stockOperate.vo.DlRepairSoiRespVO;
import cn.iocoder.yudao.module.supplier.service.BaseSupplierService;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.tickets.entity.DlRepairTitem;
import cn.iocoder.yudao.module.tickets.entity.DlTicketWares;
import cn.iocoder.yudao.module.tickets.entity.DlTwItem;
import cn.iocoder.yudao.module.tickets.service.DlRepairTicketsService;
import cn.iocoder.yudao.module.tickets.service.DlRepairTitemService;
import cn.iocoder.yudao.module.tickets.service.DlTicketWaresService;
import cn.iocoder.yudao.module.tickets.service.DlTwItemService;
import cn.iocoder.yudao.module.tickets.utils.TicketsOperateUtil;
import cn.iocoder.yudao.module.tickets.vo.AppWaresGroupVO;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;

/**
 * 针对表【dl_repair_so(采购单领料单)】的数据库操作Service实现
 * @author 小李
 * @date 9:11 2024/9/13
 **/
@Service
public class DlRepairSoServiceImpl extends ServiceImpl<DlRepairSoMapper, DlRepairSo>
        implements DlRepairSoService {

    @Resource
    private DlRepairSoMapper dlRepairSoMapper;
    @Resource
    private DlRepairSoiService repairSoiService;

    @Resource
    private DeptApi deptApi;

    @Resource
    private CompanyService companyService;

    @Resource
    @Lazy
    private RepairWaresService waresService;

    @Resource
    @Lazy
    private DlTicketWaresService ticketWaresService;

    @Resource
    @Lazy
    private DlTwItemService twItemService;

    @Resource
    @Lazy
    private DlRepairTicketsService ticketsService;

    @Resource
    @Lazy
    private DlRepairTitemService titemService;

    @Resource
    @Lazy
    private RepairWorkerService repairWorkerService;
    @Resource
    private AdminUserApi userApi;
    @Resource
    private BaseSupplierService supplierService;

    @Resource
    @Lazy
    private RepairWaresService repairWaresService;

    @Resource
    @Lazy
    private RepairRecordsService recordsService;

    @Resource
    private TicketsOperateUtil operateUtil;

    /**
     * 采购单/领料单 新增
     * @param repairSoRespVO 采购单对象
     * @author 小李
     * @date 10:49 2024/9/14
     **/
    @DSTransactional
    @Override
    public void createRepairSo(DlRepairSoRespVO repairSoRespVO) {
        repairSoRespVO.setSoTime(new Date());
        //保存供应商
        if (StringUtils.isEmpty(repairSoRespVO.getSupplierId())) {
            //采购单中录入供应商或无供应商情况
            if (StringUtils.isNotEmpty(repairSoRespVO.getSupplierName())) {
                //没有选择直接录入的情况
                String supplierId = supplierService.appSaveSupplier(repairSoRespVO.getSupplierName());
                //为供应商id赋值
                repairSoRespVO.setSupplierId(supplierId);
            }
        }
        // 取当前登录用户的门店信息
        Long deptId = SecurityFrameworkUtils.getLoginUserDeptId();
        repairSoRespVO.setDeptId(deptId);

        DeptRespDTO dept = deptApi.getDept(deptId);
        if (ObjectUtil.isNotEmpty(dept)) {
            repairSoRespVO.setCorpId(dept.getCorpId());
            Company company = companyService.getById(dept.getCorpId());
            if (ObjectUtil.isNotEmpty(company)) {
                repairSoRespVO.setCorpName(company.getCorpName());
            }
        }

        // 如果没有选择操作的人就取当前操作人
        if (ObjectUtil.isEmpty(repairSoRespVO.getUserId())) {
            repairSoRespVO.setUserId(SecurityFrameworkUtils.getLoginUserId());
            repairSoRespVO.setUserName(SecurityFrameworkUtils.getLoginUserNickname());
        }

        // 新增主表
        // 如果是采购单，就把状态变为部分入库
        if (repairSoRespVO.getSoType() != null && repairSoRespVO.getSoType().equals("01")) {
            repairSoRespVO.setSoStatus("02");
        }
        baseMapper.insertOrUpdate(repairSoRespVO);
        // 新增子表
        if (CollectionUtil.isEmpty(repairSoRespVO.getGoodsList())) {
            throw exception(RepairErrorCodeConstants.GOODS_IS_EMPTY);
        }
        repairSoRespVO.getGoodsList().forEach(item -> {
            item.setSoId(repairSoRespVO.getId());
        });
        repairSoiService.saveBatch(repairSoRespVO.getGoodsList());

        // 操作配件表
        // 前端选择了配件生成采购单的时候，可能会改配件的一些信息，但不知道会改什么，直接拿到全部，重新更新
        List<RepairWares> waresList = repairSoRespVO.getWaresList();
        waresService.updateBatchById(waresList);
    }

    /**
     * 采购单/领料单新增分页
     * @param repairSoReqVO 查询对象
     * @author 小李
     * @date 18:14 2024/9/14
     **/
    @Override
    public IPage<DlRepairSo> getRepairSoPage(DlRepairSoReqVO repairSoReqVO, Page<DlRepairSo> page) {
        return baseMapper.getRepairSoPage(repairSoReqVO, page);
    }

    /**
     * 采购单/领料单 作废
     * @param repairSoReqVO 作废对象
     * @author 小李
     * @date 11:12 2024/9/18
     **/
    @Override
    @DSTransactional
    public void voidRepairSo(DlRepairSoReqVO repairSoReqVO) {
        LambdaUpdateWrapper<DlRepairSo> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(DlRepairSo::getSoStatus, SoStatusEnum.DEPRECATED.getCode());
        String userRole = ticketsService.getUserRole();
        if (RepairRoleEnum.WAREHOUSE.getCode().equals(userRole)) {
            wrapper.eq(DlRepairSo::getId, repairSoReqVO.getId());
        } else {
            wrapper.and(i ->
                    i.eq(DlRepairSo::getId, repairSoReqVO.getId())
                            .ne(DlRepairSo::getSoStatus, SoStatusEnum.DEPRECATED.getCode())
                            .ne(DlRepairSo::getSoStatus, SoStatusEnum.PICKED.getCode())
                            .ne(DlRepairSo::getSoStatus, SoStatusEnum.RETURNED.getCode())
            );
        }
        int update = baseMapper.update(wrapper);
        if (update == 0) {
            throw exception0(500, "该单据已有其他人操作");
        }

        // 下面的代码是因为这个接口还有地方在用
        // 查主表
        DlRepairSo so = baseMapper.selectById(repairSoReqVO.getId());
        // 查当前登录操作人的userId
        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        // 如果主表记录的领退料人与操作人一致，即是员工点击的作废，即需要通知仓库
        boolean flag = so.getUserId().equals(loginUserId);
        if (flag) {
            repairWorkerService.sentMessage(SystemEnum.REPAIR.getCode(), Long.valueOf(so.getCreator()), (so.getSoType().equals("02") ? "领料单:" : "退料单:") + so.getSoNo() + "已被" + so.getUserName() + "作废");
            // 需要更新库存和申请表数据
            // 查单据子表
            List<DlRepairSoi> sois = repairSoiService.list(new LambdaQueryWrapper<DlRepairSoi>().in(DlRepairSoi::getSoId, so.getId()));
            // 查要操作申请表子表
            List<DlTwItem> oldTwItems = twItemService.list(new LambdaQueryWrapper<DlTwItem>().and(item -> {
                item.eq(DlTwItem::getTwId, so.getTwId())
                        .in(DlTwItem::getWaresId, sois.stream().map(DlRepairSoi::getGoodsId).collect(Collectors.toList()));
            }));
            // 查要操作的配件
            List<RepairWares> oldWares = repairWaresService.list(new LambdaQueryWrapper<RepairWares>().in(RepairWares::getId, sois.stream().map(DlRepairSoi::getGoodsId).collect(Collectors.toList())));
            // 新的申请表子表数据和配件数据
            List<DlTwItem> newTwItems = new ArrayList<>();
            List<RepairWares> newWares = new ArrayList<>();
            // 需要区分是领料还是退料
            // 得到新申请表子表数据
            oldTwItems.forEach(item -> {
                DlTwItem dlTwItem = new DlTwItem();
                dlTwItem.setId(item.getId());
                sois.stream().filter(i -> i.getGoodsId().equals(item.getWaresId())).findFirst().ifPresent(repairSoiByTwItem -> {
                    if (so.getSoType().equals("02")) {
                        dlTwItem.setWaresAlreadyCount(item.getWaresAlreadyCount() - repairSoiByTwItem.getGoodsCount());
                        // 不操作配件申请表子表的状态
//                        dlTwItem.setWaresStatus("02");
                    } else {
                        dlTwItem.setWaresAlreadyCount(item.getWaresAlreadyCount() + repairSoiByTwItem.getGoodsCount());
                    }
                });
                newTwItems.add(dlTwItem);
            });
            // 得到新配件数据
            oldWares.forEach(item -> {
                RepairWares wares = new RepairWares();
                wares.setId(item.getId());
                sois.stream().filter(i -> i.getGoodsId().equals(wares.getId())).findFirst().ifPresent(repairSoiByWares -> {
                    if (so.getSoType().equals("02")) {
                        wares.setStock(item.getStock().add(BigDecimal.valueOf(repairSoiByWares.getGoodsCount())));
                    }
                    // 采购改了入库逻辑，不能在这里扣库存
//                    else {
//                        wares.setStock(item.getStock().subtract(BigDecimal.valueOf(repairSoiByWares.getGoodsCount())));
//                    }
                });
                newWares.add(wares);
            });

            // 更新申请表子表
            twItemService.updateBatchById(newTwItems);
            // 更新配件
            repairWaresService.updateBatchById(newWares);
        }
    }

    /**
     * 采购单/领料单 查看
     * @param id 主键
     * @author 小李
     * @date 9:34 2024/9/22
     **/
    @Override
    public DlRepairSoRespVO getRepairSoById(String id) {
        // 查主表
        DlRepairSo dlRepairSo = baseMapper.selectById(id);
        DlRepairSoRespVO result = BeanUtil.toBean(dlRepairSo, DlRepairSoRespVO.class);

        // 查子表
        List<DlRepairSoi> list = repairSoiService.list(new LambdaQueryWrapper<DlRepairSoi>().eq(DlRepairSoi::getSoId, result.getId()));
        if (!list.isEmpty()) {
            //所有有配件的分类
            List<Map<String, String>> typeMapList = waresService.getAllTypeList();
            Map<String, String> typeMap = new HashMap<>();
            for (Map<String, String> map : typeMapList) {
                typeMap.put(map.get("id"), map.get("name"));
            }
            //关联查配件信息
            List<RepairWares> repairWaresList = waresService.listByIds(list.stream().map(DlRepairSoi::getGoodsId).collect(Collectors.toList()));
            Map<String, RepairWares> waresMap = repairWaresList.stream().collect(Collectors.toMap(RepairWares::getId, Function.identity()));
            list.forEach(item -> {
                item.setWares(waresMap.get(item.getGoodsId()));
                item.setTypeName(typeMap.get(item.getWares().getType()));
            });
        }
        result.setGoodsList(list);
        return result;
    }

    /**
     * 员工确认领料
     * @param id 单据ID 领料单主表
     * @author 小李
     * @date 11:58 2024/10/21
     **/
    @Override
    @DSTransactional
    public void confirmGet(String id, String image) {
        // 更新主表状态 为已领料 需要判断是否已经领料过了
        int update = baseMapper.update(new LambdaUpdateWrapper<DlRepairSo>()
                .set(DlRepairSo::getSoStatus, SoStatusEnum.PICKED.getCode())
                .and(i -> {
                    i.eq(DlRepairSo::getId, id)
                            .ne(DlRepairSo::getSoStatus, SoStatusEnum.PICKED.getCode())
                            .ne(DlRepairSo::getSoStatus, SoStatusEnum.DEPRECATED.getCode());
                })
        );
        if (update == 0) {
            throw exception0(500, "该领料单已有其他人操作");
        }

        // 查最新的子表信息
        DlRepairSo so = baseMapper.selectById(id);
        List<DlRepairSoi> sois = repairSoiService.list(new LambdaQueryWrapper<DlRepairSoi>().eq(DlRepairSoi::getSoId, id));
        //本次领料的配件id
        Set<String> waresIds = sois.stream().map(DlRepairSoi::getGoodsId).collect(Collectors.toSet());
        //配件库的数据集合
        List<RepairWares> repairWares = repairWaresService.listByIds(waresIds);
        List<DlRepairSoiRespVO> list = sois.stream().map(item -> {
            DlRepairSoiRespVO bean = BeanUtil.toBean(item, DlRepairSoiRespVO.class);
            repairWares.stream().filter(i -> i.getId().equals(item.getGoodsId())).findFirst().ifPresent(bean::setWares);
            return bean;
        }).collect(Collectors.toList());

        /* 这里添加新逻辑，员工确认领料时，把领的配件添加进工单子表---start */
        this.dealWareItem(true, so.getTwId(), sois, repairWares);
        /* 这里添加新逻辑，员工确认领料时，把领的配件添加进工单子表---end */

        // 通知仓库
        repairWorkerService.sentMessage(SystemEnum.REPAIR.getCode(), Long.valueOf(so.getCreator()), so.getUserName() + "已确认领料单:" + so.getSoNo());

        // 记录日志
        // 查配件申请表
        DlTicketWares byId = ticketWaresService.getById(so.getTwId());
        // 取当前操作人的名称
        StringBuilder remark = new StringBuilder("确认领料: ");
        // 构建备注
        /*
            谁，领了什么配件，领了多少个
         */
        for (int i = 0; i < list.size(); i++) {
            DlRepairSoiRespVO item = list.get(i);
            if (ObjectUtil.isNotEmpty(item.getWares())) {
                remark.append(i + 1).append(".").append(item.getWares().getName()).append("x").append(item.getGoodsCount()).append("; ");
            }
        }
        // 记录日志
        recordsService.saveRepairRecord(byId.getTicketId(), null, RecordTypeEnum.LL.getCode(), remark.toString(), image);

        // 更新工单主表时间
        if (ObjectUtil.isNotEmpty(so) && ObjectUtil.isNotEmpty(so.getTwId())) {
            DlTicketWares ticketWares = ticketWaresService.getById(so.getTwId());
            if (ObjectUtil.isNotEmpty(ticketWares) && ObjectUtil.isNotEmpty(ticketWares.getTicketId())) {
                ticketsService.refreshUpdateTime(ticketWares.getTicketId());
            }
        }
    }

    /**
     * 员工确认退料
     * @param id 退料单主表ID
     * @author 小李
     * @date 19:41 2024/10/21
     **/
    @Override
    @DSTransactional
    public void confirmBack(String id, String image) {
        // 更新主表
        int update = baseMapper.update(new LambdaUpdateWrapper<DlRepairSo>()
                .set(DlRepairSo::getSoStatus, SoStatusEnum.RETURNED.getCode())
                .and(i -> i.eq(DlRepairSo::getId, id)
                        .ne(DlRepairSo::getSoStatus, SoStatusEnum.RETURNED.getCode())
                        .ne(DlRepairSo::getSoStatus, SoStatusEnum.DEPRECATED.getCode()))
        );
        if (update == 0) {
            throw exception0(500, "该退料单已有其他人操作");
        }
        // 查主表
        DlRepairSo newSo = baseMapper.selectById(id);
        // 通知仓库
        repairWorkerService.sentMessage(SystemEnum.REPAIR.getCode(), Long.valueOf(newSo.getCreator()), newSo.getUserName() + "已确认退料单:" + newSo.getSoNo());
        // 记录日志
        // 查子表信息
        List<DlRepairSoi> sois = repairSoiService.list(new LambdaQueryWrapper<DlRepairSoi>().eq(DlRepairSoi::getSoId, id));
        Set<String> waresIds = sois.stream().map(DlRepairSoi::getGoodsId).collect(Collectors.toSet());
        List<RepairWares> repairWares = repairWaresService.listByIds(waresIds);
        List<DlRepairSoiRespVO> list = sois.stream().map(item -> {
            DlRepairSoiRespVO bean = BeanUtil.toBean(item, DlRepairSoiRespVO.class);
            repairWares.stream().filter(i -> i.getId().equals(item.getGoodsId())).findFirst().ifPresent(bean::setWares);
            return bean;
        }).collect(Collectors.toList());
        // 查申请表
        DlTicketWares byId = ticketWaresService.getById(newSo.getTwId());
        // 取当前操作人的名称
        StringBuilder remark = new StringBuilder("确认退料: ");

        /* 这里添加新逻辑，员工确认退料时，把退的配件从工单子表中删除---start */
        this.dealWareItem(false, newSo.getTwId(), sois, repairWares);
        /* 这里添加新逻辑，员工确认退料时，把退的配件从工单子表中删除---end */

        // 构建备注
        /*
            谁，退了什么配件，退了多少个
         */
        for (int i = 0; i < list.size(); i++) {
            DlRepairSoiRespVO item = list.get(i);
            if (ObjectUtil.isNotEmpty(item.getWares())) {
                remark.append(i + 1).append(".").append(item.getWares().getName()).append("x").append(item.getGoodsCount()).append("; ");
            }
        }
        // 记录日志
        recordsService.saveRepairRecord(byId.getTicketId(), null, RecordTypeEnum.TL.getCode(), remark.toString(), image);

        // 更新工单主表时间
        if (ObjectUtil.isNotEmpty(newSo) && ObjectUtil.isNotEmpty(newSo.getTwId())) {
            DlTicketWares ticketWares = ticketWaresService.getById(newSo.getTwId());
            if (ObjectUtil.isNotEmpty(ticketWares) && ObjectUtil.isNotEmpty(ticketWares.getTicketId())) {
                ticketsService.refreshUpdateTime(ticketWares.getTicketId());
            }
        }
    }

    /**
     * 领料、退料计算工单子表的通用方法
     * @param ifGet       是否是领料
     * @param applyId     配件申请单id
     * @param sois        领料单、退料单配件明细
     * @param repairWares 配件库的明细
     * @author vinjor-M
     * @date 14:31 2024/12/4
     **/
    private void dealWareItem(Boolean ifGet, String applyId, List<DlRepairSoi> sois, List<RepairWares> repairWares) {
        //配件申请单
        DlTicketWares dlTicketWares = ticketWaresService.getById(applyId);
        //工单现有的配件
        List<DlRepairTitem> titems = titemService.list(new LambdaQueryWrapper<DlRepairTitem>().and(i -> {
            i.eq(DlRepairTitem::getTicketId, dlTicketWares.getTicketId())
                    .eq(DlRepairTitem::getItemType, "02");
        }));
        //更新或插入的数据集合
        List<DlRepairTitem> saveOrUpdateList = new ArrayList<>();
        //删除的数据id集合
        List<String> delIdList = new ArrayList<>();
        //工单现有配件转MAP
        Map<String, DlRepairTitem> itemMap = titems.stream().collect(Collectors.toMap(DlRepairTitem::getPartId, Function.identity()));
        //配件库的数据集合转MAP
        Map<String, RepairWares> repairWaresMap = repairWares.stream().collect(Collectors.toMap(RepairWares::getId, Function.identity()));
        //遍历本次领料/退料的所有配件
        for (DlRepairSoi repairSoi : sois) {
            if (itemMap.containsKey(repairSoi.getGoodsId())) {
                //工单中有这个配件
                if (ifGet) {
                    //领料
                    //工单现有配件中就有这个领取的配件，需要更新这个配件的数量、价格
                    DlRepairTitem item = itemMap.get(repairSoi.getGoodsId());
                    item.setItemCount(item.getItemCount() + repairSoi.getGoodsCount());
                    item.setItemMoney(item.getItemPrice().multiply(BigDecimal.valueOf(item.getItemCount())).multiply(item.getItemDiscount()));
                    item.setItemStatus(TicketsItemStatusEnum.RECEIVED.getCode());


                    // 获取配件的售价和进价
                    BigDecimal salePrice = repairWaresMap.get(repairSoi.getGoodsId()).getPrice();     // 售价
                    BigDecimal purchasePrice = repairWaresMap.get(repairSoi.getGoodsId()).getPurPrice(); // 进价

                    //计算利润
                    BigDecimal profit = operateUtil.calcProfit(salePrice, purchasePrice, item.getItemCount());
                    // 计算毛利率
                    BigDecimal profitRate = operateUtil.calcProfitRate(salePrice, purchasePrice, item.getItemCount());

                    item.setItemProfit(profit);
                    item.setItemProfitRate(profitRate);

                    saveOrUpdateList.add(item);
                } else {
                    //退料
                    //工单现有配件中就有这个领取的配件，需要更新这个配件的数量、价格
                    DlRepairTitem item = itemMap.get(repairSoi.getGoodsId());
                    if (item.getItemCount() > repairSoi.getGoodsCount()) {
                        //现有数量大于要退的数量，扣掉
                        item.setItemCount(item.getItemCount() - repairSoi.getGoodsCount());
                        item.setItemMoney(item.getItemPrice().multiply(BigDecimal.valueOf(item.getItemCount())).multiply(item.getItemDiscount()));
                        item.setItemStatus(TicketsItemStatusEnum.RECEIVED.getCode());

                        // 重新计算利润和利润率
                        BigDecimal salePrice = repairWaresMap.get(repairSoi.getGoodsId()).getPrice();      // 售价
                        BigDecimal purchasePrice = repairWaresMap.get(repairSoi.getGoodsId()).getPurPrice(); // 进价

                        //计算利润
                        BigDecimal profit = operateUtil.calcProfit(salePrice, purchasePrice, item.getItemCount());
                        // 计算毛利率
                        BigDecimal profitRate = operateUtil.calcProfitRate(salePrice, purchasePrice, item.getItemCount());

                        item.setItemProfit(profit);
                        item.setItemProfitRate(profitRate);

                        saveOrUpdateList.add(item);
                    } else {
                        //现有数量小于或等于要退的数量，直接将这个配件删掉
                        delIdList.add(item.getId());
                    }
                }
            } else {
                //工单中没有这个配件
                if (ifGet) {
                    //领料，需要把这个配件添加到工单子表中
                    //配件库的对象
                    RepairWares waresItem = repairWaresMap.get(repairSoi.getGoodsId());
                    //工单子表对象
                    DlRepairTitem titem = new DlRepairTitem();
                    titem.setTicketId(dlTicketWares.getTicketId());
                    titem.setItemType("02");
                    titem.setItemName(waresItem.getName());
                    titem.setItemCount(repairSoi.getGoodsCount());
                    titem.setItemUnit(waresItem.getUnit());
                    //优先取领配件的价格，再取配件库的价格，
                    BigDecimal itemPrice = null != repairSoi.getGoodsPrice() ? repairSoi.getGoodsPrice() : (null != waresItem.getPrice() ? waresItem.getPrice() : BigDecimal.ZERO);
                    titem.setItemPrice(itemPrice);
                    titem.setItemDiscount(BigDecimal.ONE);
                    titem.setItemMoney(titem.getItemPrice().multiply(BigDecimal.valueOf(titem.getItemCount())).multiply(titem.getItemDiscount()));
                    titem.setRepairIds(String.valueOf(dlTicketWares.getRepairId()));
                    titem.setRepairNames(dlTicketWares.getRepairName());
                    titem.setSaleId(dlTicketWares.getAdviserId());
                    titem.setSaleName(dlTicketWares.getAdviserName());
                    titem.setPartId(repairSoi.getGoodsId());
                    titem.setItemStatus(TicketsItemStatusEnum.RECEIVED.getCode());

                    // 获取售价和进价
                    BigDecimal salePrice = waresItem.getPrice(); // 售价
                    BigDecimal purchasePrice = waresItem.getPurPrice(); // 进价

                    //计算利润
                    BigDecimal profit = operateUtil.calcProfit(salePrice, purchasePrice, titem.getItemCount());
                    // 计算毛利率
                    BigDecimal profitRate = operateUtil.calcProfitRate(salePrice, purchasePrice, titem.getItemCount());

                    titem.setItemProfitRate(profitRate);
                    titem.setItemProfit(profit);
                    saveOrUpdateList.add(titem);
                } else {
                    //退料，不可能出现，没领料就退料的情况，不用处理
                }
            }
        }
        if (!saveOrUpdateList.isEmpty()) {
            titemService.saveOrUpdateBatch(saveOrUpdateList);
        }
        if (!delIdList.isEmpty()) {
            titemService.removeBatchByIds(delIdList);
        }
        //重新计算工单的价格和订单的价格
        ticketsService.computeTicket(dlTicketWares.getTicketId());
    }


    /**
     * 采购入库
     * @param reqVO （接参实体中需传入：采购单id，单据编号soNo，备注remark,入库总价totalPrice，子表中商品id，子表中入库数量inCount）
     * @author PQZ
     * @date 14:32 2024/10/24
     **/
    @Override
    @DSTransactional
    public void inWare(DlRepairSoRespVO reqVO) {
        /*1、基础数据准备*/
        //获取当前登录用户
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        AdminUserRespDTO user = userApi.getUser(userId);
        //采购单
        DlRepairSo dlRepairSo = getById(reqVO.getId());
        //需要保存的入库单
        DlRepairSo inSo = new DlRepairSo();
        //过滤掉入库数量为null或0的情况(此为无效数据)
        List<DlRepairSoi> filterWare = reqVO.getSoiList().stream().filter(item -> item.getInCount() != null && item.getInCount() > 0).collect(Collectors.toList());
        //如果为空代表无需入库
        if (CollectionUtil.isEmpty(filterWare)) {
            return;
        }
        //即将入库采购品
        List<DlRepairSoi> pmsWaresList = repairSoiService.listByIds(filterWare.stream().map(DlRepairSoi::getId).collect(Collectors.toList()));
        //初始化本次入库采购品
        List<DlRepairSoi> inWaresList = new ArrayList<>();
        //原始配件库相关配件---不是用wareId，是用GoodsId，wareId是仓库
        List<RepairWares> waresList = waresService.listByIds(pmsWaresList.stream().map(DlRepairSoi::getGoodsId).collect(Collectors.toList()));

        /*2、采购单转入库单*/
        //入库单关联采购单
        inSo.setMainId(dlRepairSo.getId());
        inSo.setMainTable("dl_repair_so");
        //05表示入库单
        inSo.setSoType("05");
        //入库单号
        inSo.setSoNo(reqVO.getSoNo());
        //入库人
        inSo.setUserId(userId);
        inSo.setUserName(user.getNickname());
        //入库时间
        inSo.setSoTime(new Date());
        //入库商品总价
        inSo.setTotalPrice(reqVO.getTotalPrice());
        save(inSo);

        /*3、入库配件处理*/
        Map<String, DlRepairSoi> filterWareMap = filterWare.stream().collect(Collectors.toMap(DlRepairSoi::getId, soi -> soi));
        pmsWaresList.forEach(item -> {
            DlRepairSoi filterSoi = filterWareMap.get(item.getId());
            DlRepairSoi inWares = BeanUtil.copyProperties(item, DlRepairSoi.class);
            //采购单id
            inWares.setSoId(inSo.getId());
            //采购品原始id
            inWares.setRawId(item.getId());
            //入库数量
            inWares.setInCount(filterSoi.getInCount());
            inWares.setId(null);
            //采购品中入库数量字段累加---这里item.getInCount 是null的时候，应该是filterSoi的inCount而不是0
            item.setInCount(item.getInCount() == null ? filterSoi.getInCount() : item.getInCount() + filterSoi.getInCount());
            inWaresList.add(inWares);
        });
        //更新采购品
        repairSoiService.updateBatchById(pmsWaresList);
        //新增入库采购品
        repairSoiService.saveBatch(inWaresList);

        /*4、原始配件库处理*/
        //入库配件按照原始配件库id分组，目的取出数量---不是用wareId，是用GoodsId，wareId是仓库
        Map<String, DlRepairSoi> wareMap = filterWare.stream().collect(Collectors.toMap(DlRepairSoi::getGoodsId, soi -> soi));
        //采购配件按照按照原始配件库id分组，目的取出价格---不是用wareId，是用GoodsId，wareId是仓库
        Map<String, DlRepairSoi> itemsMap = pmsWaresList.stream().collect(Collectors.toMap(DlRepairSoi::getGoodsId, soi -> soi));
        waresList.forEach(item -> {
            DlRepairSoi filterSoi = wareMap.get(item.getId());
            DlRepairSoi itemSoi = itemsMap.get(item.getId());
            //进价
            item.setPurPrice(itemSoi.getGoodsPrice());
            item.setStock((item.getStock() == null ? new BigDecimal(0) : item.getStock()).add(new BigDecimal(filterSoi.getInCount())));
        });
        waresService.updateBatchById(waresList);

        // 更新采购单的状态，如果是全部入库完了，就是03已入库，反之不变
        // 查该采购单的所有采购配件
        List<DlRepairSoi> sois = repairSoiService.list(new LambdaQueryWrapper<DlRepairSoi>().eq(DlRepairSoi::getSoId, reqVO.getId()));
        // 过滤出入库数量大于等于采购数量的数据 （入库数量可以大于采购的数量）
        List<DlRepairSoi> allInSois = sois.stream()
                .filter(item -> (ObjectUtil.isNotEmpty(item.getInCount()) && item.getInCount() >= item.getGoodsCount()))
                .collect(Collectors.toList());
        // 如果allInSois的size就是sois的size，那就是全部都入库了
        if (CollectionUtil.isNotEmpty(allInSois) && allInSois.size() == sois.size()) {
            // 更新采购单的状态为已入库
            baseMapper.update(new LambdaUpdateWrapper<DlRepairSo>()
                    .set(DlRepairSo::getSoStatus, "03")
                    .eq(DlRepairSo::getId, reqVO.getId())
            );
        }

        // 不敢动上面的代码，在新加一个逻辑，重复了也没事儿
        // 更新配件信息---因为入库的时候，配件的信息还能改
        List<RepairWares> reqVOWaresList = reqVO.getWaresList();
        List<String> ids = reqVOWaresList.stream().map(item -> item.getId()).collect(Collectors.toList());
        List<RepairWares> oldWares = waresService.listByIds(ids);
        // 这里是因为传过来的库存不是最新的，但其他字段可能变了，所以用最新的库存替换传回来的，在用传回来的+最新库存构成最新数据
        List<RepairWares> newWares = reqVOWaresList.stream().map(item -> {
            RepairWares wares = BeanUtil.toBean(item, RepairWares.class);
            RepairWares findWares = oldWares.stream().filter(i -> i.getId().equals(wares.getId())).findFirst().orElse(null);
            if (findWares != null) {
                wares.setStock(findWares.getStock());
            }
            return wares;
        }).collect(Collectors.toList());
        waresService.updateBatchById(newWares);
    }

    /**
     * 领料单、退料单APP查看
     * @param id 单据id
     * @return cn.iocoder.yudao.framework.common.pojo.CommonResult<?>
     * @author vinjor-M
     * @date 11:10 2024/11/21
     **/
    @Override
    public Object getApp(String id) {
        List<DlRepairSoiRespVO> dlRepairSoiRespVOList = dlRepairSoMapper.selectByIdGroup(id);
        List<AppWaresGroupVO> waresGroupList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(dlRepairSoiRespVOList)) {
            //先过滤出itenTypeId为null或空，或者itemTypeName为null或空的，为单独一个组
            List<DlRepairSoiRespVO> nullList = dlRepairSoiRespVOList.stream().filter(item -> StringUtils.isEmpty(item.getTypeId()) || StringUtils.isEmpty(item.getTypeName())).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(nullList)) {
                AppWaresGroupVO waresGroupVO = new AppWaresGroupVO();
                waresGroupVO.setSoiRespVOList(nullList);
                waresGroupVO.setGroupName("未知分组");
                waresGroupVO.setTypeNums(nullList.size());
                waresGroupVO.setNums(nullList.stream().mapToInt(DlRepairSoi::getGoodsCount).sum());
                waresGroupList.add(waresGroupVO);
            }
            //过滤出有分类的进行分组
            Map<String, List<DlRepairSoiRespVO>> groupListMap = dlRepairSoiRespVOList.stream().filter(item -> StringUtils.isNotEmpty(item.getTypeId()) && StringUtils.isNotEmpty(item.getTypeName())).collect(Collectors.groupingBy(DlRepairSoiRespVO::getTypeId));
            for (String key : groupListMap.keySet()) {
                AppWaresGroupVO waresGroupVO = new AppWaresGroupVO();
                waresGroupVO.setSoiRespVOList(groupListMap.get(key));
                waresGroupVO.setGroupName(groupListMap.get(key).get(0).getTypeName());
                waresGroupVO.setGroupId(key);
                waresGroupVO.setTypeNums(groupListMap.get(key).size());
                waresGroupVO.setNums(groupListMap.get(key).stream().mapToInt(DlRepairSoi::getGoodsCount).sum());
                waresGroupList.add(waresGroupVO);
            }
        }
        return waresGroupList;
    }
}




