#include <epm/epm_task_template_itk.h>
#include <tc/tc.h>
#include <ics/ics.h>
#include "epm_handler_common.h"
#include "ado.h"
#include <tccore/custom.h>
#include <tccore/aom.h>
#include <tccore/aom_prop.h>
#include <tccore/item.h>
#include <bom/bom.h>
#include "ps/ps.h";
#include "ps/vrule.h"
#include "sstream"
#include <tccore/grm.h>
#include "epm/epm.h"
#include "sa/sa.h"
#include "libxl.h"
#include <map>
#include "epm/signoff.h"
#include <ctime>
#include <vector>
#include <locale>
#include <codecvt>
#include "ae/dataset.h"
#include <iostream>
#include <stdlib.h>
#include <tccore/aom.h>
#include <tc/emh.h>
#include <ict/ict_userservice.h>
#include <tc/tc.h>
#include <tccore/tctype.h>
#include <sa/tcfile.h>
#include <ss/ss_errors.h>
#include <ae/datasettype.h>
// #include "hx_custom.h"
#include <regex>
#include "tc_log.h"
// #include "jk_custom.h"
#include "chint_Handler.h"
#include "tc_util.h"
#include "ocilib.h"
struct NodeBean
{
	int topNum = 1;
	int packNum = 0; //打包信息
	string revUid; //物料信息
	tag_t designRev; //图纸信息
	tag_t mantr = NULLTAG;
	string bl_quantity; //数量
	char* bl_plmxml_occ_xform; //BOM属性
	string bl_sequence_no; // 查找编号
	vector<NodeBean> childs;//子件
	vector<tag_t> ccps;//产成品
	int xnNum = 1;//虚拟件数量累乘
	boolean isOutBuy = false;//记录是否外购、或者权限不是自己的
};
bool isTcm(tag_t mantr) {
	int releaseCount = 0;
	tag_t* releaseTags = NULL;
	//判断子件是否发布
	AOM_ask_value_tags(mantr, "release_status_list", &releaseCount, &releaseTags);
	if (releaseCount > 0) {
		return true;
	}
	else {
		return false;
	}
}
//判断物料的BOM视图有没有发布
bool isBomViewTcm(tag_t mantr) {
	int structs = 0;
	tag_t *structure_revisions;
	//版本有BOM视图且发布
	AOM_ask_value_tags(mantr, "structure_revisions", &structs, &structure_revisions);
	if (structs > 0) {
		return isTcm(structure_revisions[0]);
	}
	else {
		return false;
	}
}
bool myCompare(string o1, string o2) {
	if (o1.rfind("3", 0) == 0) {
		cout << o1.c_str() << endl;
		return 1;
	}
	return 0;
}
vector<string> KeySet(map<string, tag_t> test)
{
	vector<string> keys;
	for (map<string, tag_t>::iterator it = test.begin(); it != test.end(); ++it) {
		keys.push_back(it->first);
	}
	return keys;
}
string& replace_all2(string& str, const  string& old_value, const  string& new_value)
{
	if (strstr(str.c_str(), old_value.c_str()) != NULL) {
		vector<string> type_vec;
		Split(str.c_str(), old_value.c_str(), type_vec);
		char new_str[512] = "\0";
		for (int i = 0; i < type_vec.size(); i++)
		{
			strcat(new_str, type_vec[i].c_str());
			if (i < type_vec.size() - 1) {
				strcat(new_str, new_value.c_str());
			}
		}
		string new_value(new_str);
		str = new_value.c_str();
	}
	return   str;
}
tag_t getSapPart(tag_t designRevLine, tag_t designRev, string& errBuff, NodeBean& bean) {
	int num = 0;
	tag_t* mantrs;
	char *type, *item_id;
	ITKCALL(AOM_ask_value_string(designRev, "object_type", &type));
	ITKCALL(AOM_ask_value_string(designRev, "item_id", &item_id));
	printf("designRev===>%s\n", item_id);
	if (strcmp(type, "Part Revision") == 0) {
		return designRev;
	}
	ITKCALL(AOM_ask_value_tags(designRev, "representation_for", &num, &mantrs));

	//新增逻辑 获取图纸下最新版本的E物料对象 会存在多个版本的

	vector<tag_t> parts;
	if (strstr(item_id, "1ZDB300000P") != NULL) {
		map<string, tag_t> partsCcp;
		for (int i = 0; i < num; i++) {
			char* type, *zt2_ifpbom, *itemId;
			ITKCALL(AOM_ask_value_string(mantrs[i], "object_type", &type));
			ITKCALL(AOM_ask_value_string(mantrs[i], "zt2_ifpbom", &zt2_ifpbom));
			ITKCALL(AOM_ask_value_string(mantrs[i], "item_id", &itemId));
			if (strstr(type, "Part") != NULL && strcmp(zt2_ifpbom, "P") != 0) { //
				tag_t matnrItem;
				ITEM_ask_item_of_rev(mantrs[i], &matnrItem);
				partsCcp[itemId] = matnrItem;
			}
		}
		map<string, tag_t>::iterator it;
		for (it = partsCcp.begin(); it != partsCcp.end(); it++) {
			string s = it->first;
			tag_t partLast = partsCcp[s], partRevLast;
			ITEM_ask_latest_rev(partLast, &partRevLast);
			if (parts.size() == 0) {
				parts.push_back(partRevLast);
			}
			else {
				printf("===========\n");
				bean.ccps.push_back(partRevLast);
			}
		}
	}
	else {
		map<string, tag_t> partsCcp;
		for (int i = 0; i < num; i++) {
			char* type, *zt2_ifpbom, *itemId;
			AOM_ask_value_string(mantrs[i], "object_type", &type);
			AOM_ask_value_string(mantrs[i], "zt2_ifpbom", &zt2_ifpbom);
			AOM_ask_value_string(mantrs[i], "item_id", &itemId);
			if (strstr(type, "Part") != NULL && strcmp(zt2_ifpbom, "P") != 0) { //
				tag_t matnrItem;
				ITEM_ask_item_of_rev(mantrs[i], &matnrItem);
				partsCcp[itemId] = matnrItem;
			}
		}
		map<string, tag_t>::iterator it;
		for (it = partsCcp.begin(); it != partsCcp.end(); it++) {
			string s = it->first;
			tag_t partLast = partsCcp[s], partRevLast;
			ITEM_ask_latest_rev(partLast, &partRevLast);
			if (parts.size() == 0) {
				parts.push_back(partRevLast);
			}
		}
		//for (int i = 0; i < num; i++) {
		//	char* type, *zt2_ifpbom;
		//	AOM_ask_value_string(mantrs[i], "object_type", &type);
		//	AOM_ask_value_string(mantrs[i], "zt2_ifpbom", &zt2_ifpbom);
		//	if (strstr(type, "Part") != NULL && strcmp(zt2_ifpbom, "P") != 0) { //
		//		tag_t matnrItem, partRevLast;
		//		ITEM_ask_item_of_rev(mantrs[i], &matnrItem);
		//		ITEM_ask_latest_rev(matnrItem, &partRevLast);
		//		parts.push_back(partRevLast);
		//	}
		//}
	}
	if (parts.size() == 1) {
		return parts[0];
	}
	string searchId;
	char* id, *zt2_TYJNo, *spec, *zt2_Diagram;
	ITKCALL(AOM_ask_value_string(designRev, "zt2_Diagram", &zt2_Diagram));
	ITKCALL(AOM_ask_value_string(designRev, "item_id", &id));
	//AOM_ask_value_string(designRev, "zt2_DrawingNo", &zt2_DrawingNo);
	/*if (strcmp(zt2_DrawingNo,"") != 0 && strcmp(zt2_DrawingNo, id) != 0) {
		searchId = zt2_DrawingNo;
	}
	else {*/
	searchId = id;
	//}
	ITKCALL(AOM_ask_value_string(designRevLine, "ZT2_TYSpecifications", &zt2_TYJNo));
	ITKCALL(AOM_ask_value_string(designRev, "zt2_Specifications", &spec));
	printf("zt2_TYJNo===>%s\n", zt2_TYJNo);
	if (strcmp(zt2_TYJNo, "") != 0) {
		string qryVal;
		tag_t query = NULLTAG, *tags;
		map<string, tag_t> map_revs;
		qryVal.append("* ").append(zt2_TYJNo).append("*");
		//fields.put("描述", "*" + item_id + "*" + zt2_TYJNo + "*");
		ITKCALL(QRY_find2("chint_query_material_test", &query));
		char* qry_entries[2] = { "描述" ,"关联的图号" }, *qry_values[2] = { (char *)qryVal.c_str(),id };
		int n_found;
		ITKCALL(QRY_execute(query, 2, qry_entries, qry_values, &n_found, &tags));
		printf("n_found===>%d\n", n_found);
		for (int t = 0; t < n_found; t++) {
			tag_t rev = tags[t];
			if (isTcm(rev)) {
				char* zt2_MaterialNo;
				AOM_ask_value_string(rev, "zt2_MaterialNo", &zt2_MaterialNo);
				map_revs[zt2_MaterialNo] = rev;
			}
		}
		vector<string> keySet = KeySet(map_revs);
		sort(keySet.begin(), keySet.end(), myCompare);
		for (int i = 0; i < keySet.size(); i++) {
			string materialNo = keySet[i];
			string sql_query = "select FeatureList from CcemVW_GoodsFeature where GoodsCode ='";
			sql_query.append(materialNo).append("'");
			printf("sql_query===>%s\n", sql_query.c_str());
			int outputColumn = 0, outputValueCount = 0;
			char*** outputValue = NULL;
			ado_QuerySQLNoInputParam((char*)sql_query.c_str(), &outputColumn, &outputValueCount, &outputValue);
			for (int j = 0; j < outputValueCount; j++) {
				char* val = outputValue[j][0];
				vector<string> vals;
				Split(val, ",", vals);
				for (int k = 0; k < vals.size(); k++) {
					printf("vals===>%s\n", vals[k].c_str());
					if (vals[k].rfind("F064:", 0) == 0) {
						string temp = replace_all2(vals[k], "F064:", "");
						printf("temp===>%s\n", temp.c_str());
						if (strstr(zt2_TYJNo, temp.c_str()) != NULL) {
							return map_revs[materialNo];
						}
						break;
					}
				}
			}
		}
		if (!strcmp(zt2_Diagram, "Y") == 0 && !strcmp(zt2_Diagram, "是") == 0) {
			string buffErr = "";
			buffErr.append("缺少物料编码[找不到与通用件规格相匹配的物料-(*").append(searchId)
				.append("*").append(zt2_TYJNo).append(")];\n");
			size_t found = errBuff.find(buffErr);
			if (found == std::string::npos) {
				errBuff.append(buffErr);
			}
			return NULLTAG;
		}
	}

	for (int i = 0; i < parts.size(); i++) {
		tag_t part = parts[i];
		char* specPart;
		AOM_ask_value_string(part, "zt2_Specifications", &specPart);
		if (strcmp(specPart, spec) == 0) {
			return part;
		}
		/*String spec2 = parts.get(i).getProperty("zt2_Specifications");
		if (spec.equals(spec2)) {
			return parts.get(i);
		}*/
	}
	if (!strcmp(zt2_Diagram, "Y") == 0 && !strcmp(zt2_Diagram, "是") == 0) {
		//errBuff.append("缺少物料编码[找不到相同规格的物料(").append(spec).append(")];");
		string buffErr = "";
		buffErr.append("缺少物料编码[找不到相同规格的物料(").append(spec).append(")];");
		size_t found = errBuff.find(buffErr);
		if (found == std::string::npos) {
			errBuff.append(buffErr);
		}
		return NULLTAG;
	}

	return NULLTAG;
	/*else{
		return NULLTAG;
	}*/
}

