package com.fjhx.stock.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.constants.StatusConstant;
import com.fjhx.entity.plan.PlanConfig;
import com.fjhx.entity.stock.StockBackPlan;
import com.fjhx.entity.stock.StockBackPlanDetails;
import com.fjhx.plan.service.PlanConfigService;
import com.fjhx.stock.mapper.StockBackPlanMapper;
import com.fjhx.stock.service.StockBackPlanDetailsService;
import com.fjhx.stock.service.StockBackPlanService;
import com.fjhx.utils.BigDecimalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2022-09-02
 */
@Service
public class StockBackPlanServiceImpl extends ServiceImpl<StockBackPlanMapper, StockBackPlan> implements StockBackPlanService {

    @Autowired
    private PlanConfigService planConfigService;

    private static final RestTemplate restTemplate = new RestTemplate();

    private static final Object obj = new Object();

    @Autowired
    private StockBackPlanDetailsService stockBackPlanDetailsService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void synchronousScheduling() {

        synchronized (obj) {

            // 配置map
            Map<String, PlanConfig> planConfigMap = planConfigService.list()
                    .stream().collect(Collectors.toMap(PlanConfig::getCode, item -> item));

            Integer nextStatisticsDay = planConfigMap.get("nextStatisticsDay").getDays();
            Integer defaultStatisticsDay = planConfigMap.get("defaultStatisticsDay").getDays();
            int offset = nextStatisticsDay - 1;

            // 排除v3推送的物料
            List<String> materialNameList = Arrays.asList(planConfigMap.get("excludeMaterial").getOther().split(","));

            // 请求v3接口获取token
            String token = getToken();

            // 结束时间
            Date endDate = new Date();
            String endDateStr = DateUtil.format(endDate, "yyyy-MM-dd 23:59:59");

            // 开始时间
            Date beginDate = DateUtil.beginOfDay(DateUtil.offsetDay(endDate, -offset));
            String beginDateStr = DateUtil.format(DateUtil.offsetDay(endDate, -offset), "yyyy-MM-dd 00:00:00");

            // 请求v3接口获取所有人领料信息
            String url = "http://mes.cfmfactory.com:8087/MesWeb/planPersonOutAction.do?action=list&beginDate="
                    + beginDateStr + "&endDate=" + endDateStr + "&access_token=" + token;

            String resultStr = restTemplate.getForEntity(url, String.class).getBody();
            JSONObject resultMap = JSONObject.parseObject(resultStr);

            // 接收到的消息
            List<JSONObject> items = (List<JSONObject>) resultMap.get("items");

            // 删除原统计数据
            remove(Wrappers.<StockBackPlan>lambdaQuery().between(StockBackPlan::getPlanTime, beginDateStr, endDateStr));

            Map<String, StockBackPlan> flagMap = new HashMap<>();

            // 循环领料信息
            items.forEach(item -> {
                // 喷印人员工号
                String distributor = item.getString("distributor");
                // 打纸人员工号
                String paperMan = item.getString("paperMan");
                // 排班面积
                BigDecimal planTotalSquare = new BigDecimal(item.getString("plantotalsquare"));
                // 物料名称
                String material = item.getString("material");
                // 排班时间
                String planDate = item.getString("planDate");

                if (materialNameList.contains(material)) {
                    return;
                }

                String tech = Convert.toStr(item.get("tech"), "");

                switch (tech) {
                    case "热转印":
                    case "双面热转":
                        tech = "热转";
                        break;
                    case "双面直喷":
                        tech = "直喷";
                        break;
                }

                if (!"胶印".equals(tech)) {
                    // 喷印人员工号添加领料记录标记
                    addOrEditFlagMap(flagMap, distributor, planTotalSquare, planDate, material, tech, endDate);
                    // 打纸人员工号添加领料记录标记
                    addOrEditFlagMap(flagMap, paperMan, planTotalSquare, planDate, "热转印纸", "打纸", endDate);
                }

            });

            // 当天出库
            List<StockBackPlan> stockBackPlanList = new ArrayList<>(flagMap.values());

            // 更新当天的出库单
            saveBatch(stockBackPlanList);

            // 删除排班统计
            stockBackPlanDetailsService.remove(Wrappers.<StockBackPlanDetails>lambdaQuery()
                    .between(StockBackPlanDetails::getPlanTime, beginDate, endDate));

            // 工号，物料名称，排班时间封装成key，对象为value
            Map<String, StockBackPlanDetails> stockBackPlanMap = stockBackPlanList.stream().collect(Collectors.toMap(
                    item -> item.getJobNo() + item.getPlanMaterial() + item.getPlanTime().getTime(),
                    item -> {
                        StockBackPlanDetails stockBackPlanDetails =
                                createStockBackPlanDetails(item.getJobNo(), item.getPlanMaterial(), item.getPlanTime());
                        stockBackPlanDetails.setQuantity(item.getQuantity());
                        stockBackPlanDetails.setTech(item.getTech());
                        return stockBackPlanDetails;
                    }
            ));

            // 查询出库
            issue(planConfigMap.get("issue"), beginDate, stockBackPlanMap);

            // 转印部门出库
            issueA008(planConfigMap.get("issueA008"), beginDate, stockBackPlanMap);

            // 回仓
            returnWarehouse(planConfigMap.get("returnWarehouse"), beginDate, stockBackPlanMap);

            // 转印部门回仓
            returnWarehouseA008(planConfigMap.get("returnWarehouseA008"), beginDate, stockBackPlanMap);

            // 物料修正
            correct(planConfigMap.get("correct"), beginDate, stockBackPlanMap);

            // 转入
            transferIn(planConfigMap.get("transferIn"), beginDate, stockBackPlanMap);

            // 转出
            transferOut(planConfigMap.get("transferOut"), beginDate, stockBackPlanMap);

            // 布头布尾修正
            headTailCorrect(planConfigMap.get("headTailCorrect"), beginDate, stockBackPlanMap);

            stockBackPlanDetailsService.saveBatch(new ArrayList<>(stockBackPlanMap.values()));

            // 如果时间不相同
            if (!Objects.equals(defaultStatisticsDay, nextStatisticsDay)) {
                planConfigService.update(Wrappers.<PlanConfig>lambdaUpdate()
                        .eq(PlanConfig::getCode, "nextStatisticsDay")
                        .eq(PlanConfig::getDays, nextStatisticsDay)
                        .set(PlanConfig::getDays, defaultStatisticsDay)
                );
            }

            // 最近一次更新时间
            planConfigService.update(Wrappers.<PlanConfig>lambdaUpdate()
                    .eq(PlanConfig::getCode, "lastStatisticsTime")
                    .set(PlanConfig::getOther, DateUtil.format(endDate, "yyyy-MM-dd HH:mm:ss"))
            );

        }
    }


