global without sharing class ProductMonthlySalesCountBatch implements Database.Batchable,Database.Stateful { //统计产品月销量 精琢技术 tcm 2021-10-11 start /* tcm //by_tcm 测试代码 start //如编码错误请删除前面的空格 ①生成所有12月月销量的数据(前提是产品的生成12月月销量标识得为true,默认204传输过来的时候为true): Database.executeBatch(new ProductMonthlySalesCountBatch(true)); ②生成所有当前月月销量的1条数据 Database.executeBatch(new ProductMonthlySalesCountBatch()); ③生成指定很多产品的12月月销量的数据 List idList = new List(); //添加指定的产品的id idList.add('');//eg:dList.add('01t10000002P5yiAAC'); Database.executeBatch(new ProductMonthlySalesCountBatch(idList), 20); ④生成指定某个产品的12月月销量的数据 //下面的'' 引号里面放入指定的产品id Database.executeBatch(new ProductMonthlySalesCountBatch(''), 20); //eg:Database.executeBatch(new ProductMonthlySalesCountBatch('01t10000002P5yiAAC'), 20); ⑤生成指定很多产品的当前月月销量的数据 List idList = new List(); //添加指定的产品的id idList.add('');//eg:dList.add('01t10000002P5yiAAC'); Database.executeBatch(new ProductMonthlySalesCountBatch(idList,true), 20); ⑥生成指定某个产品的当前月月销量的数据 //下面的'' 引号里面放入指定的产品id Database.executeBatch(new ProductMonthlySalesCountBatch('',true), 20); //eg:Database.executeBatch(new ProductMonthlySalesCountBatch('01t10000002P5yiAAC',true), 20); //sql验证生成结果 select id, ProductM__c, Product2Model__c, CurrentDate__c, MonthSales__c,Earliest_Shipping__c,GenerationMonths__c from ProductMonthlySales__c order by Product2Model__c, CurrentDate__c // by_tcm 测试代码 end */ //错误邮件 start // 报错的询价ID public String logstr = ''; // 报错信息 public String errorstr = ''; // 总件数 public Integer totalCount = 0; // 失败件数 public Integer failedCount = 0; // 生成月销量起始时间 public Date productDate = Date.valueOf(Label.Product_Date); // 邮件信息 public List emailMessages = new List(); //错误邮件 end //状态 存放应执行的方法 Integer status=0; //存放方法传进来的产品ID List proList = new List(); //生成所有产品本月的月销量 status=0 global ProductMonthlySalesCountBatch(){ } //生成所有产品12个月的月销量 status=3 global ProductMonthlySalesCountBatch(Boolean all){ this.status=3; } //指定List<产品>生成12个月以内的月销量(上月月底 往前推12个月) status=1 global ProductMonthlySalesCountBatch(List pro2List){ this.proList.addAll(pro2List); this.status=1; } //指定单个产品ID 生成12个月以内的月销量(上月月底 往前推12个月) status=1 global ProductMonthlySalesCountBatch(String pro2Id){ this.proList.add(pro2Id); this.status=1; } // 生成List<> Id 本月的月销量 status=2 global ProductMonthlySalesCountBatch(List pro2List,Boolean oneMonth){ this.proList.addAll(pro2List); this.status=2; } // 生成单个Id 本月的月销量 status=2 global ProductMonthlySalesCountBatch(String pro2Id,Boolean oneMonth){ this.proList.add(pro2Id); this.status=2; } global Database.QueryLocator start(Database.BatchableContext bc){ // by_tcm 查产品 没有停产的 && 预计停止日期 != null String sql='select id,ProductCode,Correspond_Code__c,Correspond_ProductCode__c,M_BC_Stop_manufacure__c,ProductMonthlySalesFlag__c from Product2 where M_BC_Stop_manufacure__c !=null and SFDA_Status__c!=\'停止\''; // 如果执行的方法是指定Id的 if (status==1||status==2) { sql+=' and id in :proList '; } // 如果执行的方法是生成12个月的 if (status==3||status==1) { sql+=' and ProductMonthlySalesFlag__c = true'; } return Database.getQueryLocator(sql); } global void execute(Database.BatchableContext BC, List rowDataList) { //产品去重-----------------start // 新旧产品ID存入Map<> allproMap start Map oldproMap=new Map(); Map newproMap=new Map(); Map allproMap=new Map(); // 筛选旧产品 for(Product2 product : rowDataList) { oldproMap.put(product.id,product); } // 筛选新产品 for(Product2 product : rowDataList) { // 如果对应的新code不等于空 if(product.Correspond_Code__c!=null) { // 如果旧产品Map 不包含 对应的新code ,则存入新产品Map if(!oldproMap.containsKey(product.Correspond_Code__c)) { newproMap.put(product.Correspond_Code__c,product); } } } // 合并数据 allproMap.putAll(oldproMap); allproMap.putAll(newproMap); // 新旧产品ID存入Map<...> allproMap end // 新旧产品ID存入List<> strprodids start List rowListold = new List(); List rowListnew = new List(); List strprodids = new List(); // List<旧产品> for(Product2 product : oldproMap.values()) { rowListold.add(product); strprodids.add(product.Id); } // List<新产品> for(Product2 product : newproMap.values()) { rowListnew.add(product); strprodids.add(product.Correspond_Code__c); } // 新旧产品ID存入strprodids end //产品去重--------------end //查询保有设备--------------start // by_tcm 通过上边没停产 去重后 的List strprodids 查询保有设备 &&发货日期 != null List AssetList =[select Id,Product2Id,Posting_Date__c,RecordType.DeveloperName from Asset where Product2Id IN :strprodids and Posting_Date__c!=null and RecordType.DeveloperName !='Shipment' and Posting_Date__c>=:productDate order by Posting_Date__c desc]; // 设置要生成的月份数 (循环保有设备查找产品最早发货日) start Map cntMonthMap=new Map(); for (Asset ass : AssetList) { Product2 pdt=allproMap.get(ass.Product2Id); Date endDate=date.today(); Date startDate=ass.Posting_Date__c; Integer countMonths= startDate.monthsBetween(endDate); //如果执行的方法是生成1个月的,应生成月=1 if (this.status==0||this.status==2) { countMonths=1; } // 如果月份大于12,设置12 else if(countMonths>12) { countMonths=12; } cntMonthMap.put(ass.Product2Id,countMonths); } // 设置要生成的月份数 (循环保有设备查找产品最早发货日) end //查询保有设备--------------end // by_tcm 查询月销量 where id in strprodids ProductMonthlySalescMap 月销量 List ProductMonthlySalescList =[select id,Name__c, MonthSales__c, CurrentMonth__c, CurrentDate__c, CurrentYear__c, ProductM__c, Product2Model__c,Name,Earliest_Shipping__c,GenerationMonths__c from ProductMonthlySales__c where ProductM__r.id in :strprodids]; List productmonthold = new List(); List productmonthnew = new List(); //如果旧产品不为空,调用方法 if(rowListold!=null) { productmonthold = createMonthlySales(rowListold,AssetList,0,cntMonthMap,this.status,ProductMonthlySalescList); } //如果新产品不为空,调用方法 if(rowListnew!=null) { productmonthnew= createMonthlySales(rowListnew,AssetList,1,cntMonthMap,this.status,ProductMonthlySalescList); } // 合并 productmonthold.addAll(productmonthnew); //select产品月销量去重------start Map ProductMonthlySalescMap = new Map(); for(ProductMonthlySales__c pms :ProductMonthlySalescList) { ProductMonthlySalescMap.put(pms.Name,pms); } //select产品月销量去重------end //新产品月销量去重-------start for(ProductMonthlySales__c prdm : productmonthold) { ProductMonthlySalescMap.put(prdm.Name,prdm); // ProductMonthlySalescMap.put('ahaha',prdm); } //新产品月销量去重-------end List newProductMonthlySalescList=new List(); // //去重后转List start // for (ProductMonthlySales__c prdm : ProductMonthlySalescMap.values()) { // newProductMonthlySalescList.add(prdm); // newProductMonthlySalescList.add(prdm); // } // //去重后转List start Map keyProId=new Map(); if(productmonthold!=null) { Database.UpsertResult[] results = Database.upsert(ProductMonthlySalescMap.values(),ProductMonthlySales__c.Name__c,false); totalCount=results.size(); for(Integer i = 0; i < totalCount; i++) { if(!results[i].isSuccess()) { for (Database.Error err : results[i].getErrors()) { String message = '产品月销量 : 产品ID为: '+ ProductMonthlySalescMap.values()[i].ProductM__c + ' ; ' + err.getStatusCode() + '; '+ err.getFields() + ' ; '+ err.getMessage(); failedCount++; keyProId.put(ProductMonthlySalescMap.values()[i].ProductM__c,message); } } } String cacheText=''; for (String errorst: keyProId.values()) { cacheText+=errorst+'\n'; } errorstr=cacheText; } // 把 生成12月销量标识 设置为false start // 数据去重 Map pro2Map =new Map(); for (Asset aset : AssetList) { pro2Map.put(aset.Product2Id,aset); } // 批量修改数据 List updatePmsfcss =new List(); for (Asset updatePmsfcs : pro2Map.values()) { Product2 pro2=new Product2(); pro2.Id=updatePmsfcs.Product2Id; pro2.CalMonthSalesFLG__c=true; if (this.status==3||this.status==1) { pro2.ProductMonthlySalesFlag__c=false; } updatePmsfcss.add(pro2); } update updatePmsfcss; // 把 生成12月销量标识、 设置为false end } private static List createMonthlySales(List rowList,List AssetList,Integer flag,Map countMonthsMap,Integer status,List ProductMonthlySalescList) { List productmonth = new List(); // 循环产品 for(Product2 product : rowList) { //生成当月时,应生成月数量是否有变化,如有,更新产品12个月的应生成月数量数据 Map Map countStatus = new Map(); //同上,储存应生成月数量 Map Map countMonthss=new Map(); //应生成月 Integer countMonths=12; //发货日期 Date postDate=Date.today(); // 给ID code 赋值 start String Id; String Code; if(flag==0) { //产品ID Id=product.Id; //产品代码 Code=product.ProductCode; }else if(flag==1) { //对应的新CODE Id=product.Correspond_Code__c; //对应的新CODE的产品代码 Code=product.Correspond_ProductCode__c; } // 给ID code 赋值 end //存无数据的(0) Map Map AssetcountMap = new Map(); //存无数据的(0) Map Map AstcountMap = new Map(); //临时存日期用 Date starDate; if(countMonthsMap.containsKey(Id)) { //应生成月 Integer cntMonths =-countMonthsMap.get(Id); // by_tcm 预计结束日期/现在日期 Date dates=Date.today(); //如果预计结束日<今天 减掉相差的月数 => 数据0的生成量 if (product.M_BC_Stop_manufacure__cass.Posting_Date__c /*&&ass.Posting_Date__c.year()!=1900*/) { postDate=ass.Posting_Date__c; } //取应生成月 start if (status==0||status==2) { //应生成月 countMonths=ass.Posting_Date__c.monthsBetween(lastdate); //如果应生成月<12,应生成月+1 if (countMonths < 12) { countMonths++; }else { countMonths=12; } countStatus.put(Id, 1); countMonthss.put(Id, countMonths); }else { //应生成月 countMonths=ass.Posting_Date__c.monthsBetween(dates); if (countMonths > 12) { countMonths=12; } } //取应生成月 end } //取最早发货日和应生成月 start } } // by_tcm 添加有销量的数据 end //合并数据 start AstcountMap.putAll(AssetcountMap); AssetcountMap=AstcountMap; //合并数据 end } for (String key : AssetcountMap.keySet()) { // 年 Integer yearss; // 月 Integer monthss; String month=''; if (key!=null) { //拆分year_month中的年_月 List year_month=key.split('_'); yearss = Integer.valueOf(year_month[0]); monthss = Integer.valueOf(year_month[1]); } ProductMonthlySales__c pmsc=new ProductMonthlySales__c(); //如果是新产品Id,不储存新产品ID的应生成月 if (flag==0) { //应生成月 pmsc.GenerationMonths__c=countMonths; } // 月 month=String.valueOf(monthss); if(monthss<10) { month='0'+monthss; } // 发货日期 pmsc.Earliest_Shipping__c=postDate; // 月销售量 pmsc.MonthSales__c = AssetcountMap.get(key); // 当前日期 pmsc.CurrentDate__c = Date.newInstance(yearss,monthss,1); // 产品Id pmsc.ProductM__c = Id; // 产品型号 pmsc.Product2Model__c = Code; // 产品月销量名称 pmsc.Name = Code+':'+yearss+month; //作为name唯一Key pmsc.Name__c=pmsc.Name; productmonth.add(pmsc); } // //数据(应生成月)发生变化,更新数据 // if (countStatus.containsKey(Id)&&countStatus.get(Id)==1) { // if (flag==0) { // for (ProductMonthlySales__c pdmsList : ProductMonthlySalescList) { // if(pdmsList.ProductM__c==Id) { // pdmsList.GenerationMonths__c=countMonthss.get(Id); // } // } // } // } } // by_tcm 返回产品月销量数据 List productmonth return productmonth; } global void finish(Database.BatchableContext BC){ BatchIF_Log__c batchIfLog = new BatchIF_Log__c(); batchIfLog.Type__c = 'ProductMonthlySalesCountBatch'; if (logstr.length() > 60000) { logstr = logstr.substring(0, 60000); } batchIfLog.Log__c = logstr; logstr += '\nBatchProductMonthlySalesCountEnd'; if (errorstr.length() > 60000) { batchIfLog.ErrorLog__c = errorstr.substring(0, 60000); } else { batchIfLog.ErrorLog__c = errorstr.substring(0, errorstr.length()); } insert batchIfLog; emailMessages.add('失败日志ID为:' + batchIfLog.Id); sendFieldEmail(); } // 发送提醒邮件 private void sendFieldEmail() { system.debug('进入sendFieldEmail'); PretechBatchEmailUtil be = new PretechBatchEmailUtil(); String[] toList = new String[] {UserInfo.getUserEmail()}; // String[] toList = new String[] {'tangchengming@prec-tech.com' /*,'wangqingli@prec-tech.com'*/}; String title = '创建月销量数据失败!(本邮件为测试数据,请忽略!)'; String[] ccList = new String[] {}; if (System.Test.isRunningTest()) { be.successMail('', 1); } if (emailMessages.size() > 0 && failedCount > 0) { be.failedMail(toList, ccList, title,String.join(this.emailMessages, '\n'),totalCount, totalCount - failedCount, failedCount,'',false); if(!Test.isRunningTest()) be.send(); } } } //统计产品月销量 精琢技术 tcm 2021-10-11 end // List idList=new List(); // idList.add('01t10000000TfqM'); // idList.add('01t10000000ThEjAAK'); // idList.add('01t10000002HHuRAAW'); // idList.add('01t10000000ThTGAA0'); // idList.add('01t10000000ThW7AAK'); // Database.executeBatch(new ProductMonthlySalesCountBatch('')); //12 // Database.executeBatch(new ProductMonthlySalesCountBatch(pro1.id)); //12 // Database.executeBatch(new ProductMonthlySalesCountBatch(true)); //12 // Database.executeBatch(new ProductMonthlySalesCountBatch(a,true)); //1 // Database.executeBatch(new ProductMonthlySalesCountBatch(pro1.id,true)); //1 // Database.executeBatch(new ProductMonthlySalesCountBatch()); //1