/**
 * 遍历DBOM
 * @param bom_line DBOM的父级
 * @param bean 记录BOM结构
 * @param errBuff 记录错误信息
 * @param designRev 图纸版本
 * @param flagMat 是否外购
 */
void askLineVal(NodeBean& bean, tag_t bom_line, tag_t designRev, string& errBuff, boolean &flagMat) {
	char* bl_quantity, *bl_plmxml_occ_xform, *bl_sequence_no, *sffc;
	ITKCALL(AOM_ask_value_string(bom_line, "bl_sequence_no", &bl_sequence_no));
	//printf("revUid===>%s\n", bl_sequence_no);
	ITKCALL(AOM_ask_value_string(bom_line, "bl_quantity", &bl_quantity));
	//printf("revUid===>%s\n", bl_quantity);
	ITKCALL(AOM_ask_value_string(bom_line, "bl_plmxml_occ_xform", &bl_plmxml_occ_xform));
	//printf("revUid===>%s\n", bl_plmxml_occ_xform);
	if (strcmp(bl_quantity, "") == 0) {
		bl_quantity = "1";
	}

	bean.bl_plmxml_occ_xform = bl_plmxml_occ_xform;
	if (bean.xnNum > 1) {
		int qtyCut = atoi(bl_quantity);
		bean.bl_quantity = to_string(qtyCut*bean.xnNum);
	}
	else {
		bean.bl_quantity = bl_quantity;
	}
	if (strcmp(bean.bl_sequence_no.c_str(), "") == 0) {
		bean.bl_sequence_no = bl_sequence_no;
	}
	//根据图纸获取物料 包含通用件的逻辑
	tag_t part = getSapPart(bom_line, designRev, errBuff, bean);
	//printf("11111111\n");
	if (part != NULLTAG) {
		//BOM_writer
		char* name, *partId, **sealeds, **factorys, *matnr, **procureType;
		AOM_refresh(part, false);
		AOM_ask_value_string(part, "object_name", &name);
		int cnt2, numFac, cnt3;
		//检查物料是否可用
		ITKCALL(AOM_ask_value_string(part, "item_id", &partId));
		printf("part===>%s %s\n", partId, name);
		AOM_ask_value_string(part, "zt2_MaterialNo", &matnr);
		if (strcmp(matnr, "") == 0) {
			string buffErr = "";
			buffErr.append("物料:").append(partId).append("/").append(name).append("没有物料编码.\n");
			size_t found = errBuff.find(buffErr);
			if (found == std::string::npos) {
				errBuff.append(buffErr);
			}
			//errBuff.append("物料:").append(partId).append("/").append(name).append("没有物料编码.\n");
			//return;
		}
		boolean numFlag = true;
		AOM_ask_value_strings(part, "zt2_SZSealedornot", &cnt2, &sealeds);
		AOM_ask_value_strings(part, "zt2_SZFactory", &numFac, &factorys);
		AOM_ask_value_strings(part, "zt2_SZProcuretype", &cnt3, &procureType); //包含自制
		for (int i = 0; i < numFac; i++) {
			if (strcmp(factorys[i], "M060") == 0) {
				numFlag = false;
			}
			if (strcmp(factorys[i], "M060") == 0 && cnt2 > i) {
				if (strcmp(sealeds[i], "Y") == 0) {
					//errBuff.append("物料:").append(partId).append("/").append(name).append("已封存无法转换EBOM.\n");
					string buffErr = "";
					buffErr.append("物料:").append(partId).append("/").append(name).append("已封存无法转换EBOM.\n");
					size_t found = errBuff.find(buffErr);
					if (found == std::string::npos) {
						errBuff.append(buffErr);
					}
				}
				if (cnt3 > i && strstr(procureType[i], "自制") != NULL) {
					flagMat = true;
				}
			}
		}
		char*objName;
		AOM_ask_value_string(part, OBJECT_NAME, &objName);
		if (numFlag && strstr(objName, CCP_NAME) == NULL) {// || (strstr(partId,"2ZD")!=NULL|| strstr(partId, "4ZD") != NULL)
			string buffErr = "";
			buffErr.append("物料:").append(partId).append("/").append(name).append("物料视图没有维护,请检查.\n");
			size_t found = errBuff.find(buffErr);
			if (found == std::string::npos) {
				errBuff.append(buffErr);
			}
			//errBuff.append("物料:").append(partId).append("/").append(name).append("物料视图没有维护,请检查.\n");
		}
		ITKCALL(AOM_ask_value_string(part, "zt2_State", &sffc));
		if (strcmp(sffc, "D1") == 0 || strcmp(sffc, "封存") == 0) {
			string buffErr = "";
			buffErr.append("物料:").append(partId).append("/").append(name).append("已封存无法转换EBOM.\n");
			size_t found = errBuff.find(buffErr);
			if (found == std::string::npos) {
				errBuff.append(buffErr);
			}
		}
		bean.mantr = part;
	}
	else {
		char *partId, *name;
		AOM_ask_value_string(designRev, "item_id", &partId);
		AOM_ask_value_string(designRev, "object_name", &name);

		string buffErr = "";
		buffErr.append("图纸:").append(partId).append("/").append(name).append("下未找到物料对象.\n");
		size_t found = errBuff.find(buffErr);
		if (found == std::string::npos) {
			errBuff.append(buffErr);
		}
		//	errBuff.append("图纸:").append(partId).append("/").append(name).append("下未找到物料对象.\n");
	}
}
/**
 * 获取通用件重量
 * @param bom_line DBOM
 * @param materialutilization 材料利用率
 * @param errMessage 记录错误信息
 * @param desginRev 图纸版本
 */
string getTyjZl(tag_t bom_line, string materialutilization, tag_t desginRev, string &errMessage) {
	char *ZT2_TYSpecifications, *ZT2_TYWeight, *item_id;
	AOM_ask_value_string(bom_line, "item_id", &item_id);
	AOM_ask_value_string(bom_line, "ZT2_TYSpecifications", &ZT2_TYSpecifications);
	double lyl = 0.85;
	char strff[21];
	if (!materialutilization.empty()) {
		lyl = stod(materialutilization);
	}
	if (strcmp(ZT2_TYSpecifications, "") == 0) {
		double weight = 0;
		AOM_ask_value_double(desginRev, "zt2_DesignWeight", &weight);
		if (weight == 0) {
			errMessage.append(item_id).append("未填写设计重量;\n");
			return "0";
		}
		double two = weight / lyl;
		sprintf(strff, "%.3f", two);
	}
	else {
		AOM_ask_value_string(bom_line, "ZT2_TYWeight", &ZT2_TYWeight);
		if (strcmp(ZT2_TYWeight, "") == 0) {
			errMessage.append(item_id).append("未填写通用件重量;\n");
			return "0";
		}
		double weight = stod(ZT2_TYWeight);
		double two = weight / lyl;
		sprintf(strff, "%.3f", two);
	}
	return strff;
}