    private StockBackPlanDetails createStockBackPlanDetails(String jobNo, String materialName, Date planDate) {
        StockBackPlanDetails stockBackPlanDetails = new StockBackPlanDetails();
        stockBackPlanDetails.setPlanMaterial(materialName);
        stockBackPlanDetails.setPlanTime(planDate);
        stockBackPlanDetails.setQuantity(BigDecimal.ZERO);
        stockBackPlanDetails.setJobNo(jobNo);
        stockBackPlanDetails.setCorrectArea(BigDecimal.ZERO);

        stockBackPlanDetails.setPickingMoney(BigDecimal.ZERO);
        stockBackPlanDetails.setPickingNum(0);
        stockBackPlanDetails.setPickingMeters(BigDecimal.ZERO);
        stockBackPlanDetails.setPickingArea(BigDecimal.ZERO);

        stockBackPlanDetails.setBackMoney(BigDecimal.ZERO);
        stockBackPlanDetails.setBackNum(0);
        stockBackPlanDetails.setBackMeters(BigDecimal.ZERO);
        stockBackPlanDetails.setBackArea(BigDecimal.ZERO);

        stockBackPlanDetails.setTransferOutMoney(BigDecimal.ZERO);
        stockBackPlanDetails.setTransferOutMeters(BigDecimal.ZERO);
        stockBackPlanDetails.setTransferOutArea(BigDecimal.ZERO);
        stockBackPlanDetails.setTransferOutNum(0);

        stockBackPlanDetails.setTransferInMoney(BigDecimal.ZERO);
        stockBackPlanDetails.setTransferInMeters(BigDecimal.ZERO);
        stockBackPlanDetails.setTransferInArea(BigDecimal.ZERO);
        stockBackPlanDetails.setTransferInNum(0);

        stockBackPlanDetails.setHeadTailCorrectArea(BigDecimal.ZERO);

        stockBackPlanDetails.setCreateTime(new Date());

        return stockBackPlanDetails;
    }

