package cn.ezhizao.project.business.controller;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.ezhizao.common.utils.poi.ExcelUtil;
import cn.ezhizao.framework.aspectj.lang.annotation.Log;
import cn.ezhizao.framework.aspectj.lang.enums.BusinessType;
import cn.ezhizao.framework.redis.RedisCache;
import cn.ezhizao.framework.security.LoginUser;
import cn.ezhizao.framework.web.controller.BaseController;
import cn.ezhizao.framework.web.domain.AjaxResult;
import cn.ezhizao.framework.web.page.TableDataInfo;
import cn.ezhizao.project.business.domain.*;
import cn.ezhizao.project.business.service.*;
import cn.ezhizao.project.system.domain.SysDept;
import cn.ezhizao.project.system.service.ISysDeptService;
import cn.hutool.core.date.DateTime;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 外协单主
带箱方式，是整单的。如果换新箱子，明细中，都需要更换箱子Controller
 *
 * @author ezhizao
 * @date 2024-05-08
 */
@RestController
@RequestMapping("/business/returnReceipt")
public class BizReturnReceiptController extends BaseController
{
    @Resource
    private IBizReturnReceiptService bizReturnReceiptService;
    @Resource
    private IBizReturnReceiptDetailService bizReturnReceiptDetailService;
    @Resource
    private IBizOutsourcedOrderDetailProcessService bizOutsourcedOrderDetailProcessService;

    @Resource
    private IBizOutsourcedOrderDetailService bizOutsourcedOrderDetailService;
    @Resource
    private IBizDayworkItemService bizDayworkItemService;
    @Resource
    private IBizProcessInspecionService bizProcessInspecionService;
    @Resource
    private IBizCarrierService bizCarrierService;
    @Resource
    private IBizLotService bizLotService;
    @Resource
    private ISysDeptService deptService;
    @Resource
    private RedisCache redisCache;
    @Resource
    private IBizOutsourceBalanceAccountService bizOutsourceBalanceAccountService;
    @Resource
    private IBizDayworkCarrierService bizDayworkCarrierService;
    @Resource
    private IBizOutsourcedOrderService bizOutsourcedOrderService;
    @Resource
    private IBizDayworkService bizDayworkService;
    @Resource
    private IBizCarrierCategoryService bizCarrierCategoryService;
    @Resource
    HttpServletRequest request;

    final private String processInspectionNoKey = "processInspectionCode";

    /**
     * 查询外协单主
带箱方式，是整单的。如果换新箱子，明细中，都需要更换箱子列表
     */
    @PreAuthorize("@ss.hasPermi('business:returnReceipt:list')")
    @GetMapping("/list")
    @Log(title = "查询外协单列表", businessType = BusinessType.SELECT)
    public TableDataInfo list(BizReturnReceipt bizReturnReceipt) throws NoSuchFieldException, IllegalAccessException
    {
        setTenantId(bizReturnReceipt);
        if(bizReturnReceipt.getStartTime()!=null) {
            bizReturnReceipt.setStartTime(bizReturnReceipt.getStartTime()+ " 00:00:00");
        }
        if(bizReturnReceipt.getEndTime()!=null) {
            bizReturnReceipt.setEndTime(bizReturnReceipt.getEndTime()+ " 23:59:59");
        }
        startPage();
        List<BizReturnReceipt> list = bizReturnReceiptService.getList(bizReturnReceipt);
        return getDataTable(list);
    }

    /**
     * 导出外协单主
带箱方式，是整单的。如果换新箱子，明细中，都需要更换箱子列表
     */
    @PreAuthorize("@ss.hasPermi('business:returnReceipt:export')")
    @Log(title = "导出外协单", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, BizReturnReceipt bizReturnReceipt) throws NoSuchFieldException, IllegalAccessException
    {
        setTenantId(bizReturnReceipt);
        List<BizReturnReceipt> list = bizReturnReceiptService.getList(bizReturnReceipt);
        ExcelUtil<BizReturnReceipt> util = new ExcelUtil<BizReturnReceipt>(BizReturnReceipt.class);
        util.exportExcel(response, list, "外协单主 带箱方式，是整单的。如果换新箱子，明细中，都需要更换箱子数据");
    }