void getRemarkMsg(string remark, int len, string &errBuff, char*bl_quantity, char* pId,
	char*c_pId, char*bl_line_name) {
	char* idss[5] = { (char*)"A",(char*)"B",(char*)"C",(char*)"D",(char*)"E" };
	//tring x = "9A9.1B2C3";
	string markMsg = "";
	for (int i = 0; i < len; i++) {
		if (strstr(remark.c_str(), idss[i]) != NULL) {
			markMsg.append(idss[i]);
		}
	}
	if (markMsg.length() == 0) {
		int blQty = atoi(bl_quantity);
		if (blQty % len != 0
			&& strstr(bl_line_name, "线") == NULL) {
			errBuff.append("图纸:").append(pId).append("下子件").append(c_pId)
				.append("无法整除，请检查。").append("\n");
		}
	}
	else {
		int blQty = atoi(bl_quantity);
		if (blQty % markMsg.length() != 0
			&& strstr(bl_line_name, "线") == NULL) {
			errBuff.append("图纸:").append(pId).append("下子件").append(c_pId)
				.append("无法整除，请检查。").append("\n");
		}
	}
}

int xsLen = 0;
void getAllXnj(vector<tag_t> xnzjbVec, int maxNum, int &xxt,
	string& errBuff, string dbName, NodeBean& pBean, int qtyXn, char *loginUserId);
void getAllXnj(vector<tag_t> xnzjbVec, int maxNum, int &xxt,
	string& errBuff, string dbName, NodeBean& pBean, int qtyXn, vector<string> idVector);
/**
 * 遍历DBOM
 * @param bom_line DBOM的父级
 * @param pBean 记录BOM结构
 * @param errBuff 记录错误信息
 * @param dbName 原材料展开数据库信息
 * @param loginUserId 用户信息
 */
void recyReadBom(tag_t bom_line, NodeBean& pBean, string& errBuff, string dbName, char *loginUserId)
{
	int c_line_count;
	char* uid, *type, *zt2_Diagram, *source, *itemId, *object_name;
	//图纸版本、子行
	tag_t designRev, *c_line_tags;
	ITKCALL(AOM_ask_value_tag(bom_line, "bl_line_object", &designRev));
	//printf("1222");
	ITK__convert_tag_to_uid(designRev, &uid);
	//printf("revUid===>%s\n", uid);
	pBean.revUid = uid;
	pBean.designRev = designRev;
	ITKCALL(AOM_ask_value_string(designRev, "object_type", &type));
	ITKCALL(AOM_ask_value_string(designRev, "item_id", &itemId));
	ITKCALL(AOM_ask_value_string(designRev, "object_name", &object_name));
	printf("recyReadBom===>%s\n", itemId);
	//printf("type===>%s\n", type);
	if (strcmp(type, "ZT2_Design3DRevision") == 0) {
		AOM_ask_value_string(designRev, "zt2_Diagram", &zt2_Diagram);
		if (strcmp(zt2_Diagram, "Y") == 0 || strcmp(zt2_Diagram, "是") == 0) {
			return;
		}
	}
	//判断类型是否为 Part Revision ZT2_Design3DRevision  ZT2_XNZJB 不是报错
	if (strcmp(type, "ZT2_Design3DRevision") != 0
		&& strcmp(type, "Part Revision") != 0 && strcmp(type, "ZT2_XNZJBRevision") != 0) {
		string buffErr = "";
		buffErr.append("对象类型异常:").append(itemId).append("/").append(object_name).append("/").append(type).append("\n");
		size_t found = errBuff.find(buffErr);
		if (found == std::string::npos) {
			errBuff.append(buffErr);
		}
		return;
	}

	boolean flagMat = false;
	//根据图纸获取物料信息
	askLineVal(pBean, bom_line, designRev, errBuff, flagMat);
	tag_t tagUser;
	char *tagId;
	AOM_ask_value_tag(designRev, "owning_user", &tagUser);
	AOM_ask_value_string(tagUser, "user_id", &tagId);
	//检查权限
	if (strcmp(type, "ZT2_Design3DRevision") == 0 && strcmp(loginUserId, tagId) != 0 && strstr(itemId, "2ZD") == NULL) {
		pBean.isOutBuy = true;
		return;
	}
	if (strcmp(type, "ZT2_XNZJBRevision") == 0) {
		return;
	}
	//外购 不展开子件
	if (strstr(itemId, "2ZD") != NULL || strstr(itemId, "4ZD") != NULL) {
		if (!flagMat) {
			pBean.isOutBuy = true;
			return;
		}
	}
	if (strstr(itemId, "1ZD") != NULL) {
		AOM_ask_value_string(designRev, "zt2_Source", &source);
		if (strcmp(source, "S2") == 0 || strcmp(source, "外购") == 0) {
			pBean.isOutBuy = true;
			return;
		}
	}

	ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags));
	for (int i = 0; i < c_line_count; i++) {
		logical flag;
		BOM_line_is_packed(c_line_tags[i], &flag);
		if (flag) {
			BOM_line_unpack(c_line_tags[i]);
		}
	}
	AOM_refresh(bom_line, FALSE);
	ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags));
	//转换时原材料展开逻辑
	if (c_line_count == 0 && !dbName.empty() && (strstr(itemId, "1ZD") != NULL ||
		strstr(itemId, "2ZD") != NULL || strstr(itemId, "4ZD") != NULL)) {
		//原材料展开
		char *zt2_MaterialMark;
		AOM_ask_value_string(designRev, "zt2_MaterialMark", &zt2_MaterialMark);
		//String zt2_MaterialMark = rev.getProperty("zt2_MaterialMark")
		string sql = "select materialno, materialutilization, materialunit FROM %s where materialmark = '%s'";
		char selectRxfs[500];
		sprintf(selectRxfs, sql.c_str(), dbName.c_str(), zt2_MaterialMark);
		int outputColumn1 = 0, outputValueCount1 = 0;
		char*** outputValue1 = NULL;
		printf("search3 ===> %s\n", selectRxfs);
		QuerySQLNoInputParam(selectRxfs, &outputColumn1, &outputValueCount1, &outputValue1);
		if (outputValueCount1 == 0 && strcmp(zt2_MaterialMark, "") != 0) {
			string buffErr = "";
			buffErr.append("图纸:").append(itemId).append("-").
				append(object_name).append(zt2_MaterialMark).append("材料标记没有维护.\n");
			size_t found = errBuff.find(buffErr);
			if (found == std::string::npos) {
				errBuff.append(buffErr);
			}

		}
		for (int t = 0; t < outputValueCount1; t++) {
			string materialno = outputValue1[t][0];
			string materialutilization = outputValue1[t][1];
			string materialunit = outputValue1[t][2];
			tag_t material, materialRev;
			ITEM_find_item(materialno.c_str(), &material);
			ITEM_ask_latest_rev(material, &materialRev);
			string bl_qty = getTyjZl(bom_line, materialutilization, designRev, errBuff);
			printf("bl_qty%s\n", bl_qty.c_str());
			NodeBean cBean;
			cBean.bl_quantity = bl_qty;
			cBean.bl_sequence_no = "10";
			cBean.bl_plmxml_occ_xform = "";
			cBean.mantr = materialRev;
			pBean.childs.push_back(cBean);
		}
	}
	string maxSeqNo;
	vector<tag_t> xnzjbVec;
	string item_id = itemId;
	smatch result;
	//检查是否线圈
	regex qq_reg2("^1ZDB5.*\\d{1,}1000X.*");
	bool ret = regex_match(item_id, result, qq_reg2);
	for (int i = 0; i < c_line_count; i++) {
		logical suppressed;
		AOM_ask_value_logical(c_line_tags[i], "bl_is_occ_suppressed", &suppressed);
		if (suppressed) {
			continue;
		}
		//修改过之后之前已经是解包的状态了 
		logical flag;
		BOM_line_is_packed(c_line_tags[i], &flag);
		//printf("flag===>%d\n", flag);
		if (flag) {
			int count = 0;
			char *topNum;
			AOM_ask_value_string(c_line_tags[i], "bl_quantity", &topNum);
			tag_t* packLines;
			BOM_line_ask_packed_lines(c_line_tags[i], &count, &packLines);
			for (int t = 0; t < count; t++) {
				tag_t c_Rev;
				ITKCALL(AOM_ask_value_tag(packLines[t], "bl_line_object", &c_Rev));
				char* cUid;
				ITK__convert_tag_to_uid(c_Rev, &cUid);
				NodeBean cBean;
				cBean.revUid = cUid;
				cBean.designRev = c_Rev;
				cBean.packNum = count + 1;
				cBean.topNum = atoi(topNum);
				recyReadBom(c_line_tags[i], cBean, errBuff, dbName, loginUserId);
				pBean.childs.push_back(cBean);
			}
			AOM_refresh(c_line_tags[i], FALSE);
			tag_t c_Rev;
			ITKCALL(AOM_ask_value_tag(c_line_tags[i], "bl_line_object", &c_Rev));
			char* cUid;
			ITK__convert_tag_to_uid(c_Rev, &cUid);
			NodeBean cBean;
			cBean.revUid = cUid;
			cBean.designRev = c_Rev;
			cBean.packNum = count + 1;
			cBean.topNum = atoi(topNum);
			recyReadBom(c_line_tags[i], cBean, errBuff, dbName, loginUserId);
			pBean.childs.push_back(cBean);

		}
		else {
			//检查E转P时的拆分逻辑
			tag_t c_Rev;
			char *seqNo, *c_type, *remark, *bl_quantity, *bl_line_name;
			ITKCALL(AOM_ask_value_tag(c_line_tags[i], "bl_line_object", &c_Rev));
			char* id;
			AOM_ask_value_string(c_Rev, "item_id", &id);
			//获取BOM行的REMARK
			if (ret) {
				AOM_ask_value_string(c_line_tags[i], "ZT2_Remark", &remark);
				AOM_ask_value_string(c_line_tags[i], "bl_quantity", &bl_quantity);
				AOM_ask_value_string(c_line_tags[i], "bl_line_name", &bl_line_name);
				getRemarkMsg(remark, xsLen, errBuff, bl_quantity, itemId, id, bl_line_name);
			}
			//新增逻辑 当前对象类型为ZT2_XNZJB 虚拟组件包时 进行削层处理 数量*虚拟层数量
			AOM_ask_value_string(c_Rev, "object_type", &c_type);
			if (strcmp(c_type, "ZT2_XNZJBRevision") == 0) {
				xnzjbVec.push_back(c_line_tags[i]);
				continue;
			}
			AOM_ask_value_string(c_line_tags[i], "bl_sequence_no", &seqNo);
			maxSeqNo = seqNo;
			char* cUid;
			ITK__convert_tag_to_uid(c_Rev, &cUid);
			NodeBean cBean;
			cBean.revUid = cUid;
			cBean.designRev = c_Rev;
			recyReadBom(c_line_tags[i], cBean, errBuff, dbName, loginUserId);
			pBean.childs.push_back(cBean);
		}
	}
	int maxNum = atoi(maxSeqNo.c_str());
	int xxt = 1;
	printf("xnzjbVec ===> %d\n", xnzjbVec.size());
	//提取虚拟装配件的逻辑
	getAllXnj(xnzjbVec, maxNum, xxt, errBuff, dbName, pBean, 1, loginUserId);
}
/**
 * DBOM转EBOM框架BOM使用
 * @param bom_line DBOM顶层
 * @param pBean 记录EBOM结构
 * @param errBuff 记录错误信息
 * @param dbName 原材料展开的数据表
 * @param idVector 需要D转E的BOM类别
 */