    /**
     * 获取token
     */
    private String getToken() {
        String url = "http://mes.cfmfactory.com:8087/portal/getAccessTokenAction.do?AppId=1&AppSecret=a2b1c2d3";
        String result = restTemplate.getForEntity(url, String.class).getBody();
        if (ObjectUtil.isEmpty(result)) {
            return null;
        }
        JSONObject jsonObject = JSONObject.parseObject(result);
        return jsonObject.getString("token");
    }

    /**
     * 赋值排班数据
     */
    private void addOrEditFlagMap(Map<String, StockBackPlan> flagMap, String jobNo, BigDecimal plantotalsquare, String planDate, String material, String tech, Date date) {
        if (Objects.equals(jobNo, "0")) {
            return;
        }

        String key = jobNo + material + planDate;
        StockBackPlan stockBackPlan = flagMap.get(key);

        if (stockBackPlan == null) {
            stockBackPlan = new StockBackPlan();
            stockBackPlan.setJobNo(jobNo);
            stockBackPlan.setPlanMaterial(material.trim());
            stockBackPlan.setPlanTime(DateUtil.parse(planDate));
            stockBackPlan.setQuantity(plantotalsquare);
            stockBackPlan.setTech(tech);
            stockBackPlan.setCreateTime(date);

            flagMap.put(key, stockBackPlan);
        } else {
            BigDecimal quantity = stockBackPlan.getQuantity();
            stockBackPlan.setQuantity(quantity.add(plantotalsquare));
        }
    }

