global class ConsumInventoryReportDetailArchiveBatch implements Database.Batchable<sObject>, Database.Stateful {
    private Inventory_Header__c ih_new = new Inventory_Header__c();
    private String docBodyAsset = '';           // TODO 5M と batch heap size 問題
    // private String docBodyRaesd = '';           // TODO 5M と batch heap size 問題
    private String docBodyDiushi = '';          // TODO 5M と batch heap size 問題
    //private String docBodyRepair = '';          // TODO 5M と batch heap size 問題
    private Boolean falg = false;   //保存或更新标识 ymh
    Id folderId = System.Label.InventoryFolder; //ymh 添加文档库标签

    private Set<String> defaultAssetField;
    private Set<String> defaultRaesdField;
    //private Set<String> defaultRepairField;
    private List<String> cListAssetField = new List<String>();
    private List<String> cListConsumedField = new List<String>();
    private List<String> cListRaesdField = new List<String>();
    //private List<String> cListRepairField = new List<String>();
    private Map<String, String> fieldAPIName = new Map<String, String>();

    global List<String> emailMessages;
    global Integer totalCount = 0; // 总件数 (Consum_Inventory_Detail__c (Sync_Asset_Record_Flag__c = true))
    global Integer failedCount = 0;

    @TestVisible
    private static List<String> messagesForTest;

    /**
     * 批准后, Trigger 会来调
     */
    global ConsumInventoryReportDetailArchiveBatch(Inventory_Header__c ih_new) {
        this.emailMessages = new List<String>();
        this.ih_new = ih_new;
    }

    global Database.QueryLocator start(Database.BatchableContext bc) {
        // bp3_Setting__c conf = bp3_Setting__c.getOrgDefaults();
        //  ymh  更改文件链接判断 start
        if (String.isBlank(folderId)) {
        //  ymh  更改文件链接判断 end
            this.emailMessages.add('未设置CSV保存文件夹，不能开始Batch');
            failedCount = 0;
            return Database.getQueryLocator([SELECT Id FROM Consum_Inventory_Detail__c LIMIT 0]);
        }

        Inventory_Batch_Mapping__mdt columns;
        List<String> keyList;

        defaultAssetField = new Set<String>();
        defaultRaesdField = new Set<String>();
        //defaultRepairField = new Set<String>();

        columns = [select From_Columns__c, Inventory_Columns__c from Inventory_Batch_Mapping__mdt where DeveloperName = 'ConsumAsset'];
        keyList = columns.Inventory_Columns__c.split(',');
        keyList.addAll(new List<String> {
                'Inventory_Zaiku_Count_Jia__c',
                'Inventory_Shipan_Count_Jia__c',
                //'Inventory_Weixiu_Count_Jia__c',
                'Inventory_Chujie_Count_Jia__c',
                //'Inventory_Daibaofei_Diushi_Count_Jia__c',
                'Inventory_Quantity_Jia__c',
                'Inventory_Profit_Quantity__c',
                'Inventory_Loss_Quantity__c',
                'Inventory_Deviation_Jia__c',
                'Barcode__c',
                'Consumed_Count__c',
                'Inventory_Remarks__c',
                'Remarks_Person__r.Name'
        });

        String cListAssetFieldStr = 'Asset__c,Internal_asset_location__c,Salesdepartment__c,Fixture_Model_No__c,Asset_Name__c,SerialNumber__c,Equipment_Type__c,Consumable_Guaranteen_end__c,Manage_type__c,Loaner_accsessary__c,AssetManageConfirm__c,Fixture_QRCode__c,WH_location__c,Fixture_Status__c,Inventory_Zaiku_Count_Jia__c,Inventory_Shipan_Count_Jia__c,Inventory_Chujie_Count_Jia__c,Inventory_Quantity_Jia__c,Inventory_Profit_Quantity__c,Inventory_Loss_Quantity__c,Inventory_Deviation_Jia__c,Inventory_Remarks__c,Barcode__c,Consumed_Count__c,Remarks_Person__r.Name';
        cListAssetField = cListAssetFieldStr.split(',');
        for (Integer i = 0; i < keyList.size(); i++) {
            defaultAssetField.add(keyList[i]);
        }

        String cListConsumedFieldStr = 'Consum_Apply_Name__c,Account__c,RA_Status__c,Salesdept__c,WorkPlace__c,Person_In_Charge_New__c,Person_In_Charge__c,demo_purpose2__c,RAES_No__c,RAES_Status__c,RAESD_Name__c,RAESD_Status__c,Fixture_Model_No__c,SerialNumber__c,Internal_asset_location__c,Equipment_Type__c,Salesdepartment__c,WH_location__c,Consum_Start_Date__c,Show_demonstration__c,Operation_Type__c,Case_OR_animal_organ__c,Trial_User__c,Follower_User__r.Name,Spare__c,Request_approval_time__c,Select_Time__c,Request_shipping_day__c,Shipment_request_time2__c,Shippment_loaner_time__c,Loaner_received_time__c,Consum_Received_Day__c,Asset_Center_Confirm_Time__c,Lost_item_check_time__c,Lost_item_check_time_Final__c,AssetManageConfirmYN__c,RAESD__c,Consum_Apply__c,Consum_Apply_Equipment_Set__c,Asset__c';
        cListConsumedField = cListConsumedFieldStr.split(',');
        String cListRaesdFieldStr = 'Consum_Apply_Name__c,Account__c,RA_Status__c,Salesdept__c,WorkPlace__c,Person_In_Charge_New__c,Person_In_Charge__c,demo_purpose2__c,RAES_No__c,RAES_Status__c,RAESD_Name__c,RAESD_Status__c,Fixture_Model_No__c,SerialNumber_F__c,Internal_asset_location__c,Equipment_Type__c,Salesdepartment__c,WH_location__c,Consum_Start_Date__c,Show_demonstration__c,Operation_Type__c,Case_OR_animal_organ__c,Trial_User__c,Follower_User__r.Name,Spare__c,Request_approval_time__c,Select_Time__c,Request_shipping_day__c,Shipment_request_time2__c,Shippment_loaner_time__c,Loaner_received_time__c,Asset_return_time__c,Consum_Received_Day__c,Asset_Center_Confirm_Time__c,AssetManageConfirmYN__c,RAESD__c,Consum_Apply__c,Consum_Apply_Equipment_Set__c,Asset__c';
        cListRaesdField = cListRaesdFieldStr.split(cListRaesdFieldStr);
        columns = [select From_Columns__c, Inventory_Columns__c from Inventory_Batch_Mapping__mdt where DeveloperName = 'CAESD'];
        keyList = columns.Inventory_Columns__c.split(',');
        for (Integer i = 0; i < keyList.size(); i++) {
            defaultRaesdField.add(keyList[i]);
        }

        //获取label
        String objectType ='Consum_Inventory_Detail__c';
        Map<String, Schema.SObjectType> schemaMap = Schema.getGlobalDescribe();
        Schema.SObjectType leadSchema = schemaMap.get(objectType);
        Map<String, Schema.SObjectField> fieldMap = leadSchema.getDescribe().fields.getMap();
        
        for(String fieldName : fieldMap.keySet()){
            fieldAPIName.put(fieldName, fieldMap.get(fieldName).getDescribe().getLabel());
        }

        Id ih_new_Id = ih_new.Id;
        String querysql = 'select ' + String.join(new List<String>(defaultAssetField), ', ')
                + ' from Consum_Inventory_Detail__c '
                + 'where Sync_Asset_Record_Flag__c = true'
                + '  and Inventory_Header__c = :ih_new_Id';
        return Database.getQueryLocator(querysql);
    }

    global void execute(Database.BatchableContext BC, List<Consum_Inventory_Detail__c> syncAssetList) {
        totalCount += syncAssetList.size();
        try {

            String executeBodyAsset = '';           // TODO 5M と batch heap size 問題
            // String executeBodyRaesd = '';           // TODO 5M と batch heap size 問題
            String executeBodyDiushi = '';           // TODO 5M と batch heap size 問題
            //String executeBodyRepair = '';          // TODO 5M と batch heap size 問題
            String querysql;
            List<Id> assetIds = new List<Id>();
            for (Consum_Inventory_Detail__c idc : syncAssetList) {
                assetIds.add(idc.Asset__c);
            }
            Id ih_new_Id = ih_new.Id;
            List<AggregateResult> statusArList = [
                    SELECT Asset_Status__c status, sum(Amount__c) quantity
                        , sum(Inventory_Count__c) invShipanCount, Asset__c assetId
                        , sum(Inventory_Deviation__c) deviaCount
                        , sum(Sync_Asset_Frozen_Quantity__c) lossCount
                        , sum(Sync_Asset_Profit_Quantity__c) profitCount
                        , sum(Asset__r.Abandoned_Inventory__c) abCount
                    FROM Consum_Inventory_Detail__c
                    WHERE Asset__c in :assetIds
                      AND Inventory_Header__c = :ih_new_Id
                      AND Asset_Status__c != '已消耗明细'
                    GROUP BY Asset_Status__c, Asset__c];
system.debug(statusArList);
            Map<Id, InventoryReportDetailController.StatusCount> assetCountMap
                    = new Map<Id, InventoryReportDetailController.StatusCount>();
            for (AggregateResult ar : statusArList) {
                InventoryReportDetailController.StatusCount statusCount = new InventoryReportDetailController.StatusCount(0);
                Integer amount = (Integer.valueOf(ar.get('quantity')) == null) ? 0 : Integer.valueOf(ar.get('quantity'));         // 应盘数
                Integer acAmount = (Integer.valueOf(ar.get('invShipanCount')) == null) ? 0 : Integer.valueOf(ar.get('invShipanCount'));   // 实盘数
                Integer wuchaAmount = (Integer.valueOf(ar.get('deviaCount')) == null) ? 0 : Integer.valueOf(ar.get('deviaCount'));      // 盘点误差(盘盈/盘亏)
                Integer lossAmount = (Integer.valueOf(ar.get('lossCount')) == null) ? 0 : Integer.valueOf(ar.get('lossCount'));      // 盘点误差(盘盈/盘亏)
                Integer profitAmount = (Integer.valueOf(ar.get('profitCount')) == null) ? 0 : Integer.valueOf(ar.get('profitCount'));      // 盘点误差(盘盈/盘亏)
                Integer abAmount = (Integer.valueOf(ar.get('abCount')) == null) ? 0 : Integer.valueOf(ar.get('abCount'));
                Id assId = String.valueof(ar.get('assetId'));

                if (assetCountMap.containsKey(assId)) {
                    statusCount = assetCountMap.get(assId);
                }

                if (ar.get('status') == '在库') {
                    statusCount.zaikuNum += amount;
                    statusCount.quantity += abAmount;
                }
                //else if (ar.get('status') == '维修中') {
                //    statusCount.weixiuNum += amount;         // 应盘维修中
                //}
                else if (ar.get('status') == '出借中') {
                    statusCount.chujieNum += amount;         // 应盘出借中
                    statusCount.quantity += amount;              // 应盘数量
                }
                else if (ar.get('status') == '已消耗') {
                    statusCount.diushiNum += amount;         // 应盘已消耗
                }
                else if (ar.get('status') == '冻结') {
                    statusCount.zaikuNum += amount;          // 盘点在库数='在库'应盘数+'冻结'应盘数
                }
                if(ar.get('status') == '在库' || ar.get('status') == '冻结'){
                    statusCount.quantity += amount;              // 应盘数量
                    statusCount.shipanNum += acAmount;           // 实盘
                    statusCount.wuchaNum += wuchaAmount;         // 盘点误差(盘盈/盘亏)
                    statusCount.panyinNum += profitAmount;
                    statusCount.pankuiNum += lossAmount; 
                }

                assetCountMap.put(assId, statusCount);
            }
            for (Consum_Inventory_Detail__c idc : syncAssetList) {
                InventoryReportDetailController.StatusCount eachSCount = assetCountMap.get(idc.Asset__c);
                if (eachSCount != null) {
                    idc.Inventory_Zaiku_Count_Jia__c = eachSCount.zaikuNum;
                    idc.Inventory_Shipan_Count_Jia__c = eachSCount.shipanNum;
                    //idc.Inventory_Weixiu_Count_Jia__c = eachSCount.weixiuNum;
                    idc.Inventory_Chujie_Count_Jia__c = eachSCount.chujieNum;
                    //idc.Inventory_Daibaofei_Diushi_Count_Jia__c = eachSCount.diushiNum;
                    idc.Consumed_Count__c = eachSCount.diushiNum;
                    idc.Inventory_Quantity_Jia__c = eachSCount.quantity;
                    idc.Inventory_Deviation_Jia__c = eachSCount.wuchaNum;
                    idc.Inventory_Profit_Quantity__c = eachSCount.panyinNum;
                    idc.Inventory_Loss_Quantity__c = eachSCount.pankuiNum;
                    executeBodyAsset += setDocBodyObject(idc, 'Asset', false);
                }
            }


            //借出明细
            // querysql = 'select ' + String.join(new List<String>(defaultRaesdField), ', ')
            //     + ' from Inventory_Detail__c where Asset__c IN :assetIds and Asset_Status__c = \'出借中\'';
            // for (Inventory_Detail__c dl : Database.query(querysql)) {
            //     executeBodyRaesd += setDocBodyObject(dl, 'Raesd', false);
            // }

            // 已消耗明细(原丢失借出明细)
            querysql = 'select ' + String.join(new List<String>(cListConsumedField), ', ')
                + ' from Consum_Inventory_Detail__c where Asset__c IN :assetIds and Inventory_Header__c = :ih_new_Id and Asset_Status__c = \'已消耗明细\'';
            for (Consum_Inventory_Detail__c dl : Database.query(querysql)) {
                executeBodyDiushi += setDocBodyObject(dl, 'Lost', false);
            }

            //修理id
            //querysql = 'select ' + String.join(new List<String>(defaultRepairField), ', ')
            //    + ' from Consum_Inventory_Detail__c where Asset__c IN :assetIds and Inventory_Header__c = :ih_new_Id and Asset_Status__c = \'维修中\'';
            //for (Consum_Inventory_Detail__c rp : Database.query(querysql)) {
            //    executeBodyRepair += setDocBodyObject(rp, 'Repair', false);
            //}
            docBodyAsset  += executeBodyAsset;
            // docBodyRaesd  += executeBodyRaesd;
            docBodyDiushi += executeBodyDiushi;
            //docBodyRepair += executeBodyRepair;
        } catch (Exception e) {
            failedCount += syncAssetList.size();
            System.debug(LoggingLevel.ERROR, e.getMessage() + '\n' + e.getStackTraceString());
            this.emailMessages.add(e.getMessage() + '\n' + e.getStackTraceString());
        }
    }

    private String setDocBodyObject(sObject obj, String typeStr, boolean label) {
        List<String> toCol;
        if (typeStr == 'Asset') {
            toCol = cListAssetField;
        //} else if (typeStr == 'Repair') {
        //    toCol = cListRepairField;
        }
        else if(typeStr == 'Lost'){
            toCol = cListConsumedField;
        }
        else {
            toCol = cListRaesdField;
        }
        Schema.SObjectType targetType = Consum_Inventory_Detail__c.sObjectType;
        Schema.DescribeSObjectResult sobjResult = targetType.getDescribe();
        Map<string, Schema.SObjectField> m = sobjResult.fields.getMap();

        String docBody = '';
        for (Integer i = 0; i < toCol.size(); i++) {
            List<String> cols = toCol[i].split('\\.');
            if (obj == null) {
                if (label) {
                    docBody += fieldAPIName.get(toCol[i].toLowerCase().replace('__r.name','__c')).escapeCsv();
                } else {
                    docBody += toCol[i].escapeCsv();
                }
            }
            else {
                Object val = CreateRelationListPagingCmpCtrl.getObjectValue(obj, cols);
                if (val != null) {
                    Schema.DescribeFieldResult descField = m.get(toCol[i].toLowerCase().replace('__r.name','__c')).getDescribe();
                    if(descField.getType() == DisplayType.DATETIME && String.isNotBlank('' + val)){
                        docBody += (''+((Datetime) val).addHours(8)).escapeCsv();
                    }
                    else{
                        docBody += ('' + val).escapeCsv();
                    }
                }
            }
            // 加 , 和 行末 的换行
            if (i < toCol.size() - 1) {
                docBody += ',';
            } else {
                docBody += '\r\n';
            }
        }
        return docBody;
    }
    //20231018  ymh 修改文档存储  start
    
    // public Document getArchiveFilenameForUpsert(String typeStr, Inventory_Header__c ih_new) {
    //     bp3_Setting__c conf = bp3_Setting__c.getOrgDefaults();
    //     Id folderId = conf.InventoryDetailArchiveFolder__c;
    //     String filename = ih_new.Inventory_Start_Date__c.year() + ('' + ih_new.Inventory_Start_Date__c.month()).leftPad(2, '0')
    //             + '_' + ih_new.Internal_asset_location__c + '_';
    //     if(typeStr == 'Asset'){
    //         filename += '耗材资产.csv';
    //     }
    //     else if(typeStr == 'Lost') {
    //         filename += '耗材已消耗记录.csv';
    //     }
    //     else{
    //         filename += '耗材' + typeStr + '.csv';
    //     }

    //     Document ret = null;
    //     List<Document> retList = [SELECT Id
    //                 , Name
    //                 , FolderId
    //                 , Body
    //              FROM Document
    //             WHERE FolderId = :folderId
    //               AND Name =:filename];
    //     if (retList.size() > 0) {
    //         ret = retList[0];
    //     }
    //     if (ret == null) {
    //         ret = new Document();
    //         ret.Name = filename;
    //         ret.FolderId = folderId;
    //         ret.Type = 'csv';
    //         insert ret;
    //     }
    //     String docBody = setDocBodyObject(null, typeStr, false);
    //     docBody += setDocBodyObject(null, typeStr, true);
    //     ret.Body = Blob.valueOf(docBody);

    //     return ret;
    // }

    
    public ContentVersion getArchiveFilenameForUpsert(String typeStr, Inventory_Header__c ih_new) {
        String filename = ih_new.Inventory_Start_Date__c.year() + ('' + ih_new.Inventory_Start_Date__c.month()).leftPad(2, '0')
                + '_' + ih_new.Internal_asset_location__c + '_';
        if(typeStr == 'Asset'){
            filename += '耗材资产.csv';
        }
        else if(typeStr == 'Lost') {
            filename += '耗材已消耗记录.csv';
        }
        else{
            filename += '耗材' + typeStr + '.csv';
        }

        String docBody = setDocBodyObject(null, typeStr, false);
        docBody += setDocBodyObject(null, typeStr, true);

        ContentVersion version = null;        
        // 20231103 ymh 修改优化sql查询  start
        // List<ContentVersion> verlist = [SELECT Id, Title, VersionData,ContentDocumentId FROM ContentVersion WHERE Title =:filename];
        List<ContentVersion> verlist = [SELECT Id, Title, VersionData,ContentDocumentId FROM ContentVersion WHERE Title =:filename and FirstPublishLocationId =:folderId];
        
        if( verlist.size() > 0 ){
            version = verlist[0];
            falg = true;
            // List<ContentDocumentLink> linkList = [SELECT ContentDocumentId FROM ContentDocumentLink WHERE ContentDocumentId =:verlist[0].ContentDocumentId];
            // if( linkList.size() > 0 ){
            //     version = verlist[0];
            //     falg = true;
            // }
        // 20231103 ymh 修改优化sql查询  end
        }else{
            version = new ContentVersion();
            version.Title = filename;
            version.VersionData = Blob.valueOf(docBody);
            version.PathOnClient = filename+'.csv';
        }
        return version;
    }

    public String insertContentDocumentLink(String versionId){
        ContentVersion version = [select ContentDocumentId from ContentVersion where Id =: versionId];

        String res ='';
        try{
            ContentDocumentLink link = new ContentDocumentLink(); 
            link.ContentDocumentId = version.ContentDocumentId;
            link.LinkedEntityId = folderId;
            link.ShareType = 'I';
            link.Visibility = 'AllUsers';
            StaticParameter.ContentDocumentLink = false;
            insert link;
            res = '1';
        }catch(Exception e){
            res = '0';
            return res;
        }
        return res;
        
    }


    //20231018 ymh 修改文档存储  end



    global void finish(Database.BatchableContext BC) {
        Integer csvCount = 2; // 总件数 (CSV)
        Integer failedCsvCount = 0;

        if (docBodyAsset == '') {
            failedCsvCount++;
            this.emailMessages.add('耗材资产数据不存在');
        } else {
            //20231018 ymh 修改文档存储  start

            // Document assetDoc = getArchiveFilenameForUpsert('Asset', ih_new);
            // assetDoc.Body = Blob.valueOf(assetDoc.Body.toString() + docBodyAsset);
            
            ContentVersion assetVersion = getArchiveFilenameForUpsert('Asset', ih_new);
            assetVersion.VersionData = Blob.valueOf(assetVersion.VersionData.toString() + docBodyAsset);

            Database.SaveResult saveResult = Database.update(assetVersion, false);
            String result;
            if(falg){
                // csv文件存在  update
                saveResult = Database.update(assetVersion, false);
            }else{
                //csv文件不存在  insert
                saveResult = Database.insert(assetVersion, false);
                result =insertContentDocumentLink(assetVersion.Id);
            }
            

            if (!saveResult.isSuccess() || result == '0') failedCsvCount++;
            this.emailMessages = FixtureUtil.setSaveError(new List<Database.SaveResult>{saveResult}, ContentVersion.sObjectType, new List<ContentVersion>{assetVersion}, this.emailMessages);
            //20231018 ymh 修改文档存储  end
        }

        //if (docBodyRepair == '') {
        //    failedCsvCount++;
        //    this.emailMessages.add('Repair数据不存在');
        //} else {
        //    Document repairDoc = getArchiveFilenameForUpsert('Repair', ih_new);
        //    repairDoc.Body = Blob.valueOf(repairDoc.Body.toString() + docBodyRepair);
        //    Database.SaveResult saveResult = Database.update(repairDoc, false);
        //    if (!saveResult.isSuccess()) failedCsvCount++;
        //    this.emailMessages = FixtureUtil.setSaveError(new List<Database.SaveResult>{saveResult}, Document.sObjectType, new List<Document>{repairDoc}, this.emailMessages);
        //}

        // if (docBodyRaesd == '') {
        //     failedCsvCount++;
        //     this.emailMessages.add('Raesd数据不存在');
        // } else {
        //     Document raesdDoc = getArchiveFilenameForUpsert('Raesd', ih_new);
        //     raesdDoc.Body = Blob.valueOf(raesdDoc.Body.toString() + docBodyRaesd);
        //     Database.SaveResult saveResult = Database.update(raesdDoc, false);
        //     if (!saveResult.isSuccess()) failedCsvCount++;
        //     this.emailMessages = FixtureUtil.setSaveError(new List<Database.SaveResult>{saveResult}, Document.sObjectType, new List<Document>{raesdDoc}, this.emailMessages);
        // }

        if (docBodyDiushi == '') {
            failedCsvCount++;
            this.emailMessages.add('已消耗数据不存在');
        } else {
            // Document lostDoc = getArchiveFilenameForUpsert('Lost', ih_new);
            // lostDoc.Body = Blob.valueOf(lostDoc.Body.toString() + docBodyDiushi);

             //20231018 ymh 修改文档存储  start
            ContentVersion lostVersion = getArchiveFilenameForUpsert('Lost', ih_new);
            lostVersion.VersionData = Blob.valueOf(lostVersion.VersionData.toString() + docBodyDiushi);
            Database.SaveResult saveResult = Database.update(lostVersion, false);
            if(falg){
                // csv文件存在  update
                saveResult = Database.update(lostVersion, false);
            }else{
                //csv文件不存在  insert
                saveResult = Database.insert(lostVersion, false);
                insertContentDocumentLink(lostVersion.Id);
            }
             //20231018 ymh 修改文档存储  end
            if (!saveResult.isSuccess()) failedCsvCount++;
            this.emailMessages = FixtureUtil.setSaveError(new List<Database.SaveResult>{saveResult}, ContentVersion.sObjectType, new List<ContentVersion>{lostVersion}, this.emailMessages);
        }

        // TODO wwf email
        ConsumInventoryReportDetailArchiveBatch.messagesForTest = this.emailMessages;
        // 发 mail
        BatchEmailUtil be = new BatchEmailUtil();
        String[] toList = new String[]{};
        String title = '存档耗材盘点CSV数据(保有设备和已消耗明细)';
        String[] ccList = new String[]{};

        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_new.Id];
        String text = '耗材盘点报告书编号：' + iheader.Name + '  盘点地点：' + iheader.Internal_asset_location__c + '  盘点开始日：' + iheader.Inventory_Start_Date__c;
        text += '\n处理对象'+totalCount + '件 保有设备(同期的 耗材盘点明细)';
        text += '\n处理失败'+failedCount + '件 保有设备(同期的 耗材盘点明细)';

        if(this.emailMessages.size() == 0){
            toList.add(UserInfo.getUserEmail());
            be.successMail(toList,ccList, title, csvCount, text);
        }else{
            String emailLabel = 'BatchNotify';
            for (OrgWideEmailAddress tmpEmailObj : [SELECT Id, Address, DisplayName 
                    FROM OrgWideEmailAddress
                    WHERE DisplayName like :emailLabel]) {
                ccList.add(tmpEmailObj.Address);
            }
            for(String email : System.Label.Inventory_Result_Email.split(',')){
                ccList.add(email);
            }
            be.failedMail(toList, ccList, title,
                    String.join(this.emailMessages, '\n'),
                    csvCount, csvCount - failedCsvCount, failedCsvCount);
        }
        be.send();
    }
}