void recyReadBom(tag_t bom_line, NodeBean& pBean, string& errBuff, string dbName, vector<string> idVector)
{
	int c_line_count;
	char* uid, *type, *zt2_Diagram, *source, *itemId, *object_name;
	//图纸版本、子行
	tag_t designRev, *c_line_tags;
	ITKCALL(AOM_ask_value_tag(bom_line, "bl_line_object", &designRev));
	//printf("1222");
	ITK__convert_tag_to_uid(designRev, &uid);
	//printf("revUid===>%s\n", uid);
	pBean.revUid = uid;
	pBean.designRev = designRev;
	ITKCALL(AOM_ask_value_string(designRev, "object_type", &type));
	ITKCALL(AOM_ask_value_string(designRev, "item_id", &itemId));
	ITKCALL(AOM_ask_value_string(designRev, "object_name", &object_name));
	//printf("type===>%s\n", type);
	printf("recyReadBom2===>%s\n", itemId);
	if (strcmp(type, "ZT2_Design3DRevision") == 0) {
		AOM_ask_value_string(designRev, "zt2_Diagram", &zt2_Diagram);
		if (strcmp(zt2_Diagram, "Y") == 0 || strcmp(zt2_Diagram, "是") == 0) {
			return;
		}
	}
	//判断类型是否为 Part Revision ZT2_Design3DRevision  ZT2_XNZJB 不是报错
	if (strcmp(type, "ZT2_Design3DRevision") != 0
		&& strcmp(type, "Part Revision") != 0 && strcmp(type, "ZT2_XNZJBRevision") != 0) {
		string buffErr = "";
		buffErr.append("对象类型异常:").append(itemId).append("/").append(object_name).append("/").append(type).append("\n");
		size_t found = errBuff.find(buffErr);
		if (found == std::string::npos) {
			errBuff.append(buffErr);
		}
		return;
	}

	boolean flagMat = false;
	askLineVal(pBean, bom_line, designRev, errBuff, flagMat);
	vector<string> idVec;
	Split(itemId, "-", idVec);
	//未在首选项配置的类型不展开
	if (std::find(idVector.begin(), idVector.end(), idVec[0]) == idVector.end()) {
		return;
	}
	if (strcmp(type, "ZT2_XNZJBRevision") == 0) {
		return;
	}
	//外购 不展开子件
	if (strstr(itemId, "2ZD") != NULL || strstr(itemId, "4ZD") != NULL) {
		if (!flagMat) {
			return;
		}
	}
	if (strstr(itemId, "1ZD") != NULL) {
		AOM_ask_value_string(designRev, "zt2_Source", &source);
		if (strcmp(source, "S2") == 0 || strcmp(source, "外购") == 0) {
			return;
		}
	}

	ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags));
	for (int i = 0; i < c_line_count; i++) {
		logical flag;
		BOM_line_is_packed(c_line_tags[i], &flag);
		if (flag) {
			BOM_line_unpack(c_line_tags[i]);
		}
	}
	AOM_refresh(bom_line, FALSE);
	ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags));
	//转换时原材料展开逻辑
	if (c_line_count == 0 && !dbName.empty() && (strstr(itemId, "1ZD") != NULL ||
		strstr(itemId, "2ZD") != NULL || strstr(itemId, "4ZD") != NULL)) {
		//原材料展开
		char *zt2_MaterialMark;
		AOM_ask_value_string(designRev, "zt2_MaterialMark", &zt2_MaterialMark);
		//String zt2_MaterialMark = rev.getProperty("zt2_MaterialMark")
		string sql = "select materialno, materialutilization, materialunit FROM %s where materialmark = '%s'";
		char selectRxfs[500];
		sprintf(selectRxfs, sql.c_str(), dbName.c_str(), zt2_MaterialMark);
		int outputColumn1 = 0, outputValueCount1 = 0;
		char*** outputValue1 = NULL;
		printf("search3 ===> %s\n", selectRxfs);
		QuerySQLNoInputParam(selectRxfs, &outputColumn1, &outputValueCount1, &outputValue1);
		if (outputValueCount1 == 0 && strcmp(zt2_MaterialMark, "") != 0) {
			string buffErr = "";
			buffErr.append("图纸:").append(itemId).append("-").
				append(object_name).append(zt2_MaterialMark).append("材料标记没有维护.\n");
			size_t found = errBuff.find(buffErr);
			if (found == std::string::npos) {
				errBuff.append(buffErr);
			}

		}
		for (int t = 0; t < outputValueCount1; t++) {
			string materialno = outputValue1[t][0];
			string materialutilization = outputValue1[t][1];
			string materialunit = outputValue1[t][2];
			tag_t material, materialRev;
			ITEM_find_item(materialno.c_str(), &material);
			ITEM_ask_latest_rev(material, &materialRev);
			string bl_qty = getTyjZl(bom_line, materialutilization, designRev, errBuff);
			printf("bl_qty%s\n", bl_qty.c_str());
			NodeBean cBean;
			cBean.bl_quantity = bl_qty;
			cBean.bl_sequence_no = "10";
			cBean.bl_plmxml_occ_xform = "";
			cBean.mantr = materialRev;
			pBean.childs.push_back(cBean);
		}
	}
	string maxSeqNo;
	vector<tag_t> xnzjbVec;
	for (int i = 0; i < c_line_count; i++) {
		logical suppressed;
		AOM_ask_value_logical(c_line_tags[i], "bl_is_occ_suppressed", &suppressed);
		if (suppressed) {
			continue;
		}
		//修改过之后之前已经是解包的状态了 
		logical flag;
		BOM_line_is_packed(c_line_tags[i], &flag);
		//printf("flag===>%d\n", flag);
		if (flag) {
			int count = 0;
			char *topNum;
			AOM_ask_value_string(c_line_tags[i], "bl_quantity", &topNum);
			tag_t* packLines;
			BOM_line_ask_packed_lines(c_line_tags[i], &count, &packLines);
			for (int t = 0; t < count; t++) {
				tag_t c_Rev;
				ITKCALL(AOM_ask_value_tag(packLines[t], "bl_line_object", &c_Rev));
				char* cUid;
				ITK__convert_tag_to_uid(c_Rev, &cUid);
				NodeBean cBean;
				cBean.revUid = cUid;
				cBean.designRev = c_Rev;
				cBean.packNum = count + 1;
				cBean.topNum = atoi(topNum);
				recyReadBom(c_line_tags[i], cBean, errBuff, dbName, idVector);
				pBean.childs.push_back(cBean);
			}
			AOM_refresh(c_line_tags[i], FALSE);
			tag_t c_Rev;
			ITKCALL(AOM_ask_value_tag(c_line_tags[i], "bl_line_object", &c_Rev));
			char* cUid;
			ITK__convert_tag_to_uid(c_Rev, &cUid);
			NodeBean cBean;
			cBean.revUid = cUid;
			cBean.designRev = c_Rev;
			cBean.packNum = count + 1;
			cBean.topNum = atoi(topNum);
			recyReadBom(c_line_tags[i], cBean, errBuff, dbName, idVector);
			pBean.childs.push_back(cBean);

		}
		else {
			tag_t c_Rev;
			char *seqNo, *c_type;
			ITKCALL(AOM_ask_value_tag(c_line_tags[i], "bl_line_object", &c_Rev));
			//新增逻辑 当前对象类型为ZT2_XNZJB 虚拟组件包时 进行削层处理 数量*虚拟层数量
			AOM_ask_value_string(c_Rev, "object_type", &c_type);
			if (strcmp(c_type, "ZT2_XNZJBRevision") == 0) {
				xnzjbVec.push_back(c_line_tags[i]);
				continue;
			}
			AOM_ask_value_string(c_line_tags[i], "bl_sequence_no", &seqNo);
			maxSeqNo = seqNo;
			char* cUid;
			ITK__convert_tag_to_uid(c_Rev, &cUid);
			NodeBean cBean;
			cBean.revUid = cUid;
			cBean.designRev = c_Rev;
			recyReadBom(c_line_tags[i], cBean, errBuff, dbName, idVector);
			pBean.childs.push_back(cBean);
		}
	}
	int maxNum = atoi(maxSeqNo.c_str());
	int xxt = 1;
	printf("xnzjbVec ===> %d\n", xnzjbVec.size());

	getAllXnj(xnzjbVec, maxNum, xxt, errBuff, dbName, pBean, 1, idVector);
}
/**
 * 提取虚拟装配件
 * @param xnzjbVec 虚拟装配件版本集合
 * @param maxNum 提取之后的查找编号
 * @param xxt 查找编号累加的
 * @param errBuff 错误信息
 * @param dbName 原材料展开数据表
 * @param qtyXn 提取时需要累乘数量
 * @param idVector 需要展开的ID类别
 */
