global without sharing class ProductMonthlySalesCountBatch implements Database.Batchable<sObject>,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<String> idList = new List<String>();
	    //添加指定的产品的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<String> idList = new List<String>();
	    //添加指定的产品的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<String> emailMessages = new List<String>();

	//错误邮件 end

	//状态 存放应执行的方法
	Integer status=0;
	//存放方法传进来的产品ID
	List<String> proList = new List<String>();

	//生成所有产品本月的月销量	status=0
	global ProductMonthlySalesCountBatch(){
	}
	//生成所有产品12个月的月销量	status=3
	global ProductMonthlySalesCountBatch(Boolean all){
		this.status=3;
	}

	//指定List<产品>生成12个月以内的月销量(上月月底 往前推12个月)	status=1
	global ProductMonthlySalesCountBatch(List<String> 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<String> 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<Product2> rowDataList) {
		//产品去重-----------------start
		// 新旧产品ID存入Map<> allproMap start
		Map<String,Product2> oldproMap=new Map<String,Product2>();
		Map<String,Product2> newproMap=new Map<String,Product2>();
		Map<String,Product2> allproMap=new Map<String,Product2>();

		// 筛选旧产品
		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<Product2> rowListold = new List<Product2>();
		List<Product2> rowListnew = new List<Product2>();
		List<String> strprodids = new List<String>();
		// 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<ID> strprodids 查询保有设备 &&发货日期 != null
		List<Asset> 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<String,Integer> cntMonthMap=new Map<String,Integer>();
		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<ProductMonthlySales__c> 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<ProductMonthlySales__c> productmonthold = new List<ProductMonthlySales__c>();
		List<ProductMonthlySales__c> productmonthnew = new List<ProductMonthlySales__c>();
		//如果旧产品不为空，调用方法
		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<String,ProductMonthlySales__c> ProductMonthlySalescMap = new Map<String,ProductMonthlySales__c>();
		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<ProductMonthlySales__c> newProductMonthlySalescList=new List<ProductMonthlySales__c>();
		// //去重后转List start
		// for (ProductMonthlySales__c prdm : ProductMonthlySalescMap.values()) {
		// 	newProductMonthlySalescList.add(prdm);
		// 	newProductMonthlySalescList.add(prdm);
		// }
		// //去重后转List start
		Map<String,String> keyProId=new Map<String,String>();
		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<String,Asset> pro2Map =new Map<String,Asset>();
		for (Asset aset : AssetList) {
			pro2Map.put(aset.Product2Id,aset);
		}
		// 批量修改数据
		List<Product2> updatePmsfcss =new List<Product2>();
		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<ProductMonthlySales__c> createMonthlySales(List<Product2> rowList,List<Asset> AssetList,Integer flag,Map<String,Integer> countMonthsMap,Integer status,List<ProductMonthlySales__c> ProductMonthlySalescList) {

		List<ProductMonthlySales__c> productmonth = new List<ProductMonthlySales__c>();
		// 循环产品
		for(Product2 product : rowList) {
			//生成当月时，应生成月数量是否有变化，如有，更新产品12个月的应生成月数量数据 Map<Id,状态>
			Map<String,Integer> countStatus = new Map<String,Integer>();
			//同上，储存应生成月数量 Map<Id,数量>
			Map<String,Integer> countMonthss=new Map<String,Integer>();
			//应生成月
			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<year_month,数量>
			Map<String,Integer> AssetcountMap = new Map<String,Integer>();
			//存无数据的（0） Map<year_month,数量>
			Map<String,Integer> AstcountMap = new Map<String,Integer>();
			//临时存日期用
			Date starDate;

			if(countMonthsMap.containsKey(Id)) {
				//应生成月
				Integer cntMonths =-countMonthsMap.get(Id);
				// by_tcm 预计结束日期/现在日期
				Date dates=Date.today();
				//如果预计结束日<今天 减掉相差的月数 => 数据0的生成量
				if (product.M_BC_Stop_manufacure__c<dates) {
					dates=product.M_BC_Stop_manufacure__c;
					cntMonths-=date.today().monthsBetween(dates);
				}
				// by_tcm 预计开始日期
				Date datefirst=dates.addMonths(cntMonths);
				// by_tcm 开始年
				Integer yearfirst=datefirst.year();
				// by_tcm 开始月
				Integer monthfirst=datefirst.month();
				// by_tcm 停止年
				Integer yearlast=dates.year();
				// by_tcm 停止月
				Integer monthlast=dates.month();
				// by_tcm 拼接结束日期
				Date lastdate = Date.newInstance(yearlast,monthlast,0);
				// by_tcm 拼接开始日期
				Date firstdate = Date.newInstance(yearfirst,monthfirst,1);
				//如果生成一个月数据，生成当月数据（非上月）
				if (status==0||status==2) {
					// 开始日/结束日
					lastdate=lastdate.addMonths(1);
					firstdate=firstdate.addMonths(1);
				}
				// by_tcm 添加初始销量数据为0 start
				for (Integer i = 0; i < -cntMonths; i++) {
					starDate=firstdate.addMonths(i);
					if(starDate<lastdate) {
						Integer month=starDate.month();
						Integer year=starDate.year();
						String year_month=year+'_'+month;
						AstcountMap.put(year_month, 0);
					}
				}
				// by_tcm 添加初始销量数据为0 end

				// by_tcm 添加有销量的数据 start
				for(Asset ass : AssetList) {
					// by_tcm AssetList = 所有保有设备ID
					if (Id==ass.Product2Id) {
						// by_tcm 在日期区间内 拼接发货日期 year_month start
						system.debug('firstdate等于'+firstdate);
						system.debug('lastdate等于'+lastdate);
						if(firstdate<ass.Posting_Date__c&&ass.Posting_Date__c<lastdate) {
							Integer month=ass.Posting_Date__c.month();
							Integer year=ass.Posting_Date__c.year();
							String year_month=year+'_'+month;

							Integer i = 1;
							// 如果日期存在，数量+1
							if(AssetcountMap.containsKey(year_month)) {
								i = AssetcountMap.get(year_month);
								i++;
								AssetcountMap.put(year_month,i);
							}else{
								AssetcountMap.put(year_month,i);
							}
						}
						// by_tcm 在日期区间内 拼接发货日期 year_month end

						//取最早发货日和应生成月 start
						if (ass.Posting_Date__c<lastdate) {
							//最早发货日
							if(postDate>ass.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<String> 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<ProductMonthlySales__c> 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<String> idList=new List<String>();
// 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