global class MergeAgencyActivityBatch implements Database.Batchable, Database.Stateful { global Map oldIdNewContactMap = new Map(); // 7. Agency_Report_Header 和 8. Agency_Report 里用到 global Map oldIdNewUserIdMap = new Map(); // Agency_XXX table Owner 設定用 global Map newIdOldUserIdMap = new Map(); // Agency_XXX table Owner 設定用 global Map newAgencyHospitalMap = new Map(); // .客户人员(new, key is Hospital__c) public String oldAgencyCode; public String newAgencyCode; public Boolean forceFlg; public List emailMessages; public String oldAgencyId; public String newAgencyId; global Integer totalCount = 0; // 总件数 global Integer failedCount = 0; @TestVisible private static List messagesForTest; /** * @param forceFlg true:不对有没有New Agency的数据进行check */ global MergeAgencyActivityBatch(String oldAgencyCode, String newAgencyCode, Boolean forceFlg) { this.oldAgencyCode = oldAgencyCode; this.newAgencyCode = newAgencyCode; this.forceFlg = forceFlg; this.emailMessages = new List(); } // TODO katsu 暫定 1万 超えない前提 global Database.QueryLocator start(Database.BatchableContext bc) { Account[] accList; accList = [SELECT Id FROM Account WHERE Management_Code__c = :this.oldAgencyCode]; if (accList.size() != 1) { this.emailMessages.add('没有找到 或 有多条 旧经销商 [' + this.oldAgencyCode + '] 的数据, size=' + accList.size()); return Database.getQueryLocator([SELECT Id FROM Agency_Hospital_Link__c LIMIT 0]); } else { this.oldAgencyId = accList[0].Id; } accList = [SELECT Id FROM Account WHERE Management_Code__c = :this.newAgencyCode]; if (accList.size() != 1) { this.emailMessages.add('没有找到 或 有多条 新经销商 [' + this.newAgencyCode + '] 的数据, size=' + accList.size()); return Database.getQueryLocator([SELECT Id FROM Agency_Hospital_Link__c LIMIT 0]); } else { this.newAgencyId = accList[0].Id; } if (forceFlg == false && [SELECT Id FROM Agency_Contact__c WHERE Agency_Hospital__r.Agency__r.Management_Code__c = :this.newAgencyCode].size() > 0) { this.emailMessages.add('.客户人员 里不可以有 New Agency [' + this.newAgencyCode + '] 的数据'); return Database.getQueryLocator([SELECT Id FROM Agency_Hospital_Link__c LIMIT 0]); } if (forceFlg == false && [SELECT Id FROM Agency_Opportunity__c WHERE Agency_Hospital_All__r.Agency__r.Management_Code__c = :this.newAgencyCode].size() > 0) { this.emailMessages.add('经销商询价 里不可以有 New Agency [' + this.newAgencyCode + '] 的数据'); return Database.getQueryLocator([SELECT Id FROM Agency_Hospital_Link__c LIMIT 0]); } if (forceFlg == false && [SELECT Id FROM Agency_Report_Header__c WHERE Agency__r.Management_Code__c = :this.newAgencyCode].size() > 0) { this.emailMessages.add('.周报一览 里不可以有 New Agency [' + this.newAgencyCode + '] 的数据'); return Database.getQueryLocator([SELECT Id FROM Agency_Hospital_Link__c LIMIT 0]); } if (forceFlg == false && [SELECT Id FROM Agency_Report__c WHERE Agency__r.Management_Code__c = :this.newAgencyCode].size() > 0) { this.emailMessages.add('.周报明细 里不可以有 New Agency [' + this.newAgencyCode + '] 的数据'); return Database.getQueryLocator([SELECT Id FROM Agency_Hospital_Link__c LIMIT 0]); } // 事前のデータを取得 // 1. New Agency_Hospital 新的营销关系 for (Agency_Hospital_Link__c nObj : [SELECT Id , Agency__c, Agency__r.Management_Code__c, Hospital__c FROM Agency_Hospital_Link__c WHERE Agency__r.Management_Code__c = :this.newAgencyCode ORDER BY CreatedDate]) { // map的重复不用考虑 newAgencyHospitalMap.put(nObj.Hospital__c, nObj); } // 5. New Contact String Contact_Agency_RT = Schema.SObjectType.Contact.getRecordTypeInfosByDeveloperName().get('Agency').getRecordTypeId(); Map newContactMap = new Map(); // 取引先責任者(new) Map newContactNameMap = new Map(); // 取引先責任者(new, key is Name) for (Contact nObj : [SELECT Id , AccountId, Name, Agency_User__c FROM Contact WHERE RecordTypeId = :Contact_Agency_RT AND Account.Management_Code__c = :this.newAgencyCode]) { // Contact.Name重复 check Contact oObj = newContactNameMap.get(nObj.Name); if (oObj != null) { this.emailMessages.add('客户人员 ' + oObj.Name + ' 重复, 请确认 ' + oObj.Id + ' , ' + nObj.Id + ' 的数据'); return Database.getQueryLocator([SELECT Id FROM Agency_Hospital_Link__c LIMIT 0]); } newContactMap.put(nObj.Id, nObj); newContactNameMap.put(nObj.Name, nObj); } // 6. Old Contact Map oldContactMap = new Map(); Map oldContactNameMap = new Map(); // 取引先責任者(new, key is Name) for (Contact nObj : [SELECT Id, Name , Account.Management_Code__c, Agency_User__c, FirstName, LastName FROM Contact WHERE RecordTypeId = :Contact_Agency_RT AND Agency_User__c = true AND Account.Management_Code__c = :this.oldAgencyCode]) { // Contact.Name重复 check Contact oObj = oldContactNameMap.get(nObj.Name); if (oObj != null) { this.emailMessages.add('客户人员 ' + oObj.Name + ' 重复, 请确认 ' + oObj.Id + ' , ' + nObj.Id + ' 的数据'); return Database.getQueryLocator([SELECT Id FROM Agency_Hospital_Link__c LIMIT 0]); } oldContactMap.put(nObj.Id, nObj); oldContactNameMap.put(nObj.Name, nObj); } // 新旧UserのMapping Map newUserNameMap = new Map(); for (User nObj : [SELECT Id, Name , ContactId FROM User WHERE IsPortalEnabled = true AND IsActive = true AND Contact.AccountId = :this.newAgencyId AND ContactId IN :newContactMap.keySet()]) { newUserNameMap.put(nObj.Name, nObj); } Map oldUserNameMap = new Map(); for (User nObj : [SELECT Id, Name , ContactId FROM User WHERE IsPortalEnabled = true AND IsActive = true AND Contact.AccountId = :this.oldAgencyId AND ContactId IN :oldContactMap.keySet()]) { oldUserNameMap.put(nObj.Name, nObj); } // 5. New User 件数必须和 6 一样(force y也不让过) for (User oObj : oldUserNameMap.values()) { User nObj = newUserNameMap.get(oObj.Name); if (nObj == null) { this.emailMessages.add('User:' + oObj.Name + ' 在 ' + newAgencyCode + ' 里不存在, 请确认有没有造新的用户'); return Database.getQueryLocator([SELECT Id FROM Agency_Hospital_Link__c LIMIT 0]); } this.oldIdNewUserIdMap.put(oObj.Id, nObj.Id); this.newIdOldUserIdMap.put(nObj.Id, oObj.Id); } if (this.oldIdNewUserIdMap.size() == 0) { this.emailMessages.add('没有找到 新经销商的用户数据'); return Database.getQueryLocator([SELECT Id FROM Agency_Hospital_Link__c LIMIT 0]); } // 5. New Contact 件数必须和 6 一样(补到 一样 or 超过) List upsList = new List(); for (Contact oObj : oldContactMap.values()) { Contact nObj = newContactNameMap.get(oObj.Name); Boolean isTarget = false; if (nObj == null) { nObj = new Contact(Agency_User__c = true , RecordTypeId = Contact_Agency_RT , FirstName = oObj.FirstName , LastName = oObj.LastName ); isTarget = true; } if (nObj.Agency_User__c != true) { isTarget = true; } nObj.AccountId = this.newAgencyId; nObj.Agency_User__c = true; this.oldIdNewContactMap.put(oObj.Id, nObj); if (isTarget) { upsList.add(nObj); } } List urList = Database.upsert(upsList, Contact.Fields.Id, false); Integer errorCnt = setUpstError(urList, Contact.getSObjectType(), upsList); totalCount += upsList.size(); if (errorCnt > 0) { failedCount += errorCnt; return Database.getQueryLocator([SELECT Id FROM Agency_Hospital_Link__c LIMIT 0]); } // 7. Agency_Report_Header List oldArhList = [SELECT Id, Name , Old_OwnerId__c, Old_Agency__c, Old_Agency_Person2__c , OwnerId, Agency__c, Agency_Person2__c FROM Agency_Report_Header__c WHERE Agency__r.Management_Code__c = :this.oldAgencyCode]; for (Agency_Report_Header__c ups : oldArhList) { if (false == newIdOldUserIdMap.containsKey(ups.OwnerId)) { ups.Old_OwnerId__c = ups.OwnerId; ups.OwnerId = oldIdNewUserIdMap.get(ups.OwnerId); } if (ups.Agency__c != this.newAgencyId) { ups.Old_Agency__c = ups.Agency__c; ups.Agency__c = this.newAgencyId; ups.Agency_ID__c = this.newAgencyId.mid(0, 15); } if (ups.Agency_Person2__c != this.oldIdNewContactMap.get(ups.Agency_Person2__c).Id) { ups.Old_Agency_Person2__c = ups.Agency_Person2__c; ups.Agency_Person2__c = this.oldIdNewContactMap.get(ups.Agency_Person2__c).Id; } } List srList = Database.update(oldArhList, false); AgencyReportHeaderHandler.shareAgency_Report_Header_ToRole(oldArhList); errorCnt = setSaveError(srList, Agency_Report_Header__c.getSObjectType(), oldArhList); totalCount += oldArhList.size(); if (errorCnt > 0) { failedCount += errorCnt; return Database.getQueryLocator([SELECT Id FROM Agency_Hospital_Link__c LIMIT 0]); } // Batch実行 // 2. Old Agency_Hospital 为基础 return Database.getQueryLocator([SELECT Id , Agency__c, Agency__r.Management_Code__c, Hospital__c, Hospital__r.Management_Code__c FROM Agency_Hospital_Link__c WHERE Agency__r.Management_Code__c = :this.oldAgencyCode ] ); } global void execute(Database.BatchableContext BC, List oldAgencyHospitalList) { Map oldAgencyOpportunityMap = new Map(); // 经销商询价(old) Map ocsmUserMap = new Map(); //ocsm内部ユーザー // 事前のデータを取得 // 1. ocsm内部ユーザー ocsmUserMap = new Map([SELECT Id FROM User WHERE IsPortalEnabled = false]); // 2. Old Agency_Hospital 旧的营销关系 -> 新的营销关系 Map oldIdNewAgencyHospitalMap = new Map(); // 3. Agency_Contact, 4. Agency_Opportunity, 8. Agency_Report 里用到 for (Agency_Hospital_Link__c oObj : oldAgencyHospitalList) { Agency_Hospital_Link__c nObj = this.newAgencyHospitalMap.get(oObj.Hospital__c); if (nObj == null) { this.emailMessages.add('没有找到新的营销关系 请确认是否存在 ' + oObj.Hospital__r.Management_Code__c + ' 的数据'); } else { oldIdNewAgencyHospitalMap.put(oObj.Id, nObj); } } // 3. Agency_Contact List oldAgencyContactList = [SELECT Id, Name , Old_OwnerId__c, Old_Agency_Hospital__c, Old_Agency_ID__c , OwnerId, Agency_Hospital__c, Agency_ID__c FROM Agency_Contact__c WHERE Agency_Hospital__c IN :oldAgencyHospitalList]; for (Agency_Contact__c ups : oldAgencyContactList) { if (false == newIdOldUserIdMap.containsKey(ups.OwnerId)) { ups.Old_OwnerId__c = ups.OwnerId; ups.OwnerId = oldIdNewUserIdMap.get(ups.OwnerId); } if (ups.Agency_Hospital__c != oldIdNewAgencyHospitalMap.get(ups.Agency_Hospital__c).Id) { ups.Old_Agency_Hospital__c = ups.Agency_Hospital__c; ups.Agency_Hospital__c = oldIdNewAgencyHospitalMap.get(ups.Agency_Hospital__c).Id; } if (ups.Agency_ID__c != this.newAgencyId.mid(0, 15)) { ups.Old_Agency_ID__c = ups.Agency_ID__c; ups.Agency_ID__c = this.newAgencyId.mid(0, 15); } } List srList = Database.update(oldAgencyContactList, false); AgencyContactHandler.shareAgency_Contact_ToRole(oldAgencyContactList); failedCount += setSaveError(srList, Agency_Contact__c.getSObjectType(), oldAgencyContactList); totalCount += oldAgencyContactList.size(); // 4. Agency_Opportunity List oldAgencyOpportunityList = [SELECT Id, Name , Old_OwnerId__c, Old_Agency__c, Old_Agency_Hospital__c, Old_Agency_Hospital_All__c, Old_Agency_Hospital_Target__c, Old_TargetInputKey__c , OwnerId, Agency__c, Agency_ID__c, Agency_Hospital__c, Agency_Hospital_All__c, Agency_Hospital_Target__c, TargetInputKey__c FROM Agency_Opportunity__c WHERE Agency_Hospital_All__c IN :oldAgencyHospitalList]; for (Agency_Opportunity__c ups : oldAgencyOpportunityList) { if (false == newIdOldUserIdMap.containsKey(ups.OwnerId)) { if (true == ocsmUserMap.containsKey(ups.OwnerId)) { //ocsm内部ユーザー:更新しない } else { ups.Old_OwnerId__c = ups.OwnerId; ups.OwnerId = oldIdNewUserIdMap.get(ups.OwnerId); } } if (ups.Agency__c != this.newAgencyId) { ups.Old_Agency__c = ups.Agency__c; ups.Agency__c = this.newAgencyId; ups.Agency_ID__c = this.newAgencyId.mid(0, 15); } if (String.isNotBlank(ups.Agency_Hospital__c) && ups.Agency_Hospital__c != oldIdNewAgencyHospitalMap.get(ups.Agency_Hospital__c).Id) { ups.Old_Agency_Hospital__c = ups.Agency_Hospital__c; ups.Agency_Hospital__c = oldIdNewAgencyHospitalMap.get(ups.Agency_Hospital__c).Id; } if (String.isNotBlank(ups.Agency_Hospital_All__c) && ups.Agency_Hospital_All__c != oldIdNewAgencyHospitalMap.get(ups.Agency_Hospital_All__c).Id) { ups.Old_Agency_Hospital_All__c = ups.Agency_Hospital_All__c; ups.Agency_Hospital_All__c = oldIdNewAgencyHospitalMap.get(ups.Agency_Hospital_All__c).Id; } if (String.isNotBlank(ups.Agency_Hospital_Target__c) && ups.Agency_Hospital_Target__c != oldIdNewAgencyHospitalMap.get(ups.Agency_Hospital_Target__c).Id) { ups.Old_Agency_Hospital_Target__c = ups.Agency_Hospital_Target__c; ups.Agency_Hospital_Target__c = oldIdNewAgencyHospitalMap.get(ups.Agency_Hospital_Target__c).Id; ups.Old_TargetInputKey__c = ups.TargetInputKey__c; ups.TargetInputKey__c = ups.Agency_Hospital_Target__c + ups.TargetInputKey__c.mid(18, 1300); } } srList = Database.update(oldAgencyOpportunityList, false); AgencyOpportunityHandler.shareAgency_Opportunity_ToRole(oldAgencyOpportunityList); failedCount += setSaveError(srList, Agency_Opportunity__c.getSObjectType(), oldAgencyOpportunityList); totalCount += oldAgencyOpportunityList.size(); // 8. Agency_Report List oldAgencyReportList = [SELECT Id, Name , Old_Agency__c, Old_Agency_Hospital__c, Old_Person_In_Charge2__c , Agency__c, Agency_ID__c, Agency_Hospital__c, Person_In_Charge2__c FROM Agency_Report__c WHERE Agency__r.Management_Code__c = :this.oldAgencyCode AND Agency_Hospital__c IN :oldAgencyHospitalList]; for (Agency_Report__c ups : oldAgencyReportList) { if (ups.Agency__c != this.newAgencyId) { ups.Old_Agency__c = ups.Agency__c; ups.Agency__c = this.newAgencyId; ups.Agency_ID__c = this.newAgencyId.mid(0, 15); } if (String.isNotBlank(ups.Agency_Hospital__c) && ups.Agency_Hospital__c != oldIdNewAgencyHospitalMap.get(ups.Agency_Hospital__c).Id) { ups.Old_Agency_Hospital__c = ups.Agency_Hospital__c; ups.Agency_Hospital__c = oldIdNewAgencyHospitalMap.get(ups.Agency_Hospital__c).Id; } if (ups.Person_In_Charge2__c != this.oldIdNewContactMap.get(ups.Person_In_Charge2__c).Id) { ups.Old_Person_In_Charge2__c = ups.Person_In_Charge2__c; ups.Person_In_Charge2__c = this.oldIdNewContactMap.get(ups.Person_In_Charge2__c).Id; } } srList = Database.update(oldAgencyReportList, false); failedCount += setSaveError(srList, Agency_Report__c.getSObjectType(), oldAgencyReportList); totalCount += oldAgencyReportList.size(); } global void finish(Database.BatchableContext BC) { MergeAgencyActivityBatch.messagesForTest = this.emailMessages; // 发 mail BatchEmailUtil eb = new BatchEmailUtil(); String title = '经销商用户更名 ' + this.oldAgencyCode + ' -> ' + this.newAgencyCode; String ccStr = null; if(this.emailMessages.size() == 0){ eb.successMail(title, totalCount); }else{ eb.failedMail(title, String.join(this.emailMessages, '\n'), totalCount, totalCount - failedCount, failedCount); } eb.send(); } @TestVisible private Integer setUpstError(List srList, Schema.sObjectType obj , List upsList) { Integer errorCnt = 0; List errMsgList = new List(); String objectName = obj.getDescribe().getName(); String objectLabel = obj.getDescribe().getLabel(); for (Integer i = 0; i < srList.size(); i++) { SObject eObj = upsList[i]; Database.UpsertResult sr = srList[i]; if (!sr.isSuccess()) { errorCnt++; for (Database.Error err : sr.getErrors()) { String message = objectLabel + ':' + objectName + '=' + eObj.get('Name') + ', ' + err.getStatusCode() + ':' + err.getMessage() + ((err.getFields() != null && err.getFields().size() > 0) ? ', Field:' + String.valueOf(err.getFields()) : ''); this.emailMessages.add(message); } } } return errorCnt; } @TestVisible private Integer setSaveError(List srList, Schema.sObjectType obj , List upsList) { Integer errorCnt = 0; String objectName = obj.getDescribe().getName(); String objectLabel = obj.getDescribe().getLabel(); for (Integer i = 0; i < srList.size(); i++) { SObject eObj = upsList[i]; Database.SaveResult sr = srList[i]; if (!sr.isSuccess()) { errorCnt++; for (Database.Error err : sr.getErrors()) { String message = objectLabel + ':' + objectName + '=' + eObj.get('Name') + ', ' + err.getStatusCode() + ':' + err.getMessage() + ((err.getFields() != null && err.getFields().size() > 0) ? ', Field:' + String.valueOf(err.getFields()) : ''); this.emailMessages.add(message); } } } return errorCnt; } private static Map accIdGrpIdMap; public static Id accIdGrpIdMap(Id accId) { if (MergeAgencyActivityBatch.accIdGrpIdMap == null) { MergeAgencyActivityBatch.accIdGrpIdMap = new Map(); } if (MergeAgencyActivityBatch.accIdGrpIdMap.get(accId) == null) { List roles = [SELECT Id, PortalAccountId FROM UserRole WHERE PortalAccountId = :accId AND PortalRole = 'Worker']; Map roleIdAccId = new Map(); for (UserRole ur : roles) { roleIdAccId.put(ur.Id, ur.PortalAccountId); } List groups = [SELECT Id, RelatedId FROM Group WHERE RelatedId = :roleIdAccId.keySet() AND Type = 'RoleAndSubordinates']; for (Group grp : groups) { MergeAgencyActivityBatch.accIdGrpIdMap.put(roleIdAccId.get(grp.RelatedId), grp.Id); } } return MergeAgencyActivityBatch.accIdGrpIdMap.get(accId); } }