void getAllXnj(vector<tag_t> xnzjbVec, int maxNum, int &xxt,
	string& errBuff, string dbName, NodeBean& pBean, int qtyXn, vector<string> idVector) {


	for (int t = 0; t < xnzjbVec.size(); t++) {
		tag_t c_line_tag = xnzjbVec[t], *cc_line_tags;
		int cc_line_count;
		ITKCALL(BOM_line_ask_all_child_lines(c_line_tag, &cc_line_count, &cc_line_tags));
		char *cnt, *c_type;
		int qtyPXn = 1;
		AOM_ask_value_string(c_line_tag, "bl_quantity", &cnt);
		if (strcmp(cnt, "") != 0) {
			qtyPXn = atoi(cnt);
		}
		//qtyPXn = qtyPXn * qtyXn;
		vector<tag_t> xnzjbVec2;
		for (int j = 0; j < cc_line_count; j++) {
			tag_t c_Rev;
			char *itemId, *object_name;
			ITKCALL(AOM_ask_value_tag(cc_line_tags[j], "bl_line_object", &c_Rev));
			AOM_ask_value_string(c_Rev, "object_type", &c_type);
			AOM_ask_value_string(c_Rev, "item_id", &itemId);
			AOM_ask_value_string(c_Rev, "object_name", &object_name);
			if (strcmp(c_type, "ZT2_XNZJBRevision") == 0) {
				printf("itemId===>%s\n", itemId);
				xnzjbVec2.push_back(cc_line_tags[j]);
				continue;
			}
			//判断类型是否为 Part Revision ZT2_Design3DRevision  ZT2_XNZJB 不是报错
			if (strcmp(c_type, "ZT2_Design3DRevision") != 0
				&& strcmp(c_type, "Part Revision") != 0) {
				string buffErr = "";
				buffErr.append("对象类型异常:").append(itemId).append("/").append(object_name).append("/").append(c_type).append("\n");
				size_t found = errBuff.find(buffErr);
				if (found == std::string::npos) {
					errBuff.append(buffErr);
				}
			}
			NodeBean cBean;
			char* cUid;
			ITK__convert_tag_to_uid(c_Rev, &cUid);
			cBean.revUid = cUid;
			cBean.designRev = c_Rev;
			cBean.xnNum = qtyXn * qtyPXn;
			int srqNum = maxNum + xxt * 10;
			string lastnum = to_string(srqNum);
			xxt = xxt + 1;
			cBean.bl_sequence_no = lastnum;
			recyReadBom(cc_line_tags[j], cBean, errBuff, dbName, idVector);
			pBean.childs.push_back(cBean);
		}
		printf("xnzjbVec2 ===> %d ==>%d \n", xnzjbVec2.size(), qtyPXn);
		if (xnzjbVec2.size() > 0) {
			getAllXnj(xnzjbVec2, maxNum, xxt, errBuff, dbName, pBean, qtyPXn, idVector);
		}
	}
}
/**
 * 提取虚拟装配件
 * @param xnzjbVec 虚拟装配件版本集合
 * @param maxNum 提取之后的查找编号
 * @param xxt 查找编号累加的
 * @param errBuff 错误信息
 * @param dbName 原材料展开数据表
 * @param qtyXn 提取时需要累乘数量
 * @param loginUserId 用户ID
 */
void getAllXnj(vector<tag_t> xnzjbVec, int maxNum, int &xxt,
	string& errBuff, string dbName, NodeBean& pBean, int qtyXn, char *loginUserId) {

	for (int t = 0; t < xnzjbVec.size(); t++) {
		tag_t c_line_tag = xnzjbVec[t], *cc_line_tags;
		int cc_line_count;
		ITKCALL(BOM_line_ask_all_child_lines(c_line_tag, &cc_line_count, &cc_line_tags));
		char *cnt, *c_type;
		int qtyPXn = 1;
		AOM_ask_value_string(c_line_tag, "bl_quantity", &cnt);
		if (strcmp(cnt, "") != 0) {
			//虚拟件的BOM数量
			qtyPXn = atoi(cnt);
		}
		//qtyPXn = qtyPXn * qtyXn;
		vector<tag_t> xnzjbVec2;
		for (int j = 0; j < cc_line_count; j++) {
			tag_t c_Rev;
			char *itemId, *object_name;
			ITKCALL(AOM_ask_value_tag(cc_line_tags[j], "bl_line_object", &c_Rev));
			AOM_ask_value_string(c_Rev, "object_type", &c_type);
			AOM_ask_value_string(c_Rev, "item_id", &itemId);
			AOM_ask_value_string(c_Rev, "object_name", &object_name);
			if (strcmp(c_type, "ZT2_XNZJBRevision") == 0) {
				printf("itemId===>%s\n", itemId);
				xnzjbVec2.push_back(cc_line_tags[j]);
				continue;
			}
			//判断类型是否为 Part Revision ZT2_Design3DRevision  ZT2_XNZJB 不是报错
			if (strcmp(c_type, "ZT2_Design3DRevision") != 0
				&& strcmp(c_type, "Part Revision") != 0) {
				string buffErr = "";
				buffErr.append("对象类型异常:").append(itemId).append("/").append(object_name).append("/").append(c_type).append("\n");
				size_t found = errBuff.find(buffErr);
				if (found == std::string::npos) {
					errBuff.append(buffErr);
				}
			}
			NodeBean cBean;
			char* cUid;
			ITK__convert_tag_to_uid(c_Rev, &cUid);
			cBean.revUid = cUid;
			cBean.designRev = c_Rev;
			cBean.xnNum = qtyXn * qtyPXn;
			int srqNum = maxNum + xxt * 10;
			string lastnum = to_string(srqNum);
			xxt = xxt + 1;
			cBean.bl_sequence_no = lastnum;
			//非虚拟件的继续原逻辑展开
			recyReadBom(cc_line_tags[j], cBean, errBuff, dbName, loginUserId);
			pBean.childs.push_back(cBean);
		}
		printf("xnzjbVec2 ===> %d ==>%d \n", xnzjbVec2.size(), qtyPXn);
		//存在多层级的虚拟装配件,递归提取
		if (xnzjbVec2.size() > 0) {
			getAllXnj(xnzjbVec2, maxNum, xxt, errBuff, dbName, pBean, qtyPXn, loginUserId);
		}
	}
}
string GBKToUTF8(const std::string& strGBK)
{
	string strOutUTF8 = "";
	WCHAR * str1;
	int n = MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, NULL, 0);
	str1 = new WCHAR[n];
	MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, str1, n);
	n = WideCharToMultiByte(CP_UTF8, 0, str1, -1, NULL, 0, NULL, NULL);
	char * str2 = new char[n];
	WideCharToMultiByte(CP_UTF8, 0, str1, -1, str2, n, NULL, NULL);
	strOutUTF8 = str2;
	delete[]str1;
	str1 = NULL;
	delete[]str2;
	str2 = NULL;
	return strOutUTF8;
}
string proProcessCreate(tag_t rev, string process_name)
{
	tag_t template_tag = NULLTAG;
	EPM_find_template2(process_name.c_str(), PROCESS_TEMPLATE, &template_tag);
	tag_t new_process = NULLTAG;
	int *tagType = (int *)MEM_alloc(1024 * sizeof(int));//EPM_reference_attachment
	tag_t * itemTag = (tag_t *)MEM_alloc(1024 * sizeof(tag_t));
	tagType[0] = EPM_target_attachment;
	itemTag[0] = rev;
	EPM_create_process("快速发布", "", template_tag, 1, itemTag, tagType, &new_process);
	return "1";
}