    /**
     * 获取外协单主
带箱方式，是整单的。如果换新箱子，明细中，都需要更换箱子详细信息
     */
    @PreAuthorize("@ss.hasPermi('business:returnReceipt:query')")
    @GetMapping(value = "/{id}")
    @Log(title = "获取外协单详细信息", businessType = BusinessType.SELECT)
    public AjaxResult getInfo(@PathVariable("id") Long id)
    {
        // 根据 id 获取到收回订单
        BizReturnReceipt returnReceipt = bizReturnReceiptService.getById(id);
        // 根据收回订单id，获取到该收回订单的所有明细
        List<BizReturnReceiptDetail> returnReceiptDetails = bizReturnReceiptDetailService.query()
                .eq("master_id", id)
                .list();
        List<Long> outsourceDetailIds = returnReceiptDetails.stream().map(BizReturnReceiptDetail::getOutsourceDetailId).distinct().collect(Collectors.toList());
        //查询是否有序检的数据
        List<BizProcessInspecion> processInspection = bizProcessInspecionService.query().in("outsource_order_detail_id", outsourceDetailIds.isEmpty() ? Collections.singletonList(0L) : outsourceDetailIds).list();
        List<BizOutsourcedOrderDetail> list = bizOutsourcedOrderDetailService.query().in("id", outsourceDetailIds).list();
        List<BizOutsourceBalanceAccount> balanceAccounts = bizOutsourceBalanceAccountService.query().eq("return_receipt_id", id).list();
        List<BizDayworkCarrier> carriers = bizDayworkCarrierService.query().eq("is_changed", 0).in("daywork_id", returnReceiptDetails.stream().map(BizReturnReceiptDetail::getDayworkId).collect(Collectors.toList())).list();

        returnReceiptDetails.forEach(item -> {
            if(item.getIsAudit()==0) {
                item.setAuditNum(item.getReceiptNum());
            }
            item.setNewCarrier(list.stream().filter(t -> t.getId().equals(item.getOutsourceDetailId())).findFirst().orElse(null).getNewCarrierName());
            BizOutsourceBalanceAccount bizOutsourceBalanceAccount = balanceAccounts.stream().filter(balanceAccount -> balanceAccount.getReturnReceiptDetailId().equals(item.getId())).findFirst().orElse(null);
            if (bizOutsourceBalanceAccount != null) {
                item.setIsProvedForCheck(1);
            }
            if (bizOutsourceBalanceAccount != null && bizOutsourceBalanceAccount.getStatus().equals(1)) {
                item.setIsCheckout(1);
            }
            list.forEach(info ->{
                if(item.getOutsourceDetailId().equals(info.getId())) {
                    item.setProductionDeptId(info.getProductionDeptId());
                }
            });
            item.setUnbind(carriers.stream().anyMatch(t -> t.getDayworkId().equals(item.getDayworkId())) ? 0 : 1);
        });
        List<BizOutsourcedOrderDetailProcess> detailProcesses = bizOutsourcedOrderDetailProcessService.query()
                .in("detail_id", outsourceDetailIds)
                .orderByAsc(Arrays.asList("detail_id", "process_step_number"))
                .list();
        //按照批次分组，一个批次合并成一条
        List<String> lotCodeList = returnReceiptDetails.stream()
                .map(BizReturnReceiptDetail::getLotCode)
                .distinct()
                .collect(Collectors.toList());
        //一个批次一条
        Map<String, List<BizReturnReceiptDetail>> groupedByLotCode = new LinkedHashMap<>();
        for (String lotCode : lotCodeList) {
            groupedByLotCode.put(lotCode, returnReceiptDetails.stream()
                    .filter(record -> record.getLotCode().equals(lotCode))
                    .sorted(Comparator.comparing(BizReturnReceiptDetail::getProcessStepNumber))
                    .collect(Collectors.toList()));
        }
        List<BizReturnReceiptDetail> details = new ArrayList<>();
        for (Map.Entry<String, List<BizReturnReceiptDetail>> entry : groupedByLotCode.entrySet()) {
            BizReturnReceiptDetail info = new BizReturnReceiptDetail();
            String lotCode = entry.getKey();
            List<BizReturnReceiptDetail> detailList = entry.getValue();
            info.setProductDescription(detailList.get(0).getProductDescription());
            info.setOutsourceDetailId(detailList.get(0).getOutsourceDetailId());
            info.setLotCode(lotCode);
            info.setLotId(detailList.get(0).getLotId());
            info.setDayworkId(detailList.get(0).getDayworkId());
            List<BizDayworkCarrier> currentBindCarrier = carriers.stream().filter(t -> t.getDayworkId().equals(info.getDayworkId())).collect(Collectors.toList());
            List<Long> carrierIds = new ArrayList<>();
            String carrierNames = "";
            List<BizCarrier> carriersList = new ArrayList<>();
            for (BizDayworkCarrier carrier : currentBindCarrier) {
                carrierIds.add(Long.valueOf(carrier.getCarrierId().toString()));
                carrierNames = String.join(",", carrier.getCarrierCode());
                BizCarrier bizCarrier = new BizCarrier();
                bizCarrier.setId(carrier.getCarrierId());
                bizCarrier.setCode(carrier.getCarrierCode());
                carriersList.add(bizCarrier);
            }
            List<BizDayworkCarrier> notInspectionCarrierList = currentBindCarrier.stream().filter(l -> l.getProcessInspectionId() == 0).collect(Collectors.toList());
            List<Long> notInspectionCarrierIds = new ArrayList<>();
            String notInspectionCarrierNames = "";
            List<BizCarrier> notInspectionCarriersList = new ArrayList<>();
            for (BizDayworkCarrier carrier : notInspectionCarrierList) {
                notInspectionCarrierIds.add(Long.valueOf(carrier.getCarrierId().toString()));
                notInspectionCarrierNames = String.join(",", carrier.getCarrierCode());
                BizCarrier bizCarrier = new BizCarrier();
                bizCarrier.setId(carrier.getCarrierId());
                bizCarrier.setCode(carrier.getCarrierCode());
                notInspectionCarriersList.add(bizCarrier);
            }
            info.setCarrierIds(notInspectionCarrierIds);
            info.setNewCarriers(notInspectionCarriersList);
            info.setCarrierNames(notInspectionCarrierNames);
            info.setStatus(detailList.get(0).getStatus());
            info.setProductNum(detailList.get(0).getProductNum());
            info.setReceiptNum(detailList.get(detailList.size() -1).getReceiptNum());
            if(detailList.get(0).getIsAudit()==0) {
                info.setAuditNum(detailList.get(detailList.size() -1).getReceiptNum());
            }else {
                info.setAuditNum(detailList.get(detailList.size() -1).getAuditNum());
            }
            list.stream().forEach(item ->{
                if(info.getOutsourceDetailId().equals(item.getId())) {
                    info.setProductionDeptId(item.getProductionDeptId());
                }
            });
            info.setUnbind(detailList.get(0).getUnbind());
            info.setNewCarrier(detailList.get(0).getNewCarrier());
            info.setRemark(detailList.get(0).getRemark());
            info.setIsApproved(detailList.stream().allMatch(v -> v.getIsApproved() == 1) ? 1 : 0);
            info.setIsProvedForCheck(detailList.get(0).getIsProvedForCheck());
            info.setIsCheckout(detailList.get(0).getIsCheckout());
            info.setProcessAlias(detailProcesses.stream()
                    .filter(dp -> dp.getDetailId().equals(detailList.get(0).getOutsourceDetailId()))
                    .sorted(Comparator.comparing((BizOutsourcedOrderDetailProcess::getProcessStepNumber)))
                    .map(BizOutsourcedOrderDetailProcess::getProcessAlias)
                    .collect(Collectors.joining("，")));
            info.setProcessInspecionList(processInspection.stream().filter(pI -> pI.getOutsourceOrderDetailId().equals(info.getOutsourceDetailId())).collect(Collectors.toList()));
            details.add(info);
        }
//        // 将得到的收回明细的id，组合成一个集合，用于查询这个订单下的，所有收回出来的工序，
//        // 这里得到的工序清单，是混合的，并没有根据各自对应的明细，进行分组，仅仅是获取全部，为后续分组做准备
//        List<Long> detailIds = returnReceiptDetails.stream()
//                .map(BizReturnReceiptDetail::getOutsourceDetailId)
//                .collect(Collectors.toList());
//        List<BizOutsourcedOrderDetailProcess> detailProcesses = bizOutsourcedOrderDetailProcessService.query()
//                .in("detail_id", detailIds)
//                .orderByAsc(Arrays.asList("detail_id", "process_step_number"))
//                .list();

//        // 遍历明细，将对应的工序，与订单明细进行匹配
//        returnReceiptDetails.forEach(item -> {
//            // 根据明细的id，获取到该明细对应的收回工序，并将得到的工序，组成中文逗号分割的字符串
//            String processNames = detailProcesses.stream()
//                    .filter(dp -> dp.getDetailId().equals(item.getOutsourceDetailId()))
//                    .sorted(Comparator.comparing((BizOutsourcedOrderDetailProcess::getProcessStepNumber)))
//                    .map(BizOutsourcedOrderDetailProcess::getProcessAlias)
//                    .collect(Collectors.joining("，"));
//
//            item.setProcessNames(processNames);
//        });

        // 将收回明细赋值给收回订单
        returnReceipt.setDetails(details);
        returnReceipt.setDetailInfo(returnReceiptDetails);
        return success(returnReceipt);
    }
    @Log(title = "判断是否一箱多批", businessType = BusinessType.SELECT)
    @PostMapping("/checkAllowMore")
    public AjaxResult checkAllowMore(@RequestBody List<BizReturnReceiptDetail> details) {
        // 获取所有箱
        List<Long> carrierIds = new ArrayList<>();
        details.forEach(l -> {
          l.getCarrierIds().forEach(v->{
              carrierIds.add(v);
          });
        });
        List<BizCarrier> carriers = bizCarrierService.query().in("id", carrierIds.isEmpty()? Collections.singletonList(0L) : carrierIds).list();
        List<BizCarrierCategory> bizCarrierCategories = bizCarrierCategoryService.query().in("id", carriers.isEmpty() ? Collections.singletonList(0L) : carriers.stream().map(BizCarrier::getCategoryId).collect(Collectors.toList())).list();
        if(!bizCarrierCategories.isEmpty()) {
            // 没有一箱多批的箱子
            if (bizCarrierCategories.stream().noneMatch(v -> v.getIsAllowMore().equals(1))) {
                return success(true);
            }
            // 假设有一箱多批的箱子获取该箱子的所有报工
            List<BizDayworkCarrier> bizDayworkCarriers = bizDayworkCarrierService.query().in("carrier_id", carriers.stream().filter(e -> bizCarrierCategories.stream().filter(v -> v.getIsAllowMore().equals(1)).anyMatch(v -> v.getId().equals(e.getCategoryId()))).map(BizCarrier::getId).collect(Collectors.toList())).eq("is_changed", 0).list();
            List<BizDayworkCarrier> unreturn = bizDayworkCarriers.stream().filter(v -> details.stream().noneMatch(t -> t.getDayworkId().equals(v.getDayworkId()))).collect(Collectors.toList());
            List<BizDaywork> bizDayworks = bizDayworkService.query().in("id", unreturn.isEmpty() ? Collections.singletonList(0L) : unreturn.stream().map(BizDayworkCarrier::getDayworkId).collect(Collectors.toList())).list();
            if (unreturn.size() > 0) {
                String msg = "周转箱" + unreturn.stream().map(BizDayworkCarrier::getCarrierCode).distinct().collect(Collectors.joining(",")) + "中批次" + bizDayworks.stream().map(BizDaywork::getLotCode).distinct().collect(Collectors.joining(",")) + "未收回,请全部收回或更换载具";
                return AjaxResult.success(msg, false);
            }
        }
        return success(true);
    }
    @Log(title = "判断是否存在无箱批次", businessType = BusinessType.SELECT)
    @PostMapping("/checkIsNone")
    public AjaxResult checkIsNone(@RequestBody List<BizReturnReceiptDetail> details) {
        // 获取所有箱
        List<Long> carrierIds = new ArrayList<>();
        List<Long> dayworkIds = new ArrayList<>();
        details.forEach(l -> {
            l.getCarrierIds().forEach(v->{
                carrierIds.add(v);
            });
            dayworkIds.add(l.getDayworkId());
        });
        List<BizCarrier> carriers = bizCarrierService.query().in("id", carrierIds.isEmpty()? Collections.singletonList(0L) : carrierIds).list();
        List<BizCarrierCategory> bizCarrierCategories = bizCarrierCategoryService.query().in("id", carriers.isEmpty() ? Collections.singletonList(0L) : carriers.stream().map(BizCarrier::getCategoryId).collect(Collectors.toList())).list();
        if(!bizCarrierCategories.isEmpty()) {
            // 没有一箱多批的箱子
            if (bizCarrierCategories.stream().noneMatch(v -> v.getIsNone().equals(1))) {
                return success(true);
            }
            // 假设有一箱多批的箱子获取该箱子的所有报工
            List<BizDayworkCarrier> bizDayworkCarriers = bizDayworkCarrierService.query()
                    .in("carrier_id", carriers.stream().filter(e -> bizCarrierCategories.stream().filter(v -> v.getIsNone().equals(1)).anyMatch(v -> v.getId().equals(e.getCategoryId()))).map(BizCarrier::getId).collect(Collectors.toList()))
                    .eq("is_changed", 0)
                    .in("daywork_id", dayworkIds)
                    .list();
            List<Long> dayworkId = bizDayworkCarriers.stream().map(BizDayworkCarrier::getDayworkId).collect(Collectors.toList());
            String lotCode = bizDayworkService.query().in("id", dayworkId).list().stream().map(BizDaywork::getLotCode).collect(Collectors.joining(","));
            String msg = "批次" + lotCode + "使用无箱是否确认收回";
            return AjaxResult.success(msg, false);
        }
        return success(true);
    }
    @PostMapping(value = "/carrierForReturnReceipt")
    @Log(title = "获取外协箱列表", businessType = BusinessType.SELECT)
    public AjaxResult carrierForReturnReceipt(@RequestBody BizCarrier carrier) {
        List<Long> hasAddCarrierIds = new ArrayList<>();
        List<Long> hasAddLotIds = new ArrayList<>();
        List<Long> hasAddDayworkIds = new ArrayList<>();
        for (BizCarrier r : carrier.getHasAddCarriers()) {
            hasAddLotIds.add(r.getLotId());
            hasAddDayworkIds.add(r.getDayworkId());
            for (Long l : r.getHasAddCarrierIds()) {
                hasAddCarrierIds.add(l);
            }
        }
        //精确查询箱子
        BizCarrier bizCarrier = bizCarrierService.getListFromReceiptDetail(carrier);
        if(bizCarrier != null){
            //判断箱子载具类型，如果已经绑定铁箱子，不能绑定蓝箱子
            List<BizCarrier> carriers = bizCarrierService.query().in("id", carrier.getHasAddCarriers().stream().filter(v->v.getDayworkId().equals(carrier.getDayworkId())).findFirst().orElse(null)== null?Collections.singletonList(0L):carrier.getHasAddCarriers().stream().filter(v->v.getDayworkId().equals(carrier.getDayworkId())).findFirst().orElse(null).getHasAddCarrierIds().size()>0?carrier.getHasAddCarriers().stream().filter(v->v.getDayworkId().equals(carrier.getDayworkId())).findFirst().orElse(null).getHasAddCarrierIds():Collections.singletonList(0L)).list();
            List<BizCarrierCategory> bizCarrierCategories = bizCarrierCategoryService.query().in("id", carriers.isEmpty() ? Collections.singletonList(0L) : carriers.stream().map(BizCarrier::getCategoryId).collect(Collectors.toList())).list();
            if(!bizCarrierCategories.isEmpty()){
            if ((bizCarrierCategories.stream().anyMatch(v -> v.getIsAllowMore().equals(1) && bizCarrier.getIsAllowMore().equals(1)))||(bizCarrierCategories.stream().anyMatch(v -> v.getIsAllowMore().equals(1) && bizCarrier.getIsAllowMore().equals(0)))||(bizCarrierCategories.stream().allMatch(v -> v.getIsAllowMore().equals(0) && bizCarrier.getIsAllowMore().equals(1)))) {
                return success();
            }
            // 没有一箱多批的箱子
            if (bizCarrierCategories.stream().noneMatch(v -> v.getIsAllowMore().equals(1))) {
                return success(true);
            }}
            //判断箱子是否是铁箱
            if(bizCarrier.getIsAllowMore() == 1){
                //如果是铁箱，判断当前批次是否单批单改，如果单批单改，则不允许绑铁箱
                BizLot lot = bizLotService.getById(carrier.getLotId());
                if(lot.getIsAmend() == 0){
                    //判断铁箱是否绑定了批次
                    //如果绑定了批次，则需要判断绑定批次跟当前批次是否是相同工艺计划单，以及工序是否相同
                    List<BizDayworkCarrier> dayworkCarriers = bizDayworkCarrierService.query().eq("carrier_id", bizCarrier.getId()).eq("is_changed",0).list();
                    List<Long> bindDayworkIds = dayworkCarriers.stream().map(BizDayworkCarrier::getDayworkId).collect(Collectors.toList());
                    //如果绑定了批次，判断这个箱是否在页面绑定，如果页面取消绑定该箱，则可以绑定
                    List<Long> commonDayworkIds = bindDayworkIds.stream()
                            .filter(hasAddDayworkIds::contains)
                            .collect(Collectors.toList());
                    List<BizCarrier> collect = carrier.getHasAddCarriers().stream().filter(v -> commonDayworkIds.contains(v.getDayworkId())).collect(Collectors.toList());
                    List<Long> unbindDayworkIds =  new ArrayList<>();
                    for(BizCarrier v : collect){
                        if(!v.getHasAddCarrierIds().contains(bizCarrier.getId())){
                            unbindDayworkIds.add(v.getDayworkId());
                        }
                    }
                    dayworkCarriers = unbindDayworkIds.isEmpty()?dayworkCarriers:dayworkCarriers.stream().filter(v-> !unbindDayworkIds.contains(v.getDayworkId())).collect(Collectors.toList());

                    if(dayworkCarriers.isEmpty()){
                        //未绑定批次，则判断页面是否添加了铁箱，未保存
                        Long lotFlag = 0L;
                        outerLoop: // 标记外层循环
                        for (BizCarrier r : carrier.getHasAddCarriers()) {
                            for (Long l : r.getHasAddCarrierIds()) {
                                if (bizCarrier.getId().equals(l)) {
                                    lotFlag = r.getLotId();
                                    break outerLoop; // 跳出两层循环
                                }
                            }
                        }
                         if(lotFlag == 0L){
                             return success(bizCarrier);
                         }else{
                             //页面添加了当前铁箱，则判断工艺版本，计划单是否相同
                             BizLot hasBindLot = bizLotService.getById(lotFlag);
                            if(hasBindLot.getTechnologyVersion().equals(lot.getTechnologyVersion())&&hasBindLot.getProductionPlanDetailId().equals(lot.getProductionPlanDetailId())){
                                //判断当前工序是否相同
                                List<Long> lotIds = new ArrayList<Long>();
                                lotIds.add(lot.getId());
                                lotIds.add(hasBindLot.getId());
                                List<BizDayworkItem> dayworkItemList = bizDayworkItemService.query().in("lot_id", lotIds).list();
                                BizDayworkItem bizDayworkItem = dayworkItemList.stream().filter(v -> v.getLotId().equals(lot.getId())).sorted(Comparator.comparing((BizDayworkItem::getProcessStepNumber))).findFirst().orElse(null);
                                BizDayworkItem bizBindDayworkItem = dayworkItemList.stream().filter(v -> v.getLotId().equals(hasBindLot.getId())).sorted(Comparator.comparing((BizDayworkItem::getProcessStepNumber))).findFirst().orElse(null);
                                if(bizDayworkItem.getTechnologicalProcessDetailId().equals(bizBindDayworkItem.getTechnologicalProcessDetailId())){
                                    return success(bizCarrier);
                                }
                            }

                         }

                    }else{
                            //当前箱未绑定页面上的批次
                             List<Long> lotIds = bizDayworkService.query().in("id", bindDayworkIds).list().stream().map(BizDaywork::getLotId).collect(Collectors.toList());
                                                        List<BizLot> lotList = bizLotService.query().in("id", lotIds).list();
                                                        if(lotList.get(0).getTechnologyVersion().equals(lot.getTechnologyVersion()) && lotList.get(0).getProductionPlanDetailId().equals(lot.getProductionPlanDetailId())){
                                                            List<Long> lotId = new ArrayList<Long>();
                                                            lotId.add(lot.getId());
                                                            lotId.add(lotList.get(0).getId());
                                                            List<BizDayworkItem> dayworkItemList = bizDayworkItemService.query().in("lot_id", lotId).list();
                                                            BizDayworkItem bizDayworkItem = dayworkItemList.stream().filter(v -> v.getLotId().equals(lot.getId())).sorted(Comparator.comparing((BizDayworkItem::getProcessStepNumber))).findFirst().orElse(null);
                                                            BizDayworkItem bizBindDayworkItem = dayworkItemList.stream().filter(v -> v.getLotId().equals(lotList.get(0).getId())).sorted(Comparator.comparing((BizDayworkItem::getProcessStepNumber))).findFirst().orElse(null);
                                                            if(bizDayworkItem.getTechnologicalProcessDetailId().equals(bizBindDayworkItem.getTechnologicalProcessDetailId())){
                                                                return success(bizCarrier);
                                                            }

                                                        }
                    }

                }
                return success();
            }else{
                //蓝箱
                List<BizDayworkCarrier> dayworkCarrier = bizDayworkCarrierService.query().eq("carrier_id", bizCarrier.getId()).eq("is_changed", 0).list();
                List<Long> bindDayworkIds = dayworkCarrier.stream().map(BizDayworkCarrier::getDayworkId).collect(Collectors.toList());
                //如果绑定了批次，判断这个箱是否在页面绑定，如果页面取消绑定该箱，则可以绑定
                List<Long> commonDayworkIds = bindDayworkIds.stream()
                        .filter(hasAddDayworkIds::contains)
                        .collect(Collectors.toList());
                List<BizCarrier> collect = carrier.getHasAddCarriers().stream().filter(v -> commonDayworkIds.contains(v.getDayworkId())).collect(Collectors.toList());
                List<Long> unbindDayworkIds =  new ArrayList<>();
                for(BizCarrier v : collect){
                    if(!v.getHasAddCarrierIds().contains(bizCarrier.getId())){
                        unbindDayworkIds.add(v.getDayworkId());
                    }
                }
                dayworkCarrier = unbindDayworkIds.isEmpty()?dayworkCarrier:dayworkCarrier.stream().filter(v-> !unbindDayworkIds.contains(v.getDayworkId())).collect(Collectors.toList());

                if(dayworkCarrier.isEmpty()){
                    //未绑定批次，则判断页面是否添加了蓝箱，未保存
                    Long lotFlag = 0L;
                    List<Long> hasAddCarrierId = new ArrayList<Long>();
                    for (BizCarrier r : carrier.getHasAddCarriers()) {
                        for (Long l : r.getHasAddCarrierIds()) {
                            hasAddCarrierId.add((Long) l);
                        }
                    }
                    if(!hasAddCarrierId.contains(bizCarrier.getId())){
                        return success(bizCarrier);
                    }
                }
                return success();
            }
        }
        return success();
    }

