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 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();
|
if (String.isBlank(conf.InventoryDetailArchiveFolder__c)) {
|
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;
|
}
|
|
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;
|
}
|
|
global void finish(Database.BatchableContext BC) {
|
Integer csvCount = 2; // 总件数 (CSV)
|
Integer failedCsvCount = 0;
|
|
if (docBodyAsset == '') {
|
failedCsvCount++;
|
this.emailMessages.add('耗材资产数据不存在');
|
} else {
|
Document assetDoc = getArchiveFilenameForUpsert('Asset', ih_new);
|
assetDoc.Body = Blob.valueOf(assetDoc.Body.toString() + docBodyAsset);
|
Database.SaveResult saveResult = Database.update(assetDoc, false);
|
if (!saveResult.isSuccess()) failedCsvCount++;
|
this.emailMessages = FixtureUtil.setSaveError(new List<Database.SaveResult>{saveResult}, Document.sObjectType, new List<Document>{assetDoc}, this.emailMessages);
|
}
|
|
//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);
|
Database.SaveResult saveResult = Database.update(lostDoc, false);
|
if (!saveResult.isSuccess()) failedCsvCount++;
|
this.emailMessages = FixtureUtil.setSaveError(new List<Database.SaveResult>{saveResult}, Document.sObjectType, new List<Document>{lostDoc}, 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();
|
}
|
}
|