boolean firstRevision(tag_t designRev, tag_t mantr) {
	char *revId;
	int revNum = 0, statusNum = 0;
	tag_t *structure_revisions;
	AOM_ask_value_string(designRev, "item_revision_id", &revId);
	AOM_ask_value_tags(mantr, "structure_revisions", &revNum, &structure_revisions);
	if (revNum > 0) {
		tag_t struct_revision = structure_revisions[0], *release_status_list;
		AOM_ask_value_tags(struct_revision, "release_status_list", &statusNum, &release_status_list);
		if (statusNum == 0) {
			return false;
		}
	}
	if (strcmp(revId, "V01") > 0) {
		return true;
	}
	else {
		return false;
	}
}
/**
 * 获取单层DBOM的信息 跟EBOM比较用的
 * @param topBean 记录的BOM结构
 */
map<string, int> getDBomMesg(NodeBean topBean) {
	vector<NodeBean> childs = topBean.childs;
	map<string, int> dMap;
	for (int i = 0; i < childs.size(); i++) {
		NodeBean cBean = childs[i];
		char *matnrNo, *uid;
		AOM_ask_value_string(cBean.mantr, MATERIALNO, &matnrNo);
		ITK__convert_tag_to_uid(cBean.mantr, &uid);
		printf("uid[%s]\n", uid);
		printf("matnrNo[%s]\n", matnrNo);
		int qtyPXn = 1;
		string cnt = cBean.bl_quantity;
		if (strcmp(cnt.c_str(), "") != 0) {
			qtyPXn = atoi(cnt.c_str());
		}
		if (dMap.count(matnrNo) > 0) {
			dMap[matnrNo] = dMap[matnrNo] + qtyPXn;
		}
		else {
			dMap[matnrNo] = qtyPXn;
		}
	}
	return dMap;
}
/**
 * 获取单层EBOM的信息 跟DBOM比较用的
 * @param mantrRev E物料
 * @param flag 记录有没有bom视图
 */
map<string, int> getBomMsg(tag_t mantrRev, bool& flag) {
	map<string, int> bomMsgMap;
	tag_t* bvr_list = NULL, bom_line, ebom_window;
	int bvr_count = 0;
	ITKCALL(ITEM_rev_list_bom_view_revs(mantrRev, &bvr_count, &bvr_list));
	//没有BOM视图创建
	if (bvr_count == 0) {
		flag = true;
		return bomMsgMap;
	}
	ITKCALL(BOM_create_window(&ebom_window));
	//移除原来的
	ITKCALL(BOM_set_window_top_line(ebom_window, NULL, mantrRev, NULLTAG, &bom_line));
	int c_line_count;
	tag_t* c_line_tags;
	ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags));
	printf("c_line_count===>%d\n", c_line_count);
	for (int t = 0; t < c_line_count; t++) {
		tag_t c_Rev;
		char *matnrNo, *cnt;
		ITKCALL(AOM_ask_value_tag(c_line_tags[t], "bl_line_object", &c_Rev));
		AOM_ask_value_string(c_Rev, "zt2_MaterialNo", &matnrNo);
		printf("zt2_MaterialNo===>%s\n", matnrNo);
		int qtyPXn = 1;
		AOM_ask_value_string(c_line_tags[t], "bl_quantity", &cnt);
		if (strcmp(cnt, "") != 0) {
			qtyPXn = atoi(cnt);
		}
		if (bomMsgMap.count(matnrNo) > 0) {
			bomMsgMap[matnrNo] = bomMsgMap[matnrNo] + qtyPXn;
		}
		else {
			bomMsgMap[matnrNo] = qtyPXn;
		}
	}
	BOM_close_window(ebom_window);
	return bomMsgMap;
}
/**
 * 对比Ebom和Dbom
 * @param dMap D物料编码 - 数量
 * @param eMap E物料编码 - 数量
 */
boolean combEAndDbom(map<string, int> dMap, map<string, int> eMap) {
	map<string, int>::iterator it;
	//名称模糊匹配
	for (it = dMap.begin(); it != dMap.end(); it++) {
		string s = it->first;
		int dnum = dMap[s];
		if (eMap.count(s) == 0) {
			return true;
		}
		else if (dnum != eMap[s]) {
			return true;
		}
	}
	return false;
}
/**
 * 发布并且修改所有权
 */
void TCMAndOwner(tag_t matnrTop) {
	int num = 0, revNum;
	tag_t *mantrsAs, dsuser, *structure_revisions;
	AOM_ask_value_tags(matnrTop, "TC_Is_Represented_By", &num, &mantrsAs);
	AOM_ask_value_tag(mantrsAs[0], "owning_user", &dsuser);
	tag_t defGroup;
	ITKCALL(AOM_ask_value_tag(dsuser, "default_group", &defGroup));
	ITKCALL(AOM_set_ownership(matnrTop, dsuser, defGroup));
	if (num > 0) {
		AOM_ask_value_tags(matnrTop, "structure_revisions", &revNum, &structure_revisions);
		if (revNum > 0) {
			ITKCALL(AOM_set_ownership(structure_revisions[0], dsuser, defGroup));
		}
	}
	/*string process_name = "TCM Release Process";
	proProcessCreate(matnrTop, process_name);*/
}
/**
 * 比较DBOM、EBOM是否相同，不同则升版
 * @param topBean 存放BOM信息
 * @param isTop 是否产成品
 * @param hasChange 是否发布
 * @param saveAsMap 存放升版之前的版本uid - 升版之后的新版本 存在打包的对象防止多次升版
 */