    /**
     * 新增外协单主
带箱方式，是整单的。如果换新箱子，明细中，都需要更换箱子
     */
    @PreAuthorize("@ss.hasPermi('business:returnReceipt:add')")
    @Log(title = "新增外协单", businessType = BusinessType.INSERT)
    @Transactional
//    @PostMapping("/new")
    @PostMapping
    public AjaxResult addNew(@RequestBody BizReturnReceipt bizReturnReceipt) throws NoSuchFieldException, IllegalAccessException, ParseException {
        String tenantId = request.getHeader("tenantId");
        bizReturnReceipt.setTenantId(Long.valueOf(tenantId));
        // 判断是否有processes
        // 假设没有加个假的processes
        List<String> codes = new ArrayList<>();
        codes.add("27110");
        codes.add("28030");
        codes.add("28080");
        codes.add("27070");
        codes.add("27044");
        LoginUser user = getLoginUser();
        System.out.println("----- 所有的需要质检工序 ------");
        System.out.println(bizReturnReceipt.getProcesses());
        List<String> processCodes = bizReturnReceipt.getProcesses() == null ? codes : bizReturnReceipt.getProcesses();
        // 生成单据号
        // 若有id，则说将之前的明细删除不生成新的单号
        if (bizReturnReceipt.getId() != null) {
            List<Long> ids = new ArrayList<>();
        } else {
            /* 生成单号 */
            SimpleDateFormat dateFormat = new SimpleDateFormat("yy"); // 定义日期格式
            String formattedDate = dateFormat.format(new Date());
            String codeValue;
            String codeType = "returnReceiveCode";
            //查询redis中外协单号的值
            String previous = redisCache.hasKey(codeType) ? redisCache.getCacheObject(codeType) :"";
            //若不存在，则直接存入
            if (previous.isEmpty()) {
                List<BizReturnReceipt> returnReceiptList = bizReturnReceiptService.getAllList();
                if(!returnReceiptList.isEmpty()) {
                    codeValue = returnReceiptList.get(0).getFormCode();
                    int lastFourDigits = Integer.parseInt(codeValue.substring(5, 10));
                    lastFourDigits += 1; // 加1
                    codeValue = codeValue.substring(0, 5) + String.format("%05d", lastFourDigits);
                    previous = codeValue;
                }else{
                    previous = ("SHD" + formattedDate + "00001");
                }
            } else {
                codeValue = previous;
                String codeYear=codeValue.substring(3, 5);//取出当前外协单号年份
                //如果年份一致表示是当前年的发出单，如果不一致则表示已经进入了新的一年则重置发出单号
                if(codeYear.equals(formattedDate)){
                    int lastFourDigits = Integer.parseInt(codeValue.substring(5, 10));
                    lastFourDigits += 1; // 加1
                    codeValue = codeValue.substring(0, 5) + String.format("%05d", lastFourDigits);
                    previous=codeValue;
                }else{
                    previous = ("SHD" + formattedDate + "00001");
                }
            }
            //存到redis中
            redisCache.setCacheObject(codeType, previous);
            bizReturnReceipt.setFormCode(previous);
        }
        bizReturnReceipt.setStatus(1);
        bizReturnReceipt.setIsSubmit(1);
        //向收回单主表存
        bizReturnReceiptService.save(bizReturnReceipt);
        // 获取载具们
        String carriers = bizReturnReceipt.getDetailInfo().stream().map(BizReturnReceiptDetail::getNewCarrier).collect(Collectors.joining(","));
        List<String> carrierCodes = Arrays.stream(carriers.split(",")).collect(Collectors.toList());
        List<BizCarrier> carrierList = bizCarrierService.query().in("code", carrierCodes.isEmpty() ? Collections.singletonList("0") : carrierCodes).list();
        //将dayworkItem外协报工状态改成3,添加工时,审核数量设置成合格数
        List<Long> dayworkListIds = bizReturnReceipt.getDetailInfo().stream().map(BizReturnReceiptDetail::getDayworkId).distinct().collect(Collectors.toList());
        //找到要修改的报工记录
        List<Long> outsourceDetailId = bizReturnReceipt.getDetailInfo().stream().map(BizReturnReceiptDetail::getOutsourceDetailId).distinct().collect(Collectors.toList());
        List<BizOutsourcedOrderDetailProcess> bizOutsourcedOrderDetailProcess = bizOutsourcedOrderDetailProcessService.query().in("detail_id", outsourceDetailId).list();
        List<BizDayworkItem> dayworkItem = bizDayworkItemService.getListByDayworkIdsForOutsourced(dayworkListIds);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = simpleDateFormat.parse(simpleDateFormat.format(new Date()));
//        List<BizProcessInspecion> processInspecionList = new ArrayList<>();
        // 获取批次信息
        List<BizLot> bizLotList = bizLotService.query().in("id", dayworkItem.isEmpty() ? Collections.singletonList(0L) : dayworkItem.stream().map(BizDayworkItem::getLotId).collect(Collectors.toList())).list();
        //0220 收回单允许更换载具，则想收回单的newCarrier字段重新赋值，dayworkCarrier表进行修改
        List<Long> carrierIds = new ArrayList<>();
        //需要绑定的载具
        bizReturnReceipt.getDetails().forEach(l->{
            l.getCarrierIds().forEach(v->{
                carrierIds.add(v);
            });
                });
        List<BizCarrier> bizCarrierList = bizCarrierService.query().in("id", carrierIds.isEmpty()? Collections.singletonList(0L) : carrierIds).list();
        List<BizDayworkCarrier> dayworkCarrierList = bizDayworkCarrierService.query().in("daywork_id", dayworkListIds).eq("is_changed",0).eq("process_inspection_id",0).list();
        //清空载具，重新绑定
        dayworkCarrierList.forEach(item->{
            item.setIsChanged(1);
        });
        bizDayworkCarrierService.updateBatchById(dayworkCarrierList);
        //新增载具
        List<BizDayworkCarrier> needAddCarrier = new ArrayList<>();
        for(BizReturnReceiptDetail detail:bizReturnReceipt.getDetails()){
            for(Long carrierId:detail.getCarrierIds()){
                BizCarrier bizCarrier = bizCarrierList.stream().filter(e -> e.getId().equals(carrierId)).findFirst().orElse(null);
                BizDayworkCarrier dayworkCarrier = new BizDayworkCarrier();
                dayworkCarrier.setCarrierId(carrierId);
                dayworkCarrier.setCarrierCode(bizCarrier.getCode());
                dayworkCarrier.setDayworkId(detail.getDayworkId());
                needAddCarrier.add(dayworkCarrier);
            }
        }
        bizDayworkCarrierService.saveBatch(needAddCarrier);
        //向收回单明细表存
        for(BizReturnReceiptDetail bizReturnReceiptDetail : bizReturnReceipt.getDetailInfo()) {
            //存载具
            if(!needAddCarrier.isEmpty()) {
                List<BizDayworkCarrier> dayworkCarriers = needAddCarrier.stream().filter(v -> v.getDayworkId().equals(bizReturnReceiptDetail.getDayworkId())).collect(Collectors.toList());
                if(!dayworkCarriers.isEmpty()) {
                    bizReturnReceiptDetail.setNewCarrier(dayworkCarriers.stream().map(BizDayworkCarrier::getCarrierCode).collect(Collectors.joining(",")));
                    bizReturnReceiptDetail.setNewCarrierCount(dayworkCarriers.size());
                }
            }
            bizReturnReceiptDetail.setMasterId(bizReturnReceipt.getId());
            bizReturnReceiptDetail.setFormCode(bizReturnReceipt.getFormCode());
            bizReturnReceiptDetail.setSupplierId(bizReturnReceipt.getSupplierId());
            bizReturnReceiptDetail.setSupplierName(bizReturnReceipt.getSupplierName());
            bizReturnReceiptDetail.setFormDate(bizReturnReceipt.getFormDate());
            bizReturnReceiptDetail.setIsAudit(1);
            bizReturnReceiptDetail.setIsApproved(processCodes.stream().noneMatch(e -> bizReturnReceiptDetail.getProcessCode().equals(e)) ? 1 : 0);
            for(BizDayworkItem item: dayworkItem) {
                for(BizOutsourcedOrderDetailProcess info: bizOutsourcedOrderDetailProcess) {
                    if (item.getDayworkId().equals(info.getDayworkId())&&item.getProcessStepNumber().equals(info.getProcessStepNumber())&& item.getLotId().equals(bizReturnReceiptDetail.getLotId())) {
                        item.setStatus("3");
                        item.setEndTime(date);
                        item.setNickName(bizReturnReceiptDetail.getSupplierName());
                        item.setQualifiedNum(bizReturnReceiptDetail.getAuditNum());
                        long timeDifference = date.getTime() - item.getStartTime().getTime();
                        item.setWorkingHours(timeDifference);
                    }
                    if (item.getDayworkId().equals(bizReturnReceiptDetail.getDayworkId()) && item.getProcessStepNumber().equals(bizReturnReceiptDetail.getProcessStepNumber())) {
                        bizReturnReceiptDetail.setProductionPlanDetailId(item.getProductionPlanDetailId());
                        bizReturnReceiptDetail.setDayworkItemId(item.getId());
                        bizReturnReceiptDetail.setCarriers(carrierList.stream().filter(v -> Arrays.stream(bizReturnReceiptDetail.getNewCarrier().split(",")).anyMatch(t -> v.getCode().equals(t))).collect(Collectors.toList()));
                    }
                }
            }
        }
        bizDayworkItemService.updateBatchById(dayworkItem);
//        bizProcessInspecionService.saveBatch(processInspecionList);
        //如果是内部分选外协干完最后一道序，则批次收回审核后，将周转工段设置为-1
        updateOutsourceDetailDept(bizReturnReceipt.getDetailInfo());
        // 新增所有的检查单
        bizReturnReceiptDetailService.saveBatch(bizReturnReceipt.getDetailInfo());
        addProcessInspection(bizReturnReceipt.getDetailInfo(), processCodes);
        return success();
    }
    public void updateOutsourceDetailDept(List<BizReturnReceiptDetail> detailInfo){
        //判断批次是否干完了
        List<Long> dayworkIds = detailInfo.stream().map(BizReturnReceiptDetail::getDayworkId).distinct().collect(Collectors.toList());
        List<BizDaywork> dayworkList = bizDayworkService.query().in("id", dayworkIds).eq("status",2).list();
        if(!dayworkList.isEmpty()) {
            List<Long> dayworkId = dayworkList.stream().map(BizDaywork::getId).collect(Collectors.toList());
            //需要收回审核的批次
            List<BizReturnReceiptDetail> returnReceiptDetailList = detailInfo.stream().filter(v -> v.getStatus() == 1 && dayworkId.contains(v.getDayworkId())).collect(Collectors.toList());
            if (!returnReceiptDetailList.isEmpty()) {
                List<Long> outsourceDetailIds = returnReceiptDetailList.stream().map(BizReturnReceiptDetail::getOutsourceDetailId).distinct().collect(Collectors.toList());
                List<BizOutsourcedOrderDetail> outsourceOrderDetailList = bizOutsourcedOrderDetailService.query().in("id", outsourceDetailIds).list();
                List<Long> masterIds = outsourceOrderDetailList.stream().map(BizOutsourcedOrderDetail::getMasterId).collect(Collectors.toList());
                //内部外协发出单
                List<BizOutsourcedOrder> outsourcedOrderList = bizOutsourcedOrderService.query().in("id", masterIds).eq("is_inner_outsource", 1).list();
                if (!outsourcedOrderList.isEmpty()) {
                    List<Long> hasInnerOutsouceIds = outsourcedOrderList.stream().map(BizOutsourcedOrder::getId).collect(Collectors.toList());
                    List<BizOutsourcedOrderDetail> collect = outsourceOrderDetailList.stream().filter(v -> hasInnerOutsouceIds.contains(v.getMasterId())).collect(Collectors.toList());
                    collect.forEach(v -> {
                        v.setProductionDeptId(-1L);
                    });
                    bizOutsourcedOrderDetailService.updateBatchById(collect);
                }
            }
        }
    }

