package nc.bs.ic.m4d.insert;

import nc.bs.ic.general.insert.IInsertBP;
import nc.bs.ic.general.insert.rule.after.InsertAfterEventRule;
import nc.bs.ic.general.insert.rule.after.RewriteQCInsertRule;
import nc.bs.ic.general.insert.rule.before.CheckCliabilityValue;
import nc.bs.ic.general.insert.rule.before.InsertBeforeEventRule;
import nc.bs.ic.general.rule.after.AfterInsertRuleForRewriteSpecial;
import nc.bs.ic.general.rule.after.AtpAfterUpdate;
import nc.bs.ic.general.rule.before.CtplcustomeridCheck;
import nc.bs.ic.m45.insert.rule.PurchaseInProjectRule;
import nc.bs.ic.m4d.base.BPPlugInPoint;
import nc.bs.ic.m4d.base.MaterialOutCheckRule;
import nc.bs.ic.m4d.base.MaterialOutValueProcRule;
import nc.bs.ic.m4d.base.MaterialOutWarehouseAttriCheck;
import nc.bs.ic.m4d.base.PurchaseInDateCheck;
import nc.bs.ic.m4d.insert.rule.*;
import nc.bs.ic.pub.base.ICAroundProcesser;
import nc.bs.ic.pub.base.IInsertRuleProvider;
import nc.bs.scmpub.rule.CrossRuleValidateRule;
import nc.impl.pubapp.pattern.rule.processer.AroundProcesser;
import nc.vo.ic.general.define.MetaNameConst;
import nc.vo.ic.m4d.entity.MaterialOutVO;

/**
 * <p>
 * <b>材料出库单新增BP：</b>
 * <ul>
 * <li>
 * </ul>
 * <p>
 * <p>
 *
 * @version 6.0
 * @since 6.0
 * @author chennn
 * @time 2010-4-19 上午09:51:08
 */
public class InsertBP implements IInsertBP<MaterialOutVO>,
        IInsertRuleProvider<MaterialOutVO> {

    @Override
    public void addAfterRule(MaterialOutVO[] vos,
                             AroundProcesser<MaterialOutVO> processor) {
        /*
         * 放在现存量更新规则之后，因为回写销售订单，发货单时，如果出库数量等于订单数量，
         * 订单自动行关闭，行关闭会执行预留解除，导致现存量更新时，处理预留业务产生错误
         */
        ((ICAroundProcesser<MaterialOutVO>) processor).addAfterRuleAt(
                new UpdRewriteWorkOrder(), AtpAfterUpdate.class);
        processor.addAfterRule(new InsReWriteSapplyBillRule());// 回写出库申请申请
        processor.addAfterRule(new InsReWriteBuyingReqRule());// 回写物资需求申请
        // 回写项目管理备料表，放在回写出库申请之前，为了解决以下问题：
        // 不能计算预占量的问题，根本原因是因为出库申请的行关闭状态导致。
        // 之前出库单先回写出库申请，再回写备料备料表，回写备料表时，项目管理要查询当前出库申请的行状态是否关闭，根据该状态计算预占量。
        // 这样就不能区分此状态是因为出库单保存回写的还是出库单保存前就是关闭的
        ((ICAroundProcesser<MaterialOutVO>) processor).addAfterRuleAt(
                new InsReWritePIM(), InsReWriteSapplyBillRule.class);

        // 回写资产的领用单
        processor.addAfterRule(new InsRewriteRM());

        // 回写紧急放行单
        processor.addAfterRule(new RewriteQCInsertRule<MaterialOutVO>());

        /*
         * 放在现存量更新规则之后，因为回写销售订单，发货单时，如果出库数量等于订单数量，
         * 订单自动行关闭，行关闭会执行预留解除，导致现存量更新时，处理预留业务产生错误
         */
        ((ICAroundProcesser<MaterialOutVO>) processor).addAfterRuleAt(
                new InsRewriteMMPAC(), AtpAfterUpdate.class);

        // 回写生产报告
        processor.addAfterRule(new InsRewriteWR());

        //回写发货单
        processor.addAfterRule(new ReWriteSOInsertRule());

        // 工序完工报告倒冲时，回写备料计划
        processor.addAfterRule(new InsRewriteMMSFC());
        // 回写计划独立需求
        processor.addAfterRule(new InsertRewriteMMDP());
        // 回写特殊单据
        processor
                .addAfterRule(new AfterInsertRuleForRewriteSpecial<MaterialOutVO>());

        ((ICAroundProcesser<MaterialOutVO>) processor).replaceAfterRuleAt(
                new InsAfterfEventRuleFor4D(), InsertAfterEventRule.class);

    }

    @Override
    public void addBeforeRule(MaterialOutVO[] vos,
                              AroundProcesser<MaterialOutVO> processor) {
        processor.addBeforeRule(new MaterialOutValueProcRule());
        processor.addBeforeRule(new MaterialOutCheckRule());
        // 利润中心校验规则
        processor.addBeforeRule(new CheckCliabilityValue<MaterialOutVO>(MetaNameConst.CIOLIABILITYOID,MetaNameConst.CLIABILITYOID));
        //processor.addBeforeRule(new CheckBiliValue<MaterialOutVO>());//“领料利润中心有值时，出库利润中心不能为空”
        processor.addBeforeRule(new CtplcustomeridCheck<MaterialOutVO>());//表体“货主客户”与“寄存供应商”不能同时存在
        processor.addBeforeRule(new MaterialOutWarehouseAttriCheck());
        // 材料出库参照采购入库业务日期校验
        processor.addBeforeRule(new PurchaseInDateCheck());
        // 交叉校验规则
        processor.addBeforeRule(new CrossRuleValidateRule<MaterialOutVO>());

        ((ICAroundProcesser<MaterialOutVO>) processor).replaceBeforeRuleAt(
                new InsBeforeEventRuleFor4D(), InsertBeforeEventRule.class);

        //2025年6月13日09点38分 -- 物料档案基本页签启用项目辅助属性+库存组织未启用项目，采购入库单保存时（包含接口导入）清除行项目，材料出库单保存时（包含接口导入）清除行项目
        processor.addBeforeRule(new MaterialOutProjectRule());
    }

    @Override
    public MaterialOutVO[] insert(MaterialOutVO[] bills) {
        M4dInsertBPTemplate<MaterialOutVO> insertBP =
                new M4dInsertBPTemplate<MaterialOutVO>(BPPlugInPoint.InsertBP, this);
        return insertBP.insert(bills);
    }

}