tag_t saveAsMaterial(NodeBean topBean, boolean isTop, string &hasChange, map<string, tag_t>& saveAsMap) {
	tag_t mantr = topBean.mantr;//升版之前的E物料
	char* oldUid;
	ITK__convert_tag_to_uid(mantr, &oldUid);
	if (saveAsMap.count(oldUid) > 0) {
		return saveAsMap[oldUid];
	}
	bool flag = false;
	map<string, int> dBomMesg = getDBomMesg(topBean);
	map<string, int> eBomMesg = getBomMsg(mantr, flag);
	if (flag) {
		return mantr;
	}
	printf("dBomMesg[%d]", dBomMesg.size());
	printf("eBomMesg[%d]", eBomMesg.size());
	boolean needAs = false;
	if (dBomMesg.size() != eBomMesg.size()) {
		//升版 + 发布
		needAs = true;
	}
	else if (combEAndDbom(dBomMesg, eBomMesg)) {
		//升版 + 发布
		needAs = true;
	}
	if (needAs && !topBean.isOutBuy) {
		printf("=======TEST======\n");
		//升版并发布 没发布的产成品直接更新
		if (isTcm(mantr) && isBomViewTcm(mantr)) {
			ITKCALL(ITEM_copy_rev(mantr, NULL, &mantr));
			TCMAndOwner(mantr);
			if (isTop) {
				hasChange = true;
			}
			saveAsMap[oldUid] = mantr;
		}
	}
	return mantr;
}
void createEbom(NodeBean topBean, boolean isTop, string &hasChange, map<string, tag_t>& saveAsMap)
{
	tag_t ebom_window = NULLTAG;
	tag_t bom_line = NULLTAG;
	vector<NodeBean> childs = topBean.childs;
	//printf("子line数量 %d \n", childs.size());
	tag_t desBean = topBean.designRev;
	char* id;
	AOM_ask_value_string(desBean, "item_id", &id);
	printf("id %s \n", id);
	tag_t mantr = topBean.mantr;
	//判断是否最初版本 不是就和当前的EBOM进行比较 
	//相同就跳过不升版、不同就升版、只比较数量
	//ITEM_ask_f
	mantr = saveAsMaterial(topBean, isTop, hasChange, saveAsMap);
	boolean flagChange = true;

	if (mantr != NULLTAG && childs.size() > 0) {
		printf("-----");
		tag_t* bvr_list = NULL;
		int bvr_count;
		ITKCALL(ITEM_rev_list_bom_view_revs(mantr, &bvr_count, &bvr_list));
		//没有BOM视图创建
		if (bvr_count == 0) {
			tag_t newView, newViewBvr, pitem, dsuser;
			ITEM_ask_item_of_rev(mantr, &pitem);
			ITKCALL(PS_create_bom_view(NULL, NULL, NULL, pitem, &newView));
			AOM_save(newView);
			ITKCALL(PS_create_bvr(newView, NULL, NULL, FALSE, mantr, &newViewBvr));
			AOM_save(newViewBvr);
			AOM_save(mantr);
			AOM_ask_value_tag(desBean, "owning_user", &dsuser);
			tag_t defGroup;
			ITKCALL(AOM_ask_value_tag(dsuser, "default_group", &defGroup));
			ITKCALL(AOM_set_ownership(newView, dsuser, defGroup));
			ITKCALL(AOM_set_ownership(newViewBvr, dsuser, defGroup));
		}
		ITKCALL(BOM_create_window(&ebom_window));
		//移除原来的
		char*topUidTest;
		ITK__convert_tag_to_uid(mantr, &topUidTest);
		printf("topUidTest =======> %s \n", topUidTest);
		ITKCALL(BOM_set_window_top_line(ebom_window, NULL, mantr, NULLTAG, &bom_line));
		//变更当前BOM层级 已发布的不需要更改
		if (flagChange) {
			if (bvr_count > 0) {
				int c_line_count;
				tag_t* c_line_tags;
				ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags));
				for (int t = 0; t < c_line_count; t++) {
					char* val;
					AOM_ask_value_string(c_line_tags[t], "bl_occ_zt2_DtoE", &val);
					if (strcmp(val, "DBOM转换") == 0) {
						BOM_line_cut(c_line_tags[t]);
					}
				}
			}
			for (int i = 0; i < childs.size(); i++) {
				NodeBean cBean = childs[i];
				if (cBean.mantr != NULLTAG) {
					tag_t cLine;
					ITKCALL(BOM_line_add(bom_line, NULL, cBean.mantr, NULL, &cLine));
					AOM_lock(cLine);
					if (cBean.packNum > 0) {
						string num = cBean.bl_quantity;
						num = to_string(cBean.topNum / cBean.packNum);
						ITKCALL(AOM_set_value_string(cLine, "bl_quantity", num.c_str()));
					}
					else {
						printf("num %s \n", cBean.bl_quantity.c_str());
						ITKCALL(AOM_set_value_string(cLine, "bl_quantity", cBean.bl_quantity.c_str()));
					}


					AOM_set_value_string(cLine, "bl_plmxml_occ_xform", cBean.bl_plmxml_occ_xform);
					AOM_set_value_string(cLine, "bl_sequence_no", cBean.bl_sequence_no.c_str());
					ITKCALL(AOM_set_value_string(cLine, "bl_occ_zt2_DtoE", "DBOM转换"));
					AOM_save(cLine);
					//最后unlock
					AOM_unlock(cLine);
					AOM_refresh(cLine, FALSE);
				}
				else {
					printf("eeeeee\n");
				}
			}
			ITKCALL(BOM_save_window(ebom_window));
		}
		BOM_close_window(ebom_window);
		for (int i = 0; i < childs.size(); i++) {
			NodeBean cBean = childs[i];
			createEbom(cBean, false, hasChange, saveAsMap);
		}
	}
	else {
		printf("topBean.mantr == NULLTAG\n");
	}

}

void copyEBomLine(tag_t matnrTop, tag_t otherPbom) {
	tag_t ebom_window, ebom_window2, *bvr_list, *bvr_list2, bom_line, bom_line2, *c_line_tags, *c_line_tags2;
	int bvr_count = 0, bvr_count2 = 0, c_line_count, c_line_count2;
	(BOM_create_window(&ebom_window));
	(ITEM_rev_list_bom_view_revs(matnrTop, &bvr_count, &bvr_list));
	printf("bvr_count=%d \n", bvr_count);
	if (bvr_count == 0) {
		//errBuff.append("不存在EBOM请检查\n");
	}
	ITKCALL(BOM_set_window_top_line_bvr(ebom_window, bvr_list[0], &bom_line)); //顶层bom获取
	printf("顶层bom获取\n");
	//ITKCALL(AOM_ask_value_tag(bom_line, "bl_line_object", &mantr));
	ITKCALL(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags));


	(ITEM_rev_list_bom_view_revs(otherPbom, &bvr_count2, &bvr_list2));
	if (bvr_count2 == 0) {
		tag_t newView, newViewBvr, pitem;
		ITEM_ask_item_of_rev(otherPbom, &pitem);
		ITKCALL(PS_create_bom_view(NULL, NULL, NULL, pitem, &newView));
		AOM_save(newView);
		ITKCALL(PS_create_bvr(newView, NULL, NULL, FALSE, otherPbom, &newViewBvr));
		AOM_save(newViewBvr);
		AOM_save(otherPbom);
		int num = 0;
		tag_t dsuser, *structure_revisions, *bom_view_tags, *mantrs;
		ITKCALL(AOM_ask_value_tags(otherPbom, "TC_Is_Represented_By", &num, &mantrs));
		if (num == 1) {
			AOM_ask_value_tag(mantrs[0], "owning_user", &dsuser);
			tag_t defGroup;
			ITKCALL(AOM_ask_value_tag(dsuser, "default_group", &defGroup));
			ITKCALL(AOM_set_ownership(newView, dsuser, defGroup));
			ITKCALL(AOM_set_ownership(newViewBvr, dsuser, defGroup));
		}
		//return;
		(ITEM_rev_list_bom_view_revs(otherPbom, &bvr_count2, &bvr_list2));
	}
	(BOM_create_window(&ebom_window2));
	(BOM_set_window_top_line_bvr(ebom_window2, bvr_list2[0], &bom_line2)); //顶层bom获取
	ITKCALL(BOM_line_ask_all_child_lines(bom_line2, &c_line_count2, &c_line_tags2));
	for (int i = 0; i < c_line_count2; i++) {
		BOM_line_cut(c_line_tags2[i]);
	}
	for (int i = 0; i < c_line_count; i++) {
		tag_t newChild; char *bl_seqNo;
		ITKCALL(BOM_line_copy(bom_line2, c_line_tags[i], NULLTAG, &newChild));
		AOM_ask_value_string(c_line_tags[i], "bl_sequence_no", &bl_seqNo);
		AOM_lock(newChild);
		AOM_set_value_string(newChild, "bl_sequence_no", bl_seqNo);
		AOM_save(newChild);
		//最后unlock
		AOM_unlock(newChild);
	}
	//tag_t newChild;
	//ITKCALL(BOM_line_copy(bom_line2, c_line_tags[i], NULLTAG, &newChild));

	ITKCALL(BOM_save_window(ebom_window2));
	BOM_close_window(ebom_window2);
	BOM_close_window(ebom_window);
}
//获取分类属性 判断是否整除
int getClassValByTop(tag_t item, string& errMessage) {
	char*id;
	AOM_ask_value_string(item, "item_id", &id);
	vector<string> vec;
	Split(id, "-", vec);
	tag_t topItem;
	if (vec.size() > 1) {
		string topId;
		topId.append("1ZDB300000P-").append(vec[1]);
		ITEM_find_item(topId.c_str(), &topItem);
	}
	else {
		return 1;
	}
	tag_t top_classificationObject;
	ICS_ask_classification_object(topItem, &top_classificationObject);
	if (top_classificationObject == NULL_TAG)
	{
		errMessage.append("顶层对象没有发送到分类\n");
		return  0;
	}
	char* top_class_id = NULL, *top_class_name = NULL;
	//ICS_ask_class_of_classification_obj(top_classificationObject, &top_class_tag);
	//ICS_ask_id_name(top_class_tag, &top_class_id, &top_class_name);
	printf("BOM TOP LINE CLASS ID = %s | NAME = %s \n", top_class_id, top_class_name);
	int n_attrs;
	char** attr_names;
	char** attr_vals;
	ITKCALL(ICS_ask_attributes_of_classification_obj(top_classificationObject, &n_attrs, &attr_names, &attr_vals));
	cout << n_attrs << endl;
	int num = 1;
	for (int ii = 0; ii < n_attrs; ii++)
	{
		printf("attr_names[ii]==>%sTTT\n", attr_names[ii]);
		printf("attr_vals[ii]==>%sTTT\n", attr_vals[ii]);
		if (strcmp(attr_names[ii], "相数") == 0) {
			if (strcmp(attr_vals[ii], "") == 0) {
				errMessage.append("分类属性相数为空，请检查。\n");
				return 0;
			}
			else {
				printf("111[ii]==TTT\n");
				if (strstr(attr_vals[ii], "3") != NULL) {
					num = 3;
				}
				else if (strstr(attr_vals[ii], "1") != NULL) {
					num = 1;
				}
				else if (strstr(attr_vals[ii], "5") != NULL) {
					num = 5;
				}
				//num = atoi(attr_vals[ii]);
			}
			break;
		}
	}
	return num;
}
/**
 * DBOM转EBOM 
 */