    /**
     * 出库
     */
    private void issue(PlanConfig planConfig, Date beginDate, Map<String, StockBackPlanDetails> stockBackPlanMap) {

        String beginTime = planConfig.getBeginTime();
        List<String> deptIdList = Arrays.asList(planConfig.getDeptIdSet().split(","));
        List<String> notCategoryCodeList = Arrays.asList(planConfig.getNotCategoryCodeSet().split(","));

        String[] split = beginTime.split(":");
        int configH = Convert.toInt(split[0]);
        int configM = Convert.toInt(split[1]);

        List<Map<String, Object>> pickingList = baseMapper.getWater(Wrappers.query()
                .ge("swd.CreatedTime", DateUtil.format(beginDate, "yyyy-MM-dd " + beginTime))
                .in("swd.StockChangeType", 20, 23)
                .eq("uu.IsDelete", 0)
                .in("uu.DepartmentID", deptIdList)
                .notIn("m.CategoryCode", notCategoryCodeList)
                .isNotNull("uu.JobNo"));

        for (Map<String, Object> map : pickingList) {

            // 出库时间
            Date createTime = (Date) map.get("createTime");
            // 时
            int h = Integer.parseInt(DateUtil.format(createTime, "H"));
            // 分
            int m = Integer.parseInt(DateUtil.format(createTime, "m"));
            // 小于配置时分算前一日
            if (h < configH || (h == configH && m < configM)) {
                createTime = DateUtil.offsetDay(createTime, -1);
            }

            // 排班时间
            Date planDate = DateUtil.beginOfDay(createTime);
            // 工号
            String jobNo = map.get("jobNo").toString();
            // 物料名称
            String materialName = map.get("materialName").toString().split("-")[0];
            // 数量
            BigDecimal changeNum = BigDecimalUtil.keepDecimals(map.get("changeNum"));
            // 单价
            BigDecimal price = BigDecimalUtil.keepDecimals(map.get("price"));
            // 门幅
            BigDecimal width = BigDecimalUtil.keepDecimals(map.get("width"));

            // 排班对象
            StockBackPlanDetails stockBackPlanDetails = stockBackPlanMap.get(jobNo + materialName + planDate.getTime());
            if (stockBackPlanDetails == null) {
                stockBackPlanDetails = createStockBackPlanDetails(jobNo, materialName, planDate);
                stockBackPlanMap.put(jobNo + materialName + planDate.getTime(), stockBackPlanDetails);
            }

            // 金额
            stockBackPlanDetails.setPickingMoney(
                    BigDecimalUtil.init(stockBackPlanDetails.getPickingMoney()).add(price.multiply(changeNum)).getValue(2));

            // 数量
            stockBackPlanDetails.setPickingNum(stockBackPlanDetails.getPickingNum() + 1);

            // 米
            stockBackPlanDetails.setPickingMeters(stockBackPlanDetails.getPickingMeters().add(changeNum));

            // 面积
            stockBackPlanDetails.setPickingArea(stockBackPlanDetails.getPickingArea().add(
                    BigDecimalUtil.init(changeNum).multiply(width).divide(100, 2).getValue()));
        }
    }

    private void issueA008(PlanConfig planConfig, Date beginDate, Map<String, StockBackPlanDetails> stockBackPlanMap) {

        String beginTime = planConfig.getBeginTime();
        List<String> deptIdList = Arrays.asList(planConfig.getDeptIdSet().split(","));
        List<String> notCategoryCodeList = Arrays.asList(planConfig.getNotCategoryCodeSet().split(","));

        String[] split = beginTime.split(":");
        int configH = Convert.toInt(split[0]);
        int configM = Convert.toInt(split[1]);


        List<Map<String, Object>> pickingList = baseMapper.getWater(Wrappers.query()
                .ge("swd.CreatedTime", DateUtil.format(beginDate, "yyyy-MM-dd " + beginTime))
                .in("swd.StockChangeType", 20, 23)
                .eq("uu.IsDelete", 0)
                .in("uu.DepartmentID", deptIdList)
                .notIn("m.CategoryCode", notCategoryCodeList)
                .isNotNull("uu.JobNo"));

        for (Map<String, Object> map : pickingList) {

            // 出库时间
            Date createTime = (Date) map.get("createTime");
            // 时
            int h = Integer.parseInt(DateUtil.format(createTime, "H"));
            // 分
            int m = Integer.parseInt(DateUtil.format(createTime, "m"));

            // 小于配置算前一日
            if (h < configH || (h == configH && m < configM)) {
                createTime = DateUtil.offsetDay(createTime, -1);
            }

            // 排班时间
            Date planDate = DateUtil.beginOfDay(createTime);
            // 工号
            String jobNo = map.get("jobNo").toString();
            // 物料名称
            String materialName = map.get("materialName").toString().split("-")[0];
            // 数量
            BigDecimal changeNum = BigDecimalUtil.keepDecimals(map.get("changeNum"));
            // 单价
            BigDecimal price = BigDecimalUtil.keepDecimals(map.get("price"));
            // 门幅
            BigDecimal width = BigDecimalUtil.keepDecimals(map.get("width"));

            // 排班对象
            StockBackPlanDetails stockBackPlanDetails = stockBackPlanMap.get(jobNo + materialName + planDate.getTime());
            if (stockBackPlanDetails == null) {
                stockBackPlanDetails = createStockBackPlanDetails(jobNo, materialName, planDate);
                stockBackPlanMap.put(jobNo + materialName + planDate.getTime(), stockBackPlanDetails);
            }

            // 金额
            stockBackPlanDetails.setPickingMoney(
                    BigDecimalUtil.init(stockBackPlanDetails.getPickingMoney()).add(price.multiply(changeNum)).getValue(2));

            // 数量
            stockBackPlanDetails.setPickingNum(stockBackPlanDetails.getPickingNum() + 1);

            // 米
            stockBackPlanDetails.setPickingMeters(stockBackPlanDetails.getPickingMeters().add(changeNum));

            // 面积
            stockBackPlanDetails.setPickingArea(stockBackPlanDetails.getPickingArea().add(
                    BigDecimalUtil.init(changeNum).multiply(width).divide(100, 2).getValue()));
        }

    }


