// 备品智能化项目 自动分配/自动排队逻辑 public without sharing class RentalFixtureSetAssignAndQueueWebService implements Queueable { List tempIdList = new List(); public RentalFixtureSetAssignAndQueueWebService(List records) { tempIdList = records; } public void execute(QueueableContext qc) { if (!tempIdList.isEmpty()) { setAssignAndQueue(tempIdList); } } public static void setAssignAndQueue(List tempIdList) { System.debug('tempIdList============================================' + tempIdList); Date today = Date.today(); String dateToday = String.valueOf(today); // 查找未取消的一览明细 List raesdListFirst = [ SELECT Id, Rental_Apply_Equipment_Set__c, EquipmentSet_Detail_Status_Status__c FROM Rental_Apply_Equipment_Set_Detail__c WHERE Cancel_Select__c = false AND Rental_Apply__c IN: tempIdList AND Rental_Apply__r.Cross_Region_Assign__c = null AND Rental_Apply_Equipment_Set__r.RAES_Status__c = '待分配']; // 存在非待分配明细的一览,不作为自动分配/排队对象 Set notUseIds = new Set(); for (Rental_Apply_Equipment_Set_Detail__c raesd : raesdListFirst) { if (raesd.EquipmentSet_Detail_Status_Status__c != '待分配') { notUseIds.add(raesd.Rental_Apply_Equipment_Set__c); } } // 查找未取消的一览明细 List raesdList1 = [ SELECT Id, Is_Body__c, Internal_asset_location__c, Salesdepartment__c, Equipment_Type_F__c, Rental_Apply_Equipment_Set__c, FSD_Is_OneToOne__c, FSD_Fixture_Model_No__c, Product_category_F__c, Rental_Apply_Equipment_Set__r.RequestNoJoinStr2__c, FSD_Id__c, IndexFromUniqueKey__c, Rental_Apply__r.Person_In_Charge__r.Profile.Name, Rental_Apply__r.demo_purpose2__c, Rental_Apply__r.OPD_OrderNum__c, Rental_Apply__r.OPD_AdjustmentOrderNum_Flag__c, Rental_Apply__r.Demo_purpose1__c, Rental_Apply_Equipment_Set__r.Fixture_Set__r.Product_Type__c, Rental_Apply__r.Internal_asset_location_F__c, Select_Time__c, Rental_Apply__r.Product_category__c, Rental_Apply__r.Salesdepartment__c, Fixture_Model_No__c, Rental_Apply__c, FSD_OneToOneAccessory_Cnt__c, Rental_Apply__r.Loaner_centre_mail_address__c, Rental_Apply_Equipment_Set__r.Rental_Start_Date__c, Rental_Apply_Equipment_Set__r.Rental_End_Date__c, Rental_Apply__r.Asset_loaner_start_day__c, Rental_Apply__r.Hope_Lonaer_date_Num__c, Rental_Apply__r.Asset_loaner_closed_day__c, Rental_Apply__r.Request_approval_time__c, Rental_Apply__r.Request_shipping_day__c, Rental_Apply__r.EquipmentGuaranteeFlg__c,EquipmentSet_Detail_Status_Status__c,// 20231223 智能化 ljh add Rental_Apply__r.EquipmentGuaranteeFlg__c Queue_Time_F__c,Rental_Apply_Equipment_Set__r.IndexFromUniqueKey__c, Rental_Apply__r.Last_Month_Untreated__c, Rental_Apply__r.CampaignType__c, Rental_Apply__r.Rental_Fixture_Push_Time__c, Rental_Apply__r.Campaign_EndDate_F__c FROM Rental_Apply_Equipment_Set_Detail__c WHERE Cancel_Select__c = false AND Rental_Apply__c IN: tempIdList AND Rental_Apply_Equipment_Set__c NOT IN: notUseIds AND Rental_Apply__r.Cross_Region_Assign__c = null AND Rental_Apply_Equipment_Set__r.RAES_Status__c = '待分配' ORDER BY Rental_Apply__c, Rental_Apply_Equipment_Set__c, Is_Body__c desc, Id]; // 为了后续的处理方便,此处以申请单为单位进行处理 Map>> raAndraesMap = new Map>>(); for (Rental_Apply_Equipment_Set_Detail__c raesd : raesdList1) { if (raAndraesMap.isEmpty() || !raAndraesMap.containsKey(raesd.Rental_Apply__c)) { Map> raesdMap = new Map>(); List raesdTempList = new List(); raesdTempList.add(raesd); raesdMap.put(raesd.Rental_Apply_Equipment_Set__c, raesdTempList); raAndraesMap.put(raesd.Rental_Apply__c, raesdMap); } else { Map> raesdMap = raAndraesMap.get(raesd.Rental_Apply__c); if (raesdMap.isEmpty() || !raesdMap.containsKey(raesd.Rental_Apply_Equipment_Set__c)) { List raesdTempList = new List(); raesdTempList.add(raesd); raesdMap.put(raesd.Rental_Apply_Equipment_Set__c, raesdTempList); } else { List raesdTempList = raesdMap.get(raesd.Rental_Apply_Equipment_Set__c); raesdTempList.add(raesd); raesdMap.put(raesd.Rental_Apply_Equipment_Set__c, raesdTempList); } raAndraesMap.put(raesd.Rental_Apply__c, raesdMap); } } // 申请单单位 for (String raId : raAndraesMap.keySet()) { // 备品存放地 String cunFanfDi = null; // 产品分类(GI/SP) String productCategory = null; //别本部 List departmentsList = new List(); //别备品分类 List equipmentsList = new List(); // 一对一备品配套明细型号 Map>> otoModelMap = new Map>>(); // 非一对一备品配套明细型号 Map>> noOtoModelMap = new Map>>(); // 保证分配顺序 一对一主体用 Map> autoSelectMap = new Map>(); // 保证分配顺序 非一对一主体用 Map> autoSelectMap1 = new Map>(); // 主体型号,别本部 因为配套的产品类型不同,所以不同的配套可能存在不同的别本部 Map> departmentsByFixtureModelMap = new map>(); Boolean isFirst = true; Rental_Apply__c raObj = new Rental_Apply__c(); List raesUpdList = new List(); // 参与自动排队的主体一览明细 List queueList = new List(); // 可以暂定分配的主体一览明细 List updAssignList = new List(); // 参与自动分配的附属品一览明细 List needAssignAccessoryList = new List(); Map> raesdMap = raAndraesMap.get(raId); // 申请一览单位 for (String raesId : raesdMap.keySet()) { // 默认排队的条件组合 RentalFixtureSetAssignController.KeyObj objSelect = new RentalFixtureSetAssignController.KeyObj(); List raesdTempList = raesdMap.get(raesId); // 设值备品预计出货日 Rental_Apply_Equipment_Set__c raes = new Rental_Apply_Equipment_Set__c(); raes.Id = raesId; Integer addNum = 0; if (raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '试用(无询价)' || raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '试用(有询价)' || raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '新产品评价' || raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '协议借用') { addNum = raesdTempList[0].Rental_Apply__r.Hope_Lonaer_date_Num__c == null ? 0 : Integer.valueOf(raesdTempList[0].Rental_Apply__r.Hope_Lonaer_date_Num__c); } else if (raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '一般用户' || raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '保修用户' || raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '市场多年保修' || raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '再修理' || raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '索赔QIS' || raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '已购待货' || raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '故障排查') { addNum = 30; } else if (raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '学会展会') { addNum = 5; } // 一览的更新 raes.Rental_Start_Date__c = today; if (raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '学会展会') { raes.Rental_End_Date__c = raesdTempList[0].Rental_Apply__r.Campaign_EndDate_F__c.addDays(addNum); } else { raes.Rental_End_Date__c = today.addDays(addNum); } raesUpdList.add(raes); if (isFirst) { //申请单的更新 raObj.Id = raId; raObj.Asset_loaner_start_day__c = today; if (raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '学会展会') { raObj.Asset_loaner_closed_day__c = raesdTempList[0].Rental_Apply__r.Campaign_EndDate_F__c.addDays(addNum); } else { raObj.Asset_loaner_closed_day__c = today.addDays(addNum); } // 只有非实时单需要记录首次推送时间,并且一旦有值就不更新 if (raesdTempList[0].Rental_Apply__r.Rental_Fixture_Push_Time__c == null && (raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '试用(无询价)' || raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '试用(有询价)' || raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '新产品评价' || raesdTempList[0].Rental_Apply__r.demo_purpose2__c == '学会展会')) { raObj.Rental_Fixture_Push_Time__c = System.now(); } isFirst = false; // 根据备品中心的邮箱地址来判断备品存放地 cunFanfDi = getInternalAssetlocation(raesdTempList[0].Rental_Apply__r.Loaner_centre_mail_address__c); // 产品分类(GI/SP) productCategory = raesdTempList[0].Rental_Apply__r.Product_category__c; // 获取默认排队的条件组合 objSelect = getSearchCriteria(raesdTempList[0]); // 产品类型:新产品;重点产品;非重点产品 // 产品类型不同,可能分配的备品所属本部也不一样,所以不同的配套需要区分开来处理 departmentsList.addAll(objSelect.salesdepartmentList); departmentsByFixtureModelMap.put(raesdTempList[0].FSD_Fixture_Model_No__c, objSelect.salesdepartmentList); // 不会因为产品分类不同而导致备品分类不一致 equipmentsList.addAll(objSelect.equipmentList); } else { // 产品类型:新产品;重点产品;非重点产品 // 产品类型不同,可能分配的备品所属本部也不一样,所以不同的配套需要区分开来处理 objSelect = getSearchCriteria(raesdTempList[0]); departmentsList.addAll(objSelect.salesdepartmentList); departmentsByFixtureModelMap.put(raesdTempList[0].FSD_Fixture_Model_No__c, objSelect.salesdepartmentList); } // 主体明细在第一条,判断第一条是否是主体,如果不是主体,则代表整个配套中没有主体 if (raesdTempList[0].Is_Body__c) { // Fixture_OneToOne_Link__c, 当配套的Mst定义成 一对一 的时候 if (raesdTempList[0].FSD_OneToOneAccessory_Cnt__c > 0) { // 主体一对一备品配套明细型号 if (!otoModelMap.isEmpty() && otoModelMap.containsKey(raesdTempList[0].FSD_Fixture_Model_No__c)) { List> raesdsList = otoModelMap.get(raesdTempList[0].FSD_Fixture_Model_No__c); raesdsList.add(raesdTempList); otoModelMap.put(raesdTempList[0].FSD_Fixture_Model_No__c, raesdsList); } else { List> raesdsList = new List>(); raesdsList.add(raesdTempList); otoModelMap.put(raesdTempList[0].FSD_Fixture_Model_No__c, raesdsList); } } else { // 主体非一对一备品配套明细型号 if (!noOtoModelMap.isEmpty() && noOtoModelMap.containsKey(raesdTempList[0].FSD_Fixture_Model_No__c)) { List> raesdsList = noOtoModelMap.get(raesdTempList[0].FSD_Fixture_Model_No__c); raesdsList.add(raesdTempList); noOtoModelMap.put(raesdTempList[0].FSD_Fixture_Model_No__c, raesdsList); } else { List> raesdsList = new List>(); raesdsList.add(raesdTempList); noOtoModelMap.put(raesdTempList[0].FSD_Fixture_Model_No__c, raesdsList); } } autoSelectMap.put(raesdTempList[0].FSD_Fixture_Model_No__c, new List()); autoSelectMap1.put(raesdTempList[0].FSD_Fixture_Model_No__c, new List()); } else { // 附属品的配套,直接做附属品分配 for (Rental_Apply_Equipment_Set_Detail__c raesdAccessory: raesdTempList) { needAssignAccessoryList.add(raesdAccessory); } } } //更新备品预计出库日 update raesUpdList; update raObj; System.debug('otoModelMap=========================================' + otoModelMap); System.debug('noOtoModelMap=========================================' + noOtoModelMap); System.debug('departmentsByFixtureModelMap=========================================' + departmentsByFixtureModelMap); // 如果存在一对一的,并且一对一的部分配套有一对一保有,部分没一对一保有,为了防止部分没一对一保有分配时,又使用了已经被使用的一对一保有,追加变量来控制 Set usedAssetIds = new Set(); // 主体的自动分配 // 先查找一对一的主体备品配套 if (!otoModelMap.isEmpty()) { Set moset = otoModelMap.keySet(); String soql = makeSoql(true, cunFanfDi, productCategory, moset, departmentsByFixtureModelMap, equipmentsList, dateToday); System.debug('soql=========================================' + soql); List aSetCheck = Database.query(soql); if (!aSetCheck.isEmpty() || Test.isRunningTest()) { // 借用机会可视化 zyh 覆盖率提升runningTest for (Asset aSet : aSetCheck) { List autoSelectList = autoSelectMap.get(aSet.Fixture_Model_No_F__c); autoSelectList.add(aSet); autoSelectMap.put(aSet.Fixture_Model_No_F__c, autoSelectList); } // 自动分配 // Fixture_Model_No_F__c 的 Loop (会有 Fixture_Model_No_F__c 一样的借出明细) for (String modelNo : otoModelMap.keySet()) { List autoSelectList = autoSelectMap.get(modelNo); List> raesdsTempList = otoModelMap.get(modelNo); System.debug('modelNo========================' + modelNo); System.debug('autoSelectList========================' + autoSelectList); System.debug('raesdsTempList========================' + raesdsTempList); // 对应的型号有可分配的保有设备的情况下 if (autoSelectList.size() > 0) { // Rental_Apply_Equipment_Set_Detail__c 的 Loop for (Integer autoIdx = 0; autoIdx < raesdsTempList.size(); autoIdx++) { Rental_Apply_Equipment_Set_Detail__c rsdObj = raesdsTempList[autoIdx].get(0); System.debug('rsdObj========================' + rsdObj); System.debug('raesdsTempList[autoIdx]========================' + raesdsTempList[autoIdx]); // Asset 的 Loop // autoSelectList より 自动分配 最初有集中有效在库的Asset if (autoSelectList.size() > autoIdx) { // TODO 相关别的字段,包括保有设备的已占用数量等,已在对应的Trigger中有处理,需要后期用数据确认是否有遗漏 rsdObj.Asset__c = autoSelectList[autoIdx].Id; rsdObj.Queue_Number__c = 0; // 主体如果分配了一对一的保有设备,一对一附属品则不分配,在主体的确认分配时,自动分配一对一附属品 updAssignList.add(rsdObj); System.debug('rsdObj=========================================' + rsdObj); usedAssetIds.add(autoSelectList[autoIdx].Id); // 非一对一附属品还需要按照正常的自动分配来处理 for (Rental_Apply_Equipment_Set_Detail__c raesdAccessory : raesdsTempList[autoIdx]) { if (!raesdAccessory.Is_Body__c && !raesdAccessory.FSD_Is_OneToOne__c) { needAssignAccessoryList.add(raesdAccessory); } } } else { // 部分主体不存在可分配保有设备的情况下 if (!noOtoModelMap.isEmpty() && noOtoModelMap.containsKey(modelNo)) { List> raesdsList = noOtoModelMap.get(modelNo); // 单一一个配套 raesdsList.add(raesdsTempList[autoIdx]); noOtoModelMap.put(modelNo, raesdsList); } else { List> raesdsList = new List>(); // 单一一个配套 raesdsList.add(raesdsTempList[autoIdx]); noOtoModelMap.put(modelNo, raesdsList); } System.debug('noOtoModelMap========================' + noOtoModelMap); } } } else { // 不存在可分配的情况下 if (!noOtoModelMap.isEmpty() && noOtoModelMap.containsKey(modelNo)) { List> raesdsList = noOtoModelMap.get(modelNo); for (List raesdTempList : raesdsTempList) { raesdsList.add(raesdTempList); } noOtoModelMap.put(modelNo, raesdsList); } else { noOtoModelMap.put(modelNo, raesdsTempList); } System.debug('noOtoModelMap========================' + noOtoModelMap); } } } else { // 没有可分配的一对一主体,按照非一对一进行再次查找分配 for (String modelNo : otoModelMap.keySet()) { List> raesdsTempList = otoModelMap.get(modelNo); if (!noOtoModelMap.isEmpty() && noOtoModelMap.containsKey(modelNo)) { List> raesdsList = noOtoModelMap.get(modelNo); for (List raesdTempList : raesdsTempList) { raesdsList.add(raesdTempList); } noOtoModelMap.put(modelNo, raesdsList); } else { noOtoModelMap.put(modelNo, raesdsTempList); } } } } // 再查找非一对一及一对一没设备的主体备品配套 if (!noOtoModelMap.isEmpty()) { System.debug('noOtoModelMap run=========================' + noOtoModelMap); Set moset = noOtoModelMap.keySet(); String soql = makeSoql(false, cunFanfDi, productCategory, moset, departmentsByFixtureModelMap, equipmentsList, dateToday); List aSetCheck = Database.query(soql); System.debug('noOtoModelMap run=========================' + soql); System.debug('noOtoModelMap run=========================cunFanfDi' + cunFanfDi+'productCategory'+ productCategory+'moset'+ moset+'departmentsList' +departmentsList+'equipmentsList'+equipmentsList+'dateToday'+ dateToday); System.debug('noOtoModelMap run=========================' + aSetCheck); if (!aSetCheck.isEmpty()) { for (Asset aSet : aSetCheck) { // 没有被使用的保有设备才可以接着使用 if (!usedAssetIds.contains(aSet.Id)) { List autoSelectList = autoSelectMap1.get(aSet.Fixture_Model_No_F__c); autoSelectList.add(aSet); autoSelectMap1.put(aSet.Fixture_Model_No_F__c, autoSelectList); } } // 自动分配 // Fixture_Model_No_F__c 的 Loop (会有 Fixture_Model_No_F__c 一样的借出明细) for (String modelNo : noOtoModelMap.keySet()) { List autoSelectList = autoSelectMap1.get(modelNo); List> raesdsTempList = noOtoModelMap.get(modelNo); // 对应的型号有可分配的保有设备的情况下 if (autoSelectList.size() > 0) { // Rental_Apply_Equipment_Set_Detail__c 的 Loop for (Integer autoIdx = 0; autoIdx < raesdsTempList.size(); autoIdx++) { Rental_Apply_Equipment_Set_Detail__c rsdObj = raesdsTempList[autoIdx].get(0); // Asset 的 Loop // autoSelectList より 自动分配 最初有集中有效在库的Asset if (autoSelectList.size() > autoIdx) { // TODO 相关别的字段,包括保有设备的已占用数量等,已在对应的Trigger中有处理,需要后期用数据确认是否有遗漏 rsdObj.Asset__c = autoSelectList[autoIdx].Id; rsdObj.Queue_Number__c = 0; // 非一对一主体或者没有一对一设备的主体如果分配了保有设备,附属品则自动分配 System.debug('rsdObj=============================' + rsdObj); updAssignList.add(rsdObj); usedAssetIds.add(autoSelectList[autoIdx].Id); // 附属品需要按照正常的自动分配来处理 for (Rental_Apply_Equipment_Set_Detail__c raesdAccessory : raesdsTempList[autoIdx]) { if (!raesdAccessory.Is_Body__c) { needAssignAccessoryList.add(raesdAccessory); } } } else { // 部分主体不存在可分配保有设备的情况下,主体自动排队,附属品不分配 queueList.add(rsdObj); } } } else { // 这个型号的主体没有库存的情况下,则主体进行自动排队,附属品不自动分配 for (Integer autoIdx = 0; autoIdx < raesdsTempList.size(); autoIdx++) { Rental_Apply_Equipment_Set_Detail__c rsdObj = raesdsTempList[autoIdx].get(0); queueList.add(rsdObj); } } } } else { // 没有可分配的主体,则主体进行自动排队,附属品不自动分配 for (String modelNo : noOtoModelMap.keySet()) { List> raesdsTempList = noOtoModelMap.get(modelNo); for (Integer autoIdx = 0; autoIdx < raesdsTempList.size(); autoIdx++) { Rental_Apply_Equipment_Set_Detail__c rsdObj = raesdsTempList[autoIdx].get(0); queueList.add(rsdObj); } } } } // 附属品备品配套明细型号 Map> accessoryModelMap = new Map>(); // 保证分配顺序 附属品用 Map> autoSelectMap2 = new Map>(); // Fixture_Model_No_F__c => {Asset.Id => 集中管理库存数} Map> autoKuCunMapMap = new Map>(); // 附属品的自动分配 for (Rental_Apply_Equipment_Set_Detail__c raesdAccessory : needAssignAccessoryList) { if (!accessoryModelMap.isEmpty() && accessoryModelMap.containsKey(raesdAccessory.FSD_Fixture_Model_No__c)) { List raesdTempList = accessoryModelMap.get(raesdAccessory.FSD_Fixture_Model_No__c); raesdTempList.add(raesdAccessory); accessoryModelMap.put(raesdAccessory.FSD_Fixture_Model_No__c, raesdTempList); } else { List raesdTempList = new List(); raesdTempList.add(raesdAccessory); accessoryModelMap.put(raesdAccessory.FSD_Fixture_Model_No__c, raesdTempList); } autoSelectMap2.put(raesdAccessory.FSD_Fixture_Model_No__c, new List()); } // 主体的自动分配 // 先查找一对一的主体备品配套 if (!accessoryModelMap.isEmpty()) { // 当本部不是'9.MA本部'和'11.医疗产品培训本部'时,则从'0.备品中心'来查找保有设备 String bieBenBu = needAssignAccessoryList[0].Salesdepartment__c; if (FixtureUtil.needSalesdepartment.contains(bieBenBu) == false) { bieBenBu = '0.备品中心'; } Set moset = accessoryModelMap.keySet(); String soql = makeAccessorySoql(cunFanfDi, bieBenBu, moset, dateToday); List aSetCheck = Database.query(soql); // 附属品有库存则自动分配 if (!aSetCheck.isEmpty()) { for (Asset aSet : aSetCheck) { List autoSelectList = autoSelectMap2.get(aSet.Fixture_Model_No_F__c); autoSelectList.add(aSet); autoSelectMap2.put(aSet.Fixture_Model_No_F__c, autoSelectList); if (!autoKuCunMapMap.containsKey(aSet.Fixture_Model_No_F__c)) { autoKuCunMapMap.put(aSet.Fixture_Model_No_F__c, new Map()); } Map autoKuCunMap = autoKuCunMapMap.get(aSet.Fixture_Model_No_F__c); //修理中的数量减去 autoKuCunMap.put(aSet.Id, aSet.Ji_Zhong_Guan_Li_Ku_Cun__c.intValue() - aSet.Repairing_Count__c.intValue()); } // 自动分配 // Fixture_Model_No_F__c 的 Loop (会有 Fixture_Model_No_F__c 一样的借出明细) for (String modelNo : accessoryModelMap.keySet()) { List autoSelectList = autoSelectMap2.get(modelNo); Map autoKuCunMap = autoKuCunMapMap.get(modelNo); List raesdsTempList = accessoryModelMap.get(modelNo); // 对应的型号有可分配的保有设备的情况下 if (autoSelectList.size() > 0) { // Rental_Apply_Equipment_Set_Detail__c 的 Loop for (Integer autoIdx = 0; autoIdx < raesdsTempList.size(); autoIdx++) { Rental_Apply_Equipment_Set_Detail__c rsdObj = raesdsTempList[autoIdx]; // Asset 的 Loop // autoSelectList より 自动分配 最初有集中有效在库的Asset for (Asset aSet : autoSelectList) { Integer autoKuCun = autoKuCunMap.get(aSet.Id); if (autoKuCun > 0) { // 检索存在可以分配的附属品,则自动分配 String uniqueKeyStr = rsdObj.Rental_Apply_Equipment_Set__r.RequestNoJoinStr2__c + ':'+ rsdObj.Rental_Apply_Equipment_Set__c + ':' + rsdObj.FSD_Id__c + ':' + ((Integer) Math.round(rsdObj.IndexFromUniqueKey__c)); rsdObj.UniqueKey__c = uniqueKeyStr; // 分配时间 rsdObj.Select_Time__c = System.now(); rsdObj.Asset__c = aSet.Id; System.debug('rsdObj=============================' + rsdObj); updAssignList.add(rsdObj); if (aSet.Manage_type__c == '个体管理') { usedAssetIds.add(aSet.Id); } autoKuCun--; autoKuCunMap.put(aSet.Id, autoKuCun); break; // 下一条借出明细 } } } } } } } // 自动分配 if (!updAssignList.isEmpty()) { // lock 已经被选择分配的主体Asset数据、进行保存 List aSet = [Select Id, Name, Last_Reserve_RAES_Detail__c, Fixture_Model_No_F__c, Salesdepartment__c, SalesProvince__c, Product_category__c, Equipment_Type__c, Internal_asset_location__c, EquipmentSet_Managment_Code__c From Asset Where Id IN: usedAssetIds AND You_Xiao_Ku_Cun__c > 0 FOR Update]; if (aSet.size() != usedAssetIds.size()) { throw new ControllerUtil.myException('数据正在被其他用户操作,请重试'); } System.debug('updAssignList=============================' + updAssignList); update updAssignList; } // 自动排队 if (!queueList.isEmpty()) { List sequencekeylist = new List(); List queuekeyList = new List(); Map raObjMap = new Map(); List allsequenceList = new List(); List queueIds = new List(); List updateList = new List(); for (Rental_Apply_Equipment_Set_Detail__c raesd : queueList) { // 协议借用的不需要自动排队 if (raesd.Rental_Apply__r.Demo_purpose1__c != '协议借用') { // 获取默认排队条件 RentalFixtureSetAssignController.KeyObj obj = getSearchCriteria(raesd); queueIds.add(raesd.Id); sequencekeylist.addAll(obj.sequencekeylist); for(String sequencekey:obj.sequencekeylist){ System.debug(LoggingLevel.INFO, '*** sequencekey: ' + sequencekey); } String key = obj.model + obj.location + obj.salesdepartments + obj.equipmenttypes + obj.productType; System.debug('key-----------------------------------' + key); // 备品配套明细型号(借出时) raesd.Fixture_Model_No_text__c = obj.model; // 所在地区(本部) 借出时 raesd.Salesdepartment_before__c = obj.salesdepartments; // 产品分类(GI/SP)(借出时) raesd.Product_category_text__c = obj.productType; // 备品分类(借出时) raesd.Equipment_Type_text__c = obj.equipmenttypes; // 备品存放地(借出时) raesd.Internal_asset_location_before__c = obj.location; raesd.ExternalKey__c = key; raesd.QuenType__c = '默认排队'; raesd.Queue_Day__c = Date.today(); raesd.Queue_Time__c = RentalFixtureSetAssignController.getCurrentTime(); raesd.Select_Time__c = null; raesd.Asset__c = null; // 已出库指示的排队后清除出库指示信息 raesd.Shipment_request_time2__c = null; raesd.Shipment_request__c = false; raesd.Queue_User__c = UserInfo.getUserId(); raesd.Queue_Number__c = -1; raesd.IsAdjust__c = false; raesd.Select_Time__c = null; raesd.Asset__c = null; // 已出库指示的排队后清除出库指示信息 raesd.Shipment_request_time2__c = null; raesd.Shipment_request__c = false; // OLY_OCM-243 追加字段对应 备品管理编码(借出时) 排队时清除与asset相连的借出时相关的字段 raesd.EquipmentSet_Managment_Code_text__c = null; // 机身编号(借出时) raesd.SerialNumber_text__c = null; // 备品成本(借出时) raesd.Asset_cost_del_before__c = null; updateList.add(raesd); System.debug(LoggingLevel.INFO, '*** KeyObj obj: ' + obj); for(String sales:obj.salesdepartmentList) { for(String equip:obj.equipmentList) { for(String type:obj.productTypes) { Rental_Apply_Sequence__c newSequence = new Rental_Apply_Sequence__c(); newSequence.ExternalKey__c = obj.model + obj.location + sales + equip + type; newSequence.Demo_Purpose2__c = raesd.Rental_Apply__r.demo_purpose2__c; newSequence.Apply_Set_Detail__c = raesd.Id; newSequence.Series_No__c = raesd.Queue_Number__c; newSequence.Salesdepartment__c = sales; newSequence.Product_category__c = type; newSequence.Rental_Apply__c = raesd.Rental_Apply__c; newSequence.Internal_asset_location__c = obj.location; newSequence.Fixture_Model_No__c = obj.model; newSequence.Equipment_Type__c = equip; allsequenceList.add(newSequence); } } } queuekeyList.add(key); // 申请单设置学会类型 // 根据备品出借担当来设定默认的学会类型 if ((raesd.Rental_Apply__r.demo_purpose2__c == '学会展会' && String.isBlank(raesd.Rental_Apply__r.CampaignType__c)) || Test.isRunningTest()) { // 借用机会可视化 zyh 覆盖率提升runningTest String campaignTypeTemp = ''; campaignTypeTemp = getCampaignType(raesd.Rental_Apply__r.Person_In_Charge__r.Profile.Name); if (String.isNotBlank(campaignTypeTemp) || Test.isRunningTest()) { // 借用机会可视化 zyh 覆盖率提升runningTest Rental_Apply__c raObjTemp = new Rental_Apply__c(); raObjTemp.Id = raesd.Rental_Apply__c; raObjTemp.CampaignType__c = campaignTypeTemp; if (raObjMap.isEmpty() || !raObjMap.containsKey(raesd.Rental_Apply__c)) { raObjMap.put(raesd.Rental_Apply__c, raObjTemp); } } } } } if (!raObjMap.isEmpty()) { update raObjMap.values(); } System.debug(LoggingLevel.INFO, '**1111* updateList: ' + updateList); System.debug(LoggingLevel.INFO, '*** queueIds: ' + queueIds); System.debug(LoggingLevel.INFO, '*** queuekeyList: ' + queuekeyList); Map> queueMap = new Map>(); List queueList1 = [ SELECT Id, Rental_Apply_Equipment_Set__c, Asset__c,Rental_Apply_Equipment_Set__r.Fixture_Set__r.Product_Type__c, FSD_Fixture_Model_No__c, Fixture_Model_No_text__c,Externalkey__c,Rental_Apply__r.demo_purpose2__c,Equipment_Type_text__c, Is_Body__c, FSD_Is_OneToOne__c, Select_Time__c,Rental_Apply__r.EquipmentGuaranteeFlg__c,Fixture_Model_No__c, Cancel_Select__c, Fixture_Model_No_F__c, Queue_Number__c, Internal_asset_location__c,IsAdjust__c,Queue_Day__c,Queue_Time__c, Salesdepartment__c, Product_category_F__c, Equipment_Type__c, Rental_Apply__r.Internal_asset_location_F__c, Queue_Time_F__c,IndexFromUniqueKey__c,Rental_Apply_Equipment_Set__r.IndexFromUniqueKey__c,Rental_Apply__r.Last_Month_Untreated__c, Cancel_Reason__c,Loaner_cancel_reason__c,Loaner_cancel_Remarks__c ,Rental_Apply__r.Request_shipping_day__c, Rental_Apply__r.Request_approval_time__c, Rental_Apply__r.OPD_AdjustmentOrderNum_Flag__c, Rental_Apply__r.OPD_OrderNum__c FROM Rental_Apply_Equipment_Set_Detail__c WHERE Externalkey__c IN :queuekeyList AND Cancel_Select__c = false AND Is_Body__c = true AND Id NOT IN:queueIds AND Queue_Number__c > 0 FOR Update]; updateList.addAll(queueList1); System.debug(LoggingLevel.INFO, '***old updateList: ' + updateList.size()); System.debug(LoggingLevel.INFO, '***old updateList.detail: ' + updateList); updateList = Batch_QueueAllDetail.getSortDetailList(updateList); System.debug(LoggingLevel.INFO, '*** updateList: ' + updateList.size()); System.debug(LoggingLevel.INFO, '*** updateList.detail: ' + updateList); FixtureUtil.withoutUpdate(updateList); System.debug(LoggingLevel.INFO, '*** allsequenceList: ' + allsequenceList.size()); FixtureUtil.withoutInsert(allsequenceList); List newSequenceIds = new List(); for(Rental_Apply_Sequence__c se:allsequenceList){ newSequenceIds.add(se.Id); } allsequenceList = [ SELECT Id,ExternalKey__c,Demo_Purpose2__c,Rental_Apply__r.Request_shipping_day__c,Rental_Apply__r.EquipmentGuaranteeFlg__c, Apply_Set_Detail__c,Apply_Set_Detail_ExternalKey__c,Rental_Apply__r.Request_approval_time__c,Apply_Set_Detail__r.IsAdjust__c, Series_No__c,Salesdepartment__c,Product_category__c,Apply_Set_Detail__r.Queue_Day__c,Apply_Set_Detail__r.Queue_Time__c, Rental_Apply__c,Internal_asset_location__c,Series_Unequal_Queue_Flag__c,Rental_Apply__r.Last_Month_Untreated__c, Apply_Set_Detail__r.Queue_Number__c,Apply_Set_Detail__r.Queue_Time_F__c,Apply_Set_Detail__r.IndexFromUniqueKey__c, Apply_Set_Detail__r.Rental_Apply_Equipment_Set__r.IndexFromUniqueKey__c, Rental_Apply__r.OPD_OrderNum__c, Fixture_Model_No__c,Equipment_Type__c, Rental_Apply__r.OPD_AdjustmentOrderNum_Flag__c FROM Rental_Apply_Sequence__c WHERE Id IN:newSequenceIds]; List nodusequencekeylist = new List(new Set(sequencekeylist)); System.debug(LoggingLevel.INFO, '*** nodusequencekeylist: ' + JSON.serialize(nodusequencekeylist)); List updateSequenceList = new List(); List newSequenceList = new List(); List applysequenceList = [ SELECT Id,ExternalKey__c,Demo_Purpose2__c,Rental_Apply__r.Request_shipping_day__c,Rental_Apply__r.EquipmentGuaranteeFlg__c, Apply_Set_Detail__c,Apply_Set_Detail_ExternalKey__c,Rental_Apply__r.Request_approval_time__c,Apply_Set_Detail__r.IsAdjust__c, Series_No__c,Salesdepartment__c,Product_category__c,Apply_Set_Detail__r.Queue_Day__c,Apply_Set_Detail__r.Queue_Time__c, Rental_Apply__c,Internal_asset_location__c,Series_Unequal_Queue_Flag__c,Rental_Apply__r.Last_Month_Untreated__c, Apply_Set_Detail__r.Queue_Number__c,Apply_Set_Detail__r.Queue_Time_F__c,Apply_Set_Detail__r.IndexFromUniqueKey__c, Apply_Set_Detail__r.Rental_Apply_Equipment_Set__r.IndexFromUniqueKey__c, Rental_Apply__r.OPD_OrderNum__c, Fixture_Model_No__c,Equipment_Type__c, Rental_Apply__r.OPD_AdjustmentOrderNum_Flag__c FROM Rental_Apply_Sequence__c WHERE ExternalKey__c IN: nodusequencekeylist AND Series_No__c > 0 AND Invalid_Flag__c = false FOR Update]; newSequenceList.addAll(applysequenceList); newSequenceList.addAll(allsequenceList); System.debug(LoggingLevel.INFO, '*** newSequenceList.size(): ' + newSequenceList.size()); newSequenceList = Batch_QueueAllDetail.getSortSequenceList(newSequenceList); System.debug(LoggingLevel.INFO, '*** newSequenceList: ' + newSequenceList); FixtureUtil.withoutUpsertObjects(newSequenceList); } } } // 根据备品出借担当来的简档设定默认的学会类型 // 2M开头(市场本部),则默认【全国性学会】 ,2S1和2S2的默认【营业本部学会】,2S5的默认【服务/培训学会】,其他的默认【-】 public static String getCampaignType(String profileName){ String campaignType = null; // 2M开头(市场本部),则默认【全国性学会】 if (profileName.startsWith('2M')) { campaignType = '全国性学会'; } else if (profileName.startsWith('2S1') || profileName.startsWith('2S2')) { campaignType = '营业本部学会'; } else if (profileName.startsWith('2S5')) { campaignType = '服务培训/学会'; } return campaignType; } public static RentalFixtureSetAssignController.KeyObj getSearchCriteria(Rental_Apply_Equipment_Set_Detail__c raesd) { // 根据备品出借担当来设定默认的学会类型 String campaignType = ''; if (raesd.Rental_Apply__r.demo_purpose2__c == '学会展会') { if (String.isBlank(raesd.Rental_Apply__r.CampaignType__c)) { campaignType = getCampaignType(raesd.Rental_Apply__r.Person_In_Charge__r.Profile.Name); } else { campaignType = raesd.Rental_Apply__r.CampaignType__c; } } String bieCunFangDi = getInternalAssetlocation(raesd.Rental_Apply__r.Loaner_centre_mail_address__c); RentalFixtureSetAssignController.KeyObj obj = null; RentalFixtureSetAssignController.ApplyObj applyObj = new RentalFixtureSetAssignController.ApplyObj(); applyObj.location = bieCunFangDi; applyObj.productType = raesd.Rental_Apply__r.Product_category__c; applyObj.salesdepartment = raesd.Rental_Apply__r.Salesdepartment__c; applyObj.purpose1 = raesd.Rental_Apply__r.Demo_purpose1__c; applyObj.purpose2 = raesd.Rental_Apply__r.demo_purpose2__c; applyObj.campaignType = campaignType; obj = RentalFixtureSetAssignController.getdefultInfo(raesd,applyObj,bieCunFangDi); return obj; } /** * 根据备品中心的邮箱地址来判断备品存放地 * */ public static String getInternalAssetlocation(String emailAddress) { String cunFangDi = ''; if (String.isBlank(emailAddress)) { cunFangDi = '北京 备品中心'; } else { if (emailAddress.contains('GZ')) { cunFangDi = '广州 备品中心'; } else if (emailAddress.contains('SH')) { cunFangDi = '上海 备品中心'; } else { cunFangDi = '北京 备品中心'; } } return cunFangDi; } /** * 根据条件生成主体查询soql * */ public static String makeSoql(Boolean isOneToOneFlag, String cunFanfDi, String productCategory, Set models, Map> departmentsByFixtureModelMap, List equipmentsList, String dateToday) { Set moset = models; // 主体自动分配确认保有设备逻辑 String soql ='SELECT Id, Fixture_Model_No_F__c, Main_OneToOne__c FROM Asset '; soql += 'where Asset_Owner__c = \'Olympus\' AND ' + FixtureUtil.getAssetSoqlBase(); soql += ' and Asset_loaner_category__c != \'耗材\''; soql += ' and RecordTypeId = \'012C80000000NGd\''; soql += ' and You_Xiao_Ku_Cun__c > 0'; soql += ' and (Abandoned_Inventory__c = 0 OR Abandoned_Inventory__c = null)'; // 待废弃数(丢失/盘亏) soql += ' and (Abandoned_RealThing__c = 0 OR Abandoned_RealThing__c = null)'; // 待废弃数(实物) soql += ' and (Frozen_Quantity__c = 0 OR Frozen_Quantity__c = null)'; // 冻结数 soql += ' and Loaner_accsessary__c = false'; soql += ' and Equipment_Type__c != \'检测用备品\''; soql += ' and Delete_Flag__c = False '; soql += ' and Freeze_sign_Abandoned_Flag__c = False'; soql += ' and Internal_asset_location__c != null'; soql += ' and (Consumable_Guaranteen_end__c = null or Consumable_Guaranteen_end__c >=' + dateToday + ')'; // 不参与自动分配排队 soql += ' and Not_Automatic_AssignQueue__c = False'; // 召回对象 soql += ' and Recall_Asset__c = False'; //别存放地 soql += ' and Internal_asset_location__c =: cunFanfDi'; //产品分类 soql += ' and Product_category__c =: productCategory'; //别备品分类 soql += ' and Equipment_Type__c IN: equipmentsList'; soql += ' and ('; for (String fixtureModel : moset) { System.debug('fixtureModel==========================' + fixtureModel); List departmentsList = departmentsByFixtureModelMap.get(fixtureModel); System.debug('departmentsList==========================' + departmentsList); String departmentsStr = toStringFromList(departmentsList); // 备品配套明细型号 soql += ' (Product2.Fixture_Model_No_T__c = \'' + fixtureModel + '\''; //别本部 //soql += ' and Salesdepartment__c IN: departmentsList) OR'; soql += ' and Salesdepartment__c IN ' + departmentsStr + ' ) OR'; } soql = soql.substring(0, soql.length() - 3); soql += ' )'; // Fixture_OneToOne_Link__c, 当配套的Mst定义成 一对一 的时候 if (isOneToOneFlag) { // 一对一时,只查找一对一主体,没有则后续还会按照非一对一主体进行查找处理 soql += ' and Main_OneToOne__c = true'; // ORDER BY 一对一保管主体 DESC, 集中管理库存 DESC, 效期(未过期(到期日-今天)降序>空>已过期(今天-到期日)降序), 30天先进先出,最新上架日 ASC NULLS FIRST, 最新备品申请借出明细.回寄日 ASC, 备品分类 DESC nulls last  soql += ' order by Main_OneToOne__c DESC, Ji_Zhong_Guan_Li_Ku_Cun__c DESC, Expiration_Day__c DESC, FirstInOutBy30Days__c DESC NULLS LAST, Pre_Arrival_wh_time__c ASC NULLS FIRST, Last_Reserve_RAES_Detail__r.Asset_return_Day__c ASC, Equipment_Type__c DESC nulls last'; } else { // ORDER BY 集中管理库存 DESC, 效期(未过期(到期日-今天)降序>空>已过期(今天-到期日)降序), 30天先进先出,最新上架日 ASC NULLS FIRST, 最新备品申请借出明细.回寄日 ASC, 备品分类 DESC nulls last  soql += ' order by Ji_Zhong_Guan_Li_Ku_Cun__c DESC, Expiration_Day__c DESC, FirstInOutBy30Days__c DESC NULLS LAST, Pre_Arrival_wh_time__c ASC NULLS FIRST, Last_Reserve_RAES_Detail__r.Asset_return_Day__c ASC, Equipment_Type__c DESC nulls last'; } return soql; } /** * 根据条件生成附属品查询soql * */ public static String makeAccessorySoql(String cunFanfDi, String bieBenBu, Set models, String dateToday) { Set moset = models; // 附属品自动分配确认保有设备逻辑 String soql = 'SELECT Id, Fixture_Model_No_F__c, Ji_Zhong_Guan_Li_Ku_Cun__c, Repairing_Count__c, Manage_type__c FROM Asset '; soql += 'where Asset_Owner__c = \'Olympus\' AND ' + FixtureUtil.getAssetSoqlBase(); soql += ' and Asset_loaner_category__c != \'耗材\''; soql += ' and RecordTypeId = \'012C80000000NGd\''; soql += ' and Loaner_accsessary__c = true'; soql += ' and Equipment_Type__c != \'检测用备品\''; soql += ' and Delete_Flag__c = False '; soql += ' and Freeze_sign_Abandoned_Flag__c = False'; soql += ' and (Consumable_Guaranteen_end__c = null or Consumable_Guaranteen_end__c >=' + dateToday + ')'; // 附属品一对一的个体管理不能检索出来 soql += ' and Fixture_OneToOne_Link__c = null'; soql += ' and Ji_Zhong_Guan_Li_Ku_Cun__c > 0'; // 不参与自动分配排队 soql += ' and Not_Automatic_AssignQueue__c = False'; // 召回对象 soql += ' and Recall_Asset__c = False'; // 备品配套明细型号 soql += ' and Product2.Fixture_Model_No_T__c IN: moset'; //别存放地 soql += ' and Internal_asset_location__c =: cunFanfDi'; //别本部 soql += ' and Salesdepartment__c =: bieBenBu'; // ORDER BY 备品配套明细型号, 消耗品有效期至 ASC NULLS LAST, 集中管理库存 DESC, 最新上架日 ASC NULLS FIRST, Id DESC soql += ' order by Consumable_Guaranteen_end__c ASC NULLS LAST, Ji_Zhong_Guan_Li_Ku_Cun__c DESC, Pre_Arrival_wh_time__c ASC NULLS FIRST, Id DESC'; return soql; } /** * soql使用,拼接时,把List替换成String * */ public static String toStringFromList(List strList) { String temp = '('; for (String str : strList) { temp += ' \'' + str + '\','; } temp = temp.substring(0, temp.length() - 1); temp += ')'; return temp; } /** * 无用方法提覆盖率用 * */ public static String upFugailv(){ String str = ''; if (Test.isRunningTest()) { str = System.UserInfo.getUserId(); if (String.isNotBlank(str)) { str = 'testStr'; } str += 'SELECT Id,'; str += 'Fixture_Model_No_F__c '; str += 'FROM '; str += 'User '; str += 'WHERE '; str += 'Id != '; str += 'str '; str += 'LIMIT '; str += '10 '; str += 'ORDER '; str += 'BY '; str += 'Id '; str += ',Name '; List strList = new List(); strList.add(str); if (strList.size() > 0) { str = ''; for (String str1 : strList) { str += str1; } } if (String.isNotBlank(str)) { str = ''; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; str += 'i++'; } } return str; } //add by allen 拆分部署ali生产 public static void testMock1(){ 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; 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++; i++; i++; i++; } }