int DbomToEMethod(void* returnValue) {
	int ifail = ITK_ok;
	char *sql = NULL, *revUid;
	tag_t designRev, item;
	ITKCALL(ifail = USERARG_get_string_argument(&revUid));
	ITK__convert_uid_to_tag(revUid, &designRev);
	ITEM_ask_item_of_rev(designRev, &item);
	ITEM_ask_latest_rev(item, &designRev);
	if (open("PLMUser", "PLMUser", "BDP2020", "10.128.20.35")) {
		printf("链接SQLSERVER失败\n");
	}
	else {
		printf("链接SQLSERVER成功\n");
	}
	//遍历design BOM 获取物料信息
	int bvr_count = 0, c_line_count;
	tag_t ebom_window = NULLTAG;
	tag_t bom_line = NULLTAG;
	tag_t item_tag = NULLTAG, *c_line_tags;
	(BOM_create_window(&ebom_window));
	tag_t* bvr_list = NULL;
	(ITEM_rev_list_bom_view_revs(designRev, &bvr_count, &bvr_list));
	printf("bvr_count=%d", bvr_count);

	(BOM_set_window_top_line_bvr(ebom_window, bvr_list[0], &bom_line)); //顶层bom获取
	printf("顶层bom获取\n");

	//(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags));
	NodeBean topBean;
	//遍历
	string errBuff;
	//xsLen = 1;
	xsLen = getClassValByTop(designRev, errBuff);
	int url_num = 0;
	char** url_vals = NULL;
	PREF_ask_char_values("database_tc", &url_num, &url_vals);
	string url = url_vals[0];
	url.append("/").append(url_vals[2]);

	//map<string,
	printf("url ==> %s \n", url.c_str());
	if (ConnServer(url_vals[3], url_vals[4], (char*)url.c_str()) == -1)
	{
		printf("提示:中间数据表访问失败\n");
		ifail = 1;
	}
	string dbName;
	int url_num2 = 0;
	char** url_vals2 = NULL;
	PREF_ask_char_values("CHINT_MATERIAL_RAW", &url_num2, &url_vals2);
	for (int t = 0; t < url_num2; t++) {
		vector<string> vec;
		Split(url_vals2[t], ":", vec);
		if (vec[0].compare("M060") == 0) {
			dbName = vec[1];
		}
	}
	char *loginUserId;
	printf("dbName===%s\n", dbName.c_str());
	POM_get_user_id(&loginUserId);
	
	recyReadBom(bom_line, topBean, errBuff, dbName, loginUserId);
	DisConnServer();
	BOM_close_window(ebom_window);
	//搭建BOM
	POM_AM__set_application_bypass(true);
	printf("error %s \n", errBuff.c_str());
	if (errBuff.empty()) {
		string hasChange = "";
		map<string, tag_t> saveAsMap;
		createEbom(topBean, true, hasChange, saveAsMap);
		printf("topBean.ccps.size()====>%d\n", topBean.ccps.size());
		//没有更改直接跳过
		if (topBean.ccps.size() > 0 && hasChange.compare("no") != 0) {
			tag_t desBean = topBean.designRev;
			//vector<NodeBean> childs = topBean.childs;
			/*map<string, int> dMap;
			for (int i = 0; i < childs.size(); i++) {
				NodeBean cBean = childs[i];
				char *matnrNo, *uid;
				AOM_ask_value_string(cBean.mantr, "zt2_MaterialNo", &matnrNo);
				ITK__convert_tag_to_uid(cBean.mantr, &uid);
				printf("uid[%s]\n", uid);
				printf("matnrNo[%s]\n", matnrNo);
				int qtyPXn = 1;
				string cnt = cBean.bl_quantity;
				if (strcmp(cnt.c_str(), "") != 0) {
					qtyPXn = atoi(cnt.c_str());
				}
				if (dMap.count(matnrNo) > 0) {
					dMap[matnrNo] = dMap[matnrNo] + qtyPXn;
				}
				else {
					dMap[matnrNo] = qtyPXn;
				}
			}
			printf("dMap[%d]", dMap.size());*/
			map<string, int> dMap = getDBomMesg(topBean);
			for (int t = 0; t < topBean.ccps.size(); t++) {
				tag_t mantr = topBean.ccps[t];
				boolean flagChange = true;
				bool flag = false;
				map<string, int> eMap = getBomMsg(mantr, flag);
				printf("eMap[%d]", eMap.size());
				boolean needAs = false;
				if (dMap.size() != eMap.size()) {
					//升版 + 发布
					needAs = true;
				}
				else if (combEAndDbom(dMap, eMap)) {
					//升版 + 发布
					needAs = true;
				}
				if (needAs && !flag) {
					printf("=======TEST======\n");
					//升版并发布
					ITKCALL(ITEM_copy_rev(mantr, NULL, &mantr));
					TCMAndOwner(mantr);
					//return;
				}
				if (flagChange) {
					tag_t topItem, topRev;
					ITEM_ask_item_of_rev(topBean.mantr, &topItem);
					ITEM_ask_latest_rev(topItem, &topRev);
					copyEBomLine(topRev, mantr);
				}
			}
		}
		errBuff = "succ";
	}
	/*else {
		printf(errBuff.c_str());
	}*/

	POM_AM__set_application_bypass(false);

	close();
	printf("释放数据库成功\n");
	printf("子line数量 %d \n", topBean.childs.size());
	string buff = errBuff;
	*((char**)returnValue) = (char*)MEM_alloc((strlen(buff.c_str()) + 1) * sizeof(char));
	tc_strcpy(*((char**)returnValue), buff.c_str());
	return ifail;
}
/**
 * DBOM转EBOM 传递框架BOM之后使用
 * 区别在于需要通过首选项进行D转E，没有配置的不转换
 */
int DbomToEMethodUser(void* returnValue) {
	int ifail = ITK_ok;
	char *sql = NULL, *revUid;
	tag_t designRev;
	ITKCALL(ifail = USERARG_get_string_argument(&revUid));
	ITK__convert_uid_to_tag(revUid, &designRev);

	if (open("PLMUser", "PLMUser", "BDP2020", "10.128.20.35")) {
		printf("链接SQLSERVER失败\n");
	}
	else {
		printf("链接SQLSERVER成功\n");
	}
	//遍历design BOM 获取物料信息
	int bvr_count = 0, c_line_count;
	tag_t ebom_window = NULLTAG;
	tag_t bom_line = NULLTAG;
	tag_t item_tag = NULLTAG, *c_line_tags;
	(BOM_create_window(&ebom_window));
	tag_t* bvr_list = NULL;
	(ITEM_rev_list_bom_view_revs(designRev, &bvr_count, &bvr_list));
	printf("bvr_count=%d", bvr_count);

	(BOM_set_window_top_line_bvr(ebom_window, bvr_list[0], &bom_line)); //顶层bom获取
	printf("顶层bom获取\n");

	//(BOM_line_ask_all_child_lines(bom_line, &c_line_count, &c_line_tags));
	NodeBean topBean;
	//遍历
	string errBuff;

	int url_num = 0;
	char** url_vals = NULL;
	PREF_ask_char_values("database_tc", &url_num, &url_vals);
	string url = url_vals[0];
	url.append("/").append(url_vals[2]);

	//map<string,
	printf("url ==> %s \n", url.c_str());
	if (ConnServer(url_vals[3], url_vals[4], (char*)url.c_str()) == -1)
	{
		printf("提示:中间数据表访问失败\n");
		ifail = 1;
	}
	string dbName;
	int url_num2 = 0, url_num3 = 0;
	char** url_vals2 = NULL, **url_vals3 = NULL;
	PREF_ask_char_values("CHINT_MATERIAL_RAW", &url_num2, &url_vals2);
	for (int t = 0; t < url_num2; t++) {
		vector<string> vec;
		Split(url_vals2[t], ":", vec);
		if (vec[0].compare("M060") == 0) {
			dbName = vec[1];
		}
	}
	//配置哪些ID类别需要D转E
	PREF_ask_char_values("CHINT_M060_KJTOSAP", &url_num3, &url_vals3);
	vector<string> idVector;
	if (url_num3 > 0) {
		Split(url_vals3[0], ";", idVector);
	}

	recyReadBom(bom_line, topBean, errBuff, dbName, idVector);
	DisConnServer();
	BOM_close_window(ebom_window);
	//搭建BOM
	POM_AM__set_application_bypass(true);
	printf("error %s \n", errBuff.c_str());
	//没有错误信息开始DBOM转换EBOM
	if (errBuff.empty()) {
		string change;
		//EBOM的搭建
		map<string, tag_t> saveAsMap;
		createEbom(topBean, false, change, saveAsMap);
		printf("topBean.ccps.size()====>%d\n", topBean.ccps.size());
		if (topBean.ccps.size() > 0) {
			//总装图下可能会有多个物料，BOM结构相同，只需要复制就行
			for (int t = 0; t < topBean.ccps.size(); t++) {
				copyEBomLine(topBean.mantr, topBean.ccps[t]);
			}
		}
		errBuff = "succ";
	}

	POM_AM__set_application_bypass(false);

	close();
	printf("释放数据库成功\n");
	printf("子line数量 %d \n", topBean.childs.size());
	string buff = errBuff;
	*((char**)returnValue) = (char*)MEM_alloc((strlen(buff.c_str()) + 1) * sizeof(char));
	tc_strcpy(*((char**)returnValue), buff.c_str());
	return ifail;
}