    private void addProcessInspection(List<BizReturnReceiptDetail> detailInfo, List<String> codes) {
        // detailInfo 是收回单明细 codes 是需要质检的所有工序明细
        // 对detailInfo 分组 同一发出单明细的分为一组
        Map<Long, List<BizReturnReceiptDetail>> groups = detailInfo.stream().collect(Collectors.groupingBy(BizReturnReceiptDetail::getOutsourceDetailId));
        List<BizProcessInspecion> bizProcessInspecions = bizProcessInspecionService.query().in("outsource_order_detail_id", detailInfo.isEmpty() ? Collections.singletonList(0L) : detailInfo.stream().map(BizReturnReceiptDetail::getOutsourceDetailId).collect(Collectors.toList())).list();
        List<BizProcessInspecion> removeItems = new ArrayList<>();
        List<BizProcessInspecion> saveItems = new ArrayList<>();
        List<BizOutsourcedOrderDetail> bizOutsourcedOrderDetails = bizOutsourcedOrderDetailService.query().in("id", detailInfo.isEmpty() ? Collections.singletonList(0L) : detailInfo.stream().map(BizReturnReceiptDetail::getOutsourceDetailId).collect(Collectors.toList())).list();

        SysDept condition = new SysDept();
        condition.setDeptCode("170000");
        SysDept dept = deptService.selectDeptList(condition).stream().findFirst().orElse(null);

        // 对分组遍历
        groups.keySet().forEach(l -> {
            BizOutsourcedOrderDetail bizOutsourcedOrderDetail = bizOutsourcedOrderDetails.stream().filter(e -> e.getId().equals(l)).findFirst().orElse(new BizOutsourcedOrderDetail());
            List<BizReturnReceiptDetail> itemList = groups.get(l);
            // 判断该收回明细是否已审核
            if (itemList.stream().allMatch(v -> v.getStatus().equals(0))) {
                // 未审核
                // 未审核且免检
                if (itemList.stream().allMatch(v -> v.getIsApproved().equals(1))) {
                    removeItems.addAll(bizProcessInspecions.stream().filter(e -> e.getOutsourceOrderDetailId().equals(l) && e.getIsAuto().equals(1)).collect(Collectors.toList()));
                }
            } else if (itemList.stream().allMatch(v -> v.getStatus().equals(1))) {
                // 已审核
                // 免检 且没有旧质检
                if (itemList.stream().allMatch(v -> v.getIsApproved().equals(1)) && bizProcessInspecions.stream().noneMatch(v -> v.getOutsourceOrderDetailId().equals(l))) {
                    BizReturnReceiptDetail lastProcess = itemList.stream().sorted(Comparator.comparing(BizReturnReceiptDetail::getProcessStepNumber).reversed()).findFirst().orElse(new BizReturnReceiptDetail());
                    BizProcessInspecion bizProcessInspecion = new BizProcessInspecion(lastProcess);
                    bizProcessInspecion.setProcessNames(itemList.stream().map(BizReturnReceiptDetail::getProcessAlias).collect(Collectors.joining(",")));
                    bizProcessInspecion.setOutsourceOrderId(bizOutsourcedOrderDetail.getMasterId());
                    bizProcessInspecion.setDeptId(dept != null ? dept.getDeptId() : 0L);
                    bizProcessInspecion.setProductionPlanDetailId(lastProcess.getProductionPlanDetailId());
                    bizProcessInspecion.setCarrierId(lastProcess.getCarriers().isEmpty() ? 0L : lastProcess.getCarriers().get(0).getId());
                    bizProcessInspecion.setCarrierCode(lastProcess.getCarriers().isEmpty() ? "" : lastProcess.getCarriers().get(0).getCode());
                    bizProcessInspecion.setDayworkItemId(lastProcess.getDayworkItemId());
                    bizProcessInspecion.setTenantId(getLoginUser().getTenantId());
//                    bizProcessInspecion.setUserId(getLoginUser().getUserId());
//                    bizProcessInspecion.setUserName(getLoginUser().getUser().getUserName());
                    bizProcessInspecion.setReviewerId(getLoginUser().getUserId());
//                    bizProcessInspecion.setNickName(getLoginUser().getUser().getNickName());
                    bizProcessInspecion.setReturnReceiptDetailId(lastProcess.getId());
                    bizProcessInspecion.setType("outsourcedInspector");

                    String beginCode = "WDD" + DateTime.now().toString("yyMM");
                    String previous = redisCache.hasKey(processInspectionNoKey) ?  redisCache.getCacheObject(processInspectionNoKey)  : "";
                    String codeValue = "";
                    if (previous.isEmpty()) {
                        List<BizProcessInspecion> processInspectionList = bizProcessInspecionService.getAllList();
                        if(!processInspectionList.isEmpty()) {
                            codeValue = processInspectionList.get(0).getOutsourcedInspectionNo();
                            int lastFourDigits = Integer.parseInt(codeValue.substring(7, 13));
                            lastFourDigits ++; // 加1
                            codeValue = codeValue.substring(0, 7) + String.format("%06d", lastFourDigits);
                            previous = codeValue;
                        }else{
                            previous = (beginCode + "000001");
                        }
                    } else {
                        codeValue = previous.startsWith(beginCode) ? previous : beginCode + "000000";
                        int lastFourDigits = Integer.parseInt(codeValue.substring(7, 13));
                        lastFourDigits ++; // 加1
                        codeValue = codeValue.substring(0, 7) + String.format("%06d", lastFourDigits);
                        previous = codeValue;
                    }
                    bizProcessInspecion.setOutsourcedInspectionNo(previous);
                    redisCache.setCacheObject(processInspectionNoKey, previous);
                    saveItems.add(bizProcessInspecion);
                }
            }
            // 判断该发出单是否需要质检
            // 判断是否已有对应的质检单
        });
        bizProcessInspecionService.removeBatchByIds(removeItems);
        bizProcessInspecionService.saveBatch(saveItems);
    }