    /**
     * 回仓
     */
    private void returnWarehouse(PlanConfig planConfig, Date beginDate, Map<String, StockBackPlanDetails> stockBackPlanMap) {

        String beginTime = planConfig.getBeginTime();
        List<String> deptIdList = Arrays.asList(planConfig.getDeptIdSet().split(","));
        List<String> notCategoryCodeList = Arrays.asList(planConfig.getNotCategoryCodeSet().split(","));

        String[] split = beginTime.split(":");
        int configH = Convert.toInt(split[0]);
        int configM = Convert.toInt(split[1]);

        List<Map<String, Object>> backList = baseMapper.getReturnWarehouse(Wrappers.query()
                .ge("sb.operation_time", DateUtil.format(beginDate, "yyyy-MM-dd " + beginTime))
                .eq("uu.IsDelete", 0)
                .in("uu.DepartmentID", deptIdList)
                .isNotNull("uu.JobNo")
                .notIn("m.CategoryCode", notCategoryCodeList)
        );

        for (Map<String, Object> map : backList) {

            // 出库时间
            Date createTime = (Date) map.get("createTime");

            int h = Integer.parseInt(DateUtil.format(createTime, "H"));
            int m = Integer.parseInt(DateUtil.format(createTime, "m"));

            // 小于配置算前一日
            if (h < configH || (h == configH && m < configM)) {
                createTime = DateUtil.offsetDay(createTime, -1);
            }
            // 排班时间
            Date planDate = DateUtil.beginOfDay(createTime);
            // 工号
            String jobNo = map.get("jobNo").toString();
            // 物料名称
            String materialName = map.get("materialName").toString().split("-")[0];
            // 数量
            BigDecimal changeNum = BigDecimalUtil.keepDecimals(map.get("changeNum"));
            // 单价
            BigDecimal price = BigDecimalUtil.keepDecimals(map.get("price"));
            // 门幅
            BigDecimal width = BigDecimalUtil.keepDecimals(map.get("width"));

            // 排班对象
            StockBackPlanDetails stockBackPlanDetails = stockBackPlanMap.get(jobNo + materialName + planDate.getTime());
            if (stockBackPlanDetails == null) {
                stockBackPlanDetails = createStockBackPlanDetails(jobNo, materialName, planDate);
                stockBackPlanMap.put(jobNo + materialName + planDate.getTime(), stockBackPlanDetails);
            }

            // 金额
            stockBackPlanDetails.setBackMoney(
                    BigDecimalUtil.init(stockBackPlanDetails.getBackMoney()).add(price.multiply(changeNum)).getValue(2));

            // 数量
            stockBackPlanDetails.setBackNum(stockBackPlanDetails.getBackNum() + 1);

            // 米
            stockBackPlanDetails.setBackMeters(stockBackPlanDetails.getBackMeters().add(changeNum));

            // 面积
            stockBackPlanDetails.setBackArea(stockBackPlanDetails.getBackArea().add(
                    BigDecimalUtil.init(changeNum).multiply(width).divide(100, 2).getValue()));
        }
    }


