package cn.ezhizao.project.business.controller;

import cn.ezhizao.common.utils.http.HttpUtils;
import cn.ezhizao.framework.aspectj.lang.annotation.Log;
import cn.ezhizao.framework.aspectj.lang.enums.BusinessType;
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.hutool.core.io.IoUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/business/beforeCheckoutVerify")
public class BizBeforeCheckoutVerifyController extends BaseController {
    @Resource
    private IBizProcessInspecionService bizProcessInspecionService;
    @Resource
    private IBizDayworkService bizDayworkService;
    @Resource
    private IBizOutsourcedOrderDetailService bizOutsourcedOrderDetailService;
    @Resource
    private IBizReturnReceiptDetailService bizReturnReceiptDetailService;
    @Resource
    private IBizOutsourcedOrderService bizOutsourcedOrderService;
    @Resource
    private IBizOutsourcedOrderDetailProcessService bizOutsourcedOrderDetailProcessService;
    @Resource
    private IBizSupplierService bizSupplierService;
    @Resource
    private IBizSupplierProductProcessService bizSupplierProductProcessService;
    @Resource
    private IBizFurnaceNoInfoService bizFurnaceNoInfoService;
    @Resource
    private IBizProductService bizProductService;
    @Value("${p2.url}")
    private String p2Url;
    @Resource
    private IBizTechnologicalProcessService bizTechnologicalProcessService;
    @Resource
    private IBizTechnologicalProcessDetailService bizTechnologicalProcessDetailService;
    @Resource
    private IBizDayworkItemService bizDayworkItemService;
    @Resource
    private IBizOutsourceBalanceAccountService bizOutsourceBalanceAccountService;
    @Resource
    private IBizLotService bizLotService;
    @Resource
    private IBizLotTechnologicalProcessService bizLotTechnologicalProcessService;
    @Resource
    private IBizLotTechnologicalProcessDetailService bizLotTechnologicalProcessDetailService;
    @Value("${file.excelTemplate.url}")
    private  String templatePath;

    /**
     * 查询报工列表
     */
    @GetMapping("/list")
    @Log(title = "查询报工列表", businessType = BusinessType.SELECT)
    public TableDataInfo list(BizProcessInspecion bizProcessInspecion) {
        startPage();
        //查询当前生产子计划的批次报工列表
        List<BizProcessInspecion> list = bizProcessInspecionService.getVerifyList(bizProcessInspecion);
        List<BizDaywork> dayworks = bizDayworkService.query().in("id", list.isEmpty() ? Collections.singletonList(0L) : list.stream().map(BizProcessInspecion::getDayworkId).collect(Collectors.toList())).list();
        List<BizOutsourcedOrderDetail> outsourcedOrderDetails = bizOutsourcedOrderDetailService.query().in("id", list.isEmpty() ? Collections.singletonList(0L) : list.stream().map(BizProcessInspecion::getOutsourceOrderDetailId).collect(Collectors.toList())).list();
        List<BizReturnReceiptDetail> returnReceiptDetails = bizReturnReceiptDetailService.query().in("id", list.isEmpty() ? Collections.singletonList(0L) : list.stream().map(BizProcessInspecion::getReturnReceiptDetailId).collect(Collectors.toList())).list();
        list.forEach(l -> {
            l.setDaywork(dayworks.stream().filter(v -> v.getId().equals(l.getDayworkId())).findFirst().orElse(new BizDaywork()));
            l.setOutsourcedOrderDetail(outsourcedOrderDetails.stream().filter(v -> v.getId().equals(l.getOutsourceOrderDetailId())).findFirst().orElse(new BizOutsourcedOrderDetail()));
            l.setReturnReceiptDetail(returnReceiptDetails.stream().filter(v -> v.getId().equals(l.getReturnReceiptDetailId())).findFirst().orElse(new BizReturnReceiptDetail()));
        });
        //最终返回当前子计划中批次报工的工序是这个人员负责的工序
        return getDataTable(list);
    }

    @PostMapping("/reject")
    @Log(title = "外协结算前审核不通过", businessType = BusinessType.UPDATE)
    public AjaxResult reject(HttpServletRequest request, @RequestBody List<Long> ids) {
        // 判断是否已经结算 已经结算的不能改成不通过
        // 判断该结算是否为按炉结算，按炉结算需要整个发出单审核通过/取消通过。
        List<BizProcessInspecion> inspections = bizProcessInspecionService.query().in("id", ids).list();
        String authorization = request.getHeader("Authorization");
        inspections.forEach(l -> l.setAuditStatus(2));
        // 判断是否已经结算，如果已经结算则不能进行取消，未结算则删除该结算单。

        delBalanceCheckout(inspections);
        bizProcessInspecionService.updateBatchById(inspections);
        return AjaxResult.success();
    }

    @PostMapping("/confirm")
    @Log(title = "外协结算前审核通过", businessType = BusinessType.UPDATE)
    public AjaxResult confirm(HttpServletRequest request, @RequestBody List<Long> ids) {
        // 判断是否已经结算
        List<BizProcessInspecion> inspections = bizProcessInspecionService.query().in("id", ids).list();
        String authorization = request.getHeader("Authorization");
        inspections.forEach(l -> l.setAuditStatus(1));
        addBalanceCheckout(inspections, authorization);
        bizProcessInspecionService.updateBatchById(inspections);
        return AjaxResult.success();
    }

    /**
     * 判断是否按炉结算 假设按炉结算则返回该炉的所有质检单id
     * @param bizProcessInspecion 选中的质检单
     * @return 该炉所有质检单
     */
    @PostMapping("/checkFurnace")
    @Log(title = "判断是否按炉结算", businessType = BusinessType.SELECT)
    public AjaxResult checkFurnace(@RequestBody BizProcessInspecion bizProcessInspecion) {
        BizOutsourcedOrder bizOutsourcedOrder = bizOutsourcedOrderService.getById(bizProcessInspecion.getOutsourceOrderId());
        if (bizOutsourcedOrder.getSettlementType().equals("2")) {
            // 结算方式为按炉结算
            // 获取该外协单的所有明细
            List<BizOutsourcedOrderDetail> details = bizOutsourcedOrderDetailService.query().eq("master_id", bizOutsourcedOrder.getId()).list();
            List<BizProcessInspecion> processInspecionList = bizProcessInspecionService.query().in("outsource_order_detail_id", details.stream().map(BizOutsourcedOrderDetail::getId).collect(Collectors.toList())).isNull("recheck_date").eq("status", 1).list();
            // 假设有外协单明细中有一条未质检外协。则返回错误。
            if (details.stream().anyMatch(v -> processInspecionList.stream().noneMatch(p -> p.getOutsourceOrderDetailId().equals(v.getId())))) {
                return AjaxResult.error("该炉有质检单未质检");
            } else {
                return AjaxResult.success(processInspecionList.stream().map(BizProcessInspecion::getId).collect(Collectors.toList()));
            }
        } else {
            return AjaxResult.success(Collections.singletonList(bizProcessInspecion.getId()));
        }
    }
    @PostMapping("/checkMultiplyFurnace")
    @Log(title = "检查炉号", businessType = BusinessType.SELECT)
    public AjaxResult checkMultiplyFurnace(@RequestBody List<BizProcessInspecion> bizProcessInspecionList) {
        List<Long> outsourcedOrderIds = bizProcessInspecionList.stream().map(BizProcessInspecion::getOutsourceOrderId).collect(Collectors.toList());
        List<BizOutsourcedOrder> bizOutsourcedOrderList = bizOutsourcedOrderService.query().in("id", outsourcedOrderIds).list();
        List<BizOutsourcedOrderDetail> detailList = bizOutsourcedOrderDetailService.query().in("master_id",outsourcedOrderIds).list();
        List<BizProcessInspecion> processInspecionLists = bizProcessInspecionService.query().in("outsource_order_detail_id", detailList.stream().map(BizOutsourcedOrderDetail::getId).collect(Collectors.toList())).isNull("recheck_date").eq("status", 1).list();
       for (BizOutsourcedOrder v : bizOutsourcedOrderList){
            if(v.getSettlementType().equals("2")){
                // 结算方式为按炉结算
                // 获取该外协单的所有明细
                List<BizOutsourcedOrderDetail> details = detailList.stream().filter(l -> l.getMasterId().equals(v.getId())).collect(Collectors.toList());
                List<BizProcessInspecion> processInspecionList = processInspecionLists.stream()
                        .filter(l -> details.stream()
                                .map(BizOutsourcedOrderDetail::getId)
                                .collect(Collectors.toList())
                                .contains(l.getOutsourceOrderDetailId())
                                && l.getRecheckDate() == null
                                && l.getStatus() == 1)
                        .collect(Collectors.toList());
                // 假设有外协单明细中有一条未质检外协。则返回错误。
                if (details.stream().anyMatch(t -> processInspecionList.stream().noneMatch(p -> p.getOutsourceOrderDetailId().equals(t.getId())))) {
                    return AjaxResult.error("该炉有质检单未质检");
                }
            }
        }
        return AjaxResult.success(bizProcessInspecionList.stream().map(BizProcessInspecion::getId).collect(Collectors.toList()));
    }