    /**
     * 新增外协单主
     带箱方式，是整单的。如果换新箱子，明细中，都需要更换箱子
     */
    @PreAuthorize("@ss.hasPermi('business:returnReceipt:add')")
    @Log(title = "新增外协单", businessType = BusinessType.INSERT)
    @Transactional
//    @PostMapping
    public AjaxResult add(@RequestBody BizReturnReceipt bizReturnReceipt) throws NoSuchFieldException, IllegalAccessException, ParseException {
        //生成单据号
        //若有id，则说将之前的明细删除不生成新的单号
        if (bizReturnReceipt.getId() != null) {
            List<Long> ids = new ArrayList<>();
        } else {
            /* 生成单号 */
            SimpleDateFormat dateFormat = new SimpleDateFormat("yy"); // 定义日期格式
            String formattedDate = dateFormat.format(new Date());
            String codeValue;
            String codeType = "returnReceiveCode";
            //查询redis中外协单号的值
            String previous = redisCache.hasKey(codeType) ? redisCache.getCacheObject(codeType) :"";
            //若不存在，则直接存入
            if (previous.isEmpty()) {
                List<BizReturnReceipt> returnReceiptList = bizReturnReceiptService.getAllList();
                if(!returnReceiptList.isEmpty()) {
                    codeValue = returnReceiptList.get(0).getFormCode();
                    int lastFourDigits = Integer.parseInt(codeValue.substring(5, 10));
                    lastFourDigits += 1; // 加1
                    codeValue = codeValue.substring(0, 5) + String.format("%05d", lastFourDigits);
                    previous = codeValue;
                }else{
                    previous = ("SHD" + formattedDate + "000001");
                }
            } else {
                codeValue = previous;
                String codeYear=codeValue.substring(3, 5);//取出当前外协单号年份
                //如果年份一致表示是当前年的发出单，如果不一致则表示已经进入了新的一年则重置发出单号
                if(codeYear.equals(formattedDate)){
                    int lastFourDigits = Integer.parseInt(codeValue.substring(5, 10));
                    lastFourDigits += 1; // 加1
                    codeValue = codeValue.substring(0, 5) + String.format("%05d", lastFourDigits);
                    previous=codeValue;
                }else{
                    previous = ("SHD" + formattedDate + "000001");
                }
            }
            //存到redis中
            redisCache.setCacheObject(codeType, previous);
            bizReturnReceipt.setFormCode(previous);
        }

        bizReturnReceipt.setStatus(1);
        bizReturnReceipt.setIsSubmit(1);
        //向收回单主表存
        bizReturnReceiptService.save(bizReturnReceipt);
        //将dayworkItem外协报工状态改成3,添加工时,审核数量设置成合格数
        List<Long> dayworkListIds = bizReturnReceipt.getDetailInfo().stream().map(BizReturnReceiptDetail::getDayworkId).distinct().collect(Collectors.toList());
        //找到要修改的报工记录
        List<Long> outsourceDetailId = bizReturnReceipt.getDetailInfo().stream().map(BizReturnReceiptDetail::getOutsourceDetailId).distinct().collect(Collectors.toList());
        List<BizOutsourcedOrderDetailProcess> bizOutsourcedOrderDetailProcess = bizOutsourcedOrderDetailProcessService.query().in("detail_id", outsourceDetailId).list();
        List<BizDayworkItem> dayworkItem = bizDayworkItemService.getListByDayworkIdsForOutsourced(dayworkListIds);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = simpleDateFormat.parse(simpleDateFormat.format(new Date()));
        //向收回单明细表存
        for(BizReturnReceiptDetail bizReturnReceiptDetail : bizReturnReceipt.getDetailInfo()) {
            bizReturnReceiptDetail.setMasterId(bizReturnReceipt.getId());
            bizReturnReceiptDetail.setFormCode(bizReturnReceipt.getFormCode());
            bizReturnReceiptDetail.setSupplierId(bizReturnReceipt.getSupplierId());
            bizReturnReceiptDetail.setSupplierName(bizReturnReceipt.getSupplierName());
            bizReturnReceiptDetail.setFormDate(bizReturnReceipt.getFormDate());
            bizReturnReceiptDetail.setIsAudit(1);
            for(BizDayworkItem item: dayworkItem) {
                for(BizOutsourcedOrderDetailProcess info: bizOutsourcedOrderDetailProcess) {
                    if (item.getDayworkId().equals(info.getDayworkId())&&item.getProcessStepNumber().equals(info.getProcessStepNumber())&& item.getLotId().equals(bizReturnReceiptDetail.getLotId())) {
                        item.setStatus("3");
                        item.setEndTime(date);
                        item.setNickName(bizReturnReceiptDetail.getSupplierName());
                        item.setQualifiedNum(bizReturnReceiptDetail.getAuditNum());
                        long timeDifference = date.getTime() - item.getStartTime().getTime();
                        item.setWorkingHours(timeDifference);
                    }
                }
            }
        }
        bizDayworkItemService.updateBatchById(dayworkItem);
        return success(bizReturnReceiptDetailService.saveBatch(bizReturnReceipt.getDetailInfo()));
    }
    /**
     * 修改外协单主
带箱方式，是整单的。如果换新箱子，明细中，都需要更换箱子
     */
    @PreAuthorize("@ss.hasPermi('business:returnReceipt:edit')")
    @Log(title = "修改外协单", businessType = BusinessType.UPDATE)
    @Transactional
//    @PutMapping
    public AjaxResult edit(@RequestBody BizReturnReceipt bizReturnReceipt) throws NoSuchFieldException, IllegalAccessException, ParseException {
        bizReturnReceipt.setStatus(1);
        bizReturnReceipt.setIsSubmit(1);
        bizReturnReceiptService.updateById(bizReturnReceipt);
        //将dayworkItem外协报工状态改成3,添加工时,审核数量设置成合格数
        List<Long> dayworkListIds = bizReturnReceipt.getDetailInfo().stream().map(BizReturnReceiptDetail::getDayworkId).collect(Collectors.toList());
        //找到要修改的报工记录
        List<Long> outsourceDetailId = bizReturnReceipt.getDetailInfo().stream().map(BizReturnReceiptDetail::getOutsourceDetailId).collect(Collectors.toList());
        List<BizOutsourcedOrderDetailProcess> bizOutsourcedOrderDetailProcess = bizOutsourcedOrderDetailProcessService.query().in("detail_id", outsourceDetailId.isEmpty()? Collections.singletonList(0L) : bizReturnReceipt.getDetails().stream().map(BizReturnReceiptDetail::getOutsourceDetailId).collect(Collectors.toList())).list();
        List<BizDayworkItem> dayworkItem = bizDayworkItemService.getListByDayworkIdsForOutsourced(dayworkListIds.size()>0?dayworkListIds:Collections.singletonList(0L));
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = dateFormat.parse(dateFormat.format(new Date()));
        //向收回单明细表存
        for(BizReturnReceiptDetail bizReturnReceiptDetail : bizReturnReceipt.getDetailInfo()) {
            bizReturnReceiptDetail.setMasterId(bizReturnReceipt.getId());
            bizReturnReceiptDetail.setFormCode(bizReturnReceipt.getFormCode());
            bizReturnReceiptDetail.setSupplierId(bizReturnReceipt.getSupplierId());
            bizReturnReceiptDetail.setSupplierName(bizReturnReceipt.getSupplierName());
            bizReturnReceiptDetail.setFormDate(bizReturnReceipt.getFormDate());
            bizReturnReceiptDetail.setIsAudit(1);
            for(BizDayworkItem item: dayworkItem) {
                    if (item.getDayworkId().equals(bizReturnReceiptDetail.getDayworkId())&&item.getProcessStepNumber().equals(bizReturnReceiptDetail.getProcessStepNumber()) && item.getLotId().equals(bizReturnReceiptDetail.getLotId())) {
                        item.setStatus("3");
                        item.setEndTime(date);
                        item.setNickName(bizReturnReceiptDetail.getSupplierName());
                        item.setQualifiedNum(bizReturnReceiptDetail.getAuditNum());
                        long timeDifference = date.getTime() - item.getStartTime().getTime();
                        item.setWorkingHours(timeDifference);
                    }
            }
        }
        bizDayworkItemService.updateBatchById(dayworkItem);
        List<BizReturnReceiptDetail> oldList = bizReturnReceiptDetailService.query().eq("master_id", bizReturnReceipt.getId()).list();
        saveOrUpdateBatch(bizReturnReceiptDetailService, bizReturnReceipt.getDetailInfo(),oldList);
        //如果收回单里面没收回明细，则主表同时删除
        if(bizReturnReceipt.getDetailInfo().size()==0) {
            bizReturnReceiptService.removeById(bizReturnReceipt.getId());
        }
        return success();
    }
    /**
     * 修改外协单主
     带箱方式，是整单的。如果换新箱子，明细中，都需要更换箱子
     */
    @PreAuthorize("@ss.hasPermi('business:returnReceipt:edit')")
    @Log(title = "修改外协单", businessType = BusinessType.UPDATE)
    @Transactional
    @PutMapping
    public AjaxResult editNew(@RequestBody BizReturnReceipt bizReturnReceipt) throws NoSuchFieldException, IllegalAccessException, ParseException {
        String tenantId = request.getHeader("tenantId");
        bizReturnReceipt.setTenantId(Long.valueOf(tenantId));
        // 判断是否有processes
        // 假设没有加个假的processes
        List<String> codes = new ArrayList<>();
        codes.add("27110");
        codes.add("28030");
        codes.add("28080");
        codes.add("27070");
        codes.add("27044");
        LoginUser user = getLoginUser();
        System.out.println("----- 所有的需要质检工序 ------");
        System.out.println(bizReturnReceipt.getProcesses());
        List<String> processCodes = bizReturnReceipt.getProcesses() == null ? codes : bizReturnReceipt.getProcesses();

        bizReturnReceipt.setStatus(1);
        bizReturnReceipt.setIsSubmit(1);
        bizReturnReceiptService.updateById(bizReturnReceipt);
        // 获取载具们
        String carriers = bizReturnReceipt.getDetailInfo().stream().map(BizReturnReceiptDetail::getNewCarrier).collect(Collectors.joining(","));
        List<String> carrierCodes = Arrays.stream(carriers.split(",")).collect(Collectors.toList());
        List<BizCarrier> carrierList = bizCarrierService.query().in("code", carrierCodes.isEmpty() ? Collections.singletonList("0") : carrierCodes).list();
        //将dayworkItem外协报工状态改成3,添加工时,审核数量设置成合格数
        List<Long> dayworkListIds = bizReturnReceipt.getDetailInfo().stream().map(BizReturnReceiptDetail::getDayworkId).collect(Collectors.toList());
        //找到要修改的报工记录
        List<Long> outsourceDetailId = bizReturnReceipt.getDetailInfo().stream().map(BizReturnReceiptDetail::getOutsourceDetailId).collect(Collectors.toList());
        //外协厂报工明细
        List<BizOutsourcedOrderDetailProcess> bizOutsourcedOrderDetailProcess = bizOutsourcedOrderDetailProcessService.query().in("detail_id", outsourceDetailId.isEmpty()? Collections.singletonList(0L) : bizReturnReceipt.getDetails().stream().map(BizReturnReceiptDetail::getOutsourceDetailId).collect(Collectors.toList())).list();

        List<BizDayworkItem> dayworkItem = bizDayworkItemService.getListByDayworkIdsForOutsourced(dayworkListIds.size()>0?dayworkListIds:Collections.singletonList(0L)).stream().filter(item ->outsourceDetailId.contains(item.getOutsourceDetailId())).collect(Collectors.toList());
        List<BizDayworkItem> turnovered = dayworkItem.stream().filter(e -> e.getStatus().compareTo("4") >= 0).collect(Collectors.toList());
        dayworkItem = dayworkItem.stream().filter(e -> turnovered.stream().noneMatch(t -> t.getDayworkId().equals(e.getDayworkId()))).collect(Collectors.toList());

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = dateFormat.parse(dateFormat.format(new Date()));
        List<BizProcessInspecion> processInspecionList = new ArrayList<>();
        // 获取批次信息
        List<BizLot> bizLotList = bizLotService.query().in("id", dayworkItem.isEmpty() ? Collections.singletonList(0L) : dayworkItem.stream().map(BizDayworkItem::getLotId).collect(Collectors.toList())).list();
        //0220 收回单允许更换载具，则想收回单的newCarrier字段重新赋值，dayworkCarrier表进行修改
        List<Long> carrierIds = new ArrayList<>();
        //需要绑定的载具
        bizReturnReceipt.getDetails().forEach(l->{
            l.getCarrierIds().forEach(v->{
                carrierIds.add(v);
            });
        });
        List<BizCarrier> bizCarrierList = bizCarrierService.query().in("id", carrierIds.isEmpty()? Collections.singletonList(0L) : carrierIds).list();
        //载具不清空检测载具
        List<BizDayworkCarrier> dayworkCarrierList = bizDayworkCarrierService.query().in("daywork_id", dayworkListIds).eq("is_changed",0).eq("process_inspection_id",0).list();
        //清空载具，重新绑定
        dayworkCarrierList.forEach(item->{
            item.setIsChanged(1);
        });
        bizDayworkCarrierService.updateBatchById(dayworkCarrierList);
        //新增载具
        List<BizDayworkCarrier> needAddCarrier = new ArrayList<>();
        for(BizReturnReceiptDetail detail:bizReturnReceipt.getDetails()){
            for(Long carrierId:detail.getCarrierIds()){
                BizCarrier bizCarrier = bizCarrierList.stream().filter(e -> e.getId().equals(carrierId)).findFirst().orElse(null);
                BizDayworkCarrier dayworkCarrier = new BizDayworkCarrier();
                dayworkCarrier.setCarrierId(carrierId);
                dayworkCarrier.setCarrierCode(bizCarrier.getCode());
                dayworkCarrier.setDayworkId(detail.getDayworkId());
                needAddCarrier.add(dayworkCarrier);
            }
        }
        bizDayworkCarrierService.saveBatch(needAddCarrier);
        //向收回单明细表存
        for(BizReturnReceiptDetail bizReturnReceiptDetail : bizReturnReceipt.getDetailInfo()) {
            //存载具
            if(!needAddCarrier.isEmpty()) {
                List<BizDayworkCarrier> dayworkCarriers = needAddCarrier.stream().filter(v -> v.getDayworkId().equals(bizReturnReceiptDetail.getDayworkId())).collect(Collectors.toList());
                if(!dayworkCarriers.isEmpty()) {
                    bizReturnReceiptDetail.setNewCarrier(dayworkCarriers.stream().map(BizDayworkCarrier::getCarrierCode).collect(Collectors.joining(",")));
                    bizReturnReceiptDetail.setNewCarrierCount(dayworkCarriers.size());
                }
            }
            bizReturnReceiptDetail.setMasterId(bizReturnReceipt.getId());
            bizReturnReceiptDetail.setFormCode(bizReturnReceipt.getFormCode());
            bizReturnReceiptDetail.setSupplierId(bizReturnReceipt.getSupplierId());
            bizReturnReceiptDetail.setSupplierName(bizReturnReceipt.getSupplierName());
            bizReturnReceiptDetail.setFormDate(bizReturnReceipt.getFormDate());
            bizReturnReceiptDetail.setIsAudit(1);
            bizReturnReceiptDetail.setIsApproved(processCodes.stream().noneMatch(e -> bizReturnReceiptDetail.getProcessCode().equals(e)) ? 1 : 0);
            bizReturnReceiptDetail.setCarriers(carrierList.stream().filter(e -> bizReturnReceiptDetail.getNewCarrier().contains(e.getCode())).collect(Collectors.toList()));
            for(BizDayworkItem item: dayworkItem) {
                BizOutsourcedOrderDetailProcess currentOutsoucedOrderDetailProcess = bizOutsourcedOrderDetailProcess.stream().filter(v -> v.getDetailId().equals(item.getOutsourceDetailId()) && v.getProcessStepNumber().equals(item.getProcessStepNumber())).findFirst().orElse(null);
                if (item.getDayworkId().equals(bizReturnReceiptDetail.getDayworkId())&&item.getProcessStepNumber().equals(bizReturnReceiptDetail.getProcessStepNumber()) && item.getLotId().equals(bizReturnReceiptDetail.getLotId())) {
                    item.setStatus("3");
                    item.setEndTime(date);
                    item.setNickName(bizReturnReceiptDetail.getSupplierName());
                    //如果外协厂报工了，则将外协厂报工的数据存进dayworkItem
                    if(currentOutsoucedOrderDetailProcess.getProductionNum() !=0 || currentOutsoucedOrderDetailProcess.getQualifiedNum() !=0){
                        item.setProdNum(currentOutsoucedOrderDetailProcess.getProductionNum());
                        item.setQualifiedNum(currentOutsoucedOrderDetailProcess.getQualifiedNum());
                        //如果是最后一道工序，则吧AuditNum()赋给QualifiedNum()
                        BizOutsourcedOrderDetailProcess lastOutsourcedOrderDetailProcess = bizOutsourcedOrderDetailProcess.stream().filter(v -> v.getDetailId().equals(item.getOutsourceDetailId()))
                                .sorted(Comparator.comparing(BizOutsourcedOrderDetailProcess::getProcessStepNumber).reversed()).findFirst().orElse(null);
                    if(item.getProcessStepNumber().equals(lastOutsourcedOrderDetailProcess.getProcessStepNumber()) && item.getOutsourceDetailId().equals(bizReturnReceiptDetail.getOutsourceDetailId())){
                        item.setQualifiedNum(bizReturnReceiptDetail.getAuditNum());
                    }
                    }else{
                        item.setQualifiedNum(bizReturnReceiptDetail.getAuditNum());
                    }

                    long timeDifference = date.getTime() - item.getStartTime().getTime();
                    item.setWorkingHours(timeDifference);
                }
                if (item.getDayworkId().equals(bizReturnReceiptDetail.getDayworkId()) && item.getProcessStepNumber().equals(bizReturnReceiptDetail.getProcessStepNumber())) {
                    bizReturnReceiptDetail.setProductionPlanDetailId(item.getProductionPlanDetailId());
                    bizReturnReceiptDetail.setDayworkItemId(item.getId());
                    bizReturnReceiptDetail.setCarriers(carrierList.stream().filter(v -> Arrays.stream(bizReturnReceiptDetail.getNewCarrier().split(",")).anyMatch(t -> v.getCode().equals(t))).collect(Collectors.toList()));
                }
            }
        }
        bizDayworkItemService.updateBatchById(dayworkItem);
        List<BizReturnReceiptDetail> oldList = bizReturnReceiptDetailService.query().eq("master_id", bizReturnReceipt.getId()).list();
        saveOrUpdateBatch(bizReturnReceiptDetailService, bizReturnReceipt.getDetailInfo(),oldList);
        //如果收回单里面没收回明细，则主表同时删除
        if(bizReturnReceipt.getDetailInfo().size()==0) {
            bizReturnReceiptService.removeById(bizReturnReceipt.getId());
        }
        //如果是内部分选外协干完最后一道序，则批次收回审核后，将周转工段设置为-1
        updateOutsourceDetailDept(bizReturnReceipt.getDetailInfo());
        addProcessInspection(bizReturnReceipt.getDetailInfo(), processCodes);
        bizProcessInspecionService.saveBatch(processInspecionList);
        return success();
    }

