global class ConsumInventoryStartAssetSnapshotBatch implements Database.Batchable<sObject>, Database.Stateful {

    private String cunFangDi { get; set; }     //存放地, 肯定有值 不为null
    private Datetime lastInventoryTime {get;set;} // 上次盘点时间
    private Inventory_Header__c ih_new = new Inventory_Header__c(); // 借出备品盘点表头
    private Inventory_Header__c ih_consum = new Inventory_Header__c(); // 耗材备品盘点表头
    private Map<String, List<String>> statusMap = new Map<String, List<String>>();
    private Map<String, String> assetFieldMap = new Map<String, String>();
    private Map<String, String> raesdFieldMap = new Map<String, String>();
    //private Map<String, String> repairFieldMap = new Map<String, String>();
    private Set<String> availableMain = new Set<String>();
    private Set<String> availableMainOnStock = new Set<String>();
    private Set<String> defaultAssetField;
    private Set<String> defaultRaesdField;
    //private Set<String> defaultRepairField;

    global List<String> emailMessages;
    global Integer totalCount = 0; // 总件数 (Asset)
    global Integer executedCount = 0;
    global Integer failedCount = 0;
    global Id recordTypeId;

    @TestVisible
    private static List<String> messagesForTest;

    global ConsumInventoryStartAssetSnapshotBatch(String cunFangDi, Inventory_Header__c ih_new){
        Integer i = 0;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        i ++;
        this.cunFangDi = cunFangDi;
        this.ih_new = [SELECT Id, Name, InventorySubmit_PIC__c,InventoryCheck_PIC__c FROM Inventory_Header__c WHERE Id=:ih_new.Id LIMIT 1];
        this.emailMessages = new List<String>();
        this.recordTypeId = Inventory_Header__c.sObjectType.getDescribe().getRecordTypeInfosByDeveloperName().get('Consum_Header').getRecordTypeId();
    }

    global Database.QueryLocator start(Database.BatchableContext bc) {
        List<Inventory_Header__c> lastInventory = [SELECT CreatedDate
                                               FROM Inventory_Header__c
                                              WHERE Fixture_Header__c!=null
                                                AND Fixture_Header__c!=:ih_new.Id
                                              ORDER BY CreatedDate DESC
                                              LIMIT 1
                                              ];
        if(lastInventory.isEmpty()){
            lastInventoryTime = Datetime.newInstanceGMT(1970, 1, 1, 0, 0, 0);
        }
        else{
            lastInventoryTime = lastInventory[0].CreatedDate;
        }
        List<Inventory_Header__c> ihConsumList = [SELECT Id
                                                 , Name
                                                 , Inventory_Status__c
                                                 , Internal_asset_location__c
                                                 , InventorySubmit_PIC__c
                                                 , InventoryCheck_PIC__c
                                              FROM Inventory_Header__c
                                             WHERE Fixture_Header__c = :ih_new.Id];
        if (ihConsumList.size() == 0){
            Inventory_Header__c ih = new Inventory_Header__c();
            ih.Internal_asset_location__c = cunFangDi;
            ih.Inventory_Status__c = '处理中';
            ih.InventoryPIC__c = UserInfo.getUserId();
            ih.Inventory_Start_Date__c = Date.today();
            ih.InventorySubmit_PIC__c = ih_new.InventorySubmit_PIC__c;
            ih.InventoryCheck_PIC__c = ih_new.InventoryCheck_PIC__c;
            ih.Fixture_Header__c = ih_new.id;
            ih.UniqueKey__c = cunFangDi+':'+Date.today().toStartOfMonth();
            ih.RecordTypeId = this.recordTypeId;
            insert ih;
            this.ih_consum = ih;
        }
        else if (ihConsumList[0].Inventory_Status__c != '处理中') {
            if (ihConsumList[0].Inventory_Status__c == null) {
                Inventory_Header__c ih = new Inventory_Header__c();
                ih.Internal_asset_location__c = ihConsumList[0].Internal_asset_location__c;
                ih.Inventory_Status__c = '处理中';
                ih.InventoryPIC__c = UserInfo.getUserId();
                ih.Inventory_Start_Date__c = Date.today();
                ih.InventorySubmit_PIC__c = ihConsumList[0].InventorySubmit_PIC__c;
                ih.InventoryCheck_PIC__c = ihConsumList[0].InventoryCheck_PIC__c;
                ih.Fixture_Header__c = ih_new.id;
                ih.UniqueKey__c = ihConsumList[0].Internal_asset_location__c+':'+Date.today().toStartOfMonth();
                ih.RecordTypeId = this.recordTypeId;

                delete ihConsumList[0];
                insert ih;
                this.ih_consum = ih;
            } else {
                this.emailMessages.add(ihConsumList[0].Name +'的状态是' + ihConsumList[0].Inventory_Status__c + ' ,不能盘点。');
                return Database.getQueryLocator([SELECT Id FROM Asset LIMIT 0]);
            }
        }

        List<Asset> errorList = [SELECT Id
                                      , Inventory_Frozen_Quantity__c
                                   FROM Asset
                                  WHERE (Inventory_Frozen_Quantity__c>0
                                     OR Appended_Inventory_Frozen_Quantity__c>0
                                     OR Inventory_Profit_Quantity__c>0
                                     OR Appended_Inventory_Profit_Quantity__c>0)
                                     AND Asset_loaner_category__c = '耗材'
                                    AND Internal_asset_location__c = :cunFangDi];
        if (errorList.size()>0) {
            Inventory_Header__c ihc = [SELECT Name FROM Inventory_Header__c WHERE id=:this.ih_consum.Id];
            this.emailMessages.add(ihc.Name + ' 耗材资产中存在未清空的冻结数, 不能盘点。');
            return Database.getQueryLocator([SELECT Id FROM Asset LIMIT 0]);
        }

        defaultAssetField = new Set<String> {'Id','Abandoned_RealThing__c','Abandoned_Inventory__c','Barcode__c','Consumed_Count__c','Fixture_Model_No_F__c','Internal_asset_location__c','WH_location__c','Ji_Zhong_Guan_Li_Ku_Cun__c','You_Xiao_Ku_Cun__c','Out_of_wh__c','Manage_type__c','Fixture_Status__c','Quantity','Frozen_Quantity__c'};
        defaultRaesdField = new Set<String> {'Id','Asset__c','RAESD_Status__c'};

        statusMap.put('出借中', new List<String> {'已出库','申请者已收货','申请者收货NG','待消耗','已回寄'});
        statusMap.put('在库', new List<String> {'䓍案中','申请中','暂定分配','已分配','已出库指示','移至过期区','待废弃','已回库'});

        Inventory_Batch_Mapping__mdt columns = [select From_Columns__c, Inventory_Columns__c from Inventory_Batch_Mapping__mdt where DeveloperName = 'ConsumAsset'];
        List<String> keyList = columns.From_Columns__c.split(',');
        List<String> valueList = columns.Inventory_Columns__c.split(',');
        for (Integer i = 0; i < keyList.size(); i++) {
            assetFieldMap.put(keyList[i], valueList[i]);
            defaultAssetField.add(keyList[i]);
        }

        columns = [select From_Columns__c, Inventory_Columns__c from Inventory_Batch_Mapping__mdt where DeveloperName = 'CAESD'];
        keyList = columns.From_Columns__c.split(',');
        valueList = columns.Inventory_Columns__c.split(',');
        for (Integer i = 0; i < keyList.size(); i++) {
            raesdFieldMap.put(keyList[i], valueList[i]);
            defaultRaesdField.add(keyList[i]);
        }

        String querysql = 'select ' + String.join(new List<String>(defaultAssetField), ', ')
                + ' from Asset '
                + 'where Internal_asset_location__c = :cunFangDi'
                + '  and Fixture_Status__c != \'废弃\''
                + '  and Delete_Flag__c = False'
                + '  and (Quantity > 0 or Consumed_Count__c > 0)'
                + '  and Asset_Owner__c = \'Olympus\''
                + '  and ' + FixtureUtil.getAssetSoqlBase()
                + '  and Asset_loaner_category__c = \'耗材\''
                // 增加排序确保主体先处理
                + '  order by Manage_type__c desc, Main_OneToOne__c desc, Last_Reserve_RAES_Detail__r.Is_Body__c desc';
        return Database.getQueryLocator(querysql);
    }

    global void execute(Database.BatchableContext BC, list<Asset> assetList) {
        // select ih_new, is batch executing, else return
        List<Inventory_Header__c> ihConsumList = [select Id, Name, Inventory_Status__c
                from Inventory_Header__c where Fixture_Header__c = :ih_new.Id];
        if (ihConsumList.size() == 0 || ihConsumList[0].Inventory_Status__c != '处理中') {
            // emailMessages ihConsumList[0].Name 的状态是 ihConsumList[0].Inventory_Status__c 不能盘点
            this.emailMessages.add(ihConsumList[0].Name +'的状态是' + ihConsumList[0].Inventory_Status__c + ' ,不能盘点。');
            return;
        }
    Savepoint sp = Database.setSavepoint();
    try {
        //总件数count
        totalCount += assetList.size();

        // UniqueKey__c:Record
        Map<String, Consum_Inventory_Detail__c> upsertMap = new Map<String, Consum_Inventory_Detail__c>();
        Map<Id, Asset> assetMap = new Map<Id, Asset>();
        for (Asset ast : assetList) {
            assetMap.put(ast.Id, ast);
            // '在库' from Asset
            Consum_Inventory_Detail__c ihDetail = new Consum_Inventory_Detail__c();
            ihDetail.Asset__c = ast.Id;

            ihDetail.Amount__c = ast.Quantity;
            ihDetail.WH_location__c = ast.WH_location__c;

            ihDetail.Asset_Status__c = '在库';
            ihDetail.Sync_Asset_Record_Flag__c = true;
            ihDetail.UniqueKey__c = ih_consum.Id+':'+ast.Fixture_Model_No_F__c+':'+ihDetail.Asset_Status__c+':'+ast.Id;
            ihDetail.Inventory_Header__c = ih_consum.Id;
            ihDetail.Fixture_Model_No__c = ast.Fixture_Model_No_F__c;
            ihDetail.Internal_asset_location__c = ast.Internal_asset_location__c;
            ihDetail.toAbandon_amount__c = ast.Abandoned_RealThing__c;
            ihDetail.Abandoned_Inventory_Start__c = ast.Abandoned_Inventory__c;
            if(ast.Abandoned_Inventory__c!=null && ast.Abandoned_Inventory__c > 0) {
                ihDetail.Amount__c -= ast.Abandoned_Inventory__c;
            }
            // '已消耗' from Asset
            if (ast.Consumed_Count__c > 0) {
                Consum_Inventory_Detail__c ihDetail_abd = new Consum_Inventory_Detail__c();
                ihDetail_abd.Asset__c = ast.Id;
                ihDetail_abd.Asset_Status__c = '已消耗';
                ihDetail_abd.UniqueKey__c = ih_consum.Id+':'+ast.Fixture_Model_No_F__c+':'+ihDetail_abd.Asset_Status__c+':'+ast.Id;
                ihDetail_abd.Inventory_Header__c = ih_consum.Id;
                ihDetail_abd.Fixture_Model_No__c = ast.Fixture_Model_No_F__c;
                ihDetail_abd.WH_location__c = ast.WH_location__c;
                ihDetail_abd.Internal_asset_location__c = ast.Internal_asset_location__c;
                ihDetail_abd.Amount__c = ast.Consumed_Count__c;
                ihDetail_abd.Consumed_Count_Start__c = ast.Consumed_Count__c;
                setMapObject(ihDetail_abd, ast, 'Asset');
                upsertMap.put(ihDetail_abd.UniqueKey__c, ihDetail_abd);
            }
            // '冻结' from Asset
            if (ast.Frozen_Quantity__c > 0) {
                Consum_Inventory_Detail__c ihDetail_frz = new Consum_Inventory_Detail__c();
                ihDetail_frz.Asset__c = ast.Id;
                //if (ast.Main_OneToOne__c) {
                //    ihDetail_frz.OneToOne_Body__c = true;
                //}
                //if (ast.Fixture_OneToOne_Link__c != null) {
                //    ihDetail_frz.Main_Asset__c = ast.Fixture_OneToOne_Link__r.Main_Asset__c;
                //}
                ihDetail_frz.Asset_Status__c = '冻结';
                ihDetail_frz.UniqueKey__c = ih_new.Id+':'+ast.Fixture_Model_No_F__c+':'+ihDetail_frz.Asset_Status__c+':'+ast.Id;
                ihDetail_frz.Inventory_Header__c = ih_consum.Id;
                ihDetail_frz.Fixture_Model_No__c = ast.Fixture_Model_No_F__c;
                ihDetail_frz.WH_location__c = ast.WH_location__c;
                ihDetail_frz.Internal_asset_location__c = ast.Internal_asset_location__c;
                ihDetail_frz.Amount__c = ast.Frozen_Quantity__c;
                setMapObject(ihDetail_frz, ast, 'Asset');
                upsertMap.put(ihDetail_frz.UniqueKey__c, ihDetail_frz);
                ihDetail.Amount__c = ihDetail.Amount__c - ihDetail_frz.Amount__c;
            }
            //待废弃数
            if (ast.Fixture_Status__c == '待废弃') {
                ihDetail.toAbandon_amount__c = ihDetail.Amount__c;
            }
            setMapObject(ihDetail, ast, 'Asset');
            //if (ast.Fixture_OneToOne_Link__c != null) {
            //    ihDetail.WH_location__c = ast.Fixture_OneToOne_Link__r.Main_Asset__r.WH_location__c;
            //}
            upsertMap.put(ihDetail.UniqueKey__c, ihDetail);
        }

        //耗材一览明细
        List<Consum_Apply_Equipment_Set_Detail__c> copy_caList = [select Consum_Apply__c
                from Consum_Apply_Equipment_Set_Detail__c
                where Asset__c IN :assetList
                    and Consum_Apply__r.RA_Status__c ='完了'
                    and RAESD_Status__c ='已消耗'
                    and Lost_item_check_time_Final__c>:lastInventoryTime
                    ];

        Set<Id> copy_caId = new Set<Id>();
        for (Consum_Apply_Equipment_Set_Detail__c copy_ca : copy_caList) {
            copy_caId.add(copy_ca.Consum_Apply__c);
        }

        String querysql = 'select ' + String.join(new List<String>(defaultRaesdField), ', ')
                + ' from Consum_Apply_Equipment_Set_Detail__c '
                + ' where Asset__c IN :assetList '
                + ' and (Consum_Apply__r.RA_Status__c <> \'完了\' or Consum_Apply__c in :copy_caId)';

        List<Consum_Apply_Equipment_Set_Detail__c> detailList = Database.query(querysql);

        for (Consum_Apply_Equipment_Set_Detail__c dl : detailList) {
            Asset ast = assetMap.get(dl.Asset__c);
            //String main_Asset_Id = null;
            //if (ast.Fixture_OneToOne_Link__c != null) {
            //    main_Asset_Id = ast.Fixture_OneToOne_Link__r.Main_Asset__c;
            //} else if (ast.Last_Reserve_RAES_Detail__r.Is_Body__c && statusMap.get('在库').contains(ast.Last_Reserve_RAES_Detail__r.RAESD_Status__c)) {
            //    main_Asset_Id = ast.Id;
            //}

            // 已消耗的耗材明细 （仿照备品的丢失改写）
            if ('已消耗' == dl.RAESD_Status__c && dl.Lost_item_check_time_Final__c!=null && dl.Lost_item_check_time_Final__c>lastInventoryTime) {
                Consum_Inventory_Detail__c ihDetail_lend = new Consum_Inventory_Detail__c();
                ihDetail_lend.Asset__c = ast.Id;
                ihDetail_lend.RAESD__c = dl.Id;
                ihDetail_lend.RAESD_Id__c = dl.Id;
                ihDetail_lend.Asset_Status__c = '已消耗明细';
                ihDetail_lend.UniqueKey__c = ih_consum.Id+':'+ast.Fixture_Model_No_F__c+':'+ihDetail_lend.Asset_Status__c+':'+ast.Id+':'+dl.Id;
                ihDetail_lend.Inventory_Header__c = ih_consum.Id;
                ihDetail_lend.Fixture_Model_No__c = ast.Fixture_Model_No_F__c;
                ihDetail_lend.WH_location__c = ast.WH_location__c;
                ihDetail_lend.Internal_asset_location__c = ast.Internal_asset_location__c;
                ihDetail_lend.Amount__c = 1;
                setMapObject(ihDetail_lend, ast, 'Asset');
                setMapObject(ihDetail_lend, dl, 'Raesd');
                upsertMap.put(ihDetail_lend.UniqueKey__c, ihDetail_lend);
            }
            // 出借中 from 明细
            else if (statusMap.get('出借中').contains(dl.RAESD_Status__c)) {
                Consum_Inventory_Detail__c ihDetail_lend = new Consum_Inventory_Detail__c();
                ihDetail_lend.Asset__c = ast.Id;
                ihDetail_lend.RAESD__c = dl.Id;
                ihDetail_lend.RAESD_Id__c = dl.Id;
                ihDetail_lend.Asset_Status__c = '出借中';
                ihDetail_lend.UniqueKey__c = ih_consum.Id+':'+ast.Fixture_Model_No_F__c+':'+ihDetail_lend.Asset_Status__c+':'+ast.Id+':'+dl.Id;
                ihDetail_lend.Inventory_Header__c = ih_consum.Id;
                ihDetail_lend.Fixture_Model_No__c = ast.Fixture_Model_No_F__c;
                ihDetail_lend.WH_location__c = ast.WH_location__c;
                ihDetail_lend.Internal_asset_location__c = ast.Internal_asset_location__c;
                ihDetail_lend.Amount__c = 1;
                setMapObject(ihDetail_lend, ast, 'Asset');
                setMapObject(ihDetail_lend, dl, 'Raesd');
                upsertMap.put(ihDetail_lend.UniqueKey__c, ihDetail_lend);

                String uniKey = ih_consum.Id+':'+ast.Fixture_Model_No_F__c+':'+'在库'+':'+ast.Id;
                Consum_Inventory_Detail__c ihDetail = upsertMap.get(uniKey);
                if (ihDetail != null) {
                    ihDetail.Amount__c -= 1;
                    upsertMap.put(ihDetail.UniqueKey__c, ihDetail);
                }
            }
            // 待移至报废区+设置虚拟货架号 from 明细
            else if (statusMap.get('在库').contains(dl.RAESD_Status__c)) {
                //if(dl.OneToOne_Flag__c == false) {
                    String uniKey = ih_consum.Id+':'+ast.Fixture_Model_No_F__c+':'+'在库'+':'+ast.Id;
                    String vhwLocation = '待回库区';
                    //if(dl.RAESD_Status__c == '已下架' || dl.RAESD_Status__c == '出库前已检测' ){
                    //    vhwLocation = '备货区';
                    //}
                    //设置待报废数量
                    Consum_Inventory_Detail__c ihDetail = upsertMap.get(uniKey);
                    if (dl.RAESD_Status__c == '待废弃' ) {
                        if (ihDetail.toAbandon_amount__c == null) {
                            ihDetail.toAbandon_amount__c = 1;
                        } else {
                            ihDetail.toAbandon_amount__c += 1;
                        }
                    }

                    ihDetail.VWH_location__c = vhwLocation;
                    upsertMap.put(ihDetail.UniqueKey__c, ihDetail);
                //}
                // 一对一
                //else {
                //    main_Asset_Id = dl.Rental_Apply_Equipment_Set__r.First_RAESD__r.Asset__c;
                //    String uniKey = ih_new.Id+':'+ast.Fixture_Model_No_F__c+':'+'在库'+':'+main_Asset_Id+':'+ast.Id;
                //    String vhwLocation = '待回库区';
                //    if(dl.RAESD_Status__c == '已下架' || dl.RAESD_Status__c == '出库前已检测' ){
                //        vhwLocation = '备货区';
                //    }
                //    Inventory_Detail__c ihDetail = upsertMap.get(uniKey);
                //    if (ihDetail == null) {
                //        ihDetail = new Inventory_Detail__c();
                //        ihDetail.Asset__c = ast.Id;
                //        ihDetail.OneToOne_Accsessary__c = true;
                //        ihDetail.Main_Asset__c = main_Asset_Id;
                //        ihDetail.Asset_Status__c = '在库';
                //        ihDetail.UniqueKey__c = ih_new.Id+':'+ast.Fixture_Model_No_F__c+':'+ihDetail.Asset_Status__c+':'+ihDetail.Main_Asset__c+':'+ast.Id;
                //        ihDetail.Inventory_Header__c = ih_new.Id;
                //        ihDetail.Fixture_Model_No__c = ast.Fixture_Model_No_F__c;
                //        ihDetail.VWH_Location__c = vhwLocation;
                //        ihDetail.Internal_asset_location__c = ast.Internal_asset_location__c;
                //        ihDetail.Amount__c = 1;
                //        setMapObject(ihDetail, ast, 'Asset');
                //        ihDetail.WH_location__c = dl.Rental_Apply_Equipment_Set__r.First_RAESD__r.Asset__r.WH_location__c;
                //        upsertMap.put(ihDetail.UniqueKey__c, ihDetail);
                //    } else {
                //        ihDetail.Amount__c += 1;
                //        //ihDetail.VWH_location__c = vhwLocation;
                //        upsertMap.put(ihDetail.UniqueKey__c, ihDetail);
                //    }
                //    uniKey = ih_new.Id+':'+ast.Fixture_Model_No_F__c+':'+'在库'+':'+null+':'+ast.Id;
                //    if (upsertMap.containsKey(uniKey)) {
                //        Inventory_Detail__c ihDetail_org = upsertMap.get(uniKey);
                //        ihDetail_org.Amount__c -= 1;
                //        upsertMap.put(ihDetail_org.UniqueKey__c, ihDetail_org);
                //    }
                //}
            }
        }
        // link 一对一
        //List<Fixture_OneToOne_Link__c> otoAccessoryList =
        //    [select Accessory_Asset__r.Fixture_Model_No_F__c,
        //            Accessory_Asset__r.Internal_asset_location__c,
        //            Accessory_Asset__r.WH_location__c,
        //            Main_Asset__r.WH_location__c,
        //            Accessory_Asset__c,
        //            Main_Asset__c,
        //            Quantity__c
        //        from Fixture_OneToOne_Link__c
        //        where Accessory_Asset__r.Internal_asset_location__c=:cunFangDi
        //         and Accessory_Asset__c IN :assetList];
        //for (Fixture_OneToOne_Link__c odl : otoAccessoryList) {
        //    Asset ast = assetMap.get(odl.Accessory_Asset__c);
        //    String main_Asset_Id = odl.Main_Asset__c;
        //    String uniKey = ih_new.Id+':'+ast.Fixture_Model_No_F__c+':'+'在库'+':'+main_Asset_Id+':'+ast.Id;
        //    Inventory_Detail__c ihDetail = upsertMap.get(uniKey);
        //    if (ihDetail == null) {
        //        ihDetail = new Inventory_Detail__c();
        //        ihDetail.Asset__c = ast.Id;
        //        ihDetail.Asset_Status__c = '在库';
        //        ihDetail.Inventory_Header__c = ih_new.Id;
        //        ihDetail.UniqueKey__c = uniKey;
        //        ihDetail.OneToOne_Accsessary__c = true;
        //        ihDetail.Main_Asset__c = main_Asset_Id;
        //        ihDetail.Fixture_Model_No__c = odl.Accessory_Asset__r.Fixture_Model_No_F__c;
        //        ihDetail.Internal_asset_location__c = odl.Accessory_Asset__r.Internal_asset_location__c;
        //        ihDetail.Amount__c = odl.Quantity__c;
        //        setMapObject(ihDetail, ast, 'Asset');
        //        ihDetail.WH_location__c = odl.Main_Asset__r.WH_location__c;
        //        ihDetail.Fixture_OneToOne_Link__c = odl.Id;
        //        upsertMap.put(ihDetail.UniqueKey__c, ihDetail);
        //    } else {
        //        ihDetail.Amount__c += odl.Quantity__c;
        //        upsertMap.put(ihDetail.UniqueKey__c, ihDetail);
        //    }
        //    uniKey = ih_new.Id+':'+ast.Fixture_Model_No_F__c+':'+'在库'+':'+null+':'+ast.Id;
        //    if (upsertMap.containsKey(uniKey)) {
        //        Inventory_Detail__c ihDetail_org = upsertMap.get(uniKey);
        //        ihDetail_org.Amount__c -= odl.Quantity__c;
        //        upsertMap.put(ihDetail_org.UniqueKey__c, ihDetail_org);
        //    }
        //}

        //check amount
        Set<Id> asstIdSet = new Set<Id>();
        List<Consum_Inventory_Detail__c> upsertDetailList = new List<Consum_Inventory_Detail__c>();
        for (String uniKey: upsertMap.keySet()) {
            Consum_Inventory_Detail__c upsertDetail = upsertMap.get(uniKey);
            if (upsertDetail.Amount__c >= 0) {
                upsertDetailList.add(upsertDetail);
                // 收集所有在库的一对一主体Asset
                //if (upsertDetail.OneToOne_Body__c && upsertDetail.Amount__c > 0 && upsertDetail.Asset_Status__c == '在库') {
                //    availableMain.add(upsertDetail.Main_Asset__c);
                //    if (String.isBlank(upsertDetail.VWH_location__c)) availableMainOnStock.add(upsertDetail.Main_Asset__c);
                //}
            }
            if (upsertDetail.Amount__c < 0) {
                asstIdSet.add(upsertDetail.Asset__c);
                //error
                this.emailMessages.add('保有设备：'+upsertDetail.Fixture_Model_No__c + '(' + upsertDetail.Asset__c + ')的' + Consum_Inventory_Detail__c.Fields.Amount__c.getDescribe().getLabel() + ' < 0');
                //failedCount ++;
            }
        }

        // 处理找不到主体的一对一附属品
        //for (Consum_Inventory_Detail__c idc : upsertDetailList) {
        //    if (idc.OneToOne_Accsessary__c) {
        //        // 一对一附属品，并且对应的主体不是在库状态。
        //        if (!availableMain.contains(idc.Main_Asset__c) ||
        //                // 一对一附属品在借出明细里，主机单独上架了
        //                (availableMainOnStock.contains(idc.Main_Asset__c) && String.isBlank(idc.Fixture_OneToOne_Link__c))) {

        //            String uKey = idc.UniqueKey__c;
        //            List<String> parts = uKey.split(':');
        //            parts[3] = 'null';
        //            uKey = String.join(parts, (':'));
        //            // 把集中库存的的数量加回去
        //            Consum_Inventory_Detail__c ihDetail_org = upsertMap.get(uKey);
        //            if (ihDetail_org != null) {
        //                ihDetail_org.Amount__c += idc.Amount__c;
        //                upsertMap.put(ihDetail_org.UniqueKey__c, ihDetail_org);
        //                upsertMap.put(idc.UniqueKey__c, null);
        //            } else {
        //                //个体一对一附属品的话，清除一对一状态。
        //                if (idc.Manage_type__c == FixtureUtil.managetypeMap.get(FixtureUtil.Managetype.Ge_Ti_Guan_Li)) {
        //                    upsertMap.put(idc.UniqueKey__c, null);
        //                    idc.UniqueKey__c = uKey;
        //                    idc.OneToOne_Accsessary__c = false;
        //                    upsertMap.put(idc.UniqueKey__c, idc);
        //                } else {
        //                    this.emailMessages.add('不整合一对一数据：UniqueKey(' + idc.UniqueKey__c + ')');
        //                }
        //            }
        //        }
        //    }
        //}

        // 重新做成upsertlist
        upsertDetailList = new List<Consum_Inventory_Detail__c>();
        for (String uniKey: upsertMap.keySet()) {
            Consum_Inventory_Detail__c upsertDetail = upsertMap.get(uniKey);
            if (upsertDetail != null && upsertDetail.Amount__c >= 0) {
                upsertDetailList.add(upsertDetail);
            }
        }

        List<Database.UpsertResult> upResult = Database.upsert(upsertDetailList, Consum_Inventory_Detail__c.Fields.UniqueKey__c, false);
        this.emailMessages = FixtureUtil.setUpstError(upResult, Consum_Inventory_Detail__c.sObjectType, upsertDetailList, this.emailMessages);
        for (Integer i = 0; i < upResult.size(); i++) {
            Database.UpsertResult sr = upResult[i];
            if (!sr.isSuccess()) {
                Consum_Inventory_Detail__c iobj = upsertDetailList[i];
                asstIdSet.add(iobj.Asset__c);
            }
        }
        //upsert upsertDetailList UniqueKey__c;

        failedCount += asstIdSet.size();
    } catch(Exception e) {
        Database.rollback(sp);
        System.debug(LoggingLevel.ERROR, + e.getMessage() + '\n' + e.getStackTraceString());
        this.emailMessages.add(ihConsumList[0].Name  + ' 耗材盘点开始处理 Exception:' + e.getMessage() + '\n' + e.getStackTraceString());
    }
        executedCount += assetList.size();
    }

    global void finish(Database.BatchableContext BC) {
        String text = '';
        try {
            if (this.emailMessages.size() == 0 && totalCount == executedCount) {
                List<Inventory_Header__c> iheaderList = [select Id
                                                              , Inventory_Status__c
                                                              , Name
                                                              , Internal_asset_location__c
                                                              , Inventory_Start_Date__c
                                                              , Fixture_Header__c
                                                            from Inventory_Header__c
                                                            where Id = :ih_consum.Id
                                                            or Id = :ih_new.Id];
                for(Inventory_Header__c iheader : iheaderList){
                    iheader.Inventory_Status__c = '盘点中';
                    if(String.isNotBlank(iheader.Fixture_Header__c)){
                        text += '耗材盘点报告书编号：' + iheader.Name + '  耗材盘点地点：' + iheader.Internal_asset_location__c + '  耗材盘点开始日：' + iheader.Inventory_Start_Date__c;
                    }
                }
                update iheaderList;
                text += '\n耗材盘点batch已结束，可以开始盘点。';
            } else {
                Inventory_Header__c iheader = [select Id, Inventory_Status__c, Name, Internal_asset_location__c, Inventory_Start_Date__c
                                                from Inventory_Header__c
                                                where Id = :ih_consum.Id];
                text = '耗材盘点报告书编号：' + iheader.Name + '  耗材盘点地点：' + iheader.Internal_asset_location__c + '  耗材盘点开始日：' + iheader.Inventory_Start_Date__c;
                text += '\n开始盘点 处理失败。';
            }
        } catch (Exception e) {
            system.debug(e);
            this.emailMessages.add(e.getMessage());
        }
        ConsumInventoryStartAssetSnapshotBatch.messagesForTest = this.emailMessages;
        // 发 mail
        BatchEmailUtil be = new BatchEmailUtil();
        String[] toList = new String[]{UserInfo.getUserEmail()};
        String title = '开始耗材盘点';
        String[] ccList = new String[]{};
        for(String email : System.Label.Inventory_Result_Email.split(',')){
            ccList.add(email);
        }
        if(this.emailMessages.size() == 0 && totalCount == executedCount) {
            be.successMail(toList,ccList, title, totalCount, text);
        }else{
            String emailLabel = 'BatchNotify';
            for (OrgWideEmailAddress tmpEmailObj : [SELECT Id, Address, DisplayName
                    FROM OrgWideEmailAddress
                    WHERE DisplayName like :emailLabel]) {
                ccList.add(tmpEmailObj.Address);
            }
            if (totalCount != executedCount) {
                this.emailMessages.add('有一部分Batch没有运行, 请确认系统管理员。');
            }
            be.failedMail(toList, ccList, title,
                    String.join(this.emailMessages, '\n'),
                    totalCount, executedCount, failedCount);
        }
        be.send();
    }
    private void setMapObject(Consum_Inventory_Detail__c idetail, sObject obj, String typeStr) {
        List<String> fromCol;
        List<String> toCol;
        if (typeStr == 'Asset') {
            fromCol = new List<String>(assetFieldMap.keySet());
            toCol = assetFieldMap.values();
        //} else if (typeStr == 'Repair') {
        //    fromCol = new List<String>(repairFieldMap.keySet());
        //    toCol = repairFieldMap.values();
        } else {
            fromCol = new List<String>(raesdFieldMap.keySet());
            toCol = raesdFieldMap.values();
        }

        for (Integer i = 0; i < fromCol.size(); i++) {
            List<String> cols = fromCol[i].split('\\.');
            idetail.put(toCol[i], CreateRelationListPagingCmpCtrl.getObjectValue(obj, cols));
        }
    }
}