    @Log(title = "查询外协结算审核列表", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, BizProcessInspecion bizProcessInspecion) throws NoSuchFieldException, IllegalAccessException, IOException {
        List<BizProcessInspecion> list = bizProcessInspecionService.getVerifyList(bizProcessInspecion);
        List<BizDaywork> dayworks = bizDayworkService.query().in("id", list.isEmpty() ? Collections.singletonList(0L) : list.stream().map(BizProcessInspecion::getDayworkId).collect(Collectors.toList())).list();
        List<BizOutsourcedOrderDetail> outsourcedOrderDetails = bizOutsourcedOrderDetailService.query().in("id", list.isEmpty() ? Collections.singletonList(0L) : list.stream().map(BizProcessInspecion::getOutsourceOrderDetailId).collect(Collectors.toList())).list();
        List<BizReturnReceiptDetail> returnReceiptDetails = bizReturnReceiptDetailService.query().in("id", list.isEmpty() ? Collections.singletonList(0L) : list.stream().map(BizProcessInspecion::getReturnReceiptDetailId).collect(Collectors.toList())).list();
        List<BizSupplier> suppliers = bizSupplierService.query().in("id", outsourcedOrderDetails.isEmpty() ? Collections.singletonList(0L) : outsourcedOrderDetails.stream().map(BizOutsourcedOrderDetail::getSupplierId).collect(Collectors.toList())).list();
        list.forEach(l -> {
            l.setDaywork(dayworks.stream().filter(v -> v.getId().equals(l.getDayworkId())).findFirst().orElse(new BizDaywork()));
            l.setOutsourcedOrderDetail(outsourcedOrderDetails.stream().filter(v -> v.getId().equals(l.getOutsourceOrderDetailId())).findFirst().orElse(new BizOutsourcedOrderDetail()));
            l.setReturnReceiptDetail(returnReceiptDetails.stream().filter(v -> v.getId().equals(l.getReturnReceiptDetailId())).findFirst().orElse(new BizReturnReceiptDetail()));
            BizSupplier supplier = suppliers.stream().filter(e -> l.getOutsourcedOrderDetail() != null && e.getId().equals(l.getOutsourcedOrderDetail().getSupplierId())).findFirst().orElse(new BizSupplier());
            l.setSupplierName(supplier.getName());
            l.setMnemonicCode(supplier.getMnemonicCode());
            Integer materialLoss = l.getOutsourcedOrderDetail().getProductNum() - l.getReturnReceiptDetail().getAuditNum();
            l.setMaterialLoss(materialLoss);
        });
        String template = "processInspectionTemplate";
        String templateFilePath =  templatePath + template + ".xlsx";
        List<Map<String, Object>> exportList = new ArrayList<>();
        list.forEach(l -> {
            Arrays.stream(l.getProcessNames().split(",")).forEach(v -> {
                Map<String, Object> value = new HashMap<>();
                value.put("mnemonicCode", l.getMnemonicCode());
                value.put("supplierName", l.getSupplierName());
                value.put("productDescription", l.getProductDescription());
                value.put("lotCode", l.getLotCode());
                value.put("productNum", l.getOutsourcedOrderDetail().getProductNum());
                value.put("auditNum", l.getReturnReceiptDetail().getAuditNum());
                value.put("materialLoss", l.getMaterialLoss());
                value.put("processName", v);
                value.put("outsourceDate", l.getOutsourcedOrderDetail().getFormDate());
                value.put("returnReceiptDate", l.getReturnReceiptDetail().getFormDate());
                value.put("auditDate", l.getAuditStatus().equals(1) ? l.getUpdateTime() : null);
//                value.put("balanceDate", l.getBalanceDate());
                value.put("outsourcedOrderDetailFormCode", l.getOutsourcedOrderDetail().getFormCode());
                value.put("returnReceiptDetailFormCode", l.getReturnReceiptDetail().getFormCode());
                value.put("carrierNum", l.getOutsourcedOrderDetail().getCarrierNum());
                value.put("auditStatus", l.getAuditStatus().equals(1) ? "已审核" : "未审核");
                exportList.add(value);
            });
        });
        com.alibaba.excel.ExcelWriter writer = EasyExcel.write(response.getOutputStream())
                .withTemplate(templateFilePath)
                .build();
        WriteSheet firstSheet = EasyExcel.writerSheet(0).build();
        FillConfig fillConfig = FillConfig.builder()
                // 开启填充行 不开启是在一行覆盖，开启会创建新的行
                .forceNewRow(true)
                .build();
        // 执行填充操作
        writer.fill(exportList, fillConfig, firstSheet);
        writer.finish();
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        //test.xls是弹出下载对话框的文件名，不能为中文，中文请自行编码
        response.setHeader("Content-Disposition", "attachment;filename=test.xlsx");
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //此处记得关闭输出Servlet流
        IoUtil.close(out);
//        bizOutsourcedOrderService.exportTemplateProvinceAreaData(response, bizOutsourcedOrder);
    }