    /**
     * 删除外协单主
带箱方式，是整单的。如果换新箱子，明细中，都需要更换箱子
     */
    @PreAuthorize("@ss.hasPermi('business:returnReceipt:remove')")
    @Log(title = "删除收回单", businessType = BusinessType.DELETE)
    @Transactional
	@DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable List<Long> ids)
    {

        List<BizReturnReceiptDetail> bizReturnReceiptDetailList = bizReturnReceiptDetailService.query().in("master_id", ids).list();
        List<Long> bizReturnReceiptDetailIds = bizReturnReceiptDetailList.stream().map(BizReturnReceiptDetail::getId).collect(Collectors.toList());
        List<Long> outsourceDetailIds= bizReturnReceiptDetailList.stream().map(BizReturnReceiptDetail::getOutsourceDetailId).collect(Collectors.toList());
        //根据回收明细查询是否已经周转
        List<BizOutsourcedOrderDetail> outsourceDetailList =  bizOutsourcedOrderDetailService.query().in("id", outsourceDetailIds).ne("production_dept_id", 0).list();
        // 判断是否已结算
        List<BizOutsourceBalanceAccount> balanceAccountList = bizOutsourceBalanceAccountService.query().in("return_receipt_id", ids).list();
        List<BizProcessInspecion> inspections = bizProcessInspecionService.query().in("return_receipt_detail_id", bizReturnReceiptDetailIds).list();
        // 判断是否已质检
        if(outsourceDetailList.size() > 0){
            throw new RuntimeException("已有批次周转下序，不能删除");
        }
        if (balanceAccountList.size() > 0) {
            throw new RuntimeException("已有外协已进入结算，不能删除");
        }
        if (inspections.size() > 0) {
            throw new RuntimeException("有外协已质检，不能删除");
        }


        bizReturnReceiptService.removeBatchByIds(ids);
        return toAjax(bizReturnReceiptDetailService.removeBatchByIds(bizReturnReceiptDetailIds));
    }

    @Log(title = "按炉结算检测", businessType = BusinessType.SELECT)
    @Transactional
    @PostMapping("/checkFurnace")
    public AjaxResult checkFurnace(@RequestBody List<BizReturnReceiptDetail> details) {
        // 判断明细中有没有按炉结算的明细
        // 判断按炉结算的明细的发出单明细是否都包含在明细内
        List<BizOutsourcedOrderDetail> orderDetails = bizOutsourcedOrderDetailService.query().in("id", details.isEmpty() ? Collections.singletonList(0L) : details.stream().map(BizReturnReceiptDetail::getOutsourceDetailId).collect(Collectors.toList())).eq("settlement_type", "2").list();
        List<BizOutsourcedOrderDetail> allOrderDetails = bizOutsourcedOrderDetailService.query().in("master_id", orderDetails.isEmpty() ? Collections.singletonList(0L) : orderDetails.stream().map(BizOutsourcedOrderDetail::getMasterId).collect(Collectors.toList())).list();
        if (allOrderDetails.isEmpty()) {
            return success(true);
        } else if (allOrderDetails.stream().allMatch(v -> details.stream().anyMatch(e -> e.getOutsourceDetailId().equals(v.getId())))) {
            return success(true);
        } else {
            // 返回信息 哪张外协发出单哪个批次没有包含进收回单
            List<BizOutsourcedOrderDetail> lackDetails = allOrderDetails.stream().filter(v -> details.stream().noneMatch(e -> e.getOutsourceDetailId().equals(v.getId()))).collect(Collectors.toList());
            Map<String, List<String>> messageSet = new HashMap<>();
            lackDetails.forEach(l -> {
                List<String> lotCodes = messageSet.get(l.getFormCode()) != null ? messageSet.get(l.getFormCode()) : new ArrayList<>();
                lotCodes.add(l.getLotCode());
                messageSet.put(l.getFormCode(), lotCodes);
            });
            AtomicReference<String> message = new AtomicReference<>("");
            messageSet.keySet().forEach(l -> {
                message.set(message + "发出单" + l + "中批次" + messageSet.get(l).stream().collect(Collectors.joining(",")) + "，");
//                        messageSet.get(l).stream().collect(Collectors.joining(","));
            });
            message.set(message + "未包含到收回单。");
            return success(message.get(), false);
        }
    }
}