    /**
     * 转印部门回仓
     */
    private void returnWarehouseA008(PlanConfig planConfig, Date beginDate, Map<String, StockBackPlanDetails> stockBackPlanMap) {

        String beginTime = planConfig.getBeginTime();
        List<String> deptIdList = Arrays.asList(planConfig.getDeptIdSet().split(","));
        List<String> notCategoryCodeList = Arrays.asList(planConfig.getNotCategoryCodeSet().split(","));

        String[] split = beginTime.split(":");
        int configH = Convert.toInt(split[0]);
        int configM = Convert.toInt(split[1]);

        List<Map<String, Object>> backList = baseMapper.getReturnWarehouse(Wrappers.query()
                .ge("sb.operation_time", DateUtil.format(beginDate, "yyyy-MM-dd " + beginTime))
                .eq("uu.IsDelete", 0)
                .in("uu.DepartmentID", deptIdList)
                .notIn("m.CategoryCode", notCategoryCodeList)
                .isNotNull("uu.JobNo")
        );

        for (Map<String, Object> map : backList) {
            // 出库时间
            Date createTime = (Date) map.get("createTime");

            int h = Integer.parseInt(DateUtil.format(createTime, "H"));
            int m = Integer.parseInt(DateUtil.format(createTime, "m"));
            // 小于配置算前一日
            if (h < configH || (h == configH && m < configM)) {
                createTime = DateUtil.offsetDay(createTime, -1);
            }
            // 排班时间
            Date planDate = DateUtil.beginOfDay(createTime);
            // 工号
            String jobNo = map.get("jobNo").toString();
            // 物料名称
            String materialName = map.get("materialName").toString().split("-")[0];
            // 数量
            BigDecimal changeNum = BigDecimalUtil.keepDecimals(map.get("changeNum"));
            // 单价
            BigDecimal price = BigDecimalUtil.keepDecimals(map.get("price"));
            // 门幅
            BigDecimal width = BigDecimalUtil.keepDecimals(map.get("width"));

            // 排班对象
            StockBackPlanDetails stockBackPlanDetails = stockBackPlanMap.get(jobNo + materialName + planDate.getTime());
            if (stockBackPlanDetails == null) {
                stockBackPlanDetails = createStockBackPlanDetails(jobNo, materialName, planDate);
                stockBackPlanMap.put(jobNo + materialName + planDate.getTime(), stockBackPlanDetails);
            }

            // 金额
            stockBackPlanDetails.setBackMoney(
                    BigDecimalUtil.init(stockBackPlanDetails.getBackMoney()).add(price.multiply(changeNum)).getValue(2));

            // 数量
            stockBackPlanDetails.setBackNum(stockBackPlanDetails.getBackNum() + 1);

            // 米
            stockBackPlanDetails.setBackMeters(stockBackPlanDetails.getBackMeters().add(changeNum));

            // 面积
            stockBackPlanDetails.setBackArea(stockBackPlanDetails.getBackArea().add(
                    BigDecimalUtil.init(changeNum).multiply(width).divide(100, 2).getValue()));
        }

    }


    /**
     * 修正
     */
    private void correct(PlanConfig planConfig, Date beginDate, Map<String, StockBackPlanDetails> stockBackPlanMap) {
        List<String> notCategoryCodeList = Arrays.asList(planConfig.getNotCategoryCodeSet().split(","));

        List<Map<String, Object>> correctList = baseMapper.getCorrect(Wrappers.query()
                .gt("sbc.correct_time", DateUtil.format(beginDate, "yyyy-MM-dd 00:00:00"))
                .notIn("m.CategoryCode", notCategoryCodeList)
                .isNotNull("uu.JobNo")
        );

        for (Map<String, Object> map : correctList) {
            // 出库时间
            Date createTime = (Date) map.get("createTime");
            // 排班时间
            Date planDate = DateUtil.beginOfDay(createTime);
            // 工号
            String jobNo = map.get("jobNo").toString();
            // 物料名称
            String materialName = map.get("materialName").toString().split("-")[0];
            // 数量
            BigDecimal correctArea = BigDecimalUtil.keepDecimals(map.get("correctArea"));

            // 排班对象
            StockBackPlanDetails stockBackPlanDetails = stockBackPlanMap.get(jobNo + materialName + planDate.getTime());
            if (stockBackPlanDetails == null) {
                stockBackPlanDetails = createStockBackPlanDetails(jobNo, materialName, planDate);
                stockBackPlanMap.put(jobNo + materialName + planDate.getTime(), stockBackPlanDetails);
            }
            // 金额
            stockBackPlanDetails.setCorrectArea(stockBackPlanDetails.getCorrectArea().add(correctArea));
        }
    }