    private void addBalanceCheckout(List<BizProcessInspecion> inspections, String authorization) {
        // HttpUtils.sentPostJson()
        // 获取外协商
        List<BizOutsourcedOrder> outsourcedOrder = bizOutsourcedOrderService.query().in("id", inspections.isEmpty() ? Collections.singletonList(0L) : inspections.stream().map(BizProcessInspecion::getOutsourceOrderId).collect(Collectors.toList())).list();
        List<BizOutsourcedOrderDetail> bizOutsourcedOrderDetails = bizOutsourcedOrderDetailService.query().in("id", inspections.isEmpty() ? Collections.singletonList(0L) : inspections.stream().map(BizProcessInspecion::getOutsourceOrderDetailId).collect(Collectors.toList())).list();
        List<BizOutsourcedOrderDetailProcess> bizOutsourcedOrderDetailProcesses = bizOutsourcedOrderDetailProcessService.query().in("detail_id", inspections.isEmpty() ? Collections.singletonList(0L) : inspections.stream().map(BizProcessInspecion::getOutsourceOrderDetailId).collect(Collectors.toList())).list();
        List<BizSupplier> suppliers = bizSupplierService.query().in("id", outsourcedOrder.isEmpty() ? Collections.singletonList(0L) : outsourcedOrder.stream().map(BizOutsourcedOrder::getSupplierId).collect(Collectors.toList())).list();
        List<BizSupplierProductProcess> bizSupplierProductProcesses = bizSupplierProductProcessService.query().in("concat(supplier_id, product_id)", bizOutsourcedOrderDetails.isEmpty() ? Collections.singletonList(0L) : bizOutsourcedOrderDetails.stream().map(v -> v.getSupplierId().toString() + v.getProductId().toString()).collect(Collectors.toList())).list();
        // 获取炉号
        List<BizDaywork> dayworks = bizDayworkService.query().in("id", inspections.isEmpty() ? Collections.singletonList(0L) : inspections.stream().map(BizProcessInspecion::getDayworkId).collect(Collectors.toList())).list();
        List<BizLot> bizLotList = bizLotService.query().in("id", dayworks.isEmpty() ? Collections.singletonList(0L) : dayworks.stream().map(BizDaywork::getLotId).collect(Collectors.toList())).list();
        List<BizTechnologicalProcess> bizTechnologicalProcesses = bizTechnologicalProcessService.query().in("id", dayworks.isEmpty() ? Collections.singletonList(0L) : dayworks.stream().map(BizDaywork::getTechnologicalProcessId).collect(Collectors.toList())).list();
        List<BizTechnologicalProcessDetail> bizTechnologicalProcessDetails = bizTechnologicalProcessDetailService.query().in("technological_process_id", bizTechnologicalProcesses.isEmpty() ? Collections.singletonList(0L) : bizTechnologicalProcesses.stream().map(BizTechnologicalProcess::getId).collect(Collectors.toList())).list();
        List<BizLotTechnologicalProcess> bizLotTechnologicalProcesses = bizLotTechnologicalProcessService.query().in("id", dayworks.isEmpty() ? Collections.singletonList(0L) : dayworks.stream().map(BizDaywork::getTechnologicalProcessId).collect(Collectors.toList())).list();
        List<BizLotTechnologicalProcessDetail> bizLotTechnologicalProcessDetails = bizLotTechnologicalProcessDetailService.query().in("lot_technological_process_id", bizLotTechnologicalProcesses.isEmpty() ? Collections.singletonList(0L) : bizLotTechnologicalProcesses.stream().map(BizLotTechnologicalProcess::getId).collect(Collectors.toList())).list();
        List<BizFurnaceNoInfo> furnaceNoInfos = bizFurnaceNoInfoService.query().in("daywork_id", dayworks.isEmpty() ? Collections.singletonList(0L) : dayworks.stream().map(BizDaywork::getId).collect(Collectors.toList())).list();
        List<BizProduct> bizProducts = bizProductService.query().in("id", inspections.isEmpty() ? Collections.singletonList(0L) : inspections.stream().map(BizProcessInspecion::getProductId).collect(Collectors.toList())).list();
        List<BizReturnReceiptDetail> bizReturnReceiptDetails = bizReturnReceiptDetailService.query().in("outsource_detail_id", bizOutsourcedOrderDetails.isEmpty() ? Collections.singletonList(0L) : bizOutsourcedOrderDetails.stream().map(BizOutsourcedOrderDetail::getId).collect(Collectors.toList())).list();
        List<BizDayworkItem> bizDayworkItems = bizDayworkItemService.query().in("outsource_detail_id", bizOutsourcedOrderDetails.isEmpty() ? Collections.singletonList(0L) : bizOutsourcedOrderDetails.stream().map(BizOutsourcedOrderDetail::getId).collect(Collectors.toList())).list();
        // 获取原料信息
        List<BizOutsourceBalanceAccount> params = new ArrayList<>();
        inspections.forEach(l -> {
            BizOutsourceBalanceAccount bizOutsourceBalanceAccount = new BizOutsourceBalanceAccount();
            bizOutsourceBalanceAccount.setProcessInspectionId(l.getId());
            BizProduct bizProduct = bizProducts.stream().filter(b -> b.getId().equals(l.getProductId())).findFirst().orElse(new BizProduct());
            bizOutsourceBalanceAccount.setProductCode(bizProduct.getProductCode());
            BizFurnaceNoInfo furnaceNoInfo = furnaceNoInfos.stream().filter(b -> b.getDayworkId().equals(l.getDayworkId())).findFirst().orElse(new BizFurnaceNoInfo());
            bizOutsourceBalanceAccount.setRawMaterialCode(furnaceNoInfo.getRawMaterialCode());
            BizOutsourcedOrder bizOutsourcedOrder = outsourcedOrder.stream().filter(b -> b.getId().equals(l.getOutsourceOrderId())).findFirst().orElse(new BizOutsourcedOrder());
            BizSupplier bizSupplier = suppliers.stream().filter(b -> b.getId().equals(bizOutsourcedOrder.getSupplierId())).findFirst().orElse(new BizSupplier());
            bizOutsourceBalanceAccount.setSupplierCode(bizSupplier.getCode());
            params.add(bizOutsourceBalanceAccount);
        });
        JSONObject jsonObject = requestMaterialInfo(params, authorization);
        if (jsonObject.getInt("code").equals(200)) {
            // 用结果来添加结算记录。
            // 判断当有报工明细没有炉号信息则输出错误
            JSONArray array = jsonObject.getJSONArray("data");
            List<BizOutsourceBalanceAccount> returnArray = array.toList(BizOutsourceBalanceAccount.class);
            if(returnArray.stream().anyMatch(v -> v.getBizMaterialBase() == null || v.getBizMaterialBaseInfo() == null)) {
                throw new RuntimeException("有产品没有材料信息");
            }
            List<BizOutsourceBalanceAccount> addList = new ArrayList<>();
            returnArray.forEach(l -> {
                if (l.getSupplier() == null) {
                    throw new RuntimeException("找不到外协厂数据，请联系管理员");
                }
                BizProcessInspecion bizProcessInspecion = inspections.stream().filter(b -> b.getId().equals(l.getProcessInspectionId())).findFirst().orElse(new BizProcessInspecion());
                BizOutsourcedOrder bizOutsourcedOrder = outsourcedOrder.stream().filter(b -> b.getId().equals(bizProcessInspecion.getOutsourceOrderId())).findFirst().orElse(new BizOutsourcedOrder());
                BizSupplier bizSupplier = suppliers.stream().filter(b -> b.getId().equals(bizOutsourcedOrder.getSupplierId())).findFirst().orElse(new BizSupplier());
                BizOutsourcedOrderDetail bizOutsourcedOrderDetail = bizOutsourcedOrderDetails.stream().filter(b -> b.getId().equals(bizProcessInspecion.getOutsourceOrderDetailId())).findFirst().orElse(new BizOutsourcedOrderDetail());
                List<BizOutsourcedOrderDetailProcess> detailProcesses = bizOutsourcedOrderDetailProcesses.stream().filter(b -> b.getDetailId().equals(bizOutsourcedOrderDetail.getId())).collect(Collectors.toList());
                BizDaywork bizDaywork = dayworks.stream().filter(b -> b.getId().equals(bizProcessInspecion.getDayworkId())).findFirst().orElse(new BizDaywork());
                BizLot lot = bizLotList.stream().filter(b -> b.getId().equals(bizDaywork.getLotId())).findFirst().orElse(new BizLot());
                BizProduct bizProduct = bizProducts.stream().filter(b -> b.getId().equals(bizProcessInspecion.getProductId())).findFirst().orElse(new BizProduct());
                BizFurnaceNoInfo furnaceNoInfo = furnaceNoInfos.stream().filter(b -> b.getDayworkId().equals(bizDaywork.getId())).findFirst().orElse(new BizFurnaceNoInfo());
                List<BizReturnReceiptDetail> receiptDetails = bizReturnReceiptDetails.stream().filter(b -> b.getOutsourceDetailId().equals(bizOutsourcedOrderDetail.getId())).collect(Collectors.toList());
                BizTechnologicalProcess process = bizTechnologicalProcesses.stream().filter(b -> b.getId().equals(bizDaywork.getTechnologicalProcessId())).findFirst().orElse(new BizTechnologicalProcess());
                List<BizTechnologicalProcessDetail> processDetails = bizTechnologicalProcessDetails.stream().filter(b -> b.getTechnologicalProcessId().equals(process.getId())).sorted(Comparator.comparing(BizTechnologicalProcessDetail::getProcessStepNumber)).collect(Collectors.toList());
                BizLotTechnologicalProcess lotProcess = bizLotTechnologicalProcesses.stream().filter(b -> b.getId().equals(bizDaywork.getTechnologicalProcessId())).findFirst().orElse(new BizLotTechnologicalProcess());
                List<BizLotTechnologicalProcessDetail> lotProcessDetails = bizLotTechnologicalProcessDetails.stream().filter(b -> b.getLotTechnologicalProcessId().equals(lotProcess.getId())).sorted(Comparator.comparing(BizLotTechnologicalProcessDetail::getProcessStepNumber)).collect(Collectors.toList());
                List<BizDayworkItem> items = bizDayworkItems.stream().filter(b -> b.getOutsourceDetailId().equals(bizOutsourcedOrderDetail.getId())).collect(Collectors.toList());
                List<BizSupplierProductProcess> supplierProductProcesses = bizSupplierProductProcesses.stream().filter(b -> b.getSupplierId().equals(bizSupplier.getId()) && b.getProductId().equals(bizProduct.getId())).collect(Collectors.toList());
                addList.addAll(bizDaywork.getIsAmend().equals(1) || bizDaywork.getIsWasteRecycling().equals(1L) ? getBalanceAccounts(l, bizOutsourcedOrder, bizSupplier, bizOutsourcedOrderDetail, detailProcesses, bizDaywork, bizProduct, furnaceNoInfo, receiptDetails, bizProcessInspecion, lotProcess, lotProcessDetails, items, lot, supplierProductProcesses) : getBalanceAccounts(l, bizOutsourcedOrder, bizSupplier, bizOutsourcedOrderDetail, detailProcesses, bizDaywork, bizProduct, furnaceNoInfo, receiptDetails, bizProcessInspecion, process, processDetails, items, lot, supplierProductProcesses));
            });
            // System.out.println("184: " + addList.size());
            List<Long> outsourceOrderIds = addList.stream().map(BizOutsourceBalanceAccount::getOutsourceOrderId).collect(Collectors.toList());

            // 判断假设是按支结算则直接算，假设是按炉结算
            // 应得金额
            // 实得金额 = round((应得金额-其他扣款+差补额-运费-料扣金额/(1+税率/100), 4)
            // 含税金额 = round((应得金额-其他扣款+差补额-运费-料扣金额, 4)
            // 运费 round(运费单价【sfc10100.yfprc】 * 发出箱数 , 4)
            if (outsourceOrderIds.stream().distinct().count() == 1) {
                BizOutsourcedOrder bizOutsourcedOrder = outsourcedOrder.get(0);
                if (bizOutsourcedOrder.getSettlementType().equals("1")) {
                    // 按支结算
                    addList.forEach(l -> {

                        // System.out.println(l.getReceiptNum());
                        // System.out.println(l.getProcessPrice());
                        // System.out.println(l.getTaxRate());
                        // System.out.println(l.getOutputNum());
                        // 是否有表面处理
                        BigDecimal processPrice = l.getProcessPrice() == null ? BigDecimal.ZERO : l.getProcessPrice();
                        if (l.getSupplier().getSurfaceTreatment().equals("N")) {
                            if (l.getSupplierCode().equals("99024")) {
                                if (l.getProcessCode().equals("99000")) {
                                    l.setPlanAmount(BigDecimal.valueOf(l.getReceiptNum()).multiply(processPrice).multiply(BigDecimal.ONE.add(l.getTaxRate().divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP))).setScale(4, RoundingMode.HALF_UP));
                                } else {
                                    l.setPlanAmount(BigDecimal.valueOf(l.getOutputNum()).multiply(processPrice).multiply(BigDecimal.ONE.add(l.getTaxRate().divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP))).setScale(4, RoundingMode.HALF_UP));
                                }
                            } else {
                                l.setPlanAmount(BigDecimal.valueOf(l.getReceiptNum()).multiply(processPrice).multiply(BigDecimal.ONE.add(l.getTaxRate().divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP))).setScale(4, RoundingMode.HALF_UP));
                            }
                        } else {
                            if (l.getSupplierCode().equals("99024")) {
                                l.setPlanAmount(BigDecimal.valueOf(l.getOutputNum()).multiply(processPrice).multiply(BigDecimal.ONE.add(l.getTaxRate().divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP))).setScale(4, RoundingMode.HALF_UP));
                            } else {
                                l.setPlanAmount(BigDecimal.valueOf(l.getReceiptNum()).multiply(processPrice).multiply(BigDecimal.ONE.add(l.getTaxRate().divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP))).setScale(4, RoundingMode.HALF_UP));
                            }
                        }
                    });
                } else {
                    // 按炉结算 炉数*加工单价* (1.00 + 税率 /100.00 )
                    BizOutsourceBalanceAccount item = addList.get(0);
                    addList.forEach(l -> {
                        l.setProcessPrice(l.getSupplier().getFreightPrice());
                    });
//                    if (item.getSupplier() == null) {
//                        System.out.println("未找到供应商");
//                    }else {
//                        System.out.println("加工单价：" + item.getSupplier().getFreightPrice());
//                    }
                    BigDecimal freightPrice = item.getSupplier().getFreightPrice() == null ? BigDecimal.ZERO : item.getSupplier().getFreightPrice();
                    item.setPlanAmount(BigDecimal.ONE.multiply(freightPrice).multiply(BigDecimal.ONE.add(item.getTaxRate().divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP))).setScale(4, RoundingMode.HALF_UP));
                }
                bizOutsourcedOrderDetails.forEach(l -> {
                   BizOutsourceBalanceAccount item = addList.stream().filter(e -> e.getOutsourceOrderDetailId().equals(l.getId())).collect(Collectors.toList()).get(0);
                   item.setFreightAmount(item.getSupplier().getFreightDeductUnitPrice().multiply(BigDecimal.valueOf(item.getCarrierNum())));
                });
            } else {
                // 八成用不上，但是假设出现多选审核就可能用得上了。
                outsourcedOrder.forEach(t -> {
                    if (t.getSettlementType().equals("1")) {
                        // 按支结算
                        addList.stream().filter(e -> e.getOutsourceOrderId().equals(t.getId())).forEach(l -> {
                            // System.out.println(l.getReceiptNum());
                            // System.out.println(l.getProcessPrice());
                            // System.out.println(l.getTaxRate());
                            // System.out.println(l.getOutputNum());
                            BigDecimal processPrice = l.getProcessPrice() == null ? BigDecimal.ZERO : l.getProcessPrice();
                            if (l.getSupplier().getSurfaceTreatment().equals("N")) {
                                if (l.getSupplierCode().equals("99024")) {
                                    if (l.getProcessCode().equals("99000")) {
                                        l.setPlanAmount(BigDecimal.valueOf(l.getReceiptNum()).multiply(processPrice).multiply(BigDecimal.ONE.add(l.getTaxRate().divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP))).setScale(4, RoundingMode.HALF_UP));
                                    } else {
                                        l.setPlanAmount(BigDecimal.valueOf(l.getOutputNum()).multiply(processPrice).multiply(BigDecimal.ONE.add(l.getTaxRate().divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP))).setScale(4, RoundingMode.HALF_UP));
                                    }
                                } else {
                                    l.setPlanAmount(BigDecimal.valueOf(l.getReceiptNum()).multiply(processPrice).multiply(BigDecimal.ONE.add(l.getTaxRate().divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP))).setScale(4, RoundingMode.HALF_UP));
                                }
                            } else {
                                if (l.getSupplierCode().equals("99024")) {
                                    l.setPlanAmount(BigDecimal.valueOf(l.getOutputNum()).multiply(processPrice).multiply(BigDecimal.ONE.add(l.getTaxRate().divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP))).setScale(4, RoundingMode.HALF_UP));
                                } else {
                                    l.setPlanAmount(BigDecimal.valueOf(l.getReceiptNum()).multiply(processPrice).multiply(BigDecimal.ONE.add(l.getTaxRate().divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP))).setScale(4, RoundingMode.HALF_UP));
                                }
                            }
                        });
                    } else {
                        // 按炉结算 round(炉数 * 加工单价 * (1.00 + 税率 /100.00 ),4)
                        BizOutsourceBalanceAccount item = addList.stream().filter(e -> e.getOutsourceOrderId().equals(t.getId())).collect(Collectors.toList()).get(0);
                        addList.stream().filter(e -> e.getOutsourceOrderId().equals(t.getId())).collect(Collectors.toList()).forEach(l -> {
                            l.setProcessPrice(l.getSupplier().getFreightPrice());
                        });
                        BigDecimal freightPrice = item.getSupplier().getFreightPrice() == null ? BigDecimal.ZERO : item.getSupplier().getFreightPrice();
                        item.setPlanAmount(BigDecimal.ONE.multiply(freightPrice).multiply(BigDecimal.ONE.add(item.getTaxRate().divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP))).setScale(4, RoundingMode.HALF_UP));
                    }
                });
                bizOutsourcedOrderDetails.forEach(l -> {
                    BizOutsourceBalanceAccount item = addList.stream().filter(e -> e.getOutsourceOrderDetailId().equals(l.getId())).collect(Collectors.toList()).get(0);
                    item.setFreightAmount(item.getSupplier().getFreightDeductUnitPrice().multiply(BigDecimal.valueOf(item.getCarrierNum())));
                });
            }
            addList.forEach(l -> {
                BigDecimal planAmount = l.getPlanAmount() == null ? BigDecimal.ZERO : l.getPlanAmount();
                BigDecimal otherCost = l.getOtherCost() == null ? BigDecimal.ZERO : l.getOtherCost();
                BigDecimal fillDifferencePrice = l.getFillDifferencePrice() == null ? BigDecimal.ZERO : l.getFillDifferencePrice();
                BigDecimal freightAmount = l.getFreightAmount() == null ? BigDecimal.ZERO : l.getFreightAmount();
                BigDecimal materialLossAmount = l.getMaterialLossAmount() == null ? BigDecimal.ZERO : l.getMaterialLossAmount();
                BigDecimal taxAmount = planAmount.subtract(otherCost).add(fillDifferencePrice).subtract(freightAmount).subtract(materialLossAmount);
                l.setAcutalAmount(taxAmount.divide(BigDecimal.ONE.add(l.getTaxRate().divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP)), 4, RoundingMode.HALF_UP));
                l.setTaxAmount(taxAmount.setScale(4, RoundingMode.HALF_UP));
            });
            bizOutsourceBalanceAccountService.saveBatch(addList);
        } else {
            throw new RuntimeException(jsonObject.getStr("msg"));
        }
    }

    private JSONObject requestMaterialInfo(List<BizOutsourceBalanceAccount> balanceAccounts, String authorization) {
        Map<String, String> headers = new HashMap<>();
        headers.put("Authorization", authorization);
        String result = HttpUtils.sentPostJson(p2Url + "business/outsourceBalance/getSettlementInfo",  new JSONArray(balanceAccounts).toString(), headers);
        System.out.println(result);
        // 添加结算记录
        return new JSONObject(result);
    }

    private List<BizOutsourceBalanceAccount> getBalanceAccounts(BizOutsourceBalanceAccount l, BizOutsourcedOrder bizOutsourcedOrder, BizSupplier bizSupplier, BizOutsourcedOrderDetail bizOutsourcedOrderDetail, List<BizOutsourcedOrderDetailProcess> detailProcesses, BizDaywork bizDaywork, BizProduct bizProduct, BizFurnaceNoInfo furnaceNoInfo, List<BizReturnReceiptDetail> receiptDetails, BizProcessInspecion bizProcessInspecion, BizTechnologicalProcess bizTechnologicalProcess, List<BizTechnologicalProcessDetail> technologicalProcessDetails, List<BizDayworkItem> items, BizLot lot, List<BizSupplierProductProcess> supplierProductProcesses) {
        List<BizOutsourceBalanceAccount> addList = new ArrayList<>();
        detailProcesses.forEach(v -> {
            BizReturnReceiptDetail receiptDetail = receiptDetails.stream().filter(b -> b.getOutsourceDetailId().equals(v.getDetailId()) && b.getProcessId().equals(v.getProcessId())).findFirst().orElse(new BizReturnReceiptDetail());
            BizDayworkItem item = items.stream().filter(b -> b.getOutsourceDetailId().equals(v.getDetailId()) && b.getProcessId().equals(v.getProcessId())).findFirst().orElse(new BizDayworkItem());
//            System.out.println("301 daywork_item_id" + item.getId());
//            System.out.println("302 outsource_detail_id" + v.getDetailId());
//            System.out.println("303 process_id" + v.getProcessId());
            BizTechnologicalProcessDetail bizTechnologicalProcessDetail = technologicalProcessDetails.stream().filter(b -> b.getProcessStepNumber().equals(v.getProcessStepNumber())).findFirst().orElse(new BizTechnologicalProcessDetail());
            BizSupplierProductProcess supplierProductProcess = supplierProductProcesses.stream().filter(b -> b.getProcessId().equals(v.getProcessId())).findFirst().orElse(new BizSupplierProductProcess());
            BizOutsourceBalanceAccount balanceAccount = new BizOutsourceBalanceAccount();
            balanceAccount.setProcessInspectionId(l.getProcessInspectionId());
            balanceAccount.setRawMaterialCode(furnaceNoInfo.getRawMaterialCode());
            balanceAccount.setSupplierCode(bizSupplier.getCode());
            balanceAccount.setSupplierName(bizSupplier.getName());
            balanceAccount.setOutsourceOrderDetailId(bizOutsourcedOrderDetail.getId());
            balanceAccount.setTenantId(getLoginUser().getTenantId());
            balanceAccount.setSupplierId(bizSupplier.getId());
            balanceAccount.setCurrency("RMB");
            balanceAccount.setType(l.getBizMaterialBase().getType());
            balanceAccount.setAuditDate(new Date());
            balanceAccount.setReturnReceiptId(receiptDetail.getMasterId());
            balanceAccount.setReturnReceiptDetailId(receiptDetail.getId());
            balanceAccount.setDayworkId(bizDaywork.getId());
            balanceAccount.setDayworkItemId(item.getId());
            balanceAccount.setSettlementType(bizOutsourcedOrder.getSettlementType());
            balanceAccount.setLotId(bizDaywork.getLotId());
            balanceAccount.setLotCode(bizDaywork.getLotCode());
            balanceAccount.setProductId(bizProduct.getId());
            balanceAccount.setProductDescription(bizProduct.getDescription());
            balanceAccount.setProductCode(bizProduct.getProductCode());
            balanceAccount.setTechnologicalProcessId(bizTechnologicalProcess.getId());
            balanceAccount.setTechnologyVersion(bizTechnologicalProcess.getTechnologyVersion());
            balanceAccount.setTechnologicalProcessDetailId(bizTechnologicalProcessDetail.getId());
            balanceAccount.setProcessId(v.getProcessId());
            balanceAccount.setProcessStepNumber(v.getProcessStepNumber());
            balanceAccount.setProcessAlias(v.getProcessAlias());
            balanceAccount.setProcessCode(v.getProcessCode());
            balanceAccount.setOutsourceOrderDetailProcessId(v.getId());
            balanceAccount.setOutsourceOrderId(bizOutsourcedOrder.getId());
            balanceAccount.setIsAmend(bizDaywork.getIsAmend());
            balanceAccount.setIsWasteRecycling(bizDaywork.getIsWasteRecycling());
            // 产品数量
            balanceAccount.setProductNum(lot.getProductionQuantity());
            // 批次投产数量
            balanceAccount.setProductionNum(lot.getProductionQuantity());
            // 外协发出数量
            balanceAccount.setOutputNum(bizOutsourcedOrderDetail.getProductNum());
            // 收回审核数量
            balanceAccount.setReceiptNum(receiptDetail.getAuditNum());
            // 工序单价
            balanceAccount.setProcessPrice(supplierProductProcess.getPrice());
            // 材料单价 inv10100.zjunprc
            balanceAccount.setMaterialPrice(l.getBizMaterialBase().getZjunprc());
            // 销售单价 inc10100.unprc
            balanceAccount.setSalePrice(l.getProduct().getUnprc());
            // 实投料量 假设为直条料或圆盘料或半成品料
            System.out.println("投料类型是否半成品：" + l.getBizMaterialBase().getType());
            System.out.println("投料类型：" + l.getBizMaterialBase().getXzcode());
            if (l.getBizMaterialBase().getXzcode().equals("11") || l.getBizMaterialBase().getXzcode().equals("12") || l.getBizMaterialBase().getType().equals("2")) {
                // 计算公式 实际投料直径 / 2 * 实际投料直径 / 2 * 3.14 * 原料密度 / 1000 * (产品长度  + 公差长度【bom30101.gccd（材料基本信息表）按cpart产品编码取，生产计划随时变动结算时实时获取】) / 原材料利用率 / 10000
                BigDecimal length = bizProduct.getLenght();
                BigDecimal gccd = l.getBizMaterialBaseInfo().getGccd();
                BigDecimal stll = l.getBizMaterialBase().getYzj().divide(BigDecimal.valueOf(2), 6, RoundingMode.HALF_UP).pow(2).multiply(BigDecimal.valueOf(3.14)).multiply(l.getBizMaterialBase().getDensity().divide(BigDecimal.valueOf(1000), 6, RoundingMode.HALF_UP)).multiply(length.add(gccd)).divide(l.getBizMaterialBaseInfo().getUtrate() == null || l.getBizMaterialBaseInfo().getUtrate().compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ONE : l.getBizMaterialBaseInfo().getUtrate(), 6, RoundingMode.HALF_UP).divide(BigDecimal.valueOf(10000), 6, RoundingMode.HALF_UP).setScale(4, RoundingMode.HALF_UP);
                balanceAccount.setActualInventory(stll);
            } else {
                // 其他 inc10100.stqty
                balanceAccount.setActualInventory(l.getProduct().getStqty());
            }
            // 料损数量 99984与99024无料损数量
            if (bizSupplier.getCode().equals("99984") || bizSupplier.getCode().equals("99024")) {
                balanceAccount.setMaterialLoss(0);
            } else {
                // 其他外协厂[料损数量]计算公式=发出数量 * (1 - 料损率 / 1000) - 合格数量，结果取整 【料损率从外协厂基础配置表中读】
                Integer materialLoss = BigDecimal.valueOf(bizOutsourcedOrderDetail.getProductNum()).multiply(BigDecimal.ONE.subtract(bizSupplier.getLossLimit().divide(BigDecimal.valueOf(1000), 6, RoundingMode.HALF_UP))).subtract(BigDecimal.valueOf(receiptDetail.getAuditNum())).setScale(0, RoundingMode.HALF_UP).intValue();
                balanceAccount.setMaterialLoss(materialLoss);
            }

//            System.out.println("263 getMaterialLoss: " + l.getMaterialLoss());
            balanceAccount.setMaterialLoss(balanceAccount.getMaterialLoss() == null || balanceAccount.getMaterialLoss() < 0 ? 0 : balanceAccount.getMaterialLoss());
//            System.out.println("265 getMaterialLoss: " + l.getMaterialLoss());

            // 表面表示是否有表面处理
//            if (l.getSupplier() == null) {
//                throw new RuntimeException("找不到外协厂数据，请联系管理员");
//            }
            balanceAccount.setSurfaceTreatment(l.getSupplier().getSurfaceTreatment());
            balanceAccount.setCarrierNum(bizOutsourcedOrderDetail.getNewCarrierCount());
            int sort = technologicalProcessDetails.indexOf(technologicalProcessDetails.stream().filter(t -> t.getProcessStepNumber().equals(v.getProcessStepNumber())).findFirst().orElse(new BizTechnologicalProcessDetail()));
            balanceAccount.setProcessSort(sort);
            balanceAccount.setReturnDate(receiptDetail.getFormDate());
            balanceAccount.setReturnNo(receiptDetail.getFormCode());
            balanceAccount.setOutsourceNo(bizOutsourcedOrder.getFormCode());
            balanceAccount.setFurnaceNum(1);
            balanceAccount.setCheckDate(bizProcessInspecion.getEndTime());
            balanceAccount.setMaterialLossRatio(bizSupplier.getLossLimit());
            balanceAccount.setShape(l.getBizMaterialBase().getXzcode());
            balanceAccount.setDensity(l.getBizMaterialBase().getDensity());
            balanceAccount.setWastePriceCategory(l.getSupplier().getWastePriceCategory());
            balanceAccount.setTaxRate(BigDecimal.valueOf(l.getSupplier().getTaxRatio()));
            balanceAccount.setTolerance(l.getBizMaterialBase().getGccd());
            balanceAccount.setMaterialDiameter(l.getBizMaterialBase().getYzj());
            balanceAccount.setInspectionNo(bizProcessInspecion.getOutsourcedInspectionNo());
            BigDecimal processPrice = balanceAccount.getProcessPrice() == null ? BigDecimal.ZERO : balanceAccount.getProcessPrice();

            // 废品单价
            if (l.getSupplier().getSurfaceTreatment().equals("N")){
                System.out.println("废品价类别：" + l.getSupplier().getWastePriceCategory());
                System.out.println("最近采购单价：" + l.getBizMaterialBase().getZjunprc());
                // 没表面处理时
                if (l.getSupplier().getWastePriceCategory().equals("11")) {
                    // 废品价计算类别='11' round(实际投料量 * 原料最近采购单价[inv10100.zjunprc实时变更],4)
                    System.out.println("实投料量：" + balanceAccount.getActualInventory());
                    balanceAccount.setWastePrice(balanceAccount.getActualInventory().multiply(l.getBizMaterialBase().getZjunprc()).setScale(4, RoundingMode.HALF_UP));
                } else if (l.getSupplier().getWastePriceCategory().equals("12") && l.getSupplier().getCode().equals("99997") && bizProduct.getProductCode().equals("911110028")) {
                    // 废品价计算类别='12' 外协厂编码='99997' ls_cpart（产品编码）='911110028' 废品加工单价=round(原料最近采购单价 ,4)
                    balanceAccount.setWastePrice(l.getBizMaterialBase().getZjunprc().setScale(4, RoundingMode.HALF_UP));
                } else if (l.getSupplier().getWastePriceCategory().equals("12") && l.getSupplier().getCode().equals("99980") && bizProduct.getProductCode().equals("911100538")) {
                    // 废品价计算类别='12' 外协厂编码='99980' ls_cpart（产品编码）='911100538' 废品加工单价=round(原料最近采购单价 ,4)
                    balanceAccount.setWastePrice(l.getBizMaterialBase().getZjunprc().setScale(4, RoundingMode.HALF_UP));
                } else if (l.getSupplier().getWastePriceCategory().equals("24")) {
                    //  废品价计算类别='24' then 废品加工单价=round(加工单价[外协厂结算员填写的],4)
                    balanceAccount.setWastePrice(processPrice.setScale(4, RoundingMode.HALF_UP));
                }
//                System.out.println(l.getSupplier().getWastePriceCategory());
//                System.out.println("303 getMaterialLossl: "+ balanceAccount.getMaterialLoss());
//                System.out.println(l.getWastePrice());
//                System.out.println(l.getSupplier().getTaxRatio());
                BigDecimal wastePrice = balanceAccount.getWastePrice() == null ? BigDecimal.ZERO : balanceAccount.getWastePrice();
//                System.out.println(wastePrice);
                // 扣料金额 round(料损数量 * 废品加工单价 * 120/100.00 * 1.13【*税率】,4)//(1 + 税率（取自sfc10100.taxsl） /100.00 ),2)
                balanceAccount.setMaterialLossAmount(BigDecimal.valueOf(balanceAccount.getMaterialLoss()).multiply(wastePrice.multiply(BigDecimal.valueOf(120).divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP))).multiply(BigDecimal.ONE.add(BigDecimal.valueOf(l.getSupplier().getTaxRatio()).divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP))).setScale(4, RoundingMode.HALF_UP));
            } else {
                // 有时
                if(l.getSupplier().getWastePriceCategory().equals("21")) {
                    //  废品价计算类别='21' 废品加工单价=round(产品单价(inc10100.unprc) -  加工单价 ,4)
                    balanceAccount.setWastePrice(l.getProduct().getUnprc().subtract(processPrice).setScale(4, RoundingMode.HALF_UP));
                } else if (l.getSupplier().getWastePriceCategory().equals("22")) {
                    //  废品价计算类别='22' round(加工单价  * 2 ,4)
                    balanceAccount.setWastePrice(processPrice.multiply(BigDecimal.valueOf(2)).setScale(4, RoundingMode.HALF_UP));
                } else if (l.getSupplier().getWastePriceCategory().equals("23")) {
                    //  废品价计算类别='23' round(加工单价  * 3 ,4)
                    balanceAccount.setWastePrice(processPrice.multiply(BigDecimal.valueOf(3)).setScale(4, RoundingMode.HALF_UP));
                }
                // 扣料金额 round(料损数量 * 废品加工单价 * 1.13【*税率】 ,4) // (1 + 税率 /100.00 ),2)
                balanceAccount.setMaterialLossAmount(BigDecimal.valueOf(balanceAccount.getMaterialLoss()).multiply(balanceAccount.getWastePrice().multiply(BigDecimal.ONE.add(BigDecimal.valueOf(l.getSupplier().getTaxRatio()).divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP)))).setScale(4, RoundingMode.HALF_UP));
            }
            // 利用率
            balanceAccount.setUtilizationRatio(l.getBizMaterialBaseInfo().getUtrate());
            // 长度是产品长度
            balanceAccount.setLength(l.getProduct().getLenght());
            balanceAccount.setSupplier(l.getSupplier());

            addList.add(balanceAccount);
        });
        return addList;
    }

    private List<BizOutsourceBalanceAccount> getBalanceAccounts(BizOutsourceBalanceAccount l, BizOutsourcedOrder bizOutsourcedOrder, BizSupplier bizSupplier, BizOutsourcedOrderDetail bizOutsourcedOrderDetail, List<BizOutsourcedOrderDetailProcess> detailProcesses, BizDaywork bizDaywork, BizProduct bizProduct, BizFurnaceNoInfo furnaceNoInfo, List<BizReturnReceiptDetail> receiptDetails, BizProcessInspecion bizProcessInspecion, BizLotTechnologicalProcess bizTechnologicalProcess, List<BizLotTechnologicalProcessDetail> technologicalProcessDetails, List<BizDayworkItem> items, BizLot lot, List<BizSupplierProductProcess> supplierProductProcesses) {
        List<BizOutsourceBalanceAccount> addList = new ArrayList<>();
        detailProcesses.forEach(v -> {
            BizReturnReceiptDetail receiptDetail = receiptDetails.stream().filter(b -> b.getOutsourceDetailId().equals(v.getDetailId()) && b.getProcessId().equals(v.getProcessId())).findFirst().orElse(new BizReturnReceiptDetail());
            BizDayworkItem item = items.stream().filter(b -> b.getOutsourceDetailId().equals(v.getDetailId()) && b.getProcessId().equals(v.getProcessId())).findFirst().orElse(new BizDayworkItem());
//            System.out.println("301 daywork_item_id" + item.getId());
//            System.out.println("302 outsource_detail_id" + v.getDetailId());
//            System.out.println("303 process_id" + v.getProcessId());
            BizLotTechnologicalProcessDetail bizTechnologicalProcessDetail = technologicalProcessDetails.stream().filter(b -> b.getProcessStepNumber().equals(v.getProcessStepNumber())).findFirst().orElse(new BizLotTechnologicalProcessDetail());
            BizSupplierProductProcess supplierProductProcess = supplierProductProcesses.stream().filter(b -> b.getProcessId().equals(v.getProcessId())).findFirst().orElse(new BizSupplierProductProcess());
            BizOutsourceBalanceAccount balanceAccount = new BizOutsourceBalanceAccount();
            balanceAccount.setProcessInspectionId(l.getProcessInspectionId());
            balanceAccount.setRawMaterialCode(furnaceNoInfo.getRawMaterialCode());
            balanceAccount.setSupplierCode(bizSupplier.getCode());
            balanceAccount.setSupplierName(bizSupplier.getName());
            balanceAccount.setOutsourceOrderDetailId(bizOutsourcedOrderDetail.getId());
            balanceAccount.setTenantId(getLoginUser().getTenantId());
            balanceAccount.setSupplierId(bizSupplier.getId());
            balanceAccount.setCurrency("RMB");
            balanceAccount.setType(l.getBizMaterialBase().getType());
            balanceAccount.setAuditDate(new Date());
            balanceAccount.setReturnReceiptId(receiptDetail.getMasterId());
            balanceAccount.setReturnReceiptDetailId(receiptDetail.getId());
            balanceAccount.setDayworkId(bizDaywork.getId());
            balanceAccount.setDayworkItemId(item.getId());
            balanceAccount.setSettlementType(bizOutsourcedOrder.getSettlementType());
            balanceAccount.setLotId(bizDaywork.getLotId());
            balanceAccount.setLotCode(bizDaywork.getLotCode());
            balanceAccount.setProductId(bizProduct.getId());
            balanceAccount.setProductDescription(bizProduct.getDescription());
            balanceAccount.setProductCode(bizProduct.getProductCode());
            balanceAccount.setTechnologicalProcessId(bizTechnologicalProcess.getId());
            balanceAccount.setTechnologyVersion(bizTechnologicalProcess.getTechnologyVersion());
            balanceAccount.setTechnologicalProcessDetailId(bizTechnologicalProcessDetail.getId());
            balanceAccount.setProcessId(v.getProcessId());
            balanceAccount.setProcessStepNumber(v.getProcessStepNumber());
            balanceAccount.setProcessAlias(v.getProcessAlias());
            balanceAccount.setProcessCode(v.getProcessCode());
            balanceAccount.setOutsourceOrderDetailProcessId(v.getId());
            balanceAccount.setOutsourceOrderId(bizOutsourcedOrder.getId());
            balanceAccount.setIsAmend(bizDaywork.getIsAmend());
            balanceAccount.setIsWasteRecycling(bizDaywork.getIsWasteRecycling());
            // 产品数量
            balanceAccount.setProductNum(lot.getProductionQuantity());
            // 批次投产数量
            balanceAccount.setProductionNum(lot.getProductionQuantity());
            // 外协发出数量
            balanceAccount.setOutputNum(bizOutsourcedOrderDetail.getProductNum());
            // 收回审核数量
            balanceAccount.setReceiptNum(receiptDetail.getAuditNum());
            // 工序单价
            balanceAccount.setProcessPrice(supplierProductProcess.getPrice());
            // 材料单价 inv10100.zjunprc
            balanceAccount.setMaterialPrice(l.getBizMaterialBase().getZjunprc());
            // 销售单价 inc10100.unprc
            balanceAccount.setSalePrice(l.getProduct().getUnprc());
            // 实投料量 假设为直条料或圆盘料或半成品料
            if (l.getBizMaterialBase().getXzcode().equals("11") || l.getBizMaterialBase().getXzcode().equals("12") || l.getBizMaterialBase().getType().equals("2")) {
                // 计算公式 实际投料直径 / 2 * 实际投料直径 / 2 * 3.14 * 原料密度 / 1000 * (产品长度  + 公差长度【bom30101.gccd（材料基本信息表）按cpart产品编码取，生产计划随时变动结算时实时获取】) / 原材料利用率 / 10000
                BigDecimal length = bizProduct.getLenght();
                BigDecimal gccd = l.getBizMaterialBaseInfo().getGccd();
                BigDecimal stll = l.getBizMaterialBase().getYzj().divide(BigDecimal.valueOf(2), 6, RoundingMode.HALF_UP).pow(2).multiply(BigDecimal.valueOf(3.14)).multiply(l.getBizMaterialBase().getDensity().divide(BigDecimal.valueOf(1000), 6, RoundingMode.HALF_UP)).multiply(length.add(gccd)).divide(l.getBizMaterialBaseInfo().getUtrate() == null || l.getBizMaterialBaseInfo().getUtrate().compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ONE : l.getBizMaterialBaseInfo().getUtrate(), 6, RoundingMode.HALF_UP).divide(BigDecimal.valueOf(10000), 6, RoundingMode.HALF_UP).setScale(4, RoundingMode.HALF_UP);
                balanceAccount.setActualInventory(stll);
            } else {
                // 其他 inc10100.stqty
                balanceAccount.setActualInventory(l.getProduct().getStqty());
            }
            // 料损数量 99984与99024无料损数量
            if (bizSupplier.getCode().equals("99984") || bizSupplier.getCode().equals("99024")) {
                balanceAccount.setMaterialLoss(0);
            } else {
                // 其他外协厂[料损数量]计算公式=发出数量 * (1 - 料损率 / 1000) - 合格数量，结果取整 【料损率从外协厂基础配置表中读】
                Integer materialLoss = BigDecimal.valueOf(bizOutsourcedOrderDetail.getProductNum()).multiply(BigDecimal.ONE.subtract(bizSupplier.getLossLimit().divide(BigDecimal.valueOf(1000), 6, RoundingMode.HALF_UP))).subtract(BigDecimal.valueOf(receiptDetail.getAuditNum())).setScale(0, RoundingMode.HALF_UP).intValue();
                balanceAccount.setMaterialLoss(materialLoss);
            }

//            System.out.println("263 getMaterialLoss: " + l.getMaterialLoss());
            balanceAccount.setMaterialLoss(balanceAccount.getMaterialLoss() == null || balanceAccount.getMaterialLoss() < 0 ? 0 : balanceAccount.getMaterialLoss());
//            System.out.println("265 getMaterialLoss: " + l.getMaterialLoss());

            // 表面表示是否有表面处理
            balanceAccount.setSurfaceTreatment(l.getSupplier().getSurfaceTreatment());
            balanceAccount.setCarrierNum(bizOutsourcedOrderDetail.getNewCarrierCount());
            int sort = technologicalProcessDetails.indexOf(technologicalProcessDetails.stream().filter(t -> t.getProcessStepNumber().equals(v.getProcessStepNumber())).findFirst().orElse(new BizLotTechnologicalProcessDetail()));
            balanceAccount.setProcessSort(sort);
            balanceAccount.setReturnDate(receiptDetail.getFormDate());
            balanceAccount.setReturnNo(receiptDetail.getFormCode());
            balanceAccount.setOutsourceNo(bizOutsourcedOrder.getFormCode());
            balanceAccount.setFurnaceNum(1);
            balanceAccount.setCheckDate(bizProcessInspecion.getEndTime());
            balanceAccount.setMaterialLossRatio(bizSupplier.getLossLimit());
            balanceAccount.setShape(l.getBizMaterialBase().getXzcode());
            balanceAccount.setDensity(l.getBizMaterialBase().getDensity());
            balanceAccount.setWastePriceCategory(l.getSupplier().getWastePriceCategory());
            balanceAccount.setTaxRate(BigDecimal.valueOf(l.getSupplier().getTaxRatio()));
            balanceAccount.setTolerance(l.getBizMaterialBase().getGccd());
            balanceAccount.setMaterialDiameter(l.getBizMaterialBase().getYzj());
            balanceAccount.setInspectionNo(bizProcessInspecion.getOutsourcedInspectionNo());
            BigDecimal processPrice = balanceAccount.getProcessPrice() == null ? BigDecimal.ZERO : balanceAccount.getProcessPrice();

            // 废品单价
            if (l.getSupplier().getSurfaceTreatment().equals("N")){
                // 没表面处理时
                if (l.getSupplier().getWastePriceCategory().equals("11")) {
                    // 废品价计算类别='11' round(实际投料量 * 原料最近采购单价[inv10100.zjunprc实时变更],4)
                    balanceAccount.setWastePrice(balanceAccount.getActualInventory().multiply(l.getBizMaterialBase().getZjunprc()).setScale(4, RoundingMode.HALF_UP));
                } else if (l.getSupplier().getWastePriceCategory().equals("12") && l.getSupplier().getCode().equals("99997") && bizProduct.getProductCode().equals("911110028")) {
                    // 废品价计算类别='12' 外协厂编码='99997' ls_cpart（产品编码）='911110028' 废品加工单价=round(原料最近采购单价 ,4)
                    balanceAccount.setWastePrice(l.getBizMaterialBase().getZjunprc().setScale(4, RoundingMode.HALF_UP));
                } else if (l.getSupplier().getWastePriceCategory().equals("12") && l.getSupplier().getCode().equals("99980") && bizProduct.getProductCode().equals("911100538")) {
                    // 废品价计算类别='12' 外协厂编码='99980' ls_cpart（产品编码）='911100538' 废品加工单价=round(原料最近采购单价 ,4)
                    balanceAccount.setWastePrice(l.getBizMaterialBase().getZjunprc().setScale(4, RoundingMode.HALF_UP));
                } else if (l.getSupplier().getWastePriceCategory().equals("24")) {
                    //  废品价计算类别='24' then 废品加工单价=round(加工单价[外协厂结算员填写的],4)
                    balanceAccount.setWastePrice(processPrice.setScale(4, RoundingMode.HALF_UP));
                }
//                System.out.println(l.getSupplier().getWastePriceCategory());
//                System.out.println("303 getMaterialLossl: "+ balanceAccount.getMaterialLoss());
//                System.out.println(l.getWastePrice());
//                System.out.println(l.getSupplier().getTaxRatio());
                BigDecimal wastePrice = balanceAccount.getWastePrice() == null ? BigDecimal.ZERO : balanceAccount.getWastePrice();
//                System.out.println(wastePrice);
                // 扣料金额 round(料损数量 * 废品加工单价 * 120/100.00 * 1.13【*税率】,4)//(1 + 税率（取自sfc10100.taxsl） /100.00 ),2)
                balanceAccount.setMaterialLossAmount(BigDecimal.valueOf(balanceAccount.getMaterialLoss()).multiply(wastePrice.multiply(BigDecimal.valueOf(120).divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP))).multiply(BigDecimal.ONE.add(BigDecimal.valueOf(l.getSupplier().getTaxRatio()).divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP))).setScale(2, RoundingMode.HALF_UP));
            } else {
                // 有时
                if(l.getSupplier().getWastePriceCategory().equals("21")) {
                    //  废品价计算类别='21' 废品加工单价=round(产品单价(inc10100.unprc) -  加工单价 ,4)
                    balanceAccount.setWastePrice(l.getProduct().getUnprc().subtract(processPrice).setScale(4, RoundingMode.HALF_UP));
                } else if (l.getSupplier().getWastePriceCategory().equals("22")) {
                    //  废品价计算类别='22' round(加工单价  * 2 ,4)
                    balanceAccount.setWastePrice(processPrice.multiply(BigDecimal.valueOf(2)).setScale(4, RoundingMode.HALF_UP));
                } else if (l.getSupplier().getWastePriceCategory().equals("23")) {
                    //  废品价计算类别='23' round(加工单价  * 3 ,4)
                    balanceAccount.setWastePrice(processPrice.multiply(BigDecimal.valueOf(3)).setScale(4, RoundingMode.HALF_UP));
                }
                // 扣料金额 round(料损数量 * 废品加工单价 * 1.13【*税率】 ,4) // (1 + 税率 /100.00 ),2)
                // 扣料金额 round(料损数量 * 废品加工单价 * 1.13【*税率】 ,4) // (1 + 税率 /100.00 ),2)
                balanceAccount.setMaterialLossAmount(BigDecimal.valueOf(balanceAccount.getMaterialLoss()).multiply(balanceAccount.getWastePrice().multiply(BigDecimal.ONE.add(BigDecimal.valueOf(l.getSupplier().getTaxRatio()).divide(BigDecimal.valueOf(100), 6, RoundingMode.HALF_UP)))).setScale(2, RoundingMode.HALF_UP));
            }
            // 利用率
            balanceAccount.setUtilizationRatio(l.getBizMaterialBaseInfo().getUtrate());
            // 长度是产品长度
            balanceAccount.setLength(l.getProduct().getLenght());
            balanceAccount.setSupplier(l.getSupplier());

            addList.add(balanceAccount);
        });
        return addList;
    }
    private void delBalanceCheckout(List<BizProcessInspecion> inspections) {
        List<String> settledLotCodes = new ArrayList<>();
        // 删除结算记录
        List<BizOutsourceBalanceAccount> balanceAccounts = bizOutsourceBalanceAccountService.query().in("process_inspection_id", inspections.isEmpty()? Collections.singletonList(0L): inspections.stream().map(BizProcessInspecion::getId).collect(Collectors.toList())).list();
        for(BizOutsourceBalanceAccount b : balanceAccounts){
            if(b.getStatus().equals(1)) {
                if(!settledLotCodes.contains(b.getLotCode())){
                    settledLotCodes.add(b.getLotCode());
                }
            }
        }
        if(!settledLotCodes.isEmpty()){
            String lotCode = String.join(", ", settledLotCodes);
            throw new RuntimeException(lotCode + "批次外协已结算，请取消结算");
        }
        bizOutsourceBalanceAccountService.removeBatchByIds(balanceAccounts);
    }
}