    /**
     * 转入
     */
    private void transferIn(PlanConfig planConfig, Date beginDate, Map<String, StockBackPlanDetails> stockBackPlanMap) {
        String beginTime = planConfig.getBeginTime();
        List<String> notCategoryCodeList = Arrays.asList(planConfig.getNotCategoryCodeSet().split(","));

        String[] split = beginTime.split(":");
        int configH = Convert.toInt(split[0]);
        int configM = Convert.toInt(split[1]);


        List<Map<String, Object>> transferPickingList = baseMapper.getTransferPickingList(Wrappers.query()
                .ge("st.submit_time", DateUtil.format(beginDate, "yyyy-MM-dd " + beginTime))
                .eq("st.status", StatusConstant.YES)
                .eq("st.del_flag", 0)
                .notIn("m.CategoryCode", notCategoryCodeList)
        );

        for (Map<String, Object> map : transferPickingList) {

            // 出库时间
            Date createTime = (Date) map.get("createTime");

            int h = Integer.parseInt(DateUtil.format(createTime, "H"));
            int m = Integer.parseInt(DateUtil.format(createTime, "m"));
            // 小于配置算前一日
            if (h < configH || (h == configH && m < configM)) {
                createTime = DateUtil.offsetDay(createTime, -1);
            }

            // 排班时间
            Date planDate = DateUtil.beginOfDay(createTime);
            // 工号
            String jobNo = map.get("jobNo").toString();
            // 物料名称
            String materialName = map.get("materialName").toString().split("-")[0];
            // 数量
            BigDecimal changeNum = BigDecimalUtil.keepDecimals(map.get("changeNum"));
            // 单价
            BigDecimal price = BigDecimalUtil.keepDecimals(map.get("price"));
            // 门幅
            BigDecimal width = BigDecimalUtil.keepDecimals(map.get("width"));

            // 排班对象
            StockBackPlanDetails stockBackPlanDetails = stockBackPlanMap.get(jobNo + materialName + planDate.getTime());
            if (stockBackPlanDetails == null) {
                stockBackPlanDetails = createStockBackPlanDetails(jobNo, materialName, planDate);
                stockBackPlanMap.put(jobNo + materialName + planDate.getTime(), stockBackPlanDetails);
            }

            // 金额
            stockBackPlanDetails.setTransferInMoney(
                    BigDecimalUtil.init(stockBackPlanDetails.getTransferInMoney()).add(price.multiply(changeNum)).getValue(2));

            // 数量
            stockBackPlanDetails.setTransferInNum(stockBackPlanDetails.getTransferInNum() + 1);

            // 米
            stockBackPlanDetails.setTransferInMeters(stockBackPlanDetails.getTransferInMeters().add(changeNum));

            // 面积
            stockBackPlanDetails.setTransferInArea(stockBackPlanDetails.getTransferInArea().add(
                    BigDecimalUtil.init(changeNum).multiply(width).divide(100, 2).getValue()));
        }

    }

    /**
     * 转出
     */
    private void transferOut(PlanConfig planConfig, Date beginDate, Map<String, StockBackPlanDetails> stockBackPlanMap) {
        String beginTime = planConfig.getBeginTime();
        List<String> notCategoryCodeList = Arrays.asList(planConfig.getNotCategoryCodeSet().split(","));

        String[] split = beginTime.split(":");
        int configH = Convert.toInt(split[0]);
        int configM = Convert.toInt(split[1]);

        List<Map<String, Object>> transferBackList = baseMapper.getTransferBackList(Wrappers.query()
                .ge("st.submit_time", DateUtil.format(beginDate, "yyyy-MM-dd " + beginTime))
                .eq("st.status", StatusConstant.YES)
                .eq("st.del_flag", 0)
                .notIn("m.CategoryCode", notCategoryCodeList)
        );

        for (Map<String, Object> map : transferBackList) {

            // 出库时间
            Date createTime = (Date) map.get("createTime");

            int h = Integer.parseInt(DateUtil.format(createTime, "H"));
            int m = Integer.parseInt(DateUtil.format(createTime, "m"));
            // 小于配置算前一日
            if (h < configH || (h == configH && m < configM)) {
                createTime = DateUtil.offsetDay(createTime, -1);
            }
            // 排班时间
            Date planDate = DateUtil.beginOfDay(createTime);
            // 工号
            String jobNo = map.get("jobNo").toString();
            // 物料名称
            String materialName = map.get("materialName").toString().split("-")[0];
            // 数量
            BigDecimal changeNum = BigDecimalUtil.keepDecimals(map.get("changeNum"));
            // 单价
            BigDecimal price = BigDecimalUtil.keepDecimals(map.get("price"));
            // 门幅
            BigDecimal width = BigDecimalUtil.keepDecimals(map.get("width"));

            // 排班对象
            StockBackPlanDetails stockBackPlanDetails = stockBackPlanMap.get(jobNo + materialName + planDate.getTime());
            if (stockBackPlanDetails == null) {
                stockBackPlanDetails = createStockBackPlanDetails(jobNo, materialName, planDate);
                stockBackPlanMap.put(jobNo + materialName + planDate.getTime(), stockBackPlanDetails);
            }

            // 金额
            stockBackPlanDetails.setTransferOutMoney(
                    BigDecimalUtil.init(stockBackPlanDetails.getTransferOutMoney()).add(price.multiply(changeNum)).getValue(2));

            // 数量
            stockBackPlanDetails.setTransferOutNum(stockBackPlanDetails.getTransferOutNum() + 1);

            // 米
            stockBackPlanDetails.setTransferOutMeters(stockBackPlanDetails.getTransferOutMeters().add(changeNum));

            // 面积
            stockBackPlanDetails.setTransferOutArea(stockBackPlanDetails.getTransferOutArea().add(
                    BigDecimalUtil.init(changeNum).multiply(width).divide(100, 2).getValue()));
        }
    }

    private void headTailCorrect(PlanConfig planConfig, Date beginDate, Map<String, StockBackPlanDetails> stockBackPlanMap) {
        List<String> notCategoryCodeList = Arrays.asList(planConfig.getNotCategoryCodeSet().split(","));

        List<Map<String, Object>> list = baseMapper.getHeadTailCorrectList(Wrappers.query()
                .ge("sc.correct_date", beginDate)
                .notIn("m.CategoryCode", notCategoryCodeList)
        );

        for (Map<String, Object> map : list) {

            // 工号
            String jobNo = map.get("jobNo").toString();
            // 物料名称
            String materialName = map.get("materialName").toString().split("-")[0];
            // 排班时间
            Date planDate = DateUtil.beginOfDay((Date) map.get("createTime"));

            // 排班对象
            StockBackPlanDetails stockBackPlanDetails = stockBackPlanMap.get(jobNo + materialName + planDate.getTime());
            if (stockBackPlanDetails == null) {
                stockBackPlanDetails = createStockBackPlanDetails(jobNo, materialName, planDate);
                stockBackPlanMap.put(jobNo + materialName + planDate.getTime(), stockBackPlanDetails);
            }

            // 面积
            stockBackPlanDetails.setHeadTailCorrectArea(stockBackPlanDetails.getHeadTailCorrectArea().add(
                    Convert.toBigDecimal(map.get("area"), BigDecimal.ZERO)));
        }

    }

}
