{
	"info": {
		"_postman_id": "9bddf127-a444-447f-acdb-d54266a73f32",
		"name": "EKKO_1.7",
		"description": "Postman global du setup de la solution Opencell Mon pilotage elec. Version EKKO_1.7 créée le 19/07/2024",
		"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
		"_exporter_id": "5329877",
		"_collection_link": "https://universal-trinity-600546.postman.co/workspace/opencell~483c8a3a-ecd3-4966-aa10-1fe25ae77c03/collection/5329877-9bddf127-a444-447f-acdb-d54266a73f32?action=share&source=collection_link&creator=5329877"
	},
	"item": [
		{
			"name": "Scripts",
			"item": [
				{
					"name": "Rating",
					"item": [
						{
							"name": "EkkoRatingScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								},
								{
									"listen": "prerequest",
									"script": {
										"exec": [
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.rating.EkkoRatingScript\" description=\"Ekko Rating Script\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.rating;\r\n\r\nimport java.math.BigDecimal;\r\nimport java.util.Map;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.model.billing.Subscription;\r\nimport org.meveo.model.billing.WalletOperation;\r\nimport org.meveo.model.billing.WalletOperationStatusEnum;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.service.billing.impl.SubscriptionService;\r\nimport org.meveo.service.script.Script;\r\n\r\n/**\r\n * \r\n * @author anasseh\r\n * \r\n *   02/05/2022 : ENG382-84 occurence remise\r\n *\r\n */\r\npublic class EkkoRatingScript extends Script {\r\n\r\n\tprivate static final long serialVersionUID = 1L;\r\n\r\n\tprivate SubscriptionService subscriptionService = (SubscriptionService) getServiceInterface(\"SubscriptionService\");\r\n\r\n\t@Override\r\n\tpublic void execute(Map<String, Object> context) throws BusinessException {\r\n\r\n\t\tWalletOperation wo = (WalletOperation) context.get(Script.CONTEXT_ENTITY);\r\n\r\n\t\tif (wo.getSubscription() == null) {\r\n\t\t\tthrow new BusinessException(\"wo.subscription is null\");\r\n\t\t}\r\n\t\tif(wo.getCode().equals(\"CH_OS_EKKO_RESIL\")) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tMap<String, Double> prices = (Map<String, Double>) wo.getSubscription().getCfValue(\"CF_SUB_PRICES\");\r\n\t\tMap<String, String> labels = (Map<String, String>) wo.getSubscription().getCfValue(\"CF_SUB_LABELS\");\r\n\r\n\t\tlog.info(\"woCode:{}, operationDate:{}, subscriptionDate:{}, CF prices:{} \", wo.getCode(), DateUtils.formatAsDate(wo.getOperationDate()),\r\n\t\t\t\tDateUtils.formatAsDate(wo.getSubscriptionDate()), prices);\r\n\r\n\r\n\t\two.setDescription(labels.get(wo.getCode()));\r\n\r\n\t\tif (wo.getCode().startsWith(\"CH_REC\") && DateUtils.getMonthFromDate(wo.getOperationDate()).intValue() == DateUtils.getMonthFromDate(wo.getSubscriptionDate()).intValue()\r\n\t\t\t\t&& DateUtils.getYearFromDate(wo.getOperationDate()).intValue() == DateUtils.getYearFromDate(wo.getSubscriptionDate()).intValue()) {\r\n\r\n\t\t\two.setAmountTax(BigDecimal.ZERO);\r\n\t\t\two.setAmountWithoutTax(BigDecimal.ZERO);\r\n\t\t\two.setAmountWithTax(BigDecimal.ZERO);\r\n\r\n\t\t\two.setUnitAmountTax(BigDecimal.ZERO);\r\n\t\t\two.setUnitAmountWithoutTax(BigDecimal.ZERO);\r\n\t\t\two.setUnitAmountWithTax(BigDecimal.ZERO);\r\n\t\t\two.setStatus(WalletOperationStatusEnum.CANCELED);\r\n\t\t} else {\r\n\t\t\tif(prices == null || prices.isEmpty() || !prices.containsKey(wo.getCode()+ \"_HT\")) {\r\n\t\t\t\tthrow new BusinessException(\"Prices for charge :\"+wo.getCode()+\" not found\");\r\n\t\t\t}\r\n\r\n\t\t\two.setAmountTax(new BigDecimal(prices.get(wo.getCode() + \"_T\")));\r\n\t\t\two.setAmountWithoutTax(new BigDecimal(prices.get(wo.getCode() + \"_HT\")));\r\n\t\t\two.setAmountWithTax(new BigDecimal(prices.get(wo.getCode() + \"_TTC\")));\r\n\r\n\t\t\two.setUnitAmountTax(new BigDecimal(prices.get(wo.getCode() + \"_T\")));\r\n\t\t\two.setUnitAmountWithoutTax(new BigDecimal(prices.get(wo.getCode() + \"_HT\")));\r\n\t\t\two.setUnitAmountWithTax(new BigDecimal(prices.get(wo.getCode() + \"_TTC\")));\r\n\r\n\t\t\tif (wo.getCode().equals(\"CH_REC_EKKO_ABO_REM\")) {\r\n\t\t\t\tSubscription subscription = wo.getSubscription();\r\n\t\t\t\tLong cptRemise = (Long) subscription.getCfValue(\"CF_SUB_CPT_REMISE\");\r\n\t\t\t\tif (cptRemise == null) {\r\n\t\t\t\t\tcptRemise = 0L;\r\n\t\t\t\t}\r\n\t\t\t\tLong nbRemise = null;\r\n\t\t\t\tMap<String, Object> sfData = (Map<String, Object>) subscription.getCfValue(\"CF_SUB_SF_DATA\");\r\n\t\t\t\tif (sfData != null && sfData.get(\"EK_nb_rem_abt\") != null) {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tnbRemise = Long.valueOf((String) sfData.get(\"EK_nb_rem_abt\"));\r\n\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\tlog.warn(\"EK_nb_rem_abt should be numeric\");\r\n\t\t\t\t\t}\r\n\t\t\t\t}\t\t\t\t\r\n\t\t\t\tif (nbRemise != null && nbRemise != 9999L) {\r\n\t\t\t\t\tif (cptRemise.intValue() >= nbRemise.intValue()) {\r\n\t\t\t\t\t\two.setStatus(WalletOperationStatusEnum.CANCELED);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tcptRemise = cptRemise + 1;\r\n\t\t\t\t\t\tsubscription.setCfValue(\"CF_SUB_CPT_REMISE\", cptRemise);\r\n\t\t\t\t\t\tsubscriptionService.updateNoCheck(subscription);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t}\r\n}\r\n\r\n\r\n]]>\r\n            </script>\r\n         </ScriptInstance>\r\n\r\n"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						}
					]
				},
				{
					"name": "Invoicing",
					"item": [
						{
							"name": "EkkoBillingCycleScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.invoicing.EkkoBillingCycleScript\" description=\"Ekko Invoicing Script\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.invoicing;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Calendar;\r\nimport java.util.Date;\r\nimport java.util.List;\r\nimport java.util.Map;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.model.billing.BillingAccount;\r\nimport org.meveo.model.billing.Invoice;\r\nimport org.meveo.model.billing.InvoiceType;\r\nimport org.meveo.model.billing.RatedTransaction;\r\nimport org.meveo.model.billing.RatedTransactionGroup;\r\nimport org.meveo.model.billing.Subscription;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.service.billing.impl.InvoiceTypeService;\r\nimport org.meveo.service.catalog.impl.CalendarBankingService;\r\nimport org.meveo.service.script.Script;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n/**\r\n * \r\n * @author anasseh \r\n *          26/01/2022 : invoice amount zero \r\n *          20/02/2022 : ENG382-64 Bloquer la facturation des abonnements en masse \r\n *          04/06/2022 : SUPS-1687 + use simu as CF \r\n *          06/07/2002 : last SUPS-1687\r\n *          16/03/2023 : SUPS-2261\r\n */\r\npublic class EkkoBillingCycleScript extends Script {\r\n\r\n\tprivate static final long serialVersionUID = 1L;\r\n\tprivate static final String INV_TYPE_REC = \"REC\";\r\n\tprivate static final String INV_TYPE_UPF = \"UPF\";\r\n\tprivate static final String CF_SEL_INV_NB_BUSI_DAYS = \"CF_SEL_INV_NB_BUSI_DAYS\";\r\n\tprivate static final String CF_SEL_INV_NO_REC_INVOICES = \"CF_SEL_INV_NO_REC_INVOICES\";\r\n\tprivate static final String CF_SEL_INV_USE_SIMU_BUSINES_DAY = \"CF_SEL_INV_USE_SIMU_BUSINES_DAY\";\r\n\r\n\tprivate static final Logger log = LoggerFactory.getLogger(EkkoBillingCycleScript.class);\r\n\tprivate InvoiceTypeService invoiceTypeService = (InvoiceTypeService) getServiceInterface(\"InvoiceTypeService\");\r\n\tprivate CalendarBankingService calendarBankingService = (CalendarBankingService) getServiceInterface(\"CalendarBankingService\");\r\n\r\n\t@Override\r\n\tpublic void execute(Map<String, Object> context) throws BusinessException {\r\n\t\tlog.info(\"Execute context : {} \", context);\r\n\t\tList<RatedTransactionGroup> listGroupRts = new ArrayList<RatedTransactionGroup>();\r\n\r\n\t\tif (calendarBankingService.isBankWorkingDate(new Date())) {\r\n\t\t\tcontext.put(Script.RESULT_VALUE, listGroupRts);\r\n\t\t}\r\n\t\tBillingAccount billingAccountCtx = null;\r\n\t\tSubscription subscription = null;\r\n\t\tif (context.get(Script.CONTEXT_ENTITY) instanceof BillingAccount) {\r\n\t\t\tbillingAccountCtx = (BillingAccount) context.get(Script.CONTEXT_ENTITY);\r\n\t\t} else {\r\n\r\n\t\t\tsubscription = (Subscription) context.get(Script.CONTEXT_ENTITY);\r\n\t\t}\r\n\t\tif(subscription == null) {\r\n\t\t\tsubscription = \tbillingAccountCtx.getUsersAccounts().get(0).getSubscriptions().get(0);\r\n\t\t}\r\n\t\tlog.info(\"isTheFirstbusinesDay(new Date())=\" + isTheFirstbusinesDay(new Date()));\r\n\r\n\t\tList<RatedTransaction> ratedTransactions = (List<RatedTransaction>) context.get(\"ratedTransactions\");\r\n\t\tRatedTransactionGroup rtGroupRec = new RatedTransactionGroup();\r\n\t\tRatedTransactionGroup rtGroupUpfront = new RatedTransactionGroup();\r\n\t\tInvoiceType recInvoiceType = invoiceTypeService.findByCode(INV_TYPE_REC);\r\n\t\tInvoiceType upfInvoiceType = invoiceTypeService.findByCode(INV_TYPE_UPF);\r\n\r\n\t\trtGroupRec.setInvoiceType(recInvoiceType);\r\n\t\trtGroupRec.setInvoiceKey(recInvoiceType.getCode());\r\n\t\trtGroupRec.setBillingAccount(subscription.getUserAccount().getBillingAccount());\r\n\t\trtGroupRec.setSeller(subscription.getSeller());\r\n\t\trtGroupRec.setBillingCycle(subscription.getBillingCycle());\r\n\r\n\t\trtGroupUpfront.setInvoiceType(upfInvoiceType);\r\n\t\trtGroupUpfront.setInvoiceKey(upfInvoiceType.getCode());\r\n\t\trtGroupUpfront.setBillingAccount(subscription.getUserAccount().getBillingAccount());\r\n\t\trtGroupUpfront.setSeller(subscription.getSeller());\r\n\t\trtGroupUpfront.setBillingCycle(subscription.getBillingCycle());\r\n\r\n\t\tboolean dontGenerateRecInvoices = true;\r\n\t\tboolean useSimuForFistBusinesDay = false;\r\n\t\tif (subscription.getSeller().getCfValue(CF_SEL_INV_NO_REC_INVOICES) != null) {\r\n\t\t\tdontGenerateRecInvoices = (Boolean) subscription.getSeller().getCfValue(CF_SEL_INV_NO_REC_INVOICES);\r\n\t\t}\r\n\t\tif (subscription.getSeller().getCfValue(CF_SEL_INV_USE_SIMU_BUSINES_DAY) != null) {\r\n\t\t\tuseSimuForFistBusinesDay = (Boolean) subscription.getSeller().getCfValue(CF_SEL_INV_USE_SIMU_BUSINES_DAY);\r\n\t\t}\r\n\r\n\t\tboolean isUpfInvoiceAlreadyGenerated = false;\r\n\t\tBillingAccount billingAccount = subscription.getUserAccount().getBillingAccount();\r\n\t\tList<Invoice> invoices = billingAccount.getInvoices();\r\n\t\tfor (Invoice invoice : invoices) {\r\n\t\t\tif (invoice.getInvoiceType().getCode().equals(INV_TYPE_UPF)\r\n\t\t\t\t\t&& invoice.getSubscription().getCode().equals(subscription.getCode()) &&\r\n\t\t\t\t\t(invoice.getLinkedInvoices() == null || invoice.getLinkedInvoices().isEmpty())) {\r\n\t\t\t\tisUpfInvoiceAlreadyGenerated = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlog.info(\"getFirstBusinessDayInMonth(new date)=\" + getFirstBusinessDayInMonth(new Date()));\r\n\r\n\t\tfor (RatedTransaction rt : ratedTransactions) {\r\n\t\t\tlog.info(\"rt id:{} Code:{} UsageDate:{} \", rt.getId(), rt.getCode(),\r\n\t\t\t\t\tDateUtils.formatAsDate(rt.getUsageDate()));\r\n\t\t\tboolean isAboCharge = isAboCharge(rt);\r\n\r\n\t\t\tif (isUpfInvoiceAlreadyGenerated || isAboCharge) {\r\n\t\t\t\t// La facture de récurrent est envoyée et reçue le 1er jour ouvré de chaque\r\n\t\t\t\t// mois.\r\n\t\t\t\tif (DateUtils.setDateToStartOfDay(rt.getUsageDate())\r\n\t\t\t\t\t\t.before(DateUtils.setDateToEndOfDay(getFirstBusinessDayInMonth(new Date())))\r\n\t\t\t\t\t\t|| useSimuForFistBusinesDay) {\r\n\t\t\t\t\trtGroupRec.getRatedTransactions().add(rt);\r\n\t\t\t\t\tlog.info(\"END rt id:{} Code:{} UsageDate:{} \", rt.getId(), rt.getCode(),\r\n\t\t\t\t\t\t\tDateUtils.formatAsDate(rt.getUsageDate()));\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (!isAboCharge && !isUpfInvoiceAlreadyGenerated) {\r\n\t\t\t\tif (DateUtils.getDayFromDate(rt.getUsageDate()) <= 25) {\r\n\t\t\t\t\tif ((addBusinessDays(DateUtils.setDateToStartOfDay(rt.getUsageDate()),\r\n\t\t\t\t\t\t\t(Long) subscription.getSeller().getCfValue(CF_SEL_INV_NB_BUSI_DAYS))\r\n\t\t\t\t\t\t\t.before(DateUtils.setDateToEndOfDay(new Date())))) {\r\n\t\t\t\t\t\tlog.info(\"RT upf taken2\");\r\n\t\t\t\t\t\trtGroupUpfront.getRatedTransactions().add(rt);\r\n\t\t\t\t\t\tlog.info(\"END rt id:{} Code:{} UsageDate:{} \", rt.getId(), rt.getCode(),\r\n\t\t\t\t\t\t\t\tDateUtils.formatAsDate(rt.getUsageDate()));\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (DateUtils.getDayFromDate(rt.getUsageDate()) > 25) {\r\n\t\t\t\t\tlog.info(\"isTheFirstbusinesDay(new Date())=\" + isTheFirstbusinesDay(new Date()));\r\n\t\t\t\t\tlog.info(\"getFirstBusinessDayInMonth(date)=\" + getFirstBusinessDayInMonth(new Date()));\r\n\r\n\t\t\t\t\tif (isTheFirstbusinesDay(new Date()) || useSimuForFistBusinesDay) {\r\n\t\t\t\t\t\tlog.info(\"RT taken1\");\r\n\t\t\t\t\t\trtGroupUpfront.getRatedTransactions().add(rt);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tlog.info(\"RT skiped1\");\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tlog.info(\"END rt id:{} Code:{} UsageDate:{} \", rt.getId(), rt.getCode(),\r\n\t\t\t\t\tDateUtils.formatAsDate(rt.getUsageDate()));\r\n\t\t}\r\n\t\tif (!rtGroupUpfront.getRatedTransactions().isEmpty()) {\r\n\t\t\tlistGroupRts.add(rtGroupUpfront);\r\n\t\t}\r\n\t\tif (!rtGroupRec.getRatedTransactions().isEmpty() && !dontGenerateRecInvoices) {\r\n\t\t\tif (isTheFirstbusinesDay(new Date()) || useSimuForFistBusinesDay) {\r\n\t\t\t\tlistGroupRts.add(rtGroupRec);\r\n\t\t\t}\r\n\t\t}\r\n\t\tcontext.put(Script.RESULT_VALUE, listGroupRts);\r\n\r\n\t}\r\n\r\n\tprivate boolean isAboCharge(RatedTransaction rt) {\r\n\t\treturn rt.getCode().startsWith(\"CH_REC\") || rt.getCode().indexOf(\"ABO\") > -1;\r\n\r\n\t}\r\n\r\n\tprivate boolean isTheFirstbusinesDay(Date date) {\r\n\r\n\t\tDate firstBusinessDay = getFirstBusinessDayInMonth(date);\r\n\t\tdate = DateUtils.setDateToStartOfDay(date);\r\n\t\tfirstBusinessDay = DateUtils.setDateToStartOfDay(firstBusinessDay);\r\n\r\n\t\tif (date.compareTo(firstBusinessDay) == 0) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate Date getFirstBusinessDayInMonth(Date dateMonth) {\r\n\r\n\t\tCalendar calendar = Calendar.getInstance();\r\n\t\tcalendar.setTime(dateMonth);\r\n\t\tcalendar.set(Calendar.DAY_OF_MONTH, 2); // dont change this, because the rec charge whill produced at 1 , so\r\n\t\t\t\t\t\t\t\t\t\t\t\t// will not be\r\n\t\t\t\t\t\t\t\t\t\t\t\t// invoiced at 1\r\n\r\n\t\tDate firstBusinessDay = calendar.getTime();\r\n\t\tif (calendarBankingService.isBankWorkingDate(firstBusinessDay)) {\r\n\t\t\treturn firstBusinessDay;\r\n\r\n\t\t}\r\n\r\n\t\twhile (!calendarBankingService.isBankWorkingDate(firstBusinessDay)) {\r\n\t\t\tfirstBusinessDay = DateUtils.addDaysToDate(firstBusinessDay, 1);\r\n\t\t}\r\n\r\n\t\treturn firstBusinessDay;\r\n\t}\r\n\r\n\tprivate Date addBusinessDays(Date dateStart, Long nbDays) {\r\n\r\n\t\tint daysAdded = 0;\r\n\t\tDate endDate = dateStart;\r\n\t\twhile (daysAdded != nbDays.intValue()) {\r\n\t\t\tendDate = DateUtils.addDaysToDate(endDate, 1);\r\n\t\t\tif (calendarBankingService.isBankWorkingDate(endDate)) {\r\n\t\t\t\tdaysAdded++;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn DateUtils.setDateToEndOfDay(endDate);\r\n\t}\r\n\r\n}\r\n\r\n\r\n\r\n]]>\r\n            </script>\r\n</ScriptInstance>\r\n"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "InvoiceXmlScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.invoicing.InvoiceXmlScript\" description=\"Ekko Invoice Xml Script\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.invoicing;\r\n\r\nimport java.io.File;\r\nimport java.math.BigDecimal;\r\nimport java.math.RoundingMode;\r\nimport java.text.SimpleDateFormat;\r\nimport java.util.ArrayList;\r\nimport java.util.Comparator;\r\nimport java.util.Date;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Locale;\r\nimport java.util.Map;\r\nimport java.util.Set;\r\nimport java.util.regex.Matcher;\r\nimport java.util.regex.Pattern;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.commons.utils.StringUtils;\r\nimport org.meveo.model.billing.Invoice;\r\nimport org.meveo.model.billing.InvoiceAgregate;\r\nimport org.meveo.model.billing.RatedTransaction;\r\nimport org.meveo.model.billing.Subscription;\r\nimport org.meveo.model.billing.TaxInvoiceAgregate;\r\nimport org.meveo.model.payments.AccountOperation;\r\nimport org.meveo.model.payments.OperationCategoryEnum;\r\nimport org.meveo.model.payments.PaymentMethodEnum;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.service.billing.impl.EkkoXMLInvoiceCreator;\r\nimport org.meveo.service.billing.impl.InvoiceAgregateService;\r\nimport org.meveo.service.billing.impl.InvoiceService;\r\nimport org.meveo.service.billing.impl.RatedTransactionService;\r\nimport org.meveo.service.catalog.impl.CalendarBankingService;\r\nimport org.meveo.service.payments.impl.AccountOperationService;\r\nimport org.meveo.service.script.Script;\r\nimport org.w3c.dom.Document;\r\nimport org.w3c.dom.Element;\r\nimport org.w3c.dom.Text;\r\n\r\nimport static org.meveo.commons.utils.StringUtils.getDefaultIfNull;\r\n\r\n/**\r\n * Generate custom Xml Invoice Execute Context Variable :\r\n * <li>CONTEXT_ENTITY : the invoice\r\n * <li>isVirtual : invoicing mode\r\n * <li>XMLInvoiceCreator : XMLInvoiceCreator std service\r\n *\r\n * @author anasseh\r\n * \r\n *         09/06/2022 SUPS-1686 \r\n *         14/07/2022 SUPS-1765 (mounir) \r\n *         18/07/2022 SUPS-1734 \r\n *         13/04/2023 SUPS-2447 \r\n *         17/04/2023 SUPS-2365\r\n */\r\npublic class InvoiceXmlScript extends Script {\r\n\r\n\tprivate static final long serialVersionUID = 1L;\r\n\tprivate EkkoXMLInvoiceCreator xmlInvoiceCreatorScript = (EkkoXMLInvoiceCreator) getServiceInterface(\"EkkoXMLInvoiceCreator\");\r\n\tprivate InvoiceService invoiceService = (InvoiceService) getServiceInterface(\"InvoiceService\");\r\n\tprivate RatedTransactionService ratedTransactionService = (RatedTransactionService) getServiceInterface(\"RatedTransactionService\");\r\n\tprivate InvoiceAgregateService invoiceAgregateService = (InvoiceAgregateService) getServiceInterface(\"InvoiceAgregateService\");\r\n\tprivate  AccountOperationService accountOperationService = (AccountOperationService) getServiceInterface(\"AccountOperationService\");\r\n\tprivate CalendarBankingService calendarBankingService = (CalendarBankingService) getServiceInterface(\"CalendarBankingService\");\r\n\r\n\r\n\tprivate static final String CF_SUB_PAY_METHOD = \"CF_SUB_PAY_METHOD\";\r\n\tprivate static final String SHIPPING_ADDRESS = \"ShippingAddress\";\r\n\tprivate static final String CF_NbrOfRadiator = \"EK_OPP_NofRadiator__c\";\r\n\tprivate static final String CF_NbrOfRooms = \"EK_OPP_Number_Rooms__c\";\r\n\r\n\tprivate Long nbrOfRadiotor = 0L;\r\n\tprivate Long nbrOfRooms = 0L;\r\n\tList<RatedTransaction> rts = new ArrayList<RatedTransaction>();\r\n\r\n\t@Override\r\n\tpublic void execute(Map<String, Object> methodContext) throws BusinessException {\r\n\t\tlog.debug(\"EXECUTE methodContext {}\", methodContext);\r\n\t\ttry {\r\n\r\n\t\t\tInvoice invoice = (Invoice) methodContext.get(Script.CONTEXT_ENTITY);\r\n\t\t\trts = ratedTransactionService.getRatedTransactionsByInvoice(invoice, true);\r\n\t\t\tString fullXmlFilePath = invoiceService.getFullXmlFilePath(invoice, true);\r\n\t\t\tBoolean isVirtual = (Boolean) methodContext.get(\"isVirtual\");\r\n\r\n\t\t\t//ticket SUPS-2749\r\n\t\t\tupdateInvoiceDueDate(invoice);\r\n\r\n\t\t\tDocument document = xmlInvoiceCreatorScript.createDocument(invoice, isVirtual, true);\r\n\t\t\tadditionalInfos(document, invoice, \"CF_SUB_SF_DATA\");\r\n\t\t\tString defaultTemplateName = \"\";\r\n\t\t\tif (\"ADJ\".equals(invoice.getInvoiceType().getCode())) {\r\n\t\t\t\tSet<Invoice> linkedInvoices = invoice.getLinkedInvoices();\r\n\t\t\t\tif (linkedInvoices != null && !linkedInvoices.isEmpty()) {\r\n\t\t\t\t\tInvoice adjustedInvoice = linkedInvoices.iterator().next();\r\n\t\t\t\t\tdefaultTemplateName = adjustedInvoice.getInvoiceType().getCode();\r\n\t\t\t\t\tdocument.getDocumentElement().setAttribute(\"adjustedInvoiceDate\",\r\n\t\t\t\t\t\t\tDateUtils.formatDateWithPattern(adjustedInvoice.getInvoiceDate(), \"dd/MM/yyyy\"));\r\n\t\t\t\t\tcreateSubscriptionsSection(document, adjustedInvoice);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tList<RatedTransaction> rts = ratedTransactionService.getRatedTransactionsByInvoice(invoice, true);\r\n\t\t\t\t\tfor (RatedTransaction rt : rts) {\r\n\t\t\t\t\t\tif (isAboCharge(rt)) {\r\n\t\t\t\t\t\t\tdefaultTemplateName = \"REC\";\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (\"\".equals(defaultTemplateName)) {\r\n\t\t\t\t\t\tdefaultTemplateName = \"UPF\";\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tlog.info(\"defaultTemplateName:\" + defaultTemplateName);\r\n\t\t\tboolean isAdjInvoice = invoice.getInvoiceType().getCode().equals(\"ADJ\");\r\n\t\t\tif (\"REC\".equals(invoice.getInvoiceType().getCode()) || \"REC\".equals(defaultTemplateName)) {\r\n\t\t\t\taddDetailREC(document, invoice, isAdjInvoice);\r\n\t\t\t\taddTotalLInesREC(document, invoice, isAdjInvoice);\r\n\t\t\t}\r\n\t\t\tif (\"UPF\".equals(invoice.getInvoiceType().getCode()) || \"UPF\".equals(defaultTemplateName)) {\r\n\t\t\t\taddDetailUPF(document, invoice, isAdjInvoice);\r\n\t\t\t\taddRefsMats(document);\r\n\t\t\t\taddTotalLInesUPF(document, invoice, isAdjInvoice);\r\n\t\t\t}\r\n\r\n\t\t\tFile file = xmlInvoiceCreatorScript.createFile(document, invoice, fullXmlFilePath);\r\n\t\t\tmethodContext.put(Script.RESULT_VALUE, file);\r\n\t\t} catch (Exception e) {\r\n\t\t\te.printStackTrace();\r\n\t\t\tthrow new BusinessException(e.getMessage());\r\n\t\t}\r\n\t}\r\n\r\n\t// update invoice's due date. Mainly util for manuel invoices like of type ADJ\r\n\tprivate void updateInvoiceDueDate(Invoice invoice) {\r\n\t\tLong nbrJourDelay = (Long) invoice.getSubscription().getSeller().getCfValue(\"CF_SEL_PAY_NB_BUSI_DAYS\");\r\n\t\tDate dueDate = addBusinessDays(invoice.getInvoiceDate(), nbrJourDelay);\r\n\t\tinvoice.setDueDate(dueDate);\r\n\t\tinvoiceService.update(invoice);\r\n\t}\r\n\r\n\tprivate Date addBusinessDays(Date dateStart, Long nbDays) {\r\n\t\tint daysAdded = 0;\r\n\t\tDate endDate = dateStart;\r\n\t\twhile (daysAdded != nbDays.intValue()) {\r\n\t\t\tendDate = DateUtils.addDaysToDate(endDate, 1);\r\n\t\t\tif (calendarBankingService.isBankWorkingDate(endDate)) {\r\n\t\t\t\tdaysAdded++;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn DateUtils.setDateToEndOfDay(endDate);\r\n\t}\r\n\r\n\tprivate void addTotalLInesREC(Document document, Invoice invoice, boolean isAdjInvoice) {\r\n\t\tboolean isTotalHTEqualZero = round(invoice.getAmountWithoutTax()).equals(BigDecimal.ZERO);\r\n\t\tElement totauxElement = document.createElement(\"totauxElement\");\r\n\r\n\t\tBigDecimal netToPay = !isAdjInvoice ? invoice.getAmountWithoutTax() : invoice.getAmountWithoutTax().negate();\r\n\r\n\t\tElement totalHTLineElem = document.createElement(\"totalHT\");\r\n\t\ttotalHTLineElem.setAttribute(\"amount\",\r\n\t\t\t\troundFormat(!isAdjInvoice ? invoice.getAmountWithoutTax() : invoice.getAmountWithoutTax().negate()));\r\n\t\ttotauxElement.appendChild(totalHTLineElem);\r\n\r\n\t\tList<TaxInvoiceAgregate> taxInvoiceAgregates = new ArrayList<TaxInvoiceAgregate>();\r\n\t\tfor (InvoiceAgregate invoiceAgregate : invoice.getInvoiceAgregates()) {\r\n\t\t\tif (invoiceAgregate instanceof TaxInvoiceAgregate) {\r\n\t\t\t\ttaxInvoiceAgregates.add((TaxInvoiceAgregate) invoiceAgregate);\r\n\t\t\t}\r\n\t\t}\r\n\t\ttaxInvoiceAgregates.sort(Comparator.comparing(ta -> ta.getTax().getPercent()));\r\n\t\tfor (TaxInvoiceAgregate taxInvoiceAgregate : taxInvoiceAgregates) {\r\n\r\n\t\t\tElement taxElem = document.createElement(\"tvaLine\");\r\n\r\n\t\t\ttaxElem.setAttribute(\"label\", \"TVA (\" + roundFormat(taxInvoiceAgregate.getTaxPercent(), true) + \"%)\");\r\n\t\t\tBigDecimal amountTax = computeAmountsForTaxes(rts, taxInvoiceAgregate.getTaxPercent())[1];\r\n\t\t\tamountTax = !isAdjInvoice ? amountTax : amountTax.negate();\r\n\t\t\ttaxElem.setAttribute(\"amount\",\r\n\t\t\t\t\t(isTotalHTEqualZero ? roundFormat(BigDecimal.ZERO) : roundFormat(amountTax)) + \" €\");\r\n\t\t\ttotauxElement.appendChild(taxElem);\r\n\r\n\t\t\tnetToPay = netToPay.add(isTotalHTEqualZero ? BigDecimal.ZERO : round(amountTax));\r\n\r\n\t\t}\r\n\t\tBigDecimal totalTTC = netToPay;\r\n\t\tElement totalTTCLineElem = document.createElement(\"totalTTC\");\r\n\t\ttotalTTCLineElem.setAttribute(\"amount\", roundFormat(totalTTC));\r\n\t\ttotauxElement.appendChild(totalTTCLineElem);\r\n\r\n\t\tBigDecimal totalUnpaidInvoices = getRappelSolde(invoice);\r\n\r\n\t\tif (totalUnpaidInvoices.compareTo(BigDecimal.ZERO) != 0) {\r\n\t\t\tElement totalLineElt = document.createElement(\"totalLine\");\r\n\r\n\t\t\ttotalLineElt.setAttribute(\"label\", \"Rappel du solde restant d\\u00FB\");\r\n\t\t\ttotalLineElt.setAttribute(\"amount\", roundFormat(totalUnpaidInvoices) + \" €\");\r\n\t\t\ttotauxElement.appendChild(totalLineElt);\r\n\t\t\tnetToPay = netToPay.add(round(totalUnpaidInvoices));\r\n\t\t}\r\n\r\n\t\tElement totalNetToPayElem = document.createElement(\"netToPay\");\r\n\r\n\t\ttotalNetToPayElem.setAttribute(\"amount\", roundFormat(netToPay));\r\n\t\ttotauxElement.appendChild(totalNetToPayElem);\r\n\r\n\t\tdocument.getElementsByTagName(\"invoice\").item(0).appendChild(totauxElement);\r\n\r\n\t}\r\n\r\n\tprivate BigDecimal getRappelSolde(Invoice invoice) {\r\n\r\n\t\tList<AccountOperation> aos = (List<AccountOperation>) accountOperationService\r\n\t\t\t\t.executeSelectQuery(\"select ao from AccountOperation ao where (ao.reference is null or ao.reference != '\" + invoice.getInvoiceNumber()\r\n\t\t\t\t\t\t+ \"' )and ao.matchingStatus in ('O','P' ) and ao.customerAccount.id = \"\r\n\t\t\t\t\t\t+ invoice.getBillingAccount().getCustomerAccount().getId() + \" order by ao.id\", null);\r\n\r\n\t\tBigDecimal totalUnpaidInvoices = BigDecimal.ZERO;\r\n\t\tfor (AccountOperation ao : aos) {\t\t\t\r\n\t\t\tOperationCategoryEnum invOpCat = ao.getTransactionCategory();\r\n\r\n\t\t\ttotalUnpaidInvoices = totalUnpaidInvoices\r\n\t\t\t\t\t.add(invOpCat == OperationCategoryEnum.DEBIT ? ao.getUnMatchingAmount()\r\n\t\t\t\t\t\t\t: ao.getUnMatchingAmount().negate());\r\n\r\n\t\t}\r\n\t\treturn totalUnpaidInvoices;\r\n\t}\r\n\r\n\tprivate void addTotalLInesUPF(Document document, Invoice invoice, boolean isAdjInvoice) {\r\n\t\tElement totauxElement = document.createElement(\"totauxElement\");\r\n\r\n\t\tBigDecimal netToPay = !isAdjInvoice ? invoice.getAmountWithoutTax() : invoice.getAmountWithoutTax().negate();\r\n\r\n\t\tElement totalHTLineElem = document.createElement(\"totalLine\");\r\n\t\ttotalHTLineElem.setAttribute(\"name\", \"Total HT\");\r\n\t\ttotalHTLineElem.setAttribute(\"amount\",\r\n\t\t\t\troundFormat(!isAdjInvoice ? invoice.getAmountWithoutTax() : invoice.getAmountWithoutTax().negate()));\r\n\t\ttotauxElement.appendChild(totalHTLineElem);\r\n\r\n\t\tList<TaxInvoiceAgregate> taxInvoiceAgregates = new ArrayList<TaxInvoiceAgregate>();\r\n\t\tfor (InvoiceAgregate invoiceAgregate : invoice.getInvoiceAgregates()) {\r\n\t\t\tif (invoiceAgregate instanceof TaxInvoiceAgregate) {\r\n\t\t\t\ttaxInvoiceAgregates.add((TaxInvoiceAgregate) invoiceAgregate);\r\n\t\t\t}\r\n\t\t}\r\n\t\ttaxInvoiceAgregates.sort(Comparator.comparing(ta -> ta.getTax().getPercent()));\r\n\t\tfor (TaxInvoiceAgregate taxInvoiceAgregate : taxInvoiceAgregates) {\r\n\r\n\t\t\tElement taxElem = document.createElement(\"totalLine\");\r\n\r\n\t\t\ttaxElem.setAttribute(\"name\", \"TVA (\" + roundFormat(taxInvoiceAgregate.getTaxPercent(), true) + \"%)\");\r\n\t\t\tBigDecimal amountTax = computeAmountsForTaxes(rts, taxInvoiceAgregate.getTaxPercent())[1];\r\n\t\t\tamountTax = !isAdjInvoice ? amountTax : amountTax.negate();\r\n\t\t\ttaxElem.setAttribute(\"amount\", roundFormat(amountTax));\r\n\t\t\ttotauxElement.appendChild(taxElem);\r\n\r\n\t\t\tnetToPay = netToPay.add(round(amountTax));\r\n\r\n\t\t}\r\n\t\tBigDecimal totalTTC = netToPay;\r\n\t\tElement totalTTCLineElem = document.createElement(\"totalLine\");\r\n\t\ttotalTTCLineElem.setAttribute(\"name\", \"Total facture TTC\");\r\n\t\ttotalTTCLineElem.setAttribute(\"amount\", roundFormat(totalTTC));\r\n\t\ttotauxElement.appendChild(totalTTCLineElem);\r\n\r\n\t\tBigDecimal totalUnpaidInvoices = getRappelSolde(invoice);\r\n\t\tif (totalUnpaidInvoices.compareTo(BigDecimal.ZERO) != 0) {\r\n\t\t\tElement totalLineElt = document.createElement(\"totalLine\");\r\n\r\n\t\t\ttotalLineElt.setAttribute(\"name\", \"Rappel du solde restant d\\u00FB\");\r\n\t\t\ttotalLineElt.setAttribute(\"amount\", roundFormat(totalUnpaidInvoices));\r\n\t\t\ttotauxElement.appendChild(totalLineElt);\r\n\t\t\tnetToPay = netToPay.add(round(totalUnpaidInvoices));\r\n\t\t\tElement totalLineElem = document.createElement(\"totalLine\");\r\n\t\t\ttotalLineElem.setAttribute(\"name\",\r\n\t\t\t\t\tnetToPay.compareTo(BigDecimal.ZERO) >= 0 ? \"Total \\u00E0 payer TTC\" : \"Total en votre faveur TTC\");\r\n\t\t\ttotalLineElem.setAttribute(\"amount\", roundFormat(netToPay));\r\n\t\t\ttotauxElement.appendChild(totalLineElem);\r\n\t\t}\r\n\r\n\t\tdocument.getElementsByTagName(\"invoice\").item(0).appendChild(totauxElement);\r\n\r\n\t}\r\n\r\n\tprivate void addDetailREC(Document document, Invoice invoice, boolean isAdjInvoice) {\r\n\r\n\t\tElement detailREC = document.createElement(\"detailREC\");\r\n\t\tif (getPaymentMethodType(invoice) != null) {\r\n\t\t\tdetailREC.setAttribute(\"paymentMethod\", getPaymentMethodType(invoice).name());\r\n\t\t}\r\n\t\tList<RatedTransaction> rts = (List<RatedTransaction>) ratedTransactionService\r\n\t\t\t\t.executeSelectQuery(\"select rt from RatedTransaction rt where rt.invoice.id=\" + invoice.getId()\r\n\t\t\t\t\t\t+ \" and rt.amountWithTax != 0 order by rt.startDate asc, rt.description\", null);\r\n\t\tfor (RatedTransaction rt : rts) {\r\n\t\t\tElement linElem = document.createElement(\"lineREC\");\r\n\t\t\tif (rt.getCode().startsWith(\"CH_REC\")) {\r\n\t\t\t\tlinElem.setAttribute(\"label1\", rt.getDescription() + \" du \");\r\n\t\t\t\tlinElem.setAttribute(\"label2\", DateUtils.formatDateWithPattern(rt.getStartDate(), \"dd/MM/yyyy\") + \" au \"\r\n\t\t\t\t\t\t+ DateUtils.formatDateWithPattern(DateUtils.addDaysToDate(rt.getEndDate(), -1), \"dd/MM/yyyy\"));\r\n\t\t\t} else {\r\n\t\t\t\tlinElem.setAttribute(\"label1\", rt.getDescription());\r\n\t\t\t}\r\n\t\t\tlinElem.setAttribute(\"unitAmountWithoutTax\", roundFormat(rt.getUnitAmountWithoutTax()));\r\n\t\t\tlinElem.setAttribute(\"taxPercent\", roundFormat(rt.getTaxPercent(), true) + \" %\");\r\n\t\t\tlinElem.setAttribute(\"unitAmountWithTax\", roundFormat(rt.getUnitAmountWithTax()));\r\n\t\t\tlinElem.setAttribute(\"quantity\", roundFormat(!isAdjInvoice ? rt.getQuantity() : rt.getQuantity().negate()));\r\n\t\t\tlinElem.setAttribute(\"amountWithTax\",\r\n\t\t\t\t\troundFormat(!isAdjInvoice ? rt.getAmountWithTax() : rt.getAmountWithTax().negate()));\r\n\t\t\tdetailREC.appendChild(linElem);\r\n\t\t}\r\n\r\n\t\tdocument.getElementsByTagName(\"invoice\").item(0).appendChild(detailREC);\r\n\r\n\t}\r\n\r\n\tprivate BigDecimal[] computeAmounts(List<RatedTransaction> rts, String subCatCode) {\r\n\r\n\t\tBigDecimal[] amounts = new BigDecimal[3];\r\n\t\tamounts[0] = BigDecimal.ZERO;\r\n\t\tamounts[1] = BigDecimal.ZERO;\r\n\t\tamounts[2] = BigDecimal.ZERO;\r\n\r\n\t\tfor (RatedTransaction rt : rts) {\r\n\t\t\tif (subCatCode.equals(rt.getInvoiceSubCategory().getCode())) {\r\n\t\t\t\tamounts[0] = amounts[0].add(round(rt.getAmountWithoutTax()));\r\n\t\t\t\tamounts[1] = amounts[1].add(round(rt.getAmountTax()));\r\n\t\t\t\tamounts[2] = amounts[2].add(round(rt.getAmountWithTax()));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn amounts;\r\n\t}\r\n\r\n\tprivate List<RatedTransaction> getRTsBySubCatCode(List<RatedTransaction> rts, String subCatCode) {\r\n\r\n\t\tList<RatedTransaction> rtsBySubCat = new ArrayList<>();\r\n\r\n\t\tfor (RatedTransaction rt : rts) {\r\n\t\t\tif (subCatCode.equals(rt.getInvoiceSubCategory().getCode())) {\r\n\t\t\t\trtsBySubCat.add(rt);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn rtsBySubCat;\r\n\t}\r\n\r\n\tprivate Element addLineUPF(Document document, String label, String taxPercent, BigDecimal unitHt,\r\n\t\t\tBigDecimal unitTtc, BigDecimal quantity, BigDecimal ttc, boolean isAdjInvoice) {\r\n\t\tElement linElem = document.createElement(\"lineUPF\");\r\n\r\n\t\tlinElem.setAttribute(\"label\", label);\r\n\r\n\t\tlinElem.setAttribute(\"unitAmountWithoutTax\", unitHt == null ? \"-\" : roundFormat(unitHt));\r\n\t\tlinElem.setAttribute(\"taxPercent\", taxPercent == null ? \"-\" : (taxPercent + \" %\"));\r\n\t\tlinElem.setAttribute(\"unitAmountWithTax\", unitTtc == null ? \"-\" : roundFormat(unitTtc));\r\n\t\tlinElem.setAttribute(\"quantity\",\r\n\t\t\t\tquantity == null ? \"-\" : roundFormat(!isAdjInvoice ? quantity : quantity.negate()));\r\n\t\tlinElem.setAttribute(\"amountWithTax\", ttc == null ? \"-\" : roundFormat(!isAdjInvoice ? ttc : ttc.negate()));\r\n\t\treturn linElem;\r\n\r\n\t}\r\n\r\n\tprivate void addDetailUPF(Document document, Invoice invoice, boolean isAdjInvoice) {\r\n\t\tElement detailUPF = document.createElement(\"detailUPF\");\r\n\t\tif (getPaymentMethodType(invoice) != null) {\r\n\t\t\tdetailUPF.setAttribute(\"paymentMethod\", getPaymentMethodType(invoice).name());\r\n\t\t}\r\n\t\tList<RatedTransaction> rts = ratedTransactionService.getRatedTransactionsByInvoice(invoice, true);\r\n\r\n\t\tBigDecimal[] amountsMat = computeAmounts(rts, \"ISCAT_EKKO_MAT_VENTE\");\r\n\t\tBigDecimal[] amountsDEEE = computeAmounts(rts, \"ISCAT_EKKO_DEEE\");\r\n\t\tBigDecimal[] amountsInstall = computeAmounts(rts, \"ISCAT_EKKO_INSTALL\");\r\n\t\tBigDecimal[] amountsDEEERemise = computeAmounts(rts, \"ISCAT_EKKO_DEEE_REMISE\");\r\n\t\tBigDecimal[] amountsRemiseInstal = computeAmounts(rts, \"ISCAT_EKKO_INSTALL_REMISE\");\r\n\t\tBigDecimal[] amountsRemiseMat = computeAmounts(rts, \"ISCAT_EKKO_MAT_REMISE\");\r\n\t\tBigDecimal[] amountsGest = computeAmounts(rts, \"ISCAT_EKKO_INSTALL_GEST\");\r\n\r\n\t\tBigDecimal total = round(amountsInstall[2]).add(round(amountsMat[2]).add(round(amountsDEEE[2])));\r\n\t\tif (total.compareTo(BigDecimal.ZERO) != 0) {\r\n\t\t\tdetailUPF.appendChild(addLineUPF(document,\r\n\t\t\t\t\t\"Fourniture et pose de programmateurs d’intermittence de marque ENGIE sur \" + nbrOfRadiotor\r\n\t\t\t\t\t\t\t+ \" radiateurs existants \",\r\n\t\t\t\t\tnull, null, round(total), BigDecimal.ONE, round(total), isAdjInvoice));\r\n\r\n\t\t\tfor (RatedTransaction rt : getRTsBySubCatCode(rts, \"ISCAT_EKKO_MAT_VENTE\")) {\r\n\t\t\t\tdetailUPF.appendChild(\r\n\t\t\t\t\t\taddLineUPF(document, \"\\tdont \" + rt.getDescription(), \"5,5\", rt.getUnitAmountWithoutTax(),\r\n\t\t\t\t\t\t\t\trt.getUnitAmountWithTax(), rt.getQuantity(), rt.getAmountWithTax(), isAdjInvoice));\r\n\t\t\t}\r\n\t\t\tfor (RatedTransaction rt : getRTsBySubCatCode(rts, \"ISCAT_EKKO_INSTALL\")) {\r\n\t\t\t\tdetailUPF.appendChild(\r\n\t\t\t\t\t\taddLineUPF(document, \"\\tdont \" + rt.getDescription(), \"5,5\", rt.getUnitAmountWithoutTax(),\r\n\t\t\t\t\t\t\t\trt.getUnitAmountWithTax(), rt.getQuantity(), rt.getAmountWithTax(), isAdjInvoice));\r\n\t\t\t}\r\n\t\t\tfor (RatedTransaction rt : getRTsBySubCatCode(rts, \"ISCAT_EKKO_DEEE\")) {\r\n\t\t\t\tdetailUPF.appendChild(\r\n\t\t\t\t\t\taddLineUPF(document, \"\\tdont \" + rt.getDescription(), \"20\", rt.getUnitAmountWithoutTax(),\r\n\t\t\t\t\t\t\t\trt.getUnitAmountWithTax(), rt.getQuantity(), rt.getAmountWithTax(), isAdjInvoice));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tBigDecimal totalRemise = round(amountsRemiseInstal[2]).add(round(amountsRemiseMat[2]))\r\n\t\t\t\t.add(round(amountsDEEERemise[2]));\r\n\t\tif (totalRemise.compareTo(BigDecimal.ZERO) != 0) {\r\n\t\t\tdetailUPF.appendChild(addLineUPF(document, \"Remise\", null, null, round(totalRemise), BigDecimal.ONE,\r\n\t\t\t\t\tround(totalRemise), isAdjInvoice));\r\n\r\n\t\t\tfor (RatedTransaction rt : getRTsBySubCatCode(rts, \"ISCAT_EKKO_MAT_REMISE\")) {\r\n\t\t\t\tdetailUPF.appendChild(\r\n\t\t\t\t\t\taddLineUPF(document, \"\\tdont \" + rt.getDescription(), \"5,5\", rt.getUnitAmountWithoutTax(),\r\n\t\t\t\t\t\t\t\trt.getUnitAmountWithTax(), rt.getQuantity(), rt.getAmountWithTax(), isAdjInvoice));\r\n\t\t\t}\r\n\t\t\tfor (RatedTransaction rt : getRTsBySubCatCode(rts, \"ISCAT_EKKO_INSTALL_REMISE\")) {\r\n\t\t\t\tdetailUPF.appendChild(\r\n\t\t\t\t\t\taddLineUPF(document, \"\\tdont \" + rt.getDescription(), \"5,5\", rt.getUnitAmountWithoutTax(),\r\n\t\t\t\t\t\t\t\trt.getUnitAmountWithTax(), rt.getQuantity(), rt.getAmountWithTax(), isAdjInvoice));\r\n\t\t\t}\r\n\t\t\tfor (RatedTransaction rt : getRTsBySubCatCode(rts, \"ISCAT_EKKO_DEEE_REMISE\")) {\r\n\t\t\t\tdetailUPF.appendChild(\r\n\t\t\t\t\t\taddLineUPF(document, \"\\tdont \" + rt.getDescription(), \"20\", rt.getUnitAmountWithoutTax(),\r\n\t\t\t\t\t\t\t\trt.getUnitAmountWithTax(), rt.getQuantity(), rt.getAmountWithTax(), isAdjInvoice));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (amountsGest[0].compareTo(BigDecimal.ZERO) != 0) {\r\n\t\t\tfor (RatedTransaction rt : getRTsBySubCatCode(rts, \"ISCAT_EKKO_INSTALL_GEST\")) {\r\n\t\t\t\tdetailUPF.appendChild(addLineUPF(document, rt.getDescription(), \"5,5\", rt.getUnitAmountWithoutTax(),\r\n\t\t\t\t\t\trt.getUnitAmountWithTax(), rt.getQuantity(), rt.getAmountWithTax(), isAdjInvoice));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tdocument.getElementsByTagName(\"invoice\").item(0).appendChild(detailUPF);\r\n\r\n\t}\r\n\r\n\tpublic Element addMaterielLine(Document document, String name, String reference) {\r\n\t\tElement linElem = document.createElement(\"mat\");\r\n\t\tlinElem.setAttribute(\"name\", name);\r\n\t\tlinElem.setAttribute(\"reference\", reference);\r\n\t\treturn linElem;\r\n\t}\r\n\r\n\tprivate void addRefsMats(Document document) {\r\n\t\tElement refsMats = document.createElement(\"refsMats\");\r\n\t\trefsMats.appendChild(\r\n\t\t\t\taddMaterielLine(document, \"1 prise communicante « Mbox »\", \"(référence K02-GM-01.0013E-C-ETH)\"));\r\n\t\trefsMats.appendChild(addMaterielLine(document, nbrOfRadiotor + \" modules de pilotage « Dbox »\",\r\n\t\t\t\t\"(référence K01-CDK-01.1016-01-P1/TIK)\"));\r\n\t\trefsMats.appendChild(addMaterielLine(document, nbrOfRooms + \" capteurs de température « Sense-3 »\",\r\n\t\t\t\t\"(référence K02-CASTH-01.1004-01/TIK-WH)\"));\r\n\t\trefsMats.appendChild(addMaterielLine(document, \"1 câble Ethernet de longueur 5m\", \"(référence CA-ETHC2)\"));\r\n\r\n\t\tdocument.getElementsByTagName(\"invoice\").item(0).appendChild(refsMats);\r\n\t}\r\n\r\n\tprivate void additionalInfos(Document document, Invoice invoice, String cfName) {\r\n\r\n\t\tElement additionalFields = document.createElement(\"additionalFields\");\r\n\r\n\t\tSubscription sub = invoice.getSubscription();\r\n\t\tMap<String, String> sfDataMap = (Map<String, String>) sub.getCfValue(cfName);\r\n\t\tif (sfDataMap != null) {\r\n\t\t\tfor (Map.Entry<String, String> entry : sfDataMap.entrySet()) {\r\n\t\t\t\tif (SHIPPING_ADDRESS.equals(entry.getKey())) {\r\n\t\t\t\t\textractShippingAddress(document, additionalFields, entry.getValue());\r\n\t\t\t\t} else {\r\n\t\t\t\t\tElement entryElem = document.createElement(entry.getKey());\r\n\t\t\t\t\tentryElem.setTextContent(entry.getValue());\r\n\t\t\t\t\tadditionalFields.appendChild(entryElem);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (sfDataMap.get(CF_NbrOfRadiator) != null) {\r\n\t\t\t\tnbrOfRadiotor = Long.valueOf(sfDataMap.get(CF_NbrOfRadiator));\r\n\t\t\t}\r\n\t\t\tif (sfDataMap.get(CF_NbrOfRooms) != null) {\r\n\t\t\t\tnbrOfRooms = Long.valueOf(sfDataMap.get(CF_NbrOfRooms));\r\n\t\t\t}\r\n\t\t}\r\n\t\tElement dateInsElem = document.createElement(\"CF_SUB_DATE_INSTALL\");\r\n\t\tdateInsElem.setTextContent(\r\n\t\t\t\tDateUtils.formatDateWithPattern((Date) sub.getCfValue(\"CF_SUB_DATE_INSTALL\"), \"dd/MM/yyyy\"));\r\n\t\tadditionalFields.appendChild(dateInsElem);\r\n\r\n\t\tElement nbDaysElem = document.createElement(\"CF_SEL_PAY_NB_BUSI_DAYS\");\r\n\t\tnbDaysElem.setTextContent(\"\" + (Long) sub.getSeller().getCfValue(\"CF_SEL_PAY_NB_BUSI_DAYS\"));\r\n\t\tadditionalFields.appendChild(nbDaysElem);\r\n\r\n\t\tdocument.getElementsByTagName(\"invoice\").item(0).appendChild(additionalFields);\r\n\t}\r\n\r\n\tprivate BigDecimal round(BigDecimal amount) {\r\n\t\treturn round(amount, false);\r\n\t}\r\n\r\n\tprivate BigDecimal round(BigDecimal amount, boolean stripTrailingZeros) {\r\n\t\tif (amount == null) {\r\n\t\t\tamount = BigDecimal.ZERO;\r\n\t\t}\r\n\t\tint scale = 2;\r\n\r\n\t\tamount = amount.setScale(scale, RoundingMode.HALF_UP);\r\n\t\tif (stripTrailingZeros) {\r\n\t\t\tamount = amount.stripTrailingZeros();\r\n\t\t}\r\n\t\treturn amount;\r\n\t}\r\n\r\n\tprivate String roundFormat(BigDecimal amount) {\r\n\t\treturn String.valueOf(round(amount, false).toPlainString()).replaceAll(\"\\\\.\", \",\");\r\n\t}\r\n\r\n\tprivate String roundFormat(BigDecimal amount, boolean stripTrailingZeros) {\r\n\t\treturn String.valueOf(round(amount, stripTrailingZeros).toPlainString()).replaceAll(\"\\\\.\", \",\");\r\n\t}\r\n\r\n\tprivate PaymentMethodEnum getPaymentMethodType(Invoice invoice) {\r\n\t\tString paymentMethod = (String) invoice.getSubscription().getCfValue(CF_SUB_PAY_METHOD);\r\n\t\tPaymentMethodEnum paymentMethodEnumCommande = null;\r\n\t\tif (paymentMethod != null) {\r\n\t\t\tpaymentMethodEnumCommande = PaymentMethodEnum.valueOf(paymentMethod);\r\n\t\t}\r\n\t\tPaymentMethodEnum paymentMethodEnumCustomer = invoice.getBillingAccount().getCustomerAccount()\r\n\t\t\t\t.getPreferredPaymentMethodType();\r\n\r\n\t\tif (paymentMethodEnumCommande == PaymentMethodEnum.DIRECTDEBIT\r\n\t\t\t\t&& paymentMethodEnumCustomer != PaymentMethodEnum.DIRECTDEBIT) {\r\n\t\t\treturn PaymentMethodEnum.CARD;\r\n\t\t}\r\n\t\treturn paymentMethodEnumCommande;\r\n\r\n\t}\r\n\r\n\tprivate BigDecimal[] computeAmountsForTaxes(List<RatedTransaction> rts, BigDecimal taxPercent) {\r\n\r\n\t\tBigDecimal[] amounts = new BigDecimal[3];\r\n\t\tamounts[0] = BigDecimal.ZERO;\r\n\t\tamounts[1] = BigDecimal.ZERO;\r\n\t\tamounts[2] = BigDecimal.ZERO;\r\n\r\n\t\tfor (RatedTransaction rt : rts) {\r\n\t\t\tif (taxPercent.compareTo(rt.getTaxPercent()) == 0) {\r\n\t\t\t\tamounts[0] = amounts[0].add(round(rt.getAmountWithoutTax()));\r\n\t\t\t\tamounts[1] = amounts[1].add(round(rt.getAmountTax()));\r\n\t\t\t\tamounts[2] = amounts[2].add(round(rt.getAmountWithTax()));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn amounts;\r\n\t}\r\n\r\n\tprivate void extractShippingAddress(Document document, Element additionalFields, String shippingAddress) {\r\n\r\n\t\tif (!StringUtils.isBlank(shippingAddress)) {\r\n\t\t\tMatcher m = Pattern.compile(\"\\\\d{5}\").matcher(shippingAddress);\r\n\t\t\tString zipCode = null;\r\n\t\t\tString[] address = null;\r\n\t\t\tif (m.find()) {\r\n\t\t\t\tzipCode = m.group(0);\r\n\t\t\t}\r\n\t\t\tif (zipCode != null) {\r\n\t\t\t\taddress = shippingAddress.split(zipCode, shippingAddress.length());\r\n\t\t\t\tElement addressElement = document.createElement(SHIPPING_ADDRESS);\r\n\t\t\t\taddressElement.setTextContent(address[0]);\r\n\t\t\t\tadditionalFields.appendChild(addressElement);\r\n\r\n\t\t\t\tElement zipCodeElement = document.createElement(\"zipCode\");\r\n\t\t\t\tzipCodeElement.setTextContent(zipCode);\r\n\t\t\t\tadditionalFields.appendChild(zipCodeElement);\r\n\r\n\t\t\t\tElement cityElement = document.createElement(\"city\");\r\n\t\t\t\tcityElement.setTextContent(address[1]);\r\n\t\t\t\tadditionalFields.appendChild(cityElement);\r\n\t\t\t} else {\r\n\t\t\t\tElement shippingAddressElement = document.createElement(SHIPPING_ADDRESS);\r\n\t\t\t\tshippingAddressElement.setTextContent(shippingAddress);\r\n\t\t\t\tadditionalFields.appendChild(shippingAddressElement);\r\n\t\t\t}\r\n\r\n\t\t}\r\n\t}\r\n\r\n\tprivate boolean isAboCharge(RatedTransaction rt) {\r\n\t\treturn rt.getCode().startsWith(\"CH_REC\") || rt.getCode().indexOf(\"ABO\") > -1;\r\n\r\n\t}\r\n\r\n\tprivate void createSubscriptionsSection(Document doc, Invoice adjustedInvoice) {\r\n\t\tElement subscriptionsTag = doc.createElement(\"subscriptions\");\r\n\t\tSubscription subscription = adjustedInvoice.getBillingAccount().getUsersAccounts().get(0).getSubscriptions()\r\n\t\t\t\t.get(0);\r\n\r\n\t\tElement subscriptionTag = doc.createElement(\"subscription\");\r\n\t\tsubscriptionTag.setAttribute(\"id\", subscription.getId() + \"\");\r\n\t\tsubscriptionTag.setAttribute(\"code\", subscription.getCode());\r\n\t\tsubscriptionTag.setAttribute(\"description\", getDefaultIfNull(subscription.getDescription(), \"\"));\r\n\t\tsubscriptionTag.setAttribute(\"offerCode\", subscription.getOffer().getCode());\r\n\t\tElement subscriptionDateTag = doc.createElement(\"subscriptionDate\");\r\n\t\tsubscriptionDateTag.appendChild(\r\n\t\t\t\tcreateTextNode(doc, DateUtils.formatDateWithPattern(subscription.getSubscriptionDate(), \"dd/MM/yyyy\")));\r\n\t\tsubscriptionTag.appendChild(subscriptionDateTag);\r\n\t\tElement endAgreementTag = doc.createElement(\"endAgreementDate\");\r\n\t\tendAgreementTag.appendChild(createTextNode(doc,\r\n\t\t\t\tDateUtils.formatDateWithPattern(subscription.getEndAgreementDate(), \"yyyy-MM-dd'T'HH:mm:ss\")));\r\n\t\tsubscriptionTag.appendChild(endAgreementTag);\r\n\t\tsubscriptionsTag.appendChild(subscriptionTag);\r\n\r\n\t\tdoc.getElementsByTagName(\"userAccount\").item(0).appendChild(subscriptionsTag);\r\n\t}\r\n\r\n\tprivate Text createTextNode(Document doc, String data) {\r\n\t\tif (data != null) {\r\n\t\t\treturn doc.createTextNode(data);\r\n\t\t} else {\r\n\t\t\treturn doc.createTextNode(\"\");\r\n\t\t}\r\n\t}\r\n\r\n}\r\n]]>\r\n            </script>\r\n</ScriptInstance>\r\n\r\n"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "DueDateScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.invoicing.DueDateScript\" description=\"Ekko DueDateScript\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[ package com.opencellsoft.service.ekko.invoicing;\r\n\r\nimport java.util.Date;\r\n\r\nimport java.util.Map;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.model.admin.Seller;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.service.admin.impl.SellerService;\r\nimport org.meveo.service.catalog.impl.CalendarBankingService;\r\nimport org.meveo.service.script.Script;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n\r\n/**\r\n * \r\n * @author anasseh\r\n *\r\n */\r\n\r\npublic class DueDateScript extends Script {\r\n\r\n\tprivate static final long serialVersionUID = 1L;\r\n\tprivate static final String CF_SEL_PAY_NB_BUSI_DAYS = \"CF_SEL_PAY_NB_BUSI_DAYS\";\r\n\r\n\tprivate static final Logger log = LoggerFactory.getLogger(DueDateScript.class);\r\n\tprivate CalendarBankingService calendarBankingService = (CalendarBankingService) getServiceInterface(\"CalendarBankingService\");\r\n\tprivate SellerService sellerService = (SellerService) getServiceInterface(\"SellerService\");\r\n\r\n\t@Override\r\n\tpublic void execute(Map<String, Object> context) throws BusinessException {\r\n\t\tlog.info(\"Execute context : {} \", context);\r\n\t\tSeller seller = sellerService.findByCode(\"EKKO\");\r\n\t\tLong nbDaysDue = (Long) seller.getCfValue(CF_SEL_PAY_NB_BUSI_DAYS);\r\n\t\t\r\n\t\tDate dueDate = null;\r\n\t\tDate today = DateUtils.setDateToStartOfDay(new Date());\r\n\r\n\t\tdueDate = addBusinessDays(new Date(), nbDaysDue);\r\n\t\tDouble daysbetween = DateUtils.daysBetween(today, dueDate);\r\n\t\tlog.info(\"today:{} dueDate:{} \", today, dueDate, daysbetween.intValue());\r\n\r\n\t\tcontext.put(Script.RESULT_VALUE, daysbetween.intValue());\r\n\t}\r\n\r\n\tprivate Date addBusinessDays(Date dateStart, Long nbDays) {\r\n\r\n\t\tint daysAdded = 0;\r\n\t\tDate endDate = dateStart;\r\n\t\twhile (daysAdded != nbDays.intValue()) {\r\n\t\t\tendDate = DateUtils.addDaysToDate(endDate, 1);\r\n\t\t\tif (calendarBankingService.isBankWorkingDate(endDate)) {\r\n\t\t\t\tdaysAdded++;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn DateUtils.setDateToEndOfDay(endDate);\r\n\t}\r\n\r\n}\r\n]]>\r\n            </script>\r\n</ScriptInstance>\r\n\r\n"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CheckRoundingAmountsScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.invoicing.CheckRoundingAmountsScript\" description=\"CheckRoundingAmountsScript\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[              \r\npackage com.opencellsoft.service.ekko.invoicing;\r\n\r\nimport java.math.BigDecimal;\r\nimport java.math.RoundingMode;\r\nimport java.util.Date;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.commons.utils.StringUtils;\r\nimport org.meveo.model.billing.Invoice;\r\nimport org.meveo.model.billing.RatedTransaction;\r\nimport org.meveo.model.billing.SubCategoryInvoiceAgregate;\r\nimport org.meveo.model.payments.AccountOperation;\r\nimport org.meveo.model.payments.OperationCategoryEnum;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.service.billing.impl.InvoiceAgregateService;\r\nimport org.meveo.service.billing.impl.InvoiceService;\r\nimport org.meveo.service.billing.impl.RatedTransactionService;\r\nimport org.meveo.service.payments.impl.AccountOperationService;\r\nimport org.meveo.service.script.Script;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n/**\r\n *\r\n * \r\n * @author anasseh\r\n * \r\n * 02/05/2023 SUPS-2461\r\n */\r\npublic class CheckRoundingAmountsScript extends Script {\r\n\r\n\tprivate static final long serialVersionUID = 1L;\r\n\tprivate static final Logger log = LoggerFactory.getLogger(CheckRoundingAmountsScript.class);\r\n\r\n\tprivate InvoiceService invoiceService = (InvoiceService) getServiceInterface(\"InvoiceService\");\r\n\tprivate RatedTransactionService ratedTransactionService = (RatedTransactionService) getServiceInterface(\"RatedTransactionService\");\t\r\n\tprivate InvoiceAgregateService invoiceAgregateService = (InvoiceAgregateService) getServiceInterface(\"InvoiceAgregateService\");\r\n\tprivate AccountOperationService accountOperationService = (AccountOperationService) getServiceInterface(\"AccountOperationService\");\r\n\t\r\n\t\r\n\t@Override\r\n\tpublic void execute(Map<String, Object> methodContext) throws BusinessException {\r\n\t\tlog.info(\"EXECUTE methodContext {}\", methodContext);\r\n\r\n\t\tInvoice invoice = invoiceService.refreshOrRetrieve((Invoice) methodContext.get(Script.CONTEXT_ENTITY));\r\n\t\tif (StringUtils.isBlank(invoice.getComment())) {\r\n\r\n\t\t\tList<RatedTransaction> rts = ratedTransactionService.getRatedTransactionsByInvoice(invoice, true);\r\n\t\t\tif(rts != null && !rts.isEmpty()) {\r\n\t\t\t\t\r\n\t\t\t\tBigDecimal[] amounts = computeAmounts(rts);\r\n\t\t\t\tinvoice.setAmountWithoutTax(amounts[0]);\r\n\t\t\t\tinvoice.setAmountTax(amounts[1]);\r\n\t\t\t\tinvoice.setAmountWithTax(amounts[2]);\r\n\t\t\t\t\r\n\t\t\t\tinvoice.setNetToPay(getNetToPay(invoice));\r\n\t\t\t\tinvoice.setComment(\"Checked\");\r\n\t\t\t\tList<SubCategoryInvoiceAgregate> listAggregateSub =  (List<SubCategoryInvoiceAgregate>) invoiceAgregateService.listByInvoiceAndType(invoice, \"F\");\t\t\t\t\r\n\t\t\t\tfor(SubCategoryInvoiceAgregate aggragte : listAggregateSub) {\r\n\t\t\t\t\tBigDecimal[] amountsAggregate = computeAmountsBySubCat(rts, aggragte.getInvoiceSubCategory().getCode());\t\t\t\t\t\r\n\t\t\t\t\taggragte.setAmountWithoutTax(amountsAggregate[0]);\r\n\t\t\t\t\taggragte.setAmountTax(amountsAggregate[1]);\r\n\t\t\t\t\taggragte.setAmountWithTax(amountsAggregate[2]);\t\t\t\t\t\r\n\t\t\t\t\tinvoiceAgregateService.update(aggragte);\r\n\t\t\t\t}\r\n\t\t\t\tinvoiceService.updateNoCheck(invoice);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t}\r\n\t\r\n\t\r\n\r\n\tprivate BigDecimal[] computeAmountsBySubCat(List<RatedTransaction> rts, String catCode) {\r\n\r\n        BigDecimal[] amounts = new BigDecimal[3];\r\n        amounts[0] = BigDecimal.ZERO;\r\n        amounts[1] = BigDecimal.ZERO;\r\n        amounts[2] = BigDecimal.ZERO;\r\n\r\n        for(RatedTransaction rt : rts) {\r\n            if(catCode.equals(rt.getInvoiceSubCategory().getCode())) {\r\n                amounts[0] = amounts[0].add(round(rt.getAmountWithoutTax()));\r\n                amounts[1] = amounts[1].add(round(rt.getAmountTax()));\r\n                amounts[2] = amounts[2].add(round(rt.getAmountWithTax()));\r\n            }\r\n        }\r\n\r\n        return amounts;\r\n    }\r\n\r\n\tprivate BigDecimal[] computeAmounts(List<RatedTransaction> rts) {\r\n\r\n\t\tBigDecimal[] amounts = new BigDecimal[3];\r\n\t\tamounts[0] = BigDecimal.ZERO;\r\n\t\tamounts[1] = BigDecimal.ZERO;\r\n\t\tamounts[2] = BigDecimal.ZERO;\r\n\r\n\t\tfor (RatedTransaction rt : rts) {\r\n\r\n\t\t\tamounts[0] = amounts[0].add(round(rt.getAmountWithoutTax()));\r\n\t\t\tamounts[1] = amounts[1].add(round(rt.getAmountTax()));\r\n\t\t\tamounts[2] = amounts[2].add(round(rt.getAmountWithTax()));\r\n\r\n\t\t}\r\n\r\n\t\treturn amounts;\r\n\t}\r\n\r\n\tprivate BigDecimal round(BigDecimal amount) {\r\n\t\treturn round(amount, false);\r\n\t}\r\n\r\n\tprivate BigDecimal round(BigDecimal amount, boolean stripTrailingZeros) {\r\n\t\tif (amount == null) {\r\n\t\t\tamount = BigDecimal.ZERO;\r\n\t\t}\r\n\t\tint scale = 2;\r\n\r\n\t\tamount = amount.setScale(scale, RoundingMode.HALF_UP);\r\n\t\tif (stripTrailingZeros) {\r\n\t\t\tamount = amount.stripTrailingZeros();\r\n\t\t}\r\n\t\treturn amount;\r\n\t}\r\n\tprivate BigDecimal getNetToPay(Invoice invoice) {\r\n\t\tMap<String, Object> params = new HashMap<String, Object>();\r\n\t\tparams.put(\"dueDateIN\", DateUtils.setDateToEndOfDay(DateUtils.addDaysToDate(new Date(), -1)));\r\n\r\n\t\tList<AccountOperation> aos = (List<AccountOperation>) accountOperationService\r\n\t\t\t\t.executeSelectQuery(\"select ao from AccountOperation ao where (ao.reference is null or ao.reference != '\" + invoice.getInvoiceNumber()\r\n\t\t\t\t\t\t+ \"' )and ao.matchingStatus in ('O','P' ) and ao.dueDate < :dueDateIN  and ao.customerAccount.id = \"\r\n\t\t\t\t\t\t+ invoice.getBillingAccount().getCustomerAccount().getId() + \" order by ao.id\", params);\r\n\r\n\t\tBigDecimal totalUnpaidInvoices = BigDecimal.ZERO;\r\n\t\tfor (AccountOperation ao : aos) {\t\t\t\r\n\t\t\tOperationCategoryEnum invOpCat = ao.getTransactionCategory();\r\n\r\n\t\t\ttotalUnpaidInvoices = totalUnpaidInvoices\r\n\t\t\t\t\t.add(invOpCat == OperationCategoryEnum.DEBIT ? ao.getUnMatchingAmount()\r\n\t\t\t\t\t\t\t: ao.getUnMatchingAmount().negate());\r\n\r\n\t\t}\r\n\t\t\r\n\t\treturn round(totalUnpaidInvoices).add(round(invoice.getAmountWithTax()));\r\n\t}\r\n}\r\n\r\n\r\n            \r\n\r\n]]>\r\n            </script>\r\n</ScriptInstance>\r\n\r\n"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						}
					]
				},
				{
					"name": "compta",
					"item": [
						{
							"name": "ExportRapsodieScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.compta.ExportRapsodieScript\" description=\"Ekko Export Rapsodie Script\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.compta;\r\n\r\n\r\nimport static org.apache.commons.lang.StringUtils.leftPad;\r\nimport static org.apache.commons.lang.StringUtils.rightPad;\r\n\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.math.BigDecimal;\r\nimport java.math.RoundingMode;\r\nimport java.text.DecimalFormat;\r\nimport java.time.LocalDate;\r\nimport java.util.ArrayList;\r\nimport java.util.Arrays;\r\nimport java.util.Date;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Locale;\r\nimport java.util.Map;\r\nimport java.util.Map.Entry;\r\nimport java.util.TreeMap;\r\n\r\nimport javax.persistence.NoResultException;\r\nimport javax.persistence.Query;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.commons.utils.ParamBean;\r\nimport org.meveo.commons.utils.QueryBuilder;\r\nimport org.meveo.commons.utils.StringUtils;\r\nimport org.meveo.model.billing.AccountingCode;\r\nimport org.meveo.model.billing.Invoice;\r\nimport org.meveo.model.billing.SubCategoryInvoiceAgregate;\r\nimport org.meveo.model.billing.Tax;\r\nimport org.meveo.model.billing.TaxInvoiceAgregate;\r\nimport org.meveo.model.crm.Provider;\r\nimport org.meveo.model.finance.AccountingEntry;\r\nimport org.meveo.model.jobs.JobInstance;\r\nimport org.meveo.model.payments.AccountOperation;\r\nimport org.meveo.model.payments.MatchingAmount;\r\nimport org.meveo.model.payments.MatchingCode;\r\nimport org.meveo.model.payments.OCCTemplate;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.model.tax.TaxClass;\r\nimport org.meveo.service.billing.impl.AccountingCodeService;\r\nimport org.meveo.service.billing.impl.InvoiceService;\r\nimport org.meveo.service.crm.impl.ProviderService;\r\nimport org.meveo.service.finance.AccountingWritingService;\r\nimport org.meveo.service.job.JobInstanceService;\r\nimport org.meveo.service.payments.impl.OCCTemplateService;\r\nimport org.meveo.service.script.Script;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\nimport com.google.common.base.Charsets;\r\nimport com.google.common.collect.Maps;\r\nimport com.google.common.io.Files;\r\nimport org.meveo.service.catalog.impl.InvoiceSubCategoryService;\r\nimport org.meveo.model.billing.InvoiceSubCategory;\r\nimport org.meveo.model.billing.InvoiceCategory;\r\nimport org.meveo.service.catalog.impl.InvoiceCategoryService;\r\n\r\n/**\r\n/**\r\n * @author myPower team , from dump PP 19/05/2021\r\n * \r\n * @author anasseh update for OC 11 and EKKO\r\n *\r\n */\r\n\r\npublic class ExportRapsodieScript extends Script {\r\n\r\n    private static final Logger log = LoggerFactory.getLogger(ExportRapsodieScript.class);\r\n\r\n    private static final String JOB_CODE = \"EkkoExportRapsodieJob\";\r\n    private static final String PREFIX = \"EKK\";\r\n    private static final String FOLDER_ID = \"G\";\r\n    private static final String ORGA_CODE = \"9856\";\r\n    private static final String OC_CODE = \"OCE\";\r\n    private static final String MANDANT = \"500\";\r\n    private static final String DEBIT = \"40\";\r\n    private static final String CREDIT = \"50\";\r\n    private static final String CAT_VENDING_CODE = \"ICAT_EKKO_INSTALL\";\r\n    private static final String CAT_VENDING_CODE_2 = \"ICAT_EKKO_ABO\";\r\n\r\n    \r\n    private static final String CAT_SERVICE_PROVISION_CODE = \"ICAT_EKKO_MATERIEL\";\r\n    private static final String CAT_PAY_CODE = \"PAY_FF\";\r\n\r\n    private static final String COSTL_MPM = \"VCA-AU-MPM\";\r\n    private static final String COSTL_MPI = \"VCA-AU-MPI\";\r\n    private static final String COSTL_PWBONIF = \"VM-PWBONIF\";\r\n    private static final String OCC_TEMP_CODE_REF_INV= \"REF_INV\";\r\n    private static final String OCC_TEMP_CODE_INV_STD= \"INV_STD\";\r\n    private static final String SKIP_CHAR = \"/\";\r\n    private static final String NEW_LINE = \"\\n\";\r\n    private static final String PAD_STR = \" \";\r\n    \r\n    private static final String  SELLER_CODE =\"EKKO\";\r\n    \r\n    private static final String SUB_CAT_DEE= \"ISCAT_EKKO_DEEE\";\r\n    private static final String COSTL_VCA_DE = \"VCA-DE-EKO\";\r\n    private static final String COSTL_VCA_MA = \"VCA-MA-EKO\";\r\n    private static final String COSTL_VCA_IN = \"VCA-IN-EKO\";\r\n    private static final String COSTL_VCA_SE = \"VCA-SE-EKO\";\r\n    private static final String ACCOUNT_1= \"706260\";\r\n    private static final String ACCOUNT_2= \"709300\";\r\n    private static final String ACCOUNT_3= \"706800\";\r\n\r\n    private enum EventEnum {\r\n        FACTURATION(\"Facturation\"),\r\n        ANNULATION_FACTURATION(\"Annulation Facturation\"),\r\n        PAY_DDT(\"Encaissement Prelevement\"),\r\n        PAY_CRD(\"Encaissement CB\"),\r\n        PAY_CHK(\"Encaissement Cheque\"),\r\n        PAY_TRF(\"Encaissement Virement\"),\r\n        PAY_FF(\"Bonifications d'interets - Autres Banques\"),\r\n        PAY_TIP(\"Encaissement Espece\"),\r\n        //REF_DDT(\"Décaissement Prelevement\"),\r\n        REF_DDT(\"Décaissement Virement\"),\r\n        REF_CHK(\"Décaissement Cheque\"),\r\n        REF_CRD(\"Décaissement CB\"),\r\n        REF_TRF(\"Décaissement Virement\"),\r\n        REF_TIP(\"Décaissement Espece\"),\r\n        REJ_DDT(\"Prelevement Rejeter\"),\r\n        REF_INV(\"Avoir sur Facturation\");\r\n        String label;\r\n\r\n        EventEnum(String label) {\r\n            this.label = label;\r\n        }\r\n\r\n        public String getLabel() {\r\n            return label;\r\n        }\r\n    }\r\n\r\n    private enum ZUONREnum {\r\n        INVOICE(\"FACTURE\"),\r\n        PAY_DDT(\"SDD\"),\r\n        REF_DDT(\"SDD\"),\r\n        PAY_CHK(\"CHQ\"),\r\n        REF_CHK(\"CHQ\"),\r\n        PAY_TIP(\"TIP\"),\r\n        REF_TIP(\"TIP\"),\r\n        PAY_CRD(\"CB\"),\r\n        PAY_TRF(\"TRF\"),\r\n        PAY_FF(\"FF\"),\r\n        REF_TRF(\"TRF\"),\r\n        REF_CRD(\"CB\"),\r\n        REF_INV(\"SDD\"),\r\n        REJ_DDT(\"SDD\");\r\n\r\n\r\n        String label;\r\n\r\n        ZUONREnum(String label) {\r\n            this.label = label;\r\n        }\r\n\r\n        public String getLabel() {\r\n            return label;\r\n        }\r\n    }\r\n\r\n\r\n    private InvoiceService invoiceService = (InvoiceService) getServiceInterface(\"InvoiceService\");\r\n    private JobInstanceService jobInstanceService = (JobInstanceService) getServiceInterface(\"JobInstanceService\");\r\n\r\n    private AccountingWritingService accountingWritingService = (AccountingWritingService) getServiceInterface(\"AccountingWritingService\");\r\n    private AccountingCodeService accountingCodeService = (AccountingCodeService) getServiceInterface(\"AccountingCodeService\");\r\n\r\n    private OCCTemplateService occTemplateService = (OCCTemplateService) getServiceInterface(\"OCCTemplateService\");\r\n    \r\n    private InvoiceSubCategoryService invoiceSubCategoryService = (InvoiceSubCategoryService) getServiceInterface(\"InvoiceSubCategoryService\");\r\n    private InvoiceCategoryService invoiceCategoryService = (InvoiceCategoryService) getServiceInterface(\"InvoiceCategoryService\");\r\n\r\n    private DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getInstance(Locale.FRENCH);\r\n    \r\n\r\n    private long coutJobExecution = 0l;\r\n\r\n    private StringBuilder contentBuilder = new StringBuilder();\r\n\r\n    private static class Zone {\r\n        int lg;\r\n        String value;\r\n        String padStr = PAD_STR;\r\n        boolean leftPad = false;\r\n\r\n        public Zone(int lg, String value) {\r\n            this.lg = lg;\r\n            this.value = value;\r\n        }\r\n\r\n        public Zone(int lg, String value, String padStr, boolean leftPad) {\r\n            this.lg = lg;\r\n            this.value = value;\r\n            this.padStr = padStr;\r\n            this.leftPad = leftPad;\r\n        }\r\n    }\r\n\r\n    @Override\r\n    public void execute(Map<String, Object> context) throws BusinessException {\r\n    \t\r\n    \t Date lastExecutionDate = new Date(1);\r\n\r\n      //Date lastExecutionDate = DateUtils.setDateToStartOfDay(DateUtils.addDaysToDate(new Date(), -1));\r\n      \r\n    \r\n      \r\n\r\n        decimalFormat.setDecimalSeparatorAlwaysShown(true);\r\n        decimalFormat.setGroupingUsed(false);\r\n        decimalFormat.setMinimumFractionDigits(2);\r\n\r\n        log.info(\"Execute ExportRapsodie - Context: {}\", context);\r\n        Provider appProvider = ((ProviderService) getServiceInterface(\"ProviderService\")).getProvider();\r\n        String fileNameParam = (String) context.get(\"fileName\");\r\n        String outputDirParam = (String) context.get(\"outputDir\");\r\n        String archivedDirParam = (String) context.get(\"archivedDir\");\r\n\r\n        String chrootDir = ParamBean.getInstance().getChrootDir(appProvider.getCode());\r\n        String absoluteOutputFileName = chrootDir;\r\n        String absoluteArchivedFileName = chrootDir;\r\n        if (!StringUtils.isBlank(outputDirParam)) {\r\n            absoluteOutputFileName += File.separator + outputDirParam.replaceAll(\"\\\\..\", \"\");\r\n        }\r\n        if (!StringUtils.isBlank(archivedDirParam)) {\r\n            absoluteArchivedFileName += File.separator + archivedDirParam.replaceAll(\"\\\\..\", \"\");\r\n        }\r\n\r\n        // make dir if doesnt exist\r\n        File outputDir = new File(absoluteOutputFileName);\r\n        if (!outputDir.exists()) {\r\n            outputDir.mkdirs();\r\n        }\r\n        File archivedDir = new File(absoluteArchivedFileName);\r\n        if (!archivedDir.exists()) {\r\n            archivedDir.mkdirs();\r\n        }\r\n\r\n        // file name\r\n        if (!StringUtils.isBlank(fileNameParam)) {\r\n            absoluteOutputFileName += File.separator + fileNameParam;\r\n            absoluteArchivedFileName += File.separator + fileNameParam;\r\n        } else {\r\n        \tabsoluteOutputFileName += File.separator + OC_CODE + \"_\" + ORGA_CODE + \"_\" + DateUtils.formatDateWithPattern(new Date(), \"ddMMyyyy_HHmmss\");\r\n        \tabsoluteArchivedFileName += File.separator + OC_CODE + \"_\" + ORGA_CODE + \"_\" + DateUtils.formatDateWithPattern(new Date(), \"ddMMyyyy_HHmmss\");\r\n        }\r\n\r\n        // 0 : batch input (BGR00)\r\n        buildBGR00();\r\n        contentBuilder.append(NEW_LINE);\r\n\r\n        int index = 1;\r\n        int index2 = index;\r\n\r\n        List<String> lines = new ArrayList<String>();\r\n        Map<String, AccountingEntry> invoiceWritings = getInvoiceWritings();\r\n        log.info(\"invoiceWritings.size() : \" + invoiceWritings.size());\r\n        for (Entry<String, AccountingEntry> entry : invoiceWritings.entrySet()) {\r\n            log.info(\"key = {}\", entry.getKey());\r\n            log.debug(\"key = {}\", entry.getKey());\r\n\r\n            AccountingEntry invoiceWriting = entry.getValue();\r\n            Map<String, AccountingEntry> invoiceSubcatWritings = null;\r\n            Map<String, AccountingEntry> taxWritings = null;\r\n\r\n            if (!invoiceWriting.getIsWritten()) {\r\n\r\n                lines.add(buildBBKPF(invoiceWriting.getEventDate(), new Date(), index++));\r\n                index2 = index - 1;\r\n                String OCEDateNumLecture = PREFIX + DateUtils.formatDateWithPattern(new Date(), \"ddMMyyyy\") + index2;\r\n\t\t\t\t\r\n\t\t\t\tlog.info(\"accountigcode InvoiceW==>\"+invoiceWriting.getAccountingCode().getCode());\r\n\t\t\t\tlog.info(\"eventDate InvoiceW==>\"+invoiceWriting.getEventDate());\r\n\r\n                invoiceSubcatWritings = getInvoiceSubcatsWritings(invoiceWriting.getEventDate(), invoiceWriting.getAccountingCode().getCode(), null);\r\n                log.info(\"invoicessubcateg size==>\"+ invoiceSubcatWritings.size());\r\n                for (Entry<String, AccountingEntry> entry2 : invoiceSubcatWritings.entrySet()) {\r\n                    AccountingEntry invoiceSubcatWriting = entry2.getValue();\t\t\t\t\t\r\n                    invoiceSubcatWriting.setExtraParam2(OCEDateNumLecture);\r\n                    String invoiceCategoryCode = invoiceSubcatWriting.getInvoiceCategory().getCode();\r\n\t\t\t\t\tlog.info(\"invoiceCategoryCode_InvoiceW entry2==>\"+ invoiceCategoryCode);\r\n                    String costl = getCostl(invoiceCategoryCode);\r\n                    String operationType = getOperationType(invoiceSubcatWriting);\r\n                   \r\n                    String taxCode = invoiceSubcatWriting.getTax().getCode();\r\n                    log.info(\"invoiceSubcatWriting.getTax()=>\"+taxCode);\r\n                    String eventType = getEventType(invoiceWriting);\r\n                    String line = buildBBSEG(operationType, eventType, leftPad(round(invoiceSubcatWriting.getAmount().abs(), 2), 16, \"0\"), null,\r\n                            ZUONREnum.INVOICE.getLabel(), taxCode, invoiceSubcatWriting.getAccountingCode().getCode(), costl);\r\n                    lines.add(line);\r\n                }\r\n\r\n                log.info(\"accCodeFor_taxWritings==>\"+invoiceWriting.getAccountingCode().getCode());\r\n                taxWritings = getTaxWritings(invoiceWriting.getEventDate(), invoiceWriting.getAccountingCode().getCode(), null);\r\n                log.info(\"invoicesTax_size=>\"+taxWritings.size());\r\n                for (Entry<String, AccountingEntry> entry2 : taxWritings.entrySet()) {\r\n                    AccountingEntry taxWriting = entry2.getValue();\r\n\t\t\t\t\tlog.info(\"taxWriting entry2==>\"+ taxWriting);\r\n                    taxWriting.setExtraParam2(OCEDateNumLecture);\r\n                    String operationType = getOperationType(taxWriting);\r\n                    String taxCode = taxWriting.getTax().getCode();\r\n                    String taxLine = buildBBTAX(operationType, leftPad(round(taxWriting.getAmount().abs(), 2), 16, \"0\"), taxCode);\r\n                    lines.add(taxLine);\r\n                }\r\n\r\n                String eventType = getEventType(invoiceWriting);\r\n                String accountType = DEBIT;\r\n                if (invoiceWriting.getAmount().compareTo(BigDecimal.ZERO) < 0) {\r\n                    accountType = CREDIT;\r\n                }\r\n                invoiceWriting.setExtraParam2(OCEDateNumLecture);\r\n                lines.add(buildBBSEG(accountType, eventType, leftPad(round(invoiceWriting.getAmount().abs(), 2), 16, \"0\"), null, ZUONREnum.INVOICE.getLabel(), \"\",\r\n                        invoiceWriting.getAccountingCode().getCode(), null));\r\n\r\n            }\r\n\r\n            // create writings\r\n            if (!invoiceWriting.getIsWritten()) {\r\n                accountingWritingService.create(invoiceWriting);\r\n                invoiceWriting.setIsWritten(true);\r\n            }\r\n\r\n            if (invoiceSubcatWritings != null) {\r\n                for (Entry<String, AccountingEntry> entry2 : invoiceSubcatWritings.entrySet()) {\r\n                    AccountingEntry invoiceSubcatWriting = entry2.getValue();\r\n                    accountingWritingService.create(invoiceSubcatWriting);\r\n                }\r\n            }\r\n\r\n            if (taxWritings != null) {\r\n                for (Entry<String, AccountingEntry> entry2 : taxWritings.entrySet()) {\r\n                    AccountingEntry taxWriting = entry2.getValue();\r\n                    accountingWritingService.create(taxWriting);\r\n                }\r\n            }\r\n\r\n        }\r\n        log.info(\"paymentsDeb\");\r\n        Map<String, AccountingEntry> paymentWritings = getPaymentWritings(lastExecutionDate);\r\n        log.info(\"payments\");\r\n        log.info(\"paymentWritings rsltsize=>\"+paymentWritings.size());\r\n        log.info(\"paymentWritings rslt=>\"+paymentWritings);\r\n        for (Entry<String, AccountingEntry> entry2 : paymentWritings.entrySet()) {\r\n            AccountingEntry paymentWriting = entry2.getValue();\r\n\r\n            lines.add(buildBBKPF(paymentWriting.getEventDate(), new Date(), index++));\r\n            index2 = index - 1;\r\n            String OCEDateNumLecture = PREFIX + DateUtils.formatDateWithPattern(new Date(), \"ddMMyyyy\") + index2;\r\n            paymentWriting.setExtraParam2(OCEDateNumLecture);\r\n\r\n            String occCode = \"\";\r\n            String costl = \"\";\r\n            log.info(\"afficher paymentWriting=>\"+paymentWriting);\r\n            \r\n            Tax tax=findTaxByCode(\"V0\");\r\n            log.info(\"tax V0 get ==>\"+tax);\r\n            String taxCode= \"\";\r\n            for (AccountOperation ao : paymentWriting.getAccountOperations()) {\r\n                occCode = ao.getCode();\r\n                log.info(\"afficher occCode AccOperation==>\"+occCode);\r\n                costl = getCostl(occCode);\r\n                log.info(\"afficher new costl=>\"+costl);\r\n                if(occCode.equals(\"PAY_FF\")){\r\n                    paymentWriting.setTax(tax);\r\n                    taxCode= paymentWriting.getTax().getCode();\r\n                    log.info(\"ForV0_taxCode=>\"+taxCode);\r\n                }\r\n                \r\n                \r\n            }\r\n\r\n            String line = buildBBSEG(DEBIT, paymentWriting.getEventType(), leftPad(round(paymentWriting.getAmount(), 2), 16, \"0\"), paymentWriting.getEventDate(), getZUONR(occCode, paymentWriting.getAccountingCode().getCode()), taxCode, paymentWriting.getAccountingCode().getCode(), costl);\r\n            lines.add(line);\r\n\r\n            String lineInvoicing = buildBBSEG(CREDIT, paymentWriting.getEventType(), leftPad(round(paymentWriting.getAmount(), 2), 16, \"0\"), paymentWriting.getEventDate(), getZUONR(occCode, paymentWriting.getExtraParam1()), \"\", paymentWriting.getExtraParam1(), null);\r\n            lines.add(lineInvoicing);\r\n        }\r\n\r\n        for (Entry<String, AccountingEntry> entry2 : paymentWritings.entrySet()) {\r\n            AccountingEntry paymentWriting = entry2.getValue();\r\n\t\t\tlog.info(\"paymentW==>\"+paymentWriting);\r\n            accountingWritingService.create(paymentWriting);\r\n            AccountingEntry paymentWriting2 = new AccountingEntry();\r\n            paymentWriting2.setAccountOperations(paymentWriting.getAccountOperations());\r\n            paymentWriting2.setExtraParam2(paymentWriting.getExtraParam2());\r\n            paymentWriting2.setAmount(paymentWriting.getAmount());\r\n            paymentWriting2.setEventDate(paymentWriting.getEventDate());\r\n            paymentWriting2.setExportDate(paymentWriting.getExportDate());\r\n            paymentWriting2.setEventType(paymentWriting.getEventType());\r\n            paymentWriting2.setAccountingCode(accountingCodeService.findByCode(paymentWriting.getExtraParam1()));\r\n            accountingWritingService.create(paymentWriting2);\r\n        }\r\n\r\n        Map<String, AccountingEntry> refundWritings = getRefundWritings(lastExecutionDate);\r\n        log.info(\"refundWritings==>\"+refundWritings);\r\n        for (Entry<String, AccountingEntry> entry3 : refundWritings.entrySet()) {\r\n            AccountingEntry refundWriting = entry3.getValue();\r\n\r\n            lines.add(buildBBKPF(refundWriting.getEventDate(), new Date(), index++));\r\n            index2 = index - 1;\r\n            String OCEDateNumLecture = PREFIX + DateUtils.formatDateWithPattern(new Date(), \"ddMMyyyy\") + index2;\r\n            refundWriting.setExtraParam2(OCEDateNumLecture);\r\n\r\n            String occCode = \"\";\r\n            for (AccountOperation ao : refundWriting.getAccountOperations()) {\r\n                occCode = ao.getCode();\r\n\t\t\t\t log.info(\"occCode_refundWritings==>\"+occCode);\r\n            }\r\n\r\n            String line = buildBBSEG(DEBIT, refundWriting.getEventType(), leftPad(round(refundWriting.getAmount(), 2), 16, \"0\"), refundWriting.getEventDate(), getZUONR(occCode, refundWriting.getAccountingCode().getCode()), \"\", refundWriting.getAccountingCode().getCode(), null);\r\n            lines.add(line);\r\n\r\n            String linePayment = buildBBSEG(CREDIT, refundWriting.getEventType(), leftPad(round(refundWriting.getAmount(), 2), 16, \"0\"), refundWriting.getEventDate(), getZUONR(occCode, refundWriting.getExtraParam1()), \"\", refundWriting.getExtraParam1(), null);\r\n            lines.add(linePayment);\r\n        }\r\n\r\n        for (Entry<String, AccountingEntry> entry2 : refundWritings.entrySet()) {\r\n            AccountingEntry refundWriting = entry2.getValue();\r\n            accountingWritingService.create(refundWriting);\r\n            AccountingEntry refundWriting2 = new AccountingEntry();\r\n            refundWriting2.setAccountOperations(refundWriting.getAccountOperations());\r\n            refundWriting2.setExtraParam2(refundWriting.getExtraParam2());\r\n            refundWriting2.setAmount(refundWriting.getAmount());\r\n            refundWriting2.setEventDate(refundWriting.getEventDate());\r\n            refundWriting2.setExportDate(refundWriting.getExportDate());\r\n            refundWriting2.setEventType(refundWriting.getEventType());\r\n            refundWriting2.setAccountingCode(accountingCodeService.findByCode(refundWriting.getExtraParam1()));\r\n            accountingWritingService.create(refundWriting2);\r\n        }\r\n\r\n\r\n        //pour les lignes des annulations des commandes\r\n        List<String> invoiceNumberList = getCancelinvoices(lastExecutionDate);\r\n\t\tlog.info(\"invoiceNumberList_cancelInvoices==>\"+invoiceNumberList);\r\n        if (invoiceNumberList.size() > 0) {\r\n\r\n            Map<String, AccountingEntry> invoiceWritingsAvoir = getAvoirWritings(invoiceNumberList);\r\n\r\n            for (Entry<String, AccountingEntry> entry : invoiceWritingsAvoir.entrySet()) {\r\n\r\n                log.info(\"key = {}\", entry.getKey());\r\n\r\n                AccountingEntry invoiceWriting = entry.getValue();\r\n                Map<String, AccountingEntry> invoiceSubcatWritings = null;\r\n                Map<String, AccountingEntry> taxWritings = null;\r\n\r\n                if (!invoiceWriting.getIsWritten()) {\r\n\r\n                    lines.add(buildBBKPF(invoiceWriting.getEventDate(), new Date(), index++));\r\n                    index2 = index - 1;\r\n                    String OCEDateNumLecture = PREFIX + DateUtils.formatDateWithPattern(new Date(), \"ddMMyyyy\") + index2;\r\n\r\n                    invoiceSubcatWritings = getInvoiceSubcatsWritings(invoiceWriting.getEventDate(), invoiceWriting.getAccountingCode().getCode(), invoiceNumberList);\r\n                    for (Entry<String, AccountingEntry> entry2 : invoiceSubcatWritings.entrySet()) {\r\n                        AccountingEntry invoiceSubcatWriting = entry2.getValue();\r\n                        invoiceSubcatWriting.setExtraParam2(OCEDateNumLecture);\r\n                        String invoiceCategoryCode = invoiceSubcatWriting.getInvoiceCategory().getCode();\r\n\t\t\t\t\t\tlog.info(\"invoiceCategoryCode==>\"+invoiceCategoryCode);\r\n                        String costl = getCostl(invoiceCategoryCode);\r\n                        String operationType = getOperationTypeAvoir(invoiceSubcatWriting);\r\n                        String taxCode = invoiceSubcatWriting.getTax().getCode();\r\n                        String eventType = EventEnum.ANNULATION_FACTURATION.getLabel();//getEventType(invoiceWriting);\r\n                        String line = buildBBSEG(operationType, eventType, leftPad(round(invoiceSubcatWriting.getAmount().abs(), 2), 16, \"0\"), null,\r\n                                ZUONREnum.INVOICE.getLabel(), taxCode, invoiceSubcatWriting.getAccountingCode().getCode(), costl);\r\n                        lines.add(line);\r\n                    }\r\n\r\n                    taxWritings = getTaxWritings(invoiceWriting.getEventDate(), invoiceWriting.getAccountingCode().getCode(), invoiceNumberList);\r\n                    for (Entry<String, AccountingEntry> entry2 : taxWritings.entrySet()) {\r\n                        AccountingEntry taxWriting = entry2.getValue();\r\n                        taxWriting.setExtraParam2(OCEDateNumLecture);\r\n                        String operationType = getOperationTypeAvoir(taxWriting);\r\n                        String taxCode = taxWriting.getTax().getCode();\r\n                        String taxLine = buildBBTAX(operationType, leftPad(round(taxWriting.getAmount().abs(), 2), 16, \"0\"), taxCode);\r\n                        lines.add(taxLine);\r\n                    }\r\n\r\n                    String eventType = EventEnum.ANNULATION_FACTURATION.getLabel();//getEventType(invoiceWriting);\r\n                    String accountType = CREDIT;\r\n                    if (invoiceWriting.getAmount().compareTo(BigDecimal.ZERO) < 0) {\r\n                        accountType = DEBIT;\r\n                    }\r\n                    invoiceWriting.setExtraParam2(OCEDateNumLecture);\r\n                    lines.add(buildBBSEG(accountType, eventType, leftPad(round(invoiceWriting.getAmount().abs(), 2), 16, \"0\"), null, ZUONREnum.INVOICE.getLabel(), \"\",\r\n                            invoiceWriting.getAccountingCode().getCode(), null));\r\n\r\n                }\r\n\r\n                // create writings\r\n                if (!invoiceWriting.getIsWritten()) {\r\n                    accountingWritingService.create(invoiceWriting);\r\n                    invoiceWriting.setIsWritten(true);\r\n                }\r\n\r\n                if (invoiceSubcatWritings != null) {\r\n                    for (Entry<String, AccountingEntry> entry2 : invoiceSubcatWritings.entrySet()) {\r\n                        AccountingEntry invoiceSubcatWriting = entry2.getValue();\r\n                        accountingWritingService.create(invoiceSubcatWriting);\r\n                    }\r\n                }\r\n\r\n                if (taxWritings != null) {\r\n                    for (Entry<String, AccountingEntry> entry2 : taxWritings.entrySet()) {\r\n                        AccountingEntry taxWriting = entry2.getValue();\r\n                        accountingWritingService.create(taxWriting);\r\n                    }\r\n                }\r\n\r\n            }\r\n\r\n\r\n        }\r\n\r\n\r\n\r\n        try {\r\n            if(lines.size() > 0) {\r\n                for (String line : lines) {\r\n                    appendLine(line);\r\n                }\r\n                contentBuilder.deleteCharAt(contentBuilder.lastIndexOf(NEW_LINE));\r\n                Files.write(contentBuilder, new File(absoluteOutputFileName), Charsets.UTF_8);\r\n                Files.write(contentBuilder, new File(absoluteArchivedFileName), Charsets.UTF_8);\r\n            }\r\n        } catch (IOException e) {\r\n            throw new BusinessException(e);\r\n        }\r\n\r\n    }\r\n    private Map<String, AccountingEntry> getAvoirWritings(List<String> invoiceNumberList) {\r\n\r\n\r\n        Map<String, Object> params = new HashMap<>();\r\n        log.info(\"invoiceNumberListAvoir\"+invoiceNumberList);\r\n        params.put(\"invoiceList\", invoiceNumberList);\r\n        log.info(\"params\"+params);\r\n        String    query = \"Select cast(inv.recordedInvoice.auditable.created as date), inv, inv.invoiceNumber FROM Invoice inv \"\r\n                + \" WHERE ( (inv.recordedInvoice is not null and cfValues like '%CF_DATE_FIN_INSTALLATION%' and invoiceType.code = 'INS') or (inv.recordedInvoice is not null and invoiceType.code = 'PVT' ) ) and inv.invoiceNumber in :invoiceList  and inv.seller.code = '\"+SELLER_CODE+\"' \";\r\n\r\n\r\n        OCCTemplate occTemplateRefInv = occTemplateService.findByCode(OCC_TEMP_CODE_REF_INV);\r\n        Map<String, AccountingEntry> accountingEntries = new HashMap<String, AccountingEntry>();\r\n\r\n\r\n        List<Object[]> rows = (List<Object[]>) invoiceService.executeSelectQuery(query, params);\r\n        log.info(\"okkkkk\"+rows);\r\n        for (Object[] row : rows) {\r\n            Date date = (Date) row[0];\r\n            Invoice invoice = (Invoice) row[1];\r\n            String invoiceNumber = (String) row[2];\r\n\r\n            log.info(\"---- facture : \");\r\n            log.info(\"date = {}\", date);\r\n            log.info(\"invoiceNumber = {}\", invoiceNumber);\r\n\r\n\r\n            String key = date+\"_\"+occTemplateRefInv.getAccountingCode().getCode();\r\n\t\t\tlog.info(\"keyAvoir ==>\"+key);\r\n\r\n            AccountingEntry accountingWriting = new AccountingEntry();\r\n            List<AccountOperation> accountOperations = new ArrayList<AccountOperation>();\r\n            if(accountingEntries.get(key) != null) {\r\n                accountingWriting = accountingEntries.get(key);\r\n                accountingWriting.setAmount(invoice.getAmountWithTax().add(accountingWriting.getAmount()));\r\n                accountOperations.addAll(accountingWriting.getAccountOperations());\r\n            } else {\r\n                accountingWriting.setAmount(invoice.getAmountWithTax());\r\n            }\r\n            accountOperations.add(invoice.getRecordedInvoice());\r\n\r\n            accountingWriting.setAccountingCode(occTemplateRefInv.getAccountingCode());\r\n            accountingWriting.setAccountOperations(accountOperations);\r\n            accountingWriting.setEventType(EventEnum.ANNULATION_FACTURATION.getLabel());\r\n            accountingWriting.setEventDate(date);\r\n            accountingWriting.setExportDate(new Date());\r\n            accountingWriting.setIsWritten(false);\r\n            accountingEntries.put(key, accountingWriting);\r\n        }\r\n\r\n        return accountingEntries;\r\n    }\r\n\r\n    private Map<String, AccountingEntry> getInvoiceWritings() {\r\n\r\n\r\n        Map<String, Object> params = new HashMap<>();\r\n\r\n\r\n        String   query = \"Select cast(inv.recordedInvoice.auditable.created as date), inv, inv.invoiceNumber FROM Invoice inv \"\r\n                + \" WHERE inv.recordedInvoice is not null  AND inv.seller.code = '\"+SELLER_CODE+\"' \";\r\n\r\n\r\n\r\n\r\n        Map<String, AccountingEntry> accountingEntries = new HashMap<String, AccountingEntry>();\r\n\r\n\r\n        List<Object[]> rows = (List<Object[]>) invoiceService.executeSelectQuery(query, params);\r\n        log.info(\"query invoiceWritings.size() :  ==>\"+ rows.size());  \r\n        for (Object[] row : rows) {\r\n            Date date = (Date) row[0];\r\n            Invoice invoice = (Invoice) row[1];\r\n            String invoiceNumber = (String) row[2];\r\n\r\n            //log.info(\"---- facture : \");\r\n            //log.info(\"date_IW ==>\"+ date);\r\n            //log.info(\"invoiceNumber_IW ==>\"+ invoiceNumber);\r\n\r\n            Boolean isWritten = !invoice.getRecordedInvoice().getAccountingEntries().isEmpty();\r\n\r\n            String key = date+\"_\"+isWritten+\"_\"+invoice.getInvoiceType().getOccTemplate().getAccountingCode().getCode();\r\n            log.info(\"key in invoiceW ==>\"+ key);\r\n\t\t\t\r\n            AccountingEntry accountingWriting = new AccountingEntry();\r\n            List<AccountOperation> accountOperations = new ArrayList<AccountOperation>();\r\n            if(accountingEntries.get(key) != null) {\r\n                accountingWriting = accountingEntries.get(key);\r\n\t\t\t\tlog.info(\"invoice.getAmountWithTax in invoiceW ==>\"+ invoice.getAmountWithTax());\r\n\t\t\t\tlog.info(\"accountingWriting.getAmount in invoiceW ==>\"+ accountingWriting.getAmount());\r\n                accountingWriting.setAmount(invoice.getAmountWithTax().add(accountingWriting.getAmount()));\r\n                accountOperations.addAll(accountingWriting.getAccountOperations());\r\n            } else {\r\n\t\t\t\tlog.info(\"new invoice.getAmountWithTax in invoiceW ==>\"+invoice.getAmountWithTax());\r\n                accountingWriting.setAmount(invoice.getAmountWithTax());\r\n            }\r\n            accountOperations.add(invoice.getRecordedInvoice());\r\n\r\n            accountingWriting.setAccountingCode(invoice.getInvoiceType().getOccTemplate().getAccountingCode());\r\n            accountingWriting.setAccountOperations(accountOperations);\r\n            accountingWriting.setEventType(EventEnum.FACTURATION.getLabel());\r\n            accountingWriting.setEventDate(date);\r\n            accountingWriting.setExportDate(new Date());\r\n            accountingWriting.setIsWritten(isWritten);\r\n            accountingEntries.put(key, accountingWriting);\r\n        }\r\n\r\n        return accountingEntries;\r\n    }\r\n\r\n  /*  private Map<String, AccountingEntry> getPaymentWritings(Date date, String accountingCode) {\r\n\r\n        Map<String, AccountingEntry> accountingEntries = new HashMap<String, AccountingEntry>();\r\n\r\n        String query = \"Select cast(ma2.accountOperation.auditable.created as date), ma2   \"\r\n                + \" FROM MatchingCode mc2 JOIN mc2.matchingAmounts ma2 \"\r\n                + \" WHERE mc2 IN \"\r\n                + \" (SELECT mc FROM MatchingCode mc JOIN mc.matchingAmounts ma \"\r\n                + \" WHERE ma.accountOperation.transactionCategory = org.meveo.model.payments.OperationCategoryEnum.DEBIT AND ma.accountOperation.occCode != 'REJ_DDT' \"\r\n                + \" AND ma.accountOperation.accountingCode.code=:accountingCode)\"\r\n                + \" AND ma2.accountOperation.transactionCategory = org.meveo.model.payments.OperationCategoryEnum.CREDIT\"\r\n                + \" AND ma2.accountOperation.accountingEntries is empty\"\r\n                +\"AND cast(ma.accountOperation.auditable.created ) > :date\";\r\n\r\n\r\n        Map<String, Object> params = new HashMap<>();\r\n        params.put(\"accountingCode\", accountingCode);\r\n        params.put(\"date\", date);\r\n\r\n        List<Object[]> rows = (List<Object[]>) invoiceService.executeSelectQuery(query, params);\r\n\r\n\r\n        for (Object[] row : rows) {\r\n\r\n            MatchingAmount matchingAmount = (MatchingAmount) row[1];\r\n            AccountOperation accountOperation = matchingAmount.getAccountOperation();\r\n            BigDecimal amount = matchingAmount.getMatchingAmount();\r\n            String paymentAccountCode = accountOperation.getAccountingCode().getCode();\r\n            String occCode = accountOperation.getOccCode();\r\n\r\n            log.debug(\"---- encaissement : \");\r\n            log.debug(\"matchingAmount = {}\", amount);\r\n            log.debug(\"accountCode = {}\", paymentAccountCode);\r\n            log.debug(\"occCode = {}\", occCode);\r\n\r\n            String key = date+\"_\"+paymentAccountCode+\"_\"+occCode;\r\n\r\n            AccountingEntry accountingWriting = new AccountingEntry();\r\n            List<AccountOperation> accountOperations = new ArrayList<AccountOperation>();\r\n            if(accountingEntries.get(key) != null) {\r\n                accountingWriting = accountingEntries.get(key);\r\n                accountingWriting.setAmount(amount.add(accountingWriting.getAmount()));\r\n                accountOperations.addAll(accountingWriting.getAccountOperations());\r\n            } else {\r\n                accountingWriting.setAmount(amount);\r\n            }\r\n\r\n            AccountOperation aoInList = accountOperations.stream().filter(ao -> accountOperation.getId().equals(ao.getId())).findAny().orElse(null);\r\n            if(aoInList == null) {\r\n                log.debug(\"# adding AO to AW\");\r\n                accountOperations.add(accountOperation);\r\n            }\r\n\r\n            accountingWriting.setAccountingCode(matchingAmount.getAccountOperation().getAccountingCode());\r\n            accountingWriting.setAccountOperations(accountOperations);\r\n            accountingWriting.setEventType(getEventLabel(occCode));\r\n            accountingWriting.setEventDate(date);\r\n            accountingWriting.setExportDate(new Date());\r\n            accountingWriting.setIsWritten(false);\r\n            accountingEntries.put(key, accountingWriting);\r\n\r\n        }\r\n\r\n        return accountingEntries;\r\n    }\r\n*/\r\n\r\n    private Map<String, AccountingEntry> getPaymentWritings(Date date) {\r\n\r\n        Map<String, AccountingEntry> accountingEntries = new HashMap<String, AccountingEntry>();\r\n\r\n        String query = \"Select cast(ma2.accountOperation.auditable.created as date), ma2, mc2 \"\r\n                + \" FROM MatchingCode mc2 JOIN mc2.matchingAmounts ma2 \"\r\n               // + \" WHERE mc2 IN \"\r\n               // + \" (SELECT mc FROM MatchingCode mc JOIN mc.matchingAmounts ma \"\r\n               // + \" WHERE ma.accountOperation.transactionCategory = org.meveo.model.payments.OperationCategoryEnum.DEBIT AND ma.accountOperation.code != 'REJ_DDT' AND ma.accountOperation.code not like 'REF%') \"\r\n               // + \" AND ma2.accountOperation.transactionCategory = org.meveo.model.payments.OperationCategoryEnum.CREDIT\"\r\n                + \" WHERE ma2.accountOperation.transactionCategory = org.meveo.model.payments.OperationCategoryEnum.CREDIT\"\r\n                + \" AND ma2.auditable.created > :date\"\r\n                + \" AND ma2.accountOperation.code != 'REF_INV'\"\r\n                + \" AND ma2.accountOperation.accountingEntries is empty  AND ma2.accountOperation.seller.code = '\"+SELLER_CODE+\"' \";\r\n\r\n\r\n\r\n        Map<String, Object> params = new HashMap<>();\r\n        params.put(\"date\", date);\r\n\r\n        List<Object[]> rows = (List<Object[]>) invoiceService.executeSelectQuery(query, params);\r\n        log.info(\"resultPaymentMatched=>\"+rows.size());\r\n        //if(rows.isEmpty()){\r\n           // accountingEntries= getPaymentNotMatchedWritings(date);\r\n           // log.info(\"result getPaymentNotMatchedWritings=>\"+accountingEntries);\r\n        //}\r\n       \r\n       // else{\r\n        for (Object[] row : rows) {\r\n\r\n            Date eventDate = (Date) row[0];\r\n            MatchingAmount matchingAmount = (MatchingAmount) row[1];\r\n            MatchingCode matchingCode = (MatchingCode) row[2];\r\n            List<MatchingAmount> matchingAmounts = matchingCode.getMatchingAmounts();\r\n            MatchingAmount invoiceMatchingAmount = matchingAmounts.stream().filter(ma ->\r\n                    org.meveo.model.payments.OperationCategoryEnum.DEBIT.equals(ma.getAccountOperation().getTransactionCategory())\r\n            ).findAny().orElse(null);\r\n\r\n            AccountOperation accountOperation = matchingAmount.getAccountOperation();\r\n            log.info(\"accountOperation in paymentWritings=>\"+accountOperation);\r\n            BigDecimal amount = matchingAmount.getMatchingAmount();\r\n            String paymentAccountCode = accountOperation.getAccountingCode().getCode();\r\n            String occCode = accountOperation.getCode();\r\n\r\n            log.info(\"---- encaissement : \");\r\n            log.info(\"1matchingAmount ==>\"+ amount);\r\n            log.info(\"1accountCode ==>\"+ paymentAccountCode);\r\n            log.info(\"1occCode ==>\"+ occCode);\r\n            log.info(\"1eventDate ==>\"+ eventDate);\r\n\r\n\r\n            String key = eventDate+\"_\"+paymentAccountCode+\"_\"+occCode;\r\n\t\t\tlog.info(\"1key==>\"+key);\r\n\r\n            AccountingEntry accountingWriting = new AccountingEntry();\r\n            List<AccountOperation> accountOperations = new ArrayList<AccountOperation>();\r\n            if(accountingEntries.get(key) != null) {\r\n                accountingWriting = accountingEntries.get(key);\r\n                log.info(\"accountingWriting.getAmount()==>\"+accountingWriting.getAmount());\r\n                accountingWriting.setAmount(amount.add(accountingWriting.getAmount()));\r\n                log.info(\"accountingWritingAdded.getAmount()==>\"+accountingWriting.getAmount());\r\n                accountOperations.addAll(accountingWriting.getAccountOperations());\r\n                log.info(\"accountingWriting.getAccountOperations()=>\"+accountOperations);\r\n                log.info(\"accountOperations.addAll=>\"+accountingWriting.getAccountOperations());\r\n            } else {\r\n                accountingWriting.setAmount(amount);\r\n            }\r\n\r\n            AccountOperation aoInList = accountOperations.stream().filter(ao -> accountOperation.getId().equals(ao.getId())).findAny().orElse(null);\r\n            if(aoInList == null) {\r\n                log.debug(\"# adding Payment AO to AW\");\r\n                accountOperations.add(accountOperation);\r\n            }\r\n            log.info(\"accountingWritingLogAO\"+matchingAmount.getAccountOperation());\r\n            accountingWriting.setAccountingCode(matchingAmount.getAccountOperation().getAccountingCode());\r\n            accountingWriting.setAccountOperations(accountOperations);\r\n            accountingWriting.setEventType(getEventLabel(occCode));\r\n            accountingWriting.setEventDate(eventDate);\r\n            accountingWriting.setExportDate(new Date());\r\n            accountingWriting.setIsWritten(false);\r\n           /* if(invoiceMatchingAmount==null){// envoyer une AW  d'un paiement meme si la commande de solde n'existe pas encore\r\n                accountingWriting.setExtraParam1(\"411120\");\r\n            }*/\r\n            //else{\r\n                accountingWriting.setExtraParam1(invoiceMatchingAmount.getAccountOperation().getAccountingCode().getCode());\r\n            //}\r\n            log.info(\" accountingWriting.setExtraParam1=>\"+ accountingWriting.getExtraParam1());\r\n            log.info(\"accountingWritingLog=>\"+accountingWriting.getAccountingCode());\r\n            accountingEntries.put(key, accountingWriting);\r\n\t\t\tlog.info(\"accountingEntries PaymentW==>\"+accountingEntries);\r\n\r\n        }\r\n        log.info(\"to enter paymentNotMatchingWritings!\");\r\n        log.info(\"OLD Value list accountingEntries ==>\"+accountingEntries);\r\n        accountingEntries= getPaymentNotMatchedWritings(date);\r\n        log.info(\"NEW Value list accountingEntries ==>\"+accountingEntries);\r\n    //}\r\n\r\n        return accountingEntries;\r\n    }\r\n// add this method to send the AO related to payment even if it not matched and the invoice doesn't exist yet \r\n   \r\n    private Map<String, AccountingEntry> getPaymentNotMatchedWritings(Date date) {\r\n\r\n         Map<String, AccountingEntry> accountingEntries = new HashMap<String, AccountingEntry>();\r\n         //log.info(\"accountingEntries as input =>\"+accountingEntries);\r\n         String query = \"Select cast(ao.auditable.created as date), ao\"\r\n         + \" FROM AccountOperation ao\"\r\n         + \" WHERE ao.transactionCategory = org.meveo.model.payments.OperationCategoryEnum.CREDIT\"\r\n         + \" AND ao.auditable.created > :date\"\r\n         + \" AND ao.code != 'REF_INV'\"\r\n         + \" AND ao.accountingEntries is empty  AND ao.seller.code = '\"+SELLER_CODE+\"' \";\r\n\r\n         Map<String, Object> params = new HashMap<>();\r\n        params.put(\"date\", date);\r\n        List<Object[]> rows = (List<Object[]>) invoiceService.executeSelectQuery(query, params);\r\n        for (Object[] row : rows) {\r\n            Date eventDate = (Date) row[0];\r\n            AccountOperation accountOperation = (AccountOperation) row[1];\r\n            log.info(\"accountOperation in getPaymentNotMatchedWritings=>\"+accountOperation);\r\n            BigDecimal amount = accountOperation.getAmount();\r\n            String paymentAccountCode = accountOperation.getAccountingCode().getCode();\r\n            String occCode = accountOperation.getCode();\r\n            log.info(\"---- encaissement 2: \");\r\n            log.info(\"2Amount ==>\"+ amount);\r\n            log.info(\"2accountCode ==>\"+ paymentAccountCode);\r\n            log.info(\"2occCode ==>\"+ occCode);\r\n            log.info(\"2eventDate ==>\"+ eventDate);\r\n            String key = eventDate+\"_\"+paymentAccountCode+\"_\"+occCode;\r\n\t\t\tlog.info(\"2key==>\"+key);\r\n\r\n            AccountingEntry accountingWriting = new AccountingEntry();\r\n            List<AccountOperation> accountOperations = new ArrayList<AccountOperation>();\r\n            if(accountingEntries.get(key) != null) {\r\n                accountingWriting = accountingEntries.get(key);\r\n\t\t\t\tlog.info(\"accountingWriting.getAmount()==>\"+accountingWriting.getAmount());\r\n                accountingWriting.setAmount(amount.add(accountingWriting.getAmount()));\r\n                log.info(\"accountingWritingAdded.getAmount()==>\"+accountingWriting.getAmount());\r\n                accountOperations.addAll(accountingWriting.getAccountOperations());\r\n                log.info(\"accountingWriting2.getAccountOperations()=>\"+accountOperations);\r\n                log.info(\"accountOperations2.addAll=>\"+accountingWriting.getAccountOperations());\r\n            } else {\r\n\t\t\t\tlog.info(\"new amount==>\"+amount);\r\n                accountingWriting.setAmount(amount);\r\n            }\r\n\r\n            AccountOperation aoInList = accountOperations.stream().filter(ao -> accountOperation.getId().equals(ao.getId())).findAny().orElse(null);\r\n            if(aoInList == null) {\r\n                log.debug(\"# adding Payment AO to AW\");\r\n                accountOperations.add(accountOperation);\r\n            }\r\n            log.info(\"accountOperation.getAccountingCode()=>\"+accountOperation.getAccountingCode());\r\n            accountingWriting.setAccountingCode(accountOperation.getAccountingCode());       \r\n            accountingWriting.setAccountOperations(accountOperations);\r\n            accountingWriting.setEventType(getEventLabel(occCode));\r\n            accountingWriting.setEventDate(eventDate);\r\n            accountingWriting.setExportDate(new Date());\r\n            accountingWriting.setIsWritten(false);\r\n            // envoyer une AW  d'un paiement meme si la commande de solde n'existe pas encore\r\n            accountingWriting.setExtraParam1(\"411120\");\r\n            //accountingWriting.setExtraParam1(invoiceMatchingAmount.getAccountOperation().getAccountingCode().getCode());\r\n            log.info(\" accountingWriting2.setExtraParam1=>\"+ accountingWriting.getExtraParam1());\r\n            log.info(\"accountingWritingLog=>\"+accountingWriting.getAccountingCode());\r\n            accountingEntries.put(key, accountingWriting);\r\n\t\t\tlog.info(\"accountingEntries PaymentW==>\"+accountingEntries);\r\n\r\n        }\r\n        return accountingEntries;\r\n\r\n}\r\n\r\n\r\nprivate Map<String, AccountingEntry> getRefundWritings(Date date) {\r\n\r\n        Map<String, AccountingEntry> accountingEntries = new HashMap<String, AccountingEntry>();\r\n\r\n        String query = \"Select cast(ma2.accountOperation.auditable.created as date), ma2, mc2  \"\r\n                + \" FROM MatchingCode mc2 JOIN mc2.matchingAmounts ma2 \"\r\n                + \" WHERE mc2 IN \"\r\n                + \" (SELECT mc FROM MatchingCode mc JOIN mc.matchingAmounts ma \"\r\n                + \" WHERE ma.accountOperation.transactionCategory = org.meveo.model.payments.OperationCategoryEnum.CREDIT)\"\r\n                + \" AND ma2.accountOperation.transactionCategory = org.meveo.model.payments.OperationCategoryEnum.DEBIT AND ma2.accountOperation.code != 'INV_STD' \"\r\n                + \" AND ma2.auditable.created > :date AND ma2.accountOperation.seller.code = '\"+SELLER_CODE+\"' \";\r\n\r\n        Map<String, Object> params = new HashMap<>();\r\n        params.put(\"date\", date);\r\n\r\n        List<Object[]> rows = (List<Object[]>) invoiceService.executeSelectQuery(query, params);\r\n        log.info(\"rowssize=>\"+rows.size());\r\n        for (Object[] row : rows) {\r\n            Date eventDate = (Date) row[0];\r\n            MatchingAmount matchingAmount = (MatchingAmount) row[1];\r\n            log.info(\"matchingAmount in refundWritings=>\"+matchingAmount);\r\n            MatchingCode matchingCode = (MatchingCode) row[2];\r\n            log.info(\"matchingCode in refundWritings=>\"+matchingCode);\r\n            List<MatchingAmount> matchingAmounts = matchingCode.getMatchingAmounts();\r\n\r\n            MatchingAmount paymentMatchingAmount = matchingAmounts.stream().filter(ma ->\r\n                    org.meveo.model.payments.OperationCategoryEnum.CREDIT.equals(ma.getAccountOperation().getTransactionCategory())\r\n            ).findAny().orElse(null);\r\n\r\n            AccountOperation accountOperation = matchingAmount.getAccountOperation();\r\n            BigDecimal amount = matchingAmount.getMatchingAmount();\r\n            String refundAccountCode = accountOperation.getAccountingCode().getCode();\r\n            String occCode = accountOperation.getCode();\r\n\r\n            log.debug(\"---- remboursement : \");\r\n            log.debug(\"matchingAmount = {}\", matchingAmount);\r\n            log.debug(\"accountCode = {}\", refundAccountCode);\r\n            log.debug(\"occCode = {}\", occCode);\r\n\r\n            String key = date+\"_\"+refundAccountCode+\"_\"+occCode;\r\n\r\n            AccountingEntry accountingWriting = new AccountingEntry();\r\n            List<AccountOperation> refundAccountOperations = new ArrayList<AccountOperation>();\r\n            if(accountingEntries.get(key) != null) {\r\n                accountingWriting = accountingEntries.get(key);\r\n                accountingWriting.setAmount(amount.add(accountingWriting.getAmount()));\r\n                refundAccountOperations.addAll(accountingWriting.getAccountOperations());\r\n            } else {\r\n                accountingWriting.setAmount(amount);\r\n            }\r\n\r\n            AccountOperation aoInList = refundAccountOperations.stream().filter(ao -> accountOperation.getId().equals(ao.getId())).findAny().orElse(null);\r\n            if(aoInList == null) {\r\n                log.debug(\"# adding Refund AO to AW\");\r\n                refundAccountOperations.add(accountOperation);\r\n            }\r\n\r\n            accountingWriting.setAccountingCode(matchingAmount.getAccountOperation().getAccountingCode());\r\n            accountingWriting.setAccountOperations(refundAccountOperations);\r\n            accountingWriting.setEventType(getEventLabel(occCode));\r\n            accountingWriting.setEventDate(eventDate);\r\n            accountingWriting.setExportDate(new Date());\r\n            accountingWriting.setIsWritten(false);\r\n            accountingWriting.setExtraParam1(paymentMatchingAmount.getAccountOperation().getAccountingCode().getCode());\r\n            accountingEntries.put(key, accountingWriting);\r\n\r\n        }\r\n\r\n        return accountingEntries;\r\n    }\r\n\r\n\r\n\r\n    private List<String> getCancelinvoices(Date date) {\r\n        log.info(\"avoir\");\r\n        Map<String, AccountingEntry>  accountingEntries = new HashMap<String, AccountingEntry>();\r\n        List<String> invoiceNumberList = new ArrayList<>();\r\n        String query = \"Select cast(ma2.accountOperation.auditable.created as date), ma2, mc2  \"\r\n                + \" FROM MatchingCode mc2 JOIN mc2.matchingAmounts ma2 \"\r\n                + \" WHERE mc2 IN \"\r\n                + \" (SELECT mc FROM MatchingCode mc JOIN mc.matchingAmounts ma \"\r\n                + \" WHERE ma.accountOperation.transactionCategory = org.meveo.model.payments.OperationCategoryEnum.CREDIT AND ma.accountOperation.code = 'REF_INV' )\"\r\n                + \" AND ma2.accountOperation.transactionCategory = org.meveo.model.payments.OperationCategoryEnum.DEBIT  \"\r\n                + \" AND ma2.auditable.created > :date   AND ma2.accountOperation.seller.code = '\"+SELLER_CODE+\"' \";\r\n\r\n        Map<String, Object> params = new HashMap<>();\r\n        params.put(\"date\", date);\r\n\r\n        List<Object[]> rows = (List<Object[]>) invoiceService.executeSelectQuery(query, params);\r\n\r\n        log.info(\"avoir\"+rows);\r\n\r\n        for (Object[] row : rows) {\r\n            log.info(\"MatchingAmount\"+(MatchingAmount) row[1]);\r\n            log.info(\"MatchingCode\"+(MatchingCode) row[2]);\r\n            Date eventDate = (Date) row[0];\r\n            MatchingAmount matchingAmount = (MatchingAmount) row[1];\r\n            MatchingCode matchingCode = (MatchingCode) row[2];\r\n            List<MatchingAmount> matchingAmounts = matchingCode.getMatchingAmounts();\r\n\r\n            MatchingAmount invoiceMatchingAmount = matchingAmounts.stream().filter(ma ->\r\n                    org.meveo.model.payments.OperationCategoryEnum.DEBIT.equals(ma.getAccountOperation().getTransactionCategory())\r\n            ).findAny().orElse(null);\r\n\r\n            AccountOperation accountOperation = matchingAmount.getAccountOperation();//invoice\r\n            String invoiceNumber = accountOperation.getReference();\r\n            Invoice invoice = findByInvoiceNumber(invoiceNumber);\r\n            invoiceNumberList.add(invoice.getInvoiceNumber());\r\n        }\r\n\r\n        return invoiceNumberList;\r\n    }\r\n\r\n\r\n    private Map<String, AccountingEntry> getTaxWritings(Date date, String accountingCode, List<String> invoiceNumberList) {\r\n\r\n\r\n        Map<String, AccountingEntry> accountingEntries = new HashMap<String, AccountingEntry>();\r\n\r\n        String query = null;\r\n        Map<String, Object> params = new HashMap<>();\r\n        OCCTemplate occTemplateInv = occTemplateService.findByCode(OCC_TEMP_CODE_INV_STD);\r\n\t\t\r\n        if(invoiceNumberList == null) {\r\n            query = \"Select cast(taxInvAgregate.invoice.recordedInvoice.auditable.created as date), taxInvAgregate  \"\r\n                    + \" FROM TaxInvoiceAgregate taxInvAgregate\"\r\n                    + \" WHERE taxInvAgregate.invoice.recordedInvoice is not null  \"\r\n\t\t\t\t\t+ \" AND cast(taxInvAgregate.invoice.recordedInvoice.auditable.created as date)=:date\"\r\n                    + \" AND taxInvAgregate.invoice.invoiceType.occTemplate.accountingCode.code=:accountingCode\"\r\n                    + \" AND taxInvAgregate.invoice.recordedInvoice.accountingEntries is empty  AND taxInvAgregate.invoice.seller.code = '\"+SELLER_CODE+\"' \";\r\n            params.put(\"date\", date);\r\n            params.put(\"accountingCode\", accountingCode);\r\n        }\r\n        else {\r\n\r\n            query = \"Select cast(taxInvAgregate.invoice.recordedInvoice.auditable.created as date), taxInvAgregate  \"\r\n                    + \" FROM TaxInvoiceAgregate taxInvAgregate\"\r\n                    + \" WHERE taxInvAgregate.invoice.recordedInvoice is not null AND cast(taxInvAgregate.invoice.recordedInvoice.auditable.created as date)=:date\"\r\n                    + \" AND taxInvAgregate.invoice.invoiceType.occTemplate.accountingCode.code=:accountingCode\"\r\n                    + \" AND taxInvAgregate.invoice.invoiceNumber in :invoiceNumberList  AND taxInvAgregate.invoice.seller.code = '\"+SELLER_CODE+\"' \";\r\n            params.put(\"invoiceNumberList\", invoiceNumberList);\r\n            params.put(\"accountingCode\", occTemplateInv.getAccountingCode().getCode());\r\n\r\n        }\r\n\r\n\r\n\r\n        params.put(\"date\", date);\r\n\r\n        List<Object[]> rows = (List<Object[]>) invoiceService.executeSelectQuery(query, params);\r\n        log.info(\"tax<riting\"+rows);\r\n        for (Object[] row : rows) {\r\n            TaxInvoiceAgregate taxInvoiceAgregate = (TaxInvoiceAgregate) row[1];\r\n\t\t\tlog.info(\"taxInvoiceAgregate methodTaxWritings==>\"+taxInvoiceAgregate);\r\n\r\n            String amountSign = \"PLUS\";\r\n            if(taxInvoiceAgregate.getAmountTax().compareTo(BigDecimal.ZERO) < 0) {\r\n                amountSign = \"MINUS\";\r\n            }\r\n\r\n            String key = date+\"_\"+taxInvoiceAgregate.getAccountingCode().getCode()+\"_\"+taxInvoiceAgregate.getTax().getCode()+\"_\"+amountSign;\r\n\r\n            AccountingEntry accountingWriting = new AccountingEntry();\r\n            List<AccountOperation> accountOperations = new ArrayList<AccountOperation>();\r\n            if(accountingEntries.get(key) != null) {\r\n                accountingWriting = accountingEntries.get(key);\r\n                accountingWriting.setAmount(taxInvoiceAgregate.getAmountTax().add(accountingWriting.getAmount()));\r\n                accountOperations.addAll(accountingWriting.getAccountOperations());\r\n            } else {\r\n                accountingWriting.setAmount(taxInvoiceAgregate.getAmountTax());\r\n            }\r\n            if(!accountOperations.contains(taxInvoiceAgregate.getInvoice().getRecordedInvoice())) {\r\n                accountOperations.add(taxInvoiceAgregate.getInvoice().getRecordedInvoice());\r\n            }\r\n\r\n            accountingWriting.setAccountingCode(taxInvoiceAgregate.getAccountingCode());\r\n            accountingWriting.setAccountOperations(accountOperations);\r\n            accountingWriting.setTax(taxInvoiceAgregate.getTax());\r\n            accountingWriting.setEventDate(date);\r\n            accountingWriting.setExportDate(new Date());\r\n            accountingEntries.put(key, accountingWriting);\r\n        }\r\n\r\n        for (Entry<String, AccountingEntry> entry : accountingEntries.entrySet()) {\r\n            AccountingEntry accountingWriting = entry.getValue();\r\n            log.debug(\"---- tax : \");\r\n            log.debug(\"date ==>\"+ accountingWriting.getEventDate());\r\n            log.debug(\"tax ==>\"+ accountingWriting.getTax());\r\n            log.debug(\"amount ==>\"+ accountingWriting.getAmount());\r\n            for(AccountOperation ao : accountingWriting.getAccountOperations()) {\r\n                log.debug(\" |__ ao ==>\"+ ao.getId());\r\n            }\r\n        }\r\n\r\n        return accountingEntries;\r\n    }\r\n\r\n    private  Map<String, AccountingEntry> getInvoiceSubcatsWritings(Date date, String accountingCode, List<String> invoiceNumberList) {\r\n\r\n        String query = null;\r\n        Map<String, Object> params = new HashMap<>();\r\n        log.info(\"invoiceNumberList_SubCatW=>\"+invoiceNumberList);\r\n        OCCTemplate occTemplateInv = occTemplateService.findByCode(OCC_TEMP_CODE_INV_STD);\r\n\t\t\r\n        if(invoiceNumberList == null) {\r\n            query = \"Select cast(subCatInvAgregate.invoice.recordedInvoice.auditable.created as date), subCatInvAgregate \"\r\n                    + \" FROM SubCategoryInvoiceAgregate subCatInvAgregate \"\r\n                    + \" WHERE subCatInvAgregate.invoice.recordedInvoice is not null  \"\r\n\t\t\t\t\t+ \" AND cast(subCatInvAgregate.invoice.recordedInvoice.auditable.created as date)=:date\"\r\n                    + \" AND subCatInvAgregate.invoice.invoiceType.occTemplate.accountingCode.code=:accountingCode\"\r\n                    + \" AND subCatInvAgregate.invoice.recordedInvoice.accountingEntries is empty  AND subCatInvAgregate.invoice.seller.code = '\"+SELLER_CODE+\"' \";\r\n\r\n            params.put(\"accountingCode\", accountingCode);\r\n        }\r\n        else {\r\n            log.info(\"okkkk\"+accountingCode);\r\n            query = \"Select cast(subCatInvAgregate.invoice.recordedInvoice.auditable.created as date), subCatInvAgregate \"\r\n                    + \" FROM SubCategoryInvoiceAgregate subCatInvAgregate \"\r\n                    + \" WHERE subCatInvAgregate.invoice.recordedInvoice is not null AND cast(subCatInvAgregate.invoice.recordedInvoice.auditable.created as date)=:date\"\r\n                    + \" AND subCatInvAgregate.invoice.invoiceType.occTemplate.accountingCode.code=:accountingCode\"\r\n                    + \" AND subCatInvAgregate.invoice.invoiceNumber in :invoiceNumberList AND subCatInvAgregate.invoice.seller.code = '\"+SELLER_CODE+\"' \";\r\n\r\n            params.put(\"invoiceNumberList\", invoiceNumberList);\r\n            params.put(\"accountingCode\", occTemplateInv.getAccountingCode().getCode());\r\n\r\n        }\r\n        log.info(\"date here=>\"+date);\r\n        params.put(\"date\", date);\r\n\r\n        Map<String, AccountingEntry> accountingEntries = new HashMap<String, AccountingEntry>();\r\n\r\n\r\n\r\n\r\n        List<Object[]> rows = (List<Object[]>) invoiceService.executeSelectQuery(query, params);\r\n        log.info(\"result\"+rows.size());\r\n        for (Object[] row : rows) {\r\n            SubCategoryInvoiceAgregate subCatInvAgregate = (SubCategoryInvoiceAgregate) row[1];            \r\n\t\t\tlog.info(\"subcat_invoice here=>\"+subCatInvAgregate.getInvoiceSubCategory());\r\n            String queryDistinctTaxClass = \"Select  distinct(rt.taxClass) FROM RatedTransaction rt  WHERE rt.invoiceSubCategory.id=\"\r\n\t\t\t\t\t+ subCatInvAgregate.getInvoiceSubCategory().getId() +\" AND rt.seller.code = '\"+SELLER_CODE+\"' \";\r\n\t\t\tList<TaxClass> listTaxClass = (List<TaxClass>) invoiceService.executeSelectQuery(queryDistinctTaxClass, null);\r\n\t\t\tif (listTaxClass == null || listTaxClass.size() == 0) {\r\n\t\t\t\tthrow new BusinessException(\"No taxes for the subCat:\" + subCatInvAgregate.getInvoiceSubCategory().getCode());\r\n\t\t\t}\r\n\r\n\t\t\tString queryMappingTax = \"select m.tax from TaxMapping m where  m.chargeTaxClass.id=\" + listTaxClass.get(0).getId() + \"\";\r\n\t\t\tList<Tax> taxs = (List<Tax>) invoiceService.executeSelectQuery(queryMappingTax, null);\r\n\t\t\tif (taxs == null || taxs.isEmpty() || taxs.size() > 1) {\r\n\t\t\t\tthrow new BusinessException(\"Cant found tax for the taxClass:\" + listTaxClass.get(0).getCode());\r\n\t\t\t}\r\n\t\t\tTax tax = taxs.get(0);\r\n\t\t\tlog.info(\"tax byOC==>\"+tax);\r\n\r\n\t\t\tString key = date + \"_\" + subCatInvAgregate.getInvoiceSubCategory().getInvoiceCategory().getCode() + \"_\" + subCatInvAgregate.getAccountingCode().getCode() + \"_\" + tax;\r\n            log.info(\"lkey_OC here ==>\"+key);\r\n\t\t\tAccountingEntry accountingWriting = new AccountingEntry();\r\n            List<AccountOperation> accountOperations = new ArrayList<AccountOperation>();\r\n            if(accountingEntries.get(key) != null) {\r\n\t\t\t\tlog.info(\"enter key here!==>\"+key);\r\n                log.info(\"subCatInvAgregate.getAmountWithoutTax() ==>\"+subCatInvAgregate.getAmountWithoutTax());\r\n\t\t\t\tlog.info(\"accountingWriting.getAmount()before ==>\"+accountingWriting.getAmount());\r\n                accountingWriting = accountingEntries.get(key);\r\n                accountingWriting.setAmount(subCatInvAgregate.getAmountWithoutTax().add(accountingWriting.getAmount()));\r\n                log.info(\"accountingWriting.getAmount()after ==>\"+accountingWriting.getAmount());               \r\n\t\t\t   accountOperations.addAll(accountingWriting.getAccountOperations());\r\n            } else {\r\n\t\t\t\t log.info(\"NEW subCatInvAgregate.getAmountWithoutTax()==>\"+subCatInvAgregate.getAmountWithoutTax());\r\n                accountingWriting.setAmount(subCatInvAgregate.getAmountWithoutTax());\r\n            }\r\n            if(!accountOperations.contains(subCatInvAgregate.getInvoice().getRecordedInvoice())) {\r\n                accountOperations.add(subCatInvAgregate.getInvoice().getRecordedInvoice());\r\n            }\r\n\r\n            accountingWriting.setEventDate(date);\r\n            if(invoiceNumberList == null)\r\n                accountingWriting.setEventType(EventEnum.FACTURATION.getLabel());\r\n            else  accountingWriting.setEventType(EventEnum.ANNULATION_FACTURATION.getLabel());\r\n            accountingWriting.setAccountingCode(subCatInvAgregate.getAccountingCode());\r\n            accountingWriting.setInvoiceCategory(subCatInvAgregate.getInvoiceSubCategory().getInvoiceCategory());\r\n            accountingWriting.setExportDate(new Date());\r\n            accountingWriting.setAccountOperations(accountOperations);\r\n            accountingWriting.setTax(tax);\r\n            accountingEntries.put(key, accountingWriting);\r\n\r\n        }\r\n\r\n        for (Entry<String, AccountingEntry> entry : accountingEntries.entrySet()) {\r\n            AccountingEntry accountingWriting = entry.getValue();\r\n            log.debug(\"---- invoiceCategory : \");\r\n            log.debug(\"date ==>\"+ accountingWriting.getEventDate());\r\n            log.debug(\"invoiceCategory ==>\"+ accountingWriting.getInvoiceCategory());\r\n            log.debug(\"amount ==>\"+ accountingWriting.getAmount());\r\n            for(AccountOperation ao : accountingWriting.getAccountOperations()) {\r\n                log.debug(\" |__ ao ==>\"+ ao.getId());\r\n            }\r\n        }\r\n\r\n        return accountingEntries;\r\n    }\r\n\r\n    public Date getJobLastExecutionDate(String jobCode) throws BusinessException {\r\n        JobInstance jobInstance = jobInstanceService.findByCode(jobCode);\r\n        if (jobInstance == null) {\r\n            log.error(\"No Job instance by code {} was found\", jobCode);\r\n            throw new BusinessException(\"No Job instance by code was found\");\r\n        }\r\n\r\n        String query = \"select hist.startDate FROM JobExecutionResultImpl hist WHERE hist.nbItemsCorrectlyProcessed=1 AND hist.jobInstance=:jobInstance ORDER BY hist.startDate desc\";\r\n        Query q = jobInstanceService.getEntityManager().createQuery(query);\r\n        q.setParameter(\"jobInstance\", jobInstance);\r\n\r\n        try {\r\n            List<Object> results = q.getResultList();\r\n            if(results.size() == 0) {\r\n                return null;\r\n            }\r\n            Date lastExecutionDate = (Date) q.getResultList().get(0);\r\n            return lastExecutionDate;\r\n        } catch (Exception e) {\r\n            log.error(\"error = {}\", e);\r\n            return null;\r\n        }\r\n    }\r\n\r\n    public long countJobExecutionHistory(String jobCode, Date startDate, Date endDate) throws BusinessException {\r\n        JobInstance jobInstance = jobInstanceService.findByCode(jobCode);\r\n        if (jobInstance == null) {\r\n            log.error(\"No Job instance by code {} was found\", jobCode);\r\n            throw new BusinessException(\"No Job instance by code was found\");\r\n        }\r\n\r\n        Map<String, Object> params = Maps.newHashMap();\r\n        String query = \"select count(*) FROM JobExecutionResultImpl hist WHERE hist.jobInstance=:jobInstance\";\r\n        params.put(\"jobInstance\", jobInstance);\r\n        if (startDate != null) {\r\n            params.put(\"startDate\", startDate);\r\n            query += \" and hist.startDate >= :startDate\";\r\n        }\r\n        if (endDate != null) {\r\n            params.put(\"endDate\", endDate);\r\n            query += \" and hist.endDate < :endDate\";\r\n        }\r\n\r\n        Query q = jobInstanceService.getEntityManager().createQuery(query);\r\n        for (Map.Entry<String, Object> entry : params.entrySet()) {\r\n            q.setParameter(entry.getKey(), entry.getValue());\r\n        }\r\n        long result = (long) q.getSingleResult();\r\n        return result > 9 ? 0 : result;\r\n    }\r\n\r\n    private static String getEventLabel(String occCode) {\r\n        if(EventEnum.valueOf(occCode) != null) {\r\n            return EventEnum.valueOf(occCode).getLabel();\r\n        }\r\n        return \"\";\r\n    }\r\n\r\n    private String getZUONR(String occCode, String accountingCode) {\r\n        StringBuilder sb = new StringBuilder();\r\n        sb.append(accountingCode);\r\n        sb.append(PAD_STR);\r\n        log.info(\"ZUONR_accountingCode=>\"+accountingCode);\r\n        log.info(\"ZUONREnum.valueOf(occCode)=>\"+ZUONREnum.valueOf(occCode));\r\n        if(ZUONREnum.valueOf(occCode) != null) {\r\n            sb.append(ZUONREnum.valueOf(occCode).getLabel());\r\n        }\r\n\r\n        return sb.toString();\r\n    }\r\n    \r\n    private String getCostl(String invoiceCategoryCode) {\r\n    \tString costl = null;\r\n    \tString accountingCode=null;\r\n    \tInvoiceCategory invoiceCategory=invoiceCategoryService.findByCode(invoiceCategoryCode);\r\n    \tList<InvoiceSubCategory> invoiceSubCategories = invoiceSubCategoryService.findByInvoiceCategory(invoiceCategory);\r\n    \tfor(InvoiceSubCategory subCat:invoiceSubCategories) {\r\n    \t\taccountingCode=subCat.getAccountingCode().getCode();\r\n    \t\tif(accountingCode!=null) {\r\n    \t\t\t if (CAT_VENDING_CODE.equals(invoiceCategoryCode) && (ACCOUNT_1.equals(accountingCode) || ACCOUNT_2.equals(accountingCode))){\r\n    \t\t\t\tcostl=COSTL_VCA_IN;\r\n    \t\t\t}else if (CAT_VENDING_CODE_2.equals(invoiceCategoryCode) && (ACCOUNT_2.equals(accountingCode) || ACCOUNT_3.equals(accountingCode))){\r\n    \t\t\t\tcostl=COSTL_VCA_SE;\r\n    \t\t\t}else if (CAT_SERVICE_PROVISION_CODE.equals(invoiceCategoryCode)) { \r\n    \t\t\t\tif(SUB_CAT_DEE.equals(subCat.getCode()) && (ACCOUNT_1.equals(accountingCode) || ACCOUNT_2.equals(accountingCode))){\r\n    \t\t\t\t\tcostl=COSTL_VCA_DE;\r\n    \t\t\t\t}else if(ACCOUNT_1.equals(accountingCode) || ACCOUNT_2.equals(accountingCode)){\r\n    \t\t\t\t\tcostl=COSTL_VCA_MA;\r\n    \t\t\t\t} \t\r\n    \t\t\t}   \t    \r\n    \t\t}\r\n    \t}\r\n    \treturn costl;\r\n    }\r\n\r\n    private String getOperationType(AccountingEntry accountingWriting) {\r\n        String operationType = CREDIT;\r\n        if(accountingWriting.getAmount().compareTo(BigDecimal.ZERO) < 0) {\r\n            operationType = DEBIT;\r\n        }\r\n        return operationType;\r\n    }\r\n\r\n    private String getOperationTypeAvoir(AccountingEntry accountingWriting) {\r\n        String operationType = DEBIT;\r\n        if(accountingWriting.getAmount().compareTo(BigDecimal.ZERO) < 0) {\r\n            operationType = CREDIT;\r\n        }\r\n        return operationType;\r\n    }\r\n\r\n    private String getEventType(AccountingEntry accountingWriting) {\r\n        String eventType = EventEnum.FACTURATION.getLabel();\r\n        if(accountingWriting.getAmount().compareTo(BigDecimal.ZERO) < 0) {\r\n            eventType = EventEnum.ANNULATION_FACTURATION.getLabel();\r\n        }\r\n        return eventType;\r\n    }\r\n\r\n    private void appendLine(String line) {\r\n        if (!StringUtils.isBlank(line)) {\r\n            contentBuilder.append(line);\r\n            contentBuilder.append(NEW_LINE);\r\n        }\r\n    }\r\n\r\n    private void buildBGR00() {\r\n        contentBuilder.append(\"0\"); // STYPE\r\n        contentBuilder.append(FOLDER_ID).append(ORGA_CODE).append(OC_CODE);\r\n        contentBuilder.append(String.format(\"%03d\", LocalDate.now().getDayOfYear()));\r\n        contentBuilder.append(coutJobExecution); // GROUP _QUEUE_NAME\r\n        contentBuilder.append(MANDANT);\r\n        contentBuilder.append(rightPad(\"RAPEXPL\", 12, PAD_STR)); // USNAM\r\n        contentBuilder.append(rightPad(\"\", 8, PAD_STR)); // START\r\n        contentBuilder.append(\"X\"); // XKEEP\r\n        contentBuilder.append(SKIP_CHAR);// NODATA\r\n    }\r\n\r\n    private String buildBBKPF(Date bldat, Date budat, int index) {\r\n        StringBuilder stringBuilder = new StringBuilder();\r\n        stringBuilder.append(\"1\");// STYPE\r\n        stringBuilder.append(rightPad(\"FB01\", 20, PAD_STR));// TCODE\r\n        stringBuilder.append(DateUtils.formatDateWithPattern(bldat, \"ddMMyyyy\"));// BLDAT\r\n        stringBuilder.append(\"WY\");// BLART\r\n        stringBuilder.append(ORGA_CODE);// BUKRS\r\n        stringBuilder.append(DateUtils.formatDateWithPattern(budat, \"ddMMyyyy\"));// BUDAT\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 2, PAD_STR));// MONAT\r\n        stringBuilder.append(rightPad(\"EUR\", 5, PAD_STR));// WAERS\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 10, PAD_STR));// KURSF\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 10, PAD_STR));// BELNR\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 8, PAD_STR));// WWERT\r\n        stringBuilder.append(rightPad(PREFIX + DateUtils.formatDateWithPattern(new Date(), \"ddMMyyyy\") + index, 16, PAD_STR));// XBLNR\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 16, PAD_STR));// BVORG\r\n        stringBuilder.append(rightPad(ORGA_CODE + \"_\"+OC_CODE+\" \", 25, PAD_STR));// BVORG\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 4, PAD_STR));// PARGB\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 8, PAD_STR));// AUGLV\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 6, PAD_STR));// VBUND\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 1, PAD_STR));// XMWST\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 10, PAD_STR));// DOCID\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 40, PAD_STR));// BARCD\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 8, PAD_STR));// STODT\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 4, PAD_STR));// BRNCH\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 3, PAD_STR));// NUMPG\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 2, PAD_STR));// STGRD\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 10, PAD_STR));// KURSF_M\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 50, PAD_STR));// AUGTX\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 1, PAD_STR));// XPRFG\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 1, PAD_STR));// XBWAE\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 4, PAD_STR));// LDGRP\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 13, PAD_STR));// PROPMANO\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 8, PAD_STR));// VATDATE\r\n        stringBuilder.append(rightPad(SKIP_CHAR, 1, PAD_STR));// SENDE\r\n        return stringBuilder.toString();\r\n    }\r\n\r\n    private String buildBBSEG(String accountType, String eventLabel, String amount, Date valut, String zuonr, String codeTVA, String accountCode, String kostl) {\r\n        TreeMap<Integer, Zone> zonesBBSEG = new TreeMap<>();\r\n        List<Integer> zoneLenghtBGR00List = Arrays\r\n                .asList(new Integer[] { 1, 30, 2, 10, 1, 4, 16, 16, 16, 16, 2, 1, 16, 16, 4, 10, 4, 12, 10, 5, 16, 18, 4, 17, 3, 10, 6, 4, 8, 3, 8, 8, 2, 18, 3, 1, 50, 2, 16, 8, 2, 16,\r\n                        16, 4, 3, 6, 3, 6, 3, 1, 10, 4, 3, 1, 8, 1, 2, 16, 16, 11, 2, 27, 8, 2, 12, 4, 8, 3, 7, 16, 10, 1, 1, 5, 4, 10, 4, 4, 3, 3, 1, 8, 8, 8, 1, 18, 1, 35, 35, 35,\r\n                        35, 35, 35, 10, 3, 3, 15, 3, 18, 2, 16, 11, 8, 1, 3, 3, 20, 1, 1, 10, 10, 1, 1, 17, 3, 17, 10, 10, 13, 1, 4, 16, 16, 14, 6, 3, 2, 10, 12, 8, 8, 10, 12, 4, 1, 2,\r\n                        10, 24, 2, 15, 16, 10, 16, 16, 4, 12, 12, 10, 3, 8, 1, 1, 30, 30, 30, 30, 60, 60, 8, 3, 16, 16, 1, 1, 2, 1, 18, 2, 4, 4, 6, 5, 4, 4, 4, 10, 2, 6, 10, 4, 12, 3,\r\n                        1, 9, 10, 24, 12, 2, 4, 3, 4, 2, 4, 2, 2, 10, 10, 10, 2, 3, 9, 2, 2, 4, 3, 8, 10, 6, 4, 8, 1, 3, 24, 1, 2, 3, 2, 2, 2, 1, 18, 18, 20, 30, 2, 2, 2, 2, 2, 5, 16,\r\n                        4, 4, 6, 10, 8, 8, 8, 8, 13, 4, 5, 13, 10, 4, 10, 10, 10, 30, 30, 5, 15, 13, 13, 20, 1, 2, 20, 16, 1, 34, 8, 10, 10, 5, 1, 16, 8, 1, 10, 1, 1, 8, 10, 8 });\r\n\r\n        zonesBBSEG.put(1, new Zone(1, \"2\"));// STYPE\r\n        zonesBBSEG.put(2, new Zone(30, \"BBSEG\"));// TBNAM\r\n        zonesBBSEG.put(32, new Zone(2, accountType));// NEWBS : 40 si compte débit / 50 si compte crédit\r\n        zonesBBSEG.put(49, new Zone(16, amount));// WRBTR\r\n        zonesBBSEG.put(113, new Zone(2, StringUtils.isBlank(codeTVA) ? SKIP_CHAR : codeTVA));// MWSKZ\r\n        if (!StringUtils.isBlank(kostl)) {\r\n            zonesBBSEG.put(152, new Zone(10, kostl, \"\", true));// KOSTL\r\n        }\r\n        zonesBBSEG.put(282, new Zone(8, \"\"));// VALUT , previous value = DateUtils.formatDateWithPattern(valut, \"ddMMyyyy\"))\r\n        zonesBBSEG.put(300, new Zone(18, \"Opencell\")); // ZUONR , previous value = zuonr\r\n        zonesBBSEG.put(322, new Zone(50, eventLabel)); // ZUONR\r\n        zonesBBSEG.put(1059, new Zone(17, accountCode, \"0\", true)); // NEWKO\r\n\r\n        return generateRecordLine(zonesBBSEG, zoneLenghtBGR00List);\r\n    }\r\n\r\n    private String buildBBTAX(String accountType, String amount, String codeTVA) {\r\n        TreeMap<Integer, Zone> zonesBBTAX = new TreeMap<>();\r\n        List<Integer> zoneLenghtBBTAXList = Arrays.asList(new Integer[] { 1, 30, 16, 2, 2, 15, 16, 4, 16, 16, 16, 16, 16, 16, 10, 1 });\r\n\r\n        zonesBBTAX.put(1, new Zone(1, \"2\"));// STYPE\r\n        zonesBBTAX.put(2, new Zone(30, \"BBTAX\"));// TBNAM\r\n        zonesBBTAX.put(32, new Zone(16, amount));// FWSTE\r\n        zonesBBTAX.put(48, new Zone(2, StringUtils.isBlank(codeTVA) ? SKIP_CHAR : codeTVA));// MWSKZ\r\n        zonesBBTAX.put(50, new Zone(2, accountType));// BSCHL : 40 si compte débit / 50 si compte crédit\r\n\r\n        return generateRecordLine(zonesBBTAX, zoneLenghtBBTAXList);\r\n    }\r\n\r\n    private String generateRecordLine(TreeMap<Integer, Zone> zones, List<Integer> zoneLenghtList) {\r\n        int pos = 1;\r\n        int lg;\r\n        for (int i = 0; i < zoneLenghtList.size(); i++) {\r\n            lg = zoneLenghtList.get(i);\r\n            if (zones.get(pos) == null) {\r\n                zones.put(pos, new Zone(lg, SKIP_CHAR));\r\n            }\r\n            pos += lg;\r\n        }\r\n        StringBuilder sb = new StringBuilder();\r\n        zones.forEach((p, zone) -> {\r\n            if (zone.value.length() >= zone.lg) {\r\n                sb.append(zone.value.substring(0, zone.lg));\r\n            } else {\r\n                if (zone.leftPad) {\r\n                    sb.append(leftPad(zone.value, zone.lg, zone.padStr));\r\n                } else {\r\n                    sb.append(rightPad(zone.value, zone.lg, zone.padStr));\r\n                }\r\n            }\r\n        });\r\n        return sb.toString();\r\n    }\r\n\r\n    private String round(BigDecimal amount, Integer scale) {\r\n        if (amount == null) {\r\n            amount = BigDecimal.ZERO;\r\n        }\r\n        if (scale == null) {\r\n            scale = 2;\r\n        }\r\n        amount = amount.setScale(scale, RoundingMode.HALF_UP);\r\n        return decimalFormat.format(amount);\r\n    }\r\n\r\n    private String getSafeAccountingCode(AccountingCode ac) {\r\n        if (ac != null) {\r\n            return ac.getCode();\r\n        }\r\n        return \"\";\r\n    }\r\n\r\n    private Invoice findByInvoiceNumber(String invoiceNumber){\r\n        try {\r\n            \r\n            QueryBuilder qb = new QueryBuilder(Invoice.class, \"i\");\r\n            qb.addCriterion(\"invoiceNumber\", \"=\", invoiceNumber, false);\r\n\r\n            return (Invoice) qb.getQuery(invoiceService.getEntityManager()).getSingleResult();\r\n        } catch (NoResultException ne) {\r\n            return null;\r\n        }\r\n\r\n    }\r\n\r\n    private Tax findTaxByCode(String code){\r\n        try {\r\n           \r\n            QueryBuilder qb = new QueryBuilder(Tax.class, \"t\");\r\n            qb.addCriterion(\"code\", \"=\", code, false);\r\n\r\n            return (Tax) qb.getQuery(invoiceService.getEntityManager()).getSingleResult();\r\n        } catch (NoResultException ne) {\r\n            return null;\r\n        }\r\n\r\n    }\r\n\r\n}]]>\r\n            </script>\r\n</ScriptInstance>"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "FixInvoicesAmountsScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript",
										"packages": {}
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.compta.FixInvoicesAmountsScript\" description=\"FixInvoicesAmountsScript\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.compta;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.model.billing.*;\r\nimport org.meveo.service.billing.impl.InvoiceAgregateService;\r\nimport org.meveo.service.billing.impl.InvoiceService;\r\nimport org.meveo.service.billing.impl.RatedTransactionService;\r\nimport org.meveo.service.script.Script;\r\n\r\nimport javax.persistence.Tuple;\r\nimport java.math.BigDecimal;\r\nimport java.util.ArrayList;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.stream.Collectors;\r\n\r\npublic class FixInvoicesAmountsScript extends Script {\r\n\r\n\r\n    private InvoiceService invoiceService = (InvoiceService) getServiceInterface(\"InvoiceService\");\r\n    private RatedTransactionService ratedTransactionService = (RatedTransactionService) getServiceInterface(\"RatedTransactionService\");\r\n    private InvoiceAgregateService invoiceAgregateService = (InvoiceAgregateService) getServiceInterface(\"InvoiceAgregateService\");\r\n    //private RecordedInvoiceService recordedInvoiceService = (RecordedInvoiceService) getServiceInterface(\"RecordedInvoiceService\");\r\n\r\n    @Override\r\n    public void execute(Map<String, Object> context) throws BusinessException {\r\n        List<Invoice> invWithPbList = new ArrayList<>();\r\n\r\n\r\n        // lits of invoices with pb sum(RT.amounts) != inv.totals\r\n        List<Object[]> invRTSumPbList = invoiceService.getEntityManager()\r\n                .createQuery(\"SELECT inv.id, SUM(rt.amountWithoutTax), inv.amountWithoutTax \" +\r\n                                \"FROM RatedTransaction rt JOIN rt.invoice inv \" +\r\n                                \"GROUP BY inv.id \" +\r\n                                \"HAVING SUM(rt.amountWithoutTax) <> inv.amountWithoutTax \" +\r\n                                \"OR SUM(rt.amountTax) <> inv.amountTax \" +\r\n                                \"OR SUM(rt.amountWithTax) <> inv.amountWithTax\",\r\n                        Object[].class).getResultList();\r\n\r\n        log.info(\"Fixing invoices with pb sum(RT.amounts) != inv.totals. Nbr of inv to fix {}\", invRTSumPbList.size());\r\n        //invWithPbList.addAll(invRTSumPbList.stream().map(row -> invoiceService.findById((Long) row[0])).collect(Collectors.toList()));\r\n\r\n        // fixing invoice total pb\r\n        var invTotalPbList = invoiceService.getEntityManager()\r\n                .createQuery(\"Select inv from Invoice inv \" +\r\n                                \"Where inv.amountWithoutTax + inv.amountTax != inv.amountWithTax and inv.nvoiceNumber LIKE '4%'\",\r\n                        Invoice.class).getResultList();\r\n\r\n        invWithPbList.addAll(invTotalPbList.stream()\r\n                .filter(inv -> inv.getAmountWithoutTax().add(inv.getAmountTax()).compareTo(inv.getAmountWithTax()) != 0)\r\n                .collect(Collectors.toList()));\r\n\r\n        log.info(\"Start fixing invoices amounts: {} invoices to fix\", invWithPbList.size());\r\n        log.info(\"invoices numbers to fix: {}\", invWithPbList.stream().map(Invoice::getInvoiceNumber).collect(Collectors.joining(\",\")));\r\n\r\n        for (Invoice invoice : invWithPbList) {\r\n            log.info(\"start fixing invoice {}\", invoice.getInvoiceNumber());\r\n            fixInvoiceTotals(invoice);\r\n            fixInvoiceAgregats(invoice);\r\n            //fixRecordedInvoiceAmounts(invoice);\r\n            log.info(\"finish fixing invoice {}\", invoice.getInvoiceNumber());\r\n        }\r\n    }\r\n\r\n    private void fixInvoiceTotals(Invoice invoice) {\r\n        log.info(\"fixing Invoice {} totals, old amounts: ht={}, tva={}, ttc={}\", invoice.getInvoiceNumber(),\r\n                invoice.getAmountWithoutTax(), invoice.getAmountTax(), invoice.getAmountWithTax());\r\n\r\n        var jpaInvoiceTotals = \"Select SUM(rt.amountWithoutTax) as ht, SUM(rt.amountTax) as tva, SUM(rt.amountWithTax) as ttc \" +\r\n                \"From RatedTransaction rt where rt.invoice = :invoice and rt.status='BILLED'\";\r\n        var invoiceTotals = invoiceService.getEntityManager()\r\n                .createQuery(jpaInvoiceTotals, Tuple.class)\r\n                .setParameter(\"invoice\", invoice)\r\n                .getResultList().get(0);\r\n\r\n        invoice.setAmountWithoutTax(invoiceTotals.get(\"ht\", BigDecimal.class));\r\n        invoice.setAmountTax(invoiceTotals.get(\"tva\", BigDecimal.class));\r\n        invoice.setAmountWithTax(invoiceTotals.get(\"ttc\", BigDecimal.class));\r\n\r\n        invoiceService.updateNoCheck(invoice);\r\n\r\n        log.info(\"new Invoice {} totals: ht={}, tva={}, ttc={}\", invoice.getInvoiceNumber(),\r\n                invoice.getAmountWithoutTax(), invoice.getAmountTax(), invoice.getAmountWithTax());\r\n    }\r\n\r\n    private void fixInvoiceAgregats(Invoice invoice) {\r\n        Map<Long, CategoryInvoiceAgregate> catInvAgregateMap = new HashMap<>();\r\n        Map<String, SubCategoryInvoiceAgregate> subCatInvAgregateMap = new HashMap<>();\r\n        Map<String, TaxInvoiceAgregate> taxInvAgregateMap = new HashMap<>();\r\n\r\n        log.info(\"fixing Invoice {} agregates...\", invoice.getInvoiceNumber());\r\n\r\n        // reset invoice's agregates amounts\r\n        for (InvoiceAgregate invoiceAgregate: invoice.getInvoiceAgregates()) {\r\n            if (invoiceAgregate instanceof CategoryInvoiceAgregate) {\r\n                catInvAgregateMap.put(invoiceAgregate.getId(), (CategoryInvoiceAgregate) invoiceAgregate);\r\n            }\r\n            if (invoiceAgregate instanceof SubCategoryInvoiceAgregate) {\r\n                SubCategoryInvoiceAgregate subCatInvAgregate = (SubCategoryInvoiceAgregate) invoiceAgregate;\r\n                subCatInvAgregateMap.put(subCatInvAgregate.getInvoiceSubCategory().getCode(), subCatInvAgregate);\r\n                for (var amountsByTax: subCatInvAgregate.getAmountsByTax().values()) {\r\n                    amountsByTax.setAmountWithoutTax(BigDecimal.ZERO);\r\n                    amountsByTax.setAmountTax(BigDecimal.ZERO);\r\n                    amountsByTax.setAmountWithTax(BigDecimal.ZERO);\r\n                }\r\n            }\r\n            if (invoiceAgregate instanceof TaxInvoiceAgregate) {\r\n                TaxInvoiceAgregate taxInvAgregate = (TaxInvoiceAgregate) invoiceAgregate;\r\n                taxInvAgregateMap.put(taxInvAgregate.getTax().getCode(), (TaxInvoiceAgregate) invoiceAgregate);\r\n            }\r\n            invoiceAgregate.setAmount(BigDecimal.ZERO);\r\n            invoiceAgregate.setAmountWithoutTax(BigDecimal.ZERO);\r\n            invoiceAgregate.setAmountWithTax(BigDecimal.ZERO);\r\n            invoiceAgregate.setAmountTax(BigDecimal.ZERO);\r\n            invoiceAgregate.setItemNumber(0);\r\n        }\r\n\r\n        var invRTsList = ratedTransactionService.listRatedTransactionsByInvoice(invoice);\r\n\r\n        for (var rt: invRTsList) {\r\n            SubCategoryInvoiceAgregate subCatInvAgregate = subCatInvAgregateMap.get(rt.getInvoiceSubCategory().getCode());\r\n            if (subCatInvAgregate == null) {\r\n                throw new BusinessException(\"Illegal state of invoice + \" + invoice.getInvoiceNumber() + \": It contains RT(id=\"\r\n                        +rt.getId()+\", subCat=\"+rt.getInvoiceSubCategory().getCode()+\") that belongs to any of invoice's subCatAgregates\");\r\n            }\r\n\r\n            //update sub cat agregate\r\n            subCatInvAgregate.addItemNumber(1);\r\n            subCatInvAgregate.addAmountWithoutTax(rt.getAmountWithoutTax());\r\n            subCatInvAgregate.addAmountWithTax(rt.getAmountWithTax());\r\n            subCatInvAgregate.addAmountTax(rt.getAmountTax());\r\n            SubcategoryInvoiceAgregateAmount scAmountInfo = subCatInvAgregate.getAmountsByTax().get(rt.getTax());\r\n            if (scAmountInfo == null) {\r\n                throw new BusinessException(\"Illegal state of invoice + \" + invoice.getInvoiceNumber() + \": It contains RT(id=\"\r\n                        +rt.getId()+\", tax=\"+rt.getTax().getCode()+\") that belongs to any of scAmountInfo of the subCatAgregate \"+rt.getInvoiceSubCategory().getCode());\r\n            }\r\n            scAmountInfo.addAmounts(rt.getAmountWithoutTax(), rt.getAmountWithTax(), rt.getAmountTax());\r\n\r\n            //update cat agregate\r\n            CategoryInvoiceAgregate catInvAgregate = catInvAgregateMap.get(subCatInvAgregate.getCategoryInvoiceAgregate().getId());\r\n            catInvAgregate.addItemNumber(1);\r\n            catInvAgregate.addAmountWithoutTax(rt.getAmountWithoutTax());\r\n            catInvAgregate.addAmountWithTax(rt.getAmountWithTax());\r\n            catInvAgregate.addAmountTax(rt.getAmountTax());\r\n\r\n            //update cat agregate\r\n            TaxInvoiceAgregate invoiceAgregateTax = taxInvAgregateMap.get(rt.getTax().getCode());\r\n            /*if (invoiceAgregateTax == null && BigDecimal.ZERO.compareTo(rt.getAmountTax().setScale(2, RoundingMode.HALF_EVEN)) != 0) {\r\n                throw new BusinessException(\"Illegal state of invoice + \" + invoice.getInvoiceNumber() + \": It contains RT(id=\"\r\n                        +rt.getId()+\") that belongs to any of invoice's taxAgregates\");\r\n            }*/\r\n            if (invoiceAgregateTax == null) {\r\n                continue;\r\n            }\r\n            invoiceAgregateTax.addItemNumber(1);\r\n            invoiceAgregateTax.addAmountWithoutTax(rt.getAmountWithoutTax());\r\n            invoiceAgregateTax.addAmountWithTax(rt.getAmountWithTax());\r\n            invoiceAgregateTax.addAmountTax(rt.getAmountTax());\r\n        }\r\n\r\n        for (CategoryInvoiceAgregate catInvAgregate : catInvAgregateMap.values()) {\r\n            log.info(\"fixing Invoice {} catInvAgregate[code={}, ht={}, tva={}, ttc={}]\", invoice.getInvoiceNumber(), catInvAgregate.getInvoiceCategory().getCode(),\r\n                    catInvAgregate.getAmountWithoutTax(), catInvAgregate.getAmountTax(), catInvAgregate.getAmountWithTax());\r\n            invoiceAgregateService.update(catInvAgregate);\r\n        }\r\n        for (SubCategoryInvoiceAgregate subCatInvAgregate : subCatInvAgregateMap.values()) {\r\n            log.info(\"fixing Invoice {} subCatInvAgregate[code={}, ht={}, tva={}, ttc={}]\", invoice.getInvoiceNumber(), subCatInvAgregate.getInvoiceSubCategory().getCode(),\r\n                    subCatInvAgregate.getAmountWithoutTax(), subCatInvAgregate.getAmountTax(), subCatInvAgregate.getAmountWithTax());\r\n            invoiceAgregateService.update(subCatInvAgregate);\r\n        }\r\n        for (TaxInvoiceAgregate taxInvAgregate : taxInvAgregateMap.values()) {\r\n            log.info(\"fixing Invoice {} taxInvAgregate[code={}, ht={}, tva={}, ttc={}]\", invoice.getInvoiceNumber(), taxInvAgregate.getTax().getCode(),\r\n                    taxInvAgregate.getAmountWithoutTax(), taxInvAgregate.getAmountTax(), taxInvAgregate.getAmountWithTax());\r\n            invoiceAgregateService.update(taxInvAgregate);\r\n        }\r\n    }\r\n\r\n    /*private void fixRecordedInvoiceAmounts(Invoice invoice) {\r\n        if (invoice.getRecordedInvoice() == null) {\r\n            return;\r\n        }\r\n        RecordedInvoice ri = invoice.getRecordedInvoice();\r\n\r\n\r\n        // adjust RI amounts\r\n        ri.setAmount(invoice.getAmountWithTax().abs());\r\n        ri.setAmountWithoutTax(invoice.getAmountWithoutTax().abs());\r\n        ri.setTaxAmount(invoice.getAmountTax().abs());\r\n\r\n        // adjust unmatched amount\r\n        BigDecimal diffAmount = invoice.getAmountWithTax().abs().subtract(ri.getAmount().abs());\r\n        boolean unMatchingAmountAltered = diffAmount.compareTo(BigDecimal.ZERO) != 0;\r\n\r\n        if (diffAmount.compareTo(BigDecimal.ZERO) >= 0) {\r\n            ri.setUnMatchingAmount(ri.getUnMatchingAmount().add(diffAmount.abs()));\r\n        } else {\r\n            ri.setUnMatchingAmount(ri.getUnMatchingAmount().subtract(diffAmount.abs()).abs());\r\n        }\r\n        if (unMatchingAmountAltered && ri.getMatchingStatus() == MatchingStatusEnum.L) {\r\n            if (BigDecimal.ZERO.compareTo(ri.getMatchingAmount()) == 0) {\r\n                ri.setMatchingStatus(MatchingStatusEnum.O);\r\n            } else {\r\n                ri.setMatchingStatus(MatchingStatusEnum.P);\r\n            }\r\n        }\r\n\r\n        recordedInvoiceService.updateNoCheck(ri);\r\n    }*/\r\n\r\n\r\n}\r\n\r\n\r\n]]>\r\n            </script>\r\n</ScriptInstance>"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						}
					]
				},
				{
					"name": "payment",
					"item": [
						{
							"name": "MercanetIntegrationScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.payment.MercanetIntegrationScript\" description=\"Ekko Mercanet Integration Script\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.payment;\r\n\r\nimport java.io.BufferedReader;\r\nimport java.io.File;\r\nimport java.io.FileInputStream;\r\nimport java.io.FileNotFoundException;\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.InputStreamReader;\r\nimport java.math.BigDecimal;\r\nimport java.nio.charset.StandardCharsets;\r\nimport java.nio.file.Files;\r\nimport java.nio.file.Path;\r\nimport java.nio.file.Paths;\r\nimport java.time.LocalDate;\r\nimport java.time.ZoneId;\r\nimport java.util.ArrayList;\r\nimport java.util.Arrays;\r\nimport java.util.Date;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.stream.Collectors;\r\nimport java.util.stream.Stream;\r\n\r\nimport javax.persistence.NoResultException;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.admin.exception.NoAllOperationUnmatchedException;\r\nimport org.meveo.admin.exception.UnbalanceAmountException;\r\nimport org.meveo.commons.utils.ParamBean;\r\nimport org.meveo.commons.utils.ParamBeanFactory;\r\nimport org.meveo.commons.utils.QueryBuilder;\r\nimport org.meveo.commons.utils.StringUtils;\r\nimport org.meveo.model.MatchingReturnObject;\r\nimport org.meveo.model.crm.Provider;\r\nimport org.meveo.model.payments.CustomerAccount;\r\nimport org.meveo.model.payments.MatchingStatusEnum;\r\nimport org.meveo.model.payments.MatchingTypeEnum;\r\nimport org.meveo.model.payments.OCCTemplate;\r\nimport org.meveo.model.payments.Payment;\r\nimport org.meveo.model.payments.PaymentMethodEnum;\r\nimport org.meveo.model.payments.RecordedInvoice;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.service.admin.impl.SellerService;\r\nimport org.meveo.service.crm.impl.ProviderService;\r\nimport org.meveo.service.payments.impl.AccountOperationService;\r\nimport org.meveo.service.payments.impl.CustomerAccountService;\r\nimport org.meveo.service.payments.impl.MatchingCodeService;\r\nimport org.meveo.service.payments.impl.OCCTemplateService;\r\nimport org.meveo.service.payments.impl.PaymentService;\r\nimport org.meveo.service.payments.impl.RecordedInvoiceService;\r\nimport org.meveo.service.script.Script;\r\n\r\nimport com.google.common.collect.Maps;\r\n\r\n/**\r\n * /**\r\n * \r\n * @author myPower team , from dump PP 19/05/2021\r\n * \r\n * @author anasseh update for OC 11 and EKKO\r\n * @author anasseh 05/06/2022 SUPS-1688\r\n * @author anasseh 08/05/2023 SUPS-2462\r\n * \r\n * \r\n *\r\n */\r\npublic class MercanetIntegrationScript extends Script {\r\n\r\n\tprivate static final String SELLER_CODE = \"EKKO\";\r\n\tprivate static final String DATETIME_FORMAT = \"dd_MM_yyyy-HHmm\";\r\n\tprivate static final String MERCANET_INPUT_DIR = \"MERCANET_INPUT_DIR\";\r\n\tprivate static final String MERCANET_FILE_EXT = \"MERCANET_FILE_EXT\";\r\n\tprivate static final String MERCANET_DELIMITER = \"MERCANET_DELIMITER\";\r\n\tprivate static final String MERCANET_ARCH_DIR = \"MERCANET_ARCH_DIR\";\r\n\tprivate static final String MERCANET_ERR_DIR = \"MERCANET_ERR_DIR\";\r\n\tprivate static final String MERCANET_WARN_DIR = \"MERCANET_WARN_DIR\";\r\n\tprivate static final String MERCANET_REPORT_DIR = \"MERCANET_REPORT_DIR\";\r\n\tprivate RecordedInvoiceService recordedInvoiceService = (RecordedInvoiceService) getServiceInterface(\"RecordedInvoiceService\");\r\n\tprivate PaymentService paymentService = (PaymentService) getServiceInterface(\"PaymentService\");\r\n\tprivate ParamBeanFactory paramBeanFactory = (ParamBeanFactory) getServiceInterface(\"ParamBeanFactory\");\r\n\tprivate OCCTemplateService oCCTemplateService = (OCCTemplateService) getServiceInterface(\"OCCTemplateService\");\r\n\tprivate MatchingCodeService matchingCodeService = (MatchingCodeService) getServiceInterface(\"MatchingCodeService\");\r\n\tprivate Provider appProvider = ((ProviderService) getServiceInterface(\"ProviderService\")).getProvider();\r\n\tprivate SellerService sellerService = (SellerService) getServiceInterface(\"SellerService\");\r\n\tprivate CustomerAccountService customerAccountService = (CustomerAccountService) getServiceInterface(\"CustomerAccountService\");\r\n\tprivate AccountOperationService accountOperationService = (AccountOperationService) getServiceInterface(\"AccountOperationService\");\r\n\t\r\n\r\n\tprivate String delimiter;\r\n\tprivate OCCTemplate occCardTemplate;\r\n\tprivate Map<String, Integer> processedItemsIndexes;\r\n\tprivate List<String> reportMessages = new ArrayList<>();\r\n\t\r\n\r\n\t/**\r\n\t * script main execute method \r\n\t * \r\n\t * @param methodContext method context params\r\n\t * @throws BusinessException business exception\r\n\t */\r\n\t@Override\r\n\tpublic void execute(Map<String, Object> methodContext) throws BusinessException {\r\n\t\tlog.info(\"Execute methodContext:{}\", methodContext);\r\n\t\tlong startTime = System.currentTimeMillis();\r\n\t\tString mercanetDir = (String) methodContext.get(MERCANET_INPUT_DIR);\r\n\t\tString archiveDir = (String) methodContext.get(MERCANET_ARCH_DIR);\r\n\t\tString errorDir = (String) methodContext.get(MERCANET_ERR_DIR);\r\n\t\tString warnDir = (String) methodContext.get(MERCANET_WARN_DIR);\r\n\t\tString reportDir = (String) methodContext.get(MERCANET_REPORT_DIR);\r\n\t\tString mercanetFileExt = (String) methodContext.get(MERCANET_FILE_EXT);\r\n\t\tString mercanetDelimiter = (String) methodContext.get(MERCANET_DELIMITER);\r\n\t\tlog.debug(\"MERCANET_INPUT_DIR={}\", mercanetDir);\r\n\t\tlog.debug(\"MERCANET_FILE_EXT={}\", mercanetFileExt);\r\n\t\tlog.debug(\"MERCANET_DELIMITER={}\", mercanetDelimiter);\r\n\t\tlog.debug(\"MERCANET_ARCH_DIR={}\", archiveDir);\r\n\t\tlog.debug(\"MERCANET_WARN_DIR={}\", warnDir);\r\n\t\tlog.debug(\"MERCANET_ERR_DIR={}\", errorDir);\r\n\t\tlog.debug(\"MERCANET_REPORT_DIR={}\", reportDir);\r\n\t\tif (StringUtils.isBlank(mercanetDir)) {\r\n\t\t\tthrow new BusinessException(\"The variable input \" + MERCANET_INPUT_DIR + \" is mandatory\");\r\n\t\t}\r\n\t\tString rootDir = ParamBean.getInstance().getChrootDir(appProvider.getCode());\r\n\t\tPath archiveDirPath = Paths.get(rootDir + File.separator + (!StringUtils.isBlank(archiveDir) ? archiveDir : \"mercanet_archive\"));\r\n\t\tPath errorDirPath = Paths.get(rootDir + File.separator + (!StringUtils.isBlank(errorDir) ? errorDir : \"mercanet_errors\"));\r\n\t\tPath warnDirPath = Paths.get(rootDir + File.separator + (!StringUtils.isBlank(warnDir) ? warnDir : \"mercanet_warns\"));\r\n\t\tPath reportDirPath = Paths.get(rootDir + File.separator + (!StringUtils.isBlank(reportDir) ? reportDir : \"mercanet_reports\"));\r\n\t\tmercanetFileExt = !StringUtils.isBlank(mercanetFileExt) ? \".\" + mercanetFileExt : \".csv\";\r\n\t\tthis.delimiter = !StringUtils.isBlank(mercanetDelimiter) ? mercanetDelimiter : \"\\t\";\r\n\t\tPath inputDir = Paths.get(rootDir + File.separator + mercanetDir);\r\n\t\tif (!createDirIfNotExist(inputDir)) {\r\n\t\t\tthrow new BusinessException(\"inputDir doesn't exist and could not be created\");\r\n\t\t}\r\n\t\tif (!createDirIfNotExist(warnDirPath)) {\r\n\t\t\tthrow new BusinessException(\"warnDirPath doesn't exist and could not be created\");\r\n\t\t}\r\n\t\tList<Path> mercanetFiles = getMercanetLogFiles(inputDir, mercanetFileExt);\r\n\t\tlog.info(\"mercanetFiles\" + mercanetFiles);\r\n\r\n\t\tif (!createDirIfNotExist(reportDirPath)) {\r\n\t\t\tthrow new BusinessException(\"reportDirPath doesn't exist and could not be created\");\r\n\t\t}\r\n\t\tif (mercanetFiles == null || mercanetFiles.isEmpty()) {\r\n\t\t\tlog.warn(\"No mercanet files are found in the input Dir. will exit!\");\r\n\t\t\tmethodContext.put(Script.JOB_RESULT_NB_OK, 0);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlog.debug(\"{} mercanet files found. start import them...\", mercanetFiles.size());\r\n\t\tif (!createDirIfNotExist(archiveDirPath)) {\r\n\t\t\tthrow new BusinessException(\"Archive dir doesn't exist and could not be created\");\r\n\t\t}\r\n\t\tif (!createDirIfNotExist(errorDirPath)) {\r\n\t\t\tthrow new BusinessException(\"Error dir doesn't exist and could not be created\");\r\n\t\t}\r\n\t\tStringBuilder sbFiles = new StringBuilder(\"Processed \" + mercanetFiles.size() + \" mercanet files :\\n\");\r\n\t\tmercanetFiles.forEach(file -> {\r\n\t\t\tsbFiles.append(file.getFileName() + \"\\n\");\r\n\t\t});\r\n\t\t// OCC template for card and refund\r\n\t\tParamBean paramBean = paramBeanFactory.getInstance();\r\n\t\tString occCardTemplateCode = paramBean.getProperty(\"occ.payment.card\", \"PAY_CRD\");\r\n\t\tthis.occCardTemplate = getOCCTemplate(occCardTemplateCode);\r\n\t\t// counters for all import\r\n\t\tProcessingReport allReport = new ProcessingReport();\r\n\t\tprocessedItemsIndexes = new HashMap<>();\r\n\t\tfor (Path mercanetFile : mercanetFiles) {\r\n\t\t\tString fileName = mercanetFile.getFileName().toString();\r\n\t\t\t// addReportMessage(\"Start processing file \" +fileName+ \"...\", null);\r\n\t\t\tInputStream inputStream = null;\r\n\t\t\ttry {\r\n\t\t\t\tinputStream = new FileInputStream(mercanetFile.toFile());\r\n\t\t\t} catch (FileNotFoundException e) {\r\n\t\t\t\tlog.error(\"Error reading mercanet file \", mercanetFile.toString(), e);\r\n\t\t\t\taddReportMessage(\"Error reading file: \" + e.getMessage(), fileName);\r\n\t\t\t\tallReport.opKo++;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\ttry (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {\r\n\t\t\t\t// skip the headers of the csv\r\n\t\t\t\tbufferedReader.readLine();\r\n\t\t\t\tbufferedReader.readLine();\r\n\t\t\t\t// counters per file\r\n\t\t\t\tProcessingReport fileReport = new ProcessingReport();\r\n\t\t\t\t// Read operations lines\r\n\t\t\t\tString line;\r\n\t\t\t\tint index = 2;\r\n\t\t\t\twhile ((line = bufferedReader.readLine()) != null && !line.equals(\"END\") && !StringUtils.isBlank(line)) {\r\n\t\t\t\t\tindex++;\r\n\t\t\t\t\tMercanetItem item = mapToItem(line, index);\r\n\t\t\t\t\titem.fileName = fileName;\r\n\t\t\t\t\t// #203 : Uniqueness of payment based on reference and MerchantId\r\n\t\t\t\t\tif (findPaymentByReferenceAndPaymentOrder(item.transactionReference) != null) {\r\n\t\t\t\t\t\tlog.error(\"Payment already created for mercanet operation at line n={}, fileName={}\", item.numLine, item.fileName);\r\n\t\t\t\t\t\taddReportMessage(\"Payment already created for line n=\" + item.numLine, item.fileName);\r\n\t\t\t\t\t\tfileReport.opKo++;\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (processedItemsIndexes.get(item.getIdentifier()) != null) {\r\n\t\t\t\t\t\tInteger duplicateIndex = processedItemsIndexes.get(item.getIdentifier());\r\n\t\t\t\t\t\tlog.debug(\"Warning! Line \" + index + \" is a duplicate of line number \" + processedItemsIndexes.get(item.getIdentifier()) + \". Filename=\" + fileName);\r\n\t\t\t\t\t\taddReportMessage(\"Warning! Line=\" + index + \", message=Line is escaped because it's a duplicate of line number \" + duplicateIndex, fileName);\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (item.operationType.equals(\"CREDIT\") || item.operationType.equals(\"DEBIT\") || item.operationType.equals(\"DEBIT_CAPTURE\")) {\r\n\t\t\t\t\t\ttry {\r\n\t\t\t\t\t\t\tPayment payment =  null;\r\n\t\t\t\t\t\t\tRecordedInvoice mainRecordedInvoice  = getRecordedInvoice(item.invoiceNumber);\r\n\t\t\t\t\t\t\tCustomerAccount customerAccount = null;\r\n\t\t\t\t\t\t\tif(mainRecordedInvoice != null) {\r\n\t\t\t\t\t\t\t\tcustomerAccount = mainRecordedInvoice.getCustomerAccount();\r\n\t\t\t\t\t\t\t\tpayment = createPayment(item, fileReport,customerAccount);\r\n\t\t\t\t\t\t\t\tif (payment != null) {\r\n\t\t\t\t\t\t\t\t\t// matching the created payment\r\n\t\t\t\t\t\t\t\t\tmatchOperation(item.transactionReference, payment, mainRecordedInvoice, fileName, index, fileReport);\r\n\t\t\t\t\t\t\t\t\tpayment = (Payment) accountOperationService.findById(payment.getId());\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}else {\r\n\t\t\t\t\t\t\t\tcustomerAccount = customerAccountService.findByCode(item.customerCode);\r\n\t\t\t\t\t\t\t\tif(customerAccount == null) {\r\n\t\t\t\t\t\t\t\t\tlog.error(\"Can't found invoice and customer at line n={}, fileName={}\", item.numLine, item.fileName);\r\n\t\t\t\t\t\t\t\t\taddReportMessage(\"Can't found invoice and customer for line n=\" + item.numLine, item.fileName);\r\n\t\t\t\t\t\t\t\t\tfileReport.opKo++;\r\n\t\t\t\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\tpayment = createPayment(item, fileReport,customerAccount);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tList<RecordedInvoice> listOpenedInvoioces = getListOpenedInvoioces(customerAccount);\r\n\t\t\t\t\t\t\tfor (RecordedInvoice aoINV : listOpenedInvoioces) {\r\n\t\t\t\t                if (BigDecimal.ZERO.compareTo(payment.getUnMatchingAmount()) == 0) {\r\n\t\t\t\t                    break;\r\n\t\t\t\t                }\r\n\t\t\t\t                log.info(\"matching .... AO invoice id:{} unmatchingAount:{}\", aoINV.getId(), aoINV.getUnMatchingAmount());\r\n\t\t\t\t                matchOperation(item.transactionReference, payment, aoINV, fileName, index, fileReport);\r\n\t\t\t\t                payment = (Payment) accountOperationService.findById(payment.getId());\r\n\t\t\t\t            }\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\t\tlog.error(\"Error processing line {}, file {}\", index, fileName, e);\r\n\t\t\t\t\t\t\taddReportMessage(\"Error processing line=\" + index + \", message=\" + e.getMessage() + \"\", fileName);\r\n\t\t\t\t\t\t\tfileReport.opKo++;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}else {\r\n\t\t\t\t\t\tlog.debug(\"Error on line=\" + index + \", operationType \\\"\" + item.operationType + \"\\\" not recognized. Filename=\" + fileName);\r\n\t\t\t\t\t\taddReportMessage(\"Error processing line=\" + index + \", message= Operation type \\\"\" + item.operationType + \"\\\" not recognized.\", fileName);\r\n\t\t\t\t\t\tfileReport.opKo++;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tprocessedItemsIndexes.put(item.getIdentifier(), index);\r\n\t\t\t\t}\r\n\t\t\t\t// close mercanet file\r\n\t\t\t\tbufferedReader.close();\r\n\t\t\t\tinputStream.close();\r\n\t\t\t\t// report for one file\r\n\t\t\t\tfileReport.opAll = index - 2;\r\n\t\t\t\tif (fileReport.opKo > 0) {\r\n\t\t\t\t\tmoveToErrorDirectory(errorDirPath, mercanetFile);\r\n\t\t\t\t} else if (fileReport.matchKo > 0) {\r\n\t\t\t\t\tmoveToWarnDirectory(warnDirPath, mercanetFile);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tarchivateMercanetFile(archiveDirPath, mercanetFile);\r\n\t\t\t\t}\r\n\t\t\t\tallReport.opAll += fileReport.opAll;\r\n\t\t\t\tallReport.opOk += fileReport.opOk;\r\n\t\t\t\tallReport.opKo += fileReport.opKo;\r\n\t\t\t\tallReport.matchOk += fileReport.matchOk;\r\n\t\t\t\tallReport.matchKo += fileReport.matchKo;\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tlog.error(\"Error processing mercanet file {}\", fileName, e);\r\n\t\t\t\taddReportMessage(\"Error processing mercanet file [ message=\" + e.getMessage() + \" ]\", fileName);\r\n\t\t\t\tallReport.opKo = 1;\r\n\t\t\t\tmoveToErrorDirectory(errorDirPath, mercanetFile);\r\n\t\t\t}\r\n\t\t}\r\n\t\tmethodContext.put(Script.JOB_RESULT_NB_OK, allReport.opOk);\r\n\t\tmethodContext.put(Script.JOB_RESULT_NB_WARN, allReport.matchKo);\r\n\t\tmethodContext.put(Script.JOB_RESULT_NB_KO, allReport.opKo);\r\n\t\tmethodContext.put(Script.JOB_RESULT_REPORT, reportMessages);\r\n\t\taddReportMessage(sbFiles.toString(), null);\r\n\t\tlong processDuration = (System.currentTimeMillis() - startTime) / 1000;\r\n\t\taddReportMessage(\"Files are processed in \" + processDuration + \" seconds.\", null);\r\n\t\taddReportMessage(\"Import report : Total=\" + allReport.opAll + \". \" + \"AO creation: Ok=\" + allReport.opOk + \", KO=\" + allReport.opKo + \". \" + \"AO matching: OK=\"\r\n\t\t\t\t+ allReport.matchOk + \", KO=\" + allReport.matchKo, null);\r\n\t\t// create import report file in input dir\r\n\t\tPath reportFile = Paths.get(reportDirPath.toString() + File.separator + \"report_\" + DateUtils.formatDateWithPattern(new Date(), DATETIME_FORMAT));\r\n\t\ttry {\r\n\t\t\tFiles.createFile(reportFile);\r\n\t\t\tlog.debug(\"creating mercanet import report file at {}\", reportFile);\r\n\t\t\tFiles.write(reportFile, reportMessages, StandardCharsets.UTF_8);\r\n\t\t} catch (IOException e) {\r\n\t\t\tlog.error(\"Could not create or write to mercanet import report file at {}\", reportFile, e);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Create a payment from mercanet log item\r\n\t * \r\n\t * @param item   mercanet item\r\n\t * @param report processing report\r\n\t * @return OC payment entity\r\n\t */\r\n\tprivate Payment createPayment(MercanetItem item, ProcessingReport report,CustomerAccount  customerAccount) throws BusinessException {\r\n\t\tPayment payment = new Payment();\r\n\t\tsetAOProperties(payment, item,customerAccount);\r\n\t\tif (payment.getCustomerAccount() != null) {\r\n\t\t\ttry {\r\n\t\t\t\tpayment.setPaymentOrder(item.merchantId);\r\n\t\t\t\tpaymentService.create(payment);\r\n\t\t\t\treport.opOk++;\r\n\t\t\t\treturn payment;\r\n\t\t\t} catch (BusinessException e) {\r\n\t\t\t\tlog.error(\"Couldn't create Payement entity for mercanet operation at line n={}, error={}\", item.numLine, e);\r\n\t\t\t\taddReportMessage(\"Couldn't create payment for line n=\" + item.numLine + \". error=\" + e.getMessage(), item.fileName);\r\n\t\t\t\treport.opKo++;\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tlog.error(\"Couldn't create Payement entity for mercanet operation at line n={} : transactionReference={} not found\", item.numLine, item.transactionReference);\r\n\t\t\taddReportMessage(\"Couldn't create payment for line n=\" + item.numLine + \". transactionReference=\" + item.transactionReference + \" not found\", item.fileName);\r\n\t\t\treport.opKo++;\r\n\t\t\treturn null;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * move mercanet file containing errors to error directory\r\n\t * \r\n\t * @param errorDirPath error dir pth\r\n\t * @param mercanetFile mercanet file\r\n\t */\r\n\tprivate void moveToErrorDirectory(Path errorDirPath, Path mercanetFile) {\r\n\t\tlog.debug(\"moving mercanet file {} to error dir.\", mercanetFile);\r\n\t\ttry {\r\n\t\t\tFiles.move(mercanetFile, Paths.get(errorDirPath + File.separator + mercanetFile.getFileName() + \".\" + DateUtils.formatDateWithPattern(new Date(), DATETIME_FORMAT)));\r\n\t\t} catch (IOException e) {\r\n\t\t\tlog.error(\"Couldn't move mercanet file {} to errors dir {}\", mercanetFile.toString(), errorDirPath, e);\r\n\t\t\taddReportMessage(\"Couldn't move mercanet file to errors dir: \" + e.getMessage(), null);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * move mercanet file containing errors to error directory\r\n\t * \r\n\t * @param mercanetFile mercanet file\r\n\t */\r\n\tprivate void moveToWarnDirectory(Path warnDirPath, Path mercanetFile) {\r\n\t\tlog.debug(\"moving mercanet file {} to warn dir.\", mercanetFile);\r\n\t\ttry {\r\n\t\t\tFiles.move(mercanetFile, Paths.get(warnDirPath + File.separator + mercanetFile.getFileName() + \".\" + DateUtils.formatDateWithPattern(new Date(), DATETIME_FORMAT)));\r\n\t\t} catch (IOException e) {\r\n\t\t\tlog.error(\"Couldn't move mercanet file {} to warns dir {}\", mercanetFile.toString(), warnDirPath, e);\r\n\t\t\taddReportMessage(\"Couldn't move mercanet file to warns dir: \" + e.getMessage(), null);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * archivate imported mercanet file\r\n\t * \r\n\t * @param archiveDirPath archive directory path\r\n\t * @param mercanetFile   mercanet file to archive\r\n\t */\r\n\tprivate void archivateMercanetFile(Path archiveDirPath, Path mercanetFile) {\r\n\t\tString strArchiFilePath = archiveDirPath + File.separator + mercanetFile.getFileName() + \".\" + DateUtils.formatDateWithPattern(new Date(), DATETIME_FORMAT);\r\n\t\tPath archFile = Paths.get(strArchiFilePath);\r\n\t\ttry {\r\n\t\t\tFiles.move(mercanetFile, archFile);\r\n\t\t} catch (IOException e) {\r\n\t\t\tlog.error(\"Couldn't arcivate mercanet file {} to {}\", mercanetFile.toString(), archFile.toString(), e);\r\n\t\t\taddReportMessage(\"Couldn't move mercanet file to errors dir: \" + e.getMessage(), null);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t *\r\n\t * @param reportMessage report message\r\n\t * @param fileName      current processing mercanet file name\r\n\t */\r\n\tprivate void addReportMessage(String reportMessage, String fileName) {\r\n\t\tif (fileName != null) {\r\n\t\t\treportMessages.add(fileName + \" >> \" + reportMessage);\r\n\t\t} else {\r\n\t\t\treportMessages.add(reportMessage);\r\n\t\t}\r\n\t}\r\n\t\r\n\tprivate List<RecordedInvoice> getListOpenedInvoioces(CustomerAccount ca) {\r\n        try {\r\n            String query = \"select inv from RecordedInvoice inv where inv.code='INV_STD' and inv.matchingStatus in ('O','P') and inv.customerAccount.id =:caIdIN  and inv.unMatchingAmount > 0 order by inv.invoiceDate \";\r\n            Map<String, Object> queryParams = new HashMap<>();\r\n            queryParams.put(\"caIdIN\", ca.getId());\r\n            List<RecordedInvoice> listOpenedInvoioces = (List<RecordedInvoice>) recordedInvoiceService.executeSelectQuery(query, queryParams);\r\n            return listOpenedInvoioces;\r\n        } catch (Exception e) {\r\n            log.error(\"rror on getListOpenedInvoioces: [{}] \", e.getMessage(), e);\r\n            throw new BusinessException(\"Error on getListOpenedInvoioces\");\r\n        }\r\n    }\r\n\r\n\t/**\r\n\t * create directory if not exists\r\n\t * \r\n\t * @param dirPath directory path\r\n\t * @return true if created else false\r\n\t */\r\n\tprivate boolean createDirIfNotExist(Path dirPath) {\r\n\t\tif (!dirPath.toFile().exists()) {\r\n\t\t\ttry {\r\n\t\t\t\tFiles.createDirectories(dirPath);\r\n\t\t\t\tlog.debug(\"dir {} didn't exist and is created successfully.\", dirPath);\r\n\t\t\t} catch (IOException e) {\r\n\t\t\t\tlog.error(\"Error creating directory {}\", dirPath, e);\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t *\r\n\t * @param inputDir mercanet input dierctory\r\n\t * @param ext      mercanet file extention\r\n\t * @return list of mercanet files found into input directory\r\n\t * @throws BusinessException business exception\r\n\t */\r\n\tprivate List<Path> getMercanetLogFiles(Path inputDir, String ext) throws BusinessException {\r\n\t\tif (!inputDir.toFile().exists() || !inputDir.toFile().isDirectory()) {\r\n\t\t\tlog.error(\"Mercanet input path {} is not a valid directory!\", inputDir);\r\n\t\t\tthrow new BusinessException(\"Param inputDir is not a valid directory\");\r\n\t\t}\r\n\t\ttry (Stream<Path> filesStream = Files.list(inputDir)) {\r\n\t\t\tif (filesStream != null) {\r\n\t\t\t\treturn filesStream.map(Path::toAbsolutePath).collect(Collectors.toList());\r\n\t\t\t} else {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t} catch (IOException e) {\r\n\t\t\tlog.error(\"Error on getting list Mercanet log files!\", e);\r\n\t\t\tthrow new BusinessException(e);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * set AO properties from mercanet item and OCC template\r\n\t * \r\n\t * @param payment account operation\r\n\t * @param item    mercanet log item\r\n\t */\r\n\tprivate void setAOProperties(Payment payment, MercanetItem item,CustomerAccount customerAccount) throws BusinessException {\r\n\r\n\t\tpayment.setCustomerAccount(customerAccount);\r\n\r\n\t\tpayment.setPaymentMethod(PaymentMethodEnum.CARD);\r\n\r\n\t\tpayment.setAmount(item.amount);\r\n\t\tpayment.setMatchingAmount(BigDecimal.ZERO);\r\n\t\tpayment.setUnMatchingAmount(item.amount);\r\n\t\tpayment.setAccountingCode(occCardTemplate.getAccountingCode());\r\n\t\tpayment.setCode(occCardTemplate.getCode());\r\n\t\tpayment.setDescription(occCardTemplate.getDescription());\r\n\t\tpayment.setTransactionCategory(occCardTemplate.getOccCategory());\r\n\t\tpayment.setAccountCodeClientSide(occCardTemplate.getAccountCodeClientSide());\r\n\t\tpayment.setReference(item.transactionReference);\r\n\t\t// tansaction date + 1 jour\r\n\t\tif (item.transactionDateTime != null) {\r\n\t\t\tLocalDate trDatePlus1Day = item.transactionDateTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate().plusDays(1);\r\n\t\t\tpayment.setTransactionDate(Date.from(trDatePlus1Day.atStartOfDay(ZoneId.systemDefault()).toInstant()));\r\n\t\t}\r\n\t\tpayment.setDueDate(new Date());\r\n\t\tpayment.setMatchingStatus(MatchingStatusEnum.O);\r\n\t\tpayment.setSeller(sellerService.findByCode(SELLER_CODE));\r\n\t}\r\n\r\n\t/**\r\n\t * get OCC template by code\r\n\t * \r\n\t * @param occTemplateCode occ template code\r\n\t * @return OCC Template\r\n\t * @throws BusinessException Business Exception\r\n\t */\r\n\tprivate OCCTemplate getOCCTemplate(String occTemplateCode) throws BusinessException {\r\n\t\tOCCTemplate occTemplate = oCCTemplateService.findByCode(occTemplateCode);\r\n\t\tif (occTemplate == null) {\r\n\t\t\tthrow new BusinessException(\"Cannot find OCC Template with code=\" + occTemplateCode);\r\n\t\t}\r\n\t\treturn occTemplate;\r\n\t}\r\n\r\n\t/**\r\n\t * get recorded invoice by order number\r\n\t * \r\n\t * @param orderNumber order number\r\n\t * @return recorded invoice\r\n\t */\r\n\tprivate RecordedInvoice getRecordedInvoice(String invoiceNumber) throws BusinessException {\r\n\r\n\t\tMap<String, Object> params = Maps.newHashMap();\r\n\t\tString query = \"From RecordedInvoice ri where ri.reference=:invoiceNumberIN and (ri.matchingStatus ='O' or ri.matchingStatus ='P')\";\r\n\t\tparams.put(\"invoiceNumberIN\", invoiceNumber);\r\n\t\tList<RecordedInvoice> recordedInvoices = (List<RecordedInvoice>) recordedInvoiceService.executeSelectQuery(query, params);\r\n\t\tif (recordedInvoices.isEmpty()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn recordedInvoices.iterator().next();\r\n\t}\r\n\r\n\t/**\r\n\t * Match the open\r\n\t * \r\n\t * @param payment  operationToMatch\r\n\t * @param fileName mercanet file name currently processed\r\n\t * @param numLine  line index\r\n\t * @param report   processing report\r\n\t */\r\n\tprivate void matchOperation(String orderNumber, Payment payment, RecordedInvoice recordedInvoice, String fileName, Integer numLine, ProcessingReport report) {\r\n\r\n\t\tList<Long> operationIds = new ArrayList<Long>();\r\n\t\toperationIds.add(payment.getId());\r\n\t\toperationIds.add(recordedInvoice.getId());\r\n\r\n\t\tMatchingReturnObject matchingReturn = null;\r\n\t\ttry {\r\n\t\t\tmatchingReturn = matchingCodeService.matchOperations(payment.getCustomerAccount().getId(), null, operationIds, null, MatchingTypeEnum.A);\r\n\t\t} catch (BusinessException | NoAllOperationUnmatchedException | UnbalanceAmountException e) {\r\n\t\t\tlog.warn(\"Problem on matching operation id={}, line n={}!\", payment.getId(), numLine, e);\r\n\t\t\taddReportMessage(\"[WARN] Problem on matching operation on line=\" + numLine + \", opid=\" + payment.getId() + \", message=\" + e.getMessage(), fileName);\r\n\t\t\treport.matchKo++;\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (matchingReturn.isOk()) {\r\n\t\t\tlog.debug(\"Matching is OK for the operation id={}, line n={}!\", payment.getId(), numLine);\r\n\t\t\treport.matchOk++;\r\n\t\t} else {\r\n\t\t\tlog.warn(\"Matching is NOK for the operation id={}, line n°{}!\", payment.getId(), numLine);\r\n\t\t\taddReportMessage(\"[WARN] Matching NOK for operation on line=\" + numLine + \", opid=\" + payment.getId(), fileName);\r\n\t\t\treport.matchKo++;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * map mercanet file line with MercanetItem item\r\n\t * \r\n\t * @param line  mercanet operation line\r\n\t * @param index line index\r\n\t * @return MercanetItem item\r\n\t */\r\n\tprivate MercanetItem mapToItem(String line, int index) throws BusinessException {\r\n\t\ttry {\r\n\t\t\tString[] lineFields = line.split(this.delimiter);\r\n\t\t\tlog.info(\"lineFields:\" + Arrays.toString(lineFields));\r\n\t\t\tint lineLength = lineFields.length;\r\n\t\t\tMercanetItem item = new MercanetItem();\r\n\t\t\titem.numLine = index;\r\n\t\t\titem.merchantId = lineLength > 1 ? lineFields[1] : null;\r\n\t\t\titem.transactionReference = lineLength > 2 ? lineFields[2] : null;\r\n\t\t\titem.transactionDateTime = lineLength > 7 ? toDate(lineFields[7]) : null;\r\n\t\t\titem.operationType = lineLength > 4 ? lineFields[4] : null;\r\n\t\t\titem.amount = lineLength > 5 ? toBigDecimal(lineFields[5]) : null;\r\n\t\t\tif (StringUtils.isBlank(item.transactionReference) || item.transactionReference.length() < 12) {\r\n\t\t\t\tthrow new BusinessException(\"transactionReference length should be 12 char at less\");\r\n\t\t\t}\r\n\t\t\titem.invoiceNumber = item.transactionReference.substring(0, 12);\r\n\t\t\titem.customerCode = lineLength > 17 ? lineFields[17] : null;\r\n\t\t\treturn item;\r\n\t\t} catch (Exception e) {\r\n\t\t\tthrow new BusinessException(e.getMessage());\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * String to bigdecimal\r\n\t * \r\n\t * @param input string\r\n\t * @return bigdecimal\r\n\t */\r\n\tprivate BigDecimal toBigDecimal(String input) throws BusinessException {\r\n\t\ttry{\r\n\t\t\treturn new BigDecimal(input).divide(new BigDecimal(100));\r\n\t\t\t\r\n\t\t}catch (Exception e) {\r\n\t\t\tthrow new BusinessException(\"Amount is null or invalid:\"+input);\r\n\t\t}\t\r\n\t}\r\n\r\n\t/**\r\n\t * String to date\r\n\t * \r\n\t * @param input string\r\n\t * @return date\r\n\t */\r\n\tprivate Date toDate(String input) {\r\n\t\treturn DateUtils.guessDate(input, \"yyyyMMdd hhmmss\", \"yyyy-MM-dd hh:mm:ss\");\r\n\t}\r\n\r\n\t/**\r\n\t * Classe to map mercanet line\r\n\t */\r\n\tprivate class MercanetItem {\r\n\t\tString fileName;\r\n\t\tint numLine;\r\n\t\tString merchantId;\r\n\t\tString transactionReference;\r\n\t\tDate transactionDateTime;\r\n\t\tString operationType;\r\n\t\tBigDecimal amount;\r\n\t\tString invoiceNumber;\r\n\t\tString customerCode;\r\n\r\n\t\tString getIdentifier() {\r\n\t\t\treturn fileName + \"_\" + transactionReference;\r\n\t\t}\r\n\r\n\t\t@Override\r\n\t\tpublic String toString() {\r\n\t\t\treturn \"MercanetItem [fileName=\" + fileName + \", numLine=\" + numLine + \", merchantId=\" + merchantId + \", transactionReference=\" + transactionReference\r\n\t\t\t\t\t+ \", transactionDateTime=\" + transactionDateTime + \", operationType=\" + operationType + \", amount=\" + amount + \", invoiceNumber=\" + invoiceNumber + \", customerCode=\"+customerCode+\"]\";\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tprivate class ProcessingReport {\r\n\t\tint opAll = 0;\r\n\t\tint opOk = 0;\r\n\t\tint opKo = 0;\r\n\t\tint matchOk = 0;\r\n\t\tint matchKo = 0;\r\n\t}\r\n\r\n\t/**\r\n\t * Find payment by reference and payment order.\r\n\t *\r\n\t * @param reference    the reference\r\n\t * @param paymentOrder the payment order\r\n\t * @return the payment\r\n\t */\r\n\tpublic Payment findPaymentByReferenceAndPaymentOrder(String reference) {\r\n\t\ttry {\r\n\r\n\t\t\tQueryBuilder qb = new QueryBuilder(Payment.class, \"p\");\r\n\t\t\tqb.addCriterion(\"reference\", \"=\", reference, false);\r\n\r\n\t\t\treturn (Payment) qb.getQuery(paymentService.getEntityManager()).getSingleResult();\r\n\t\t} catch (NoResultException ne) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t}\r\n}\r\n\r\n]]>\r\n            </script>\r\n</ScriptInstance>"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "AOFilterScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Proxy-Authorization",
										"value": "{{proxy.auth}}"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.payment.AOFilterScript\" description=\"Ekko AOFilterScript\">\r\n    <type>JAVA</type>\r\n    <reuse>true</reuse>\r\n    <script><![CDATA[package com.opencellsoft.service.ekko.payment;\r\n\r\nimport java.math.BigDecimal;\r\nimport java.util.ArrayList;\r\nimport java.util.Date;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.stream.Collectors;\r\n\r\nimport org.meveo.commons.utils.EjbUtils;\r\nimport org.meveo.model.admin.Seller;\r\nimport org.meveo.model.billing.Subscription;\r\nimport org.meveo.model.payments.AccountOperation;\r\nimport org.meveo.model.payments.CustomerAccount;\r\nimport org.meveo.model.payments.OperationCategoryEnum;\r\nimport org.meveo.model.payments.PaymentMethodEnum;\r\nimport org.meveo.service.admin.impl.SellerService;\r\nimport org.meveo.service.billing.impl.SubscriptionService;\r\nimport org.meveo.service.payments.impl.AccountOperationService;\r\nimport org.meveo.service.payments.impl.CustomerAccountService;\r\nimport org.meveo.service.script.payment.AccountOperationFilterScript;\r\n\r\n/**\r\n * \r\n * @author anasseh\r\n *  \r\n *  16/06/2023 SUPS-2597(bis)\r\n */\r\npublic class AOFilterScript extends AccountOperationFilterScript {\r\n\r\n\r\n\tprivate final AccountOperationService accountOperationService = (AccountOperationService) getServiceInterface(\"AccountOperationService\");\r\n\tprivate SellerService sellerService = (SellerService) EjbUtils.getServiceInterface(\"SellerService\");\r\n\tprivate SubscriptionService subscriptionService = (SubscriptionService) EjbUtils.getServiceInterface(\"SubscriptionService\");\r\n\tprivate CustomerAccountService customerAccountService = (CustomerAccountService) EjbUtils.getServiceInterface(\"CustomerAccountService\");\r\n\tprivate static final String CF_SUB_PAY_METHOD = \"CF_SUB_PAY_METHOD\";\r\n\t\r\n\t@SuppressWarnings(\"unchecked\")\r\n\t@Override\r\n\tpublic List<AccountOperation> filterAoToPay(Map<String, Object> methodContext) {\r\n\t\tlog.debug(\" filterAoToPay : [{}]\", methodContext);\r\n\t\tDate fromDueDate = (Date) methodContext.get(AccountOperationFilterScript.FROM_DUE_DATE);\r\n\t\tDate toDateFrom = (Date) methodContext.get(AccountOperationFilterScript.TO_DUE_DATE);\r\n\t\tPaymentMethodEnum paymentMethod = (PaymentMethodEnum) methodContext\r\n\t\t\t\t.get(AccountOperationFilterScript.PAYMENT_METHOD);\r\n\t\tOperationCategoryEnum catToProcess = (OperationCategoryEnum) methodContext\r\n\t\t\t\t.get(AccountOperationFilterScript.CAT_TO_PROCESS);\r\n\r\n\t\tString typeIN = \" ('I','OCC') \";\r\n\t\tif(catToProcess == OperationCategoryEnum.CREDIT) {\t\t\r\n\t\t\ttypeIN =  \" ('I','OCC','P','AP') \";\r\n\t\t}\r\n\t\t\r\n\t\tString queryStr = \"Select ao  from AccountOperation as ao,PaymentMethod as pm  where ao.transactionCategory =:catToProcessIN and ao.type  in \"+typeIN+\"  and \"\r\n\t\t\t\t+ \" ao.matchingStatus ='O' and ao.customerAccount.excludedFromPayment = false and ao.customerAccount.id = pm.customerAccount.id and pm.paymentType =:paymentMethodIN  and \"\r\n\t\t\t\t+ \" pm.preferred is true and ao.dueDate >=:fromDueDateIN and ao.dueDate <:toDueDateIN\";\r\n\r\n\t\tMap<String, Object> params = new HashMap<String, Object>();\r\n\t\tparams.put(\"fromDueDateIN\", fromDueDate);\r\n\t\tparams.put(\"toDueDateIN\", toDateFrom);\r\n\t\tparams.put(\"paymentMethodIN\", paymentMethod);\r\n\t\tparams.put(\"catToProcessIN\", catToProcess);\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\tlog.debug(\"fromDueDateIN={} , toDueDateIN={} ,paymentMethodIN={} , catToProcessIN={} \", fromDueDate, toDateFrom, paymentMethod, catToProcess);\r\n\t\tList<AccountOperation> aos = (List<AccountOperation>) accountOperationService.executeSelectQuery(queryStr, params);\r\n\t\tlog.info(\"findListAoToPay  aos:{}\",aos);\r\n\t\taos = aos.stream().filter(ao -> (isDirectDebitOrder(ao))).collect(Collectors.toList());\t\t\r\n\t\tSeller seller = sellerService.findByCode(\"EKKO\");\r\n\t\tDouble paymentThreshold = (Double) seller.getCfValue(\"CF_SEL_PAY_AMOUNT_THRESHOLD\");\r\n\t\tif(paymentThreshold == null) {\r\n\t\t\tpaymentThreshold = 1d;\r\n\t\t}\r\n\r\n\t\tMap<CustomerAccount, List<AccountOperation>> aosByCA = new HashMap<CustomerAccount, List<AccountOperation>>();\r\n\t\tfor (AccountOperation ao : aos) {\r\n\t\t\tao = accountOperationService.refreshOrRetrieve(ao);\r\n\t\t\tCustomerAccount ca = customerAccountService.refreshOrRetrieve(ao.getCustomerAccount());\r\n\t\t\tList<AccountOperation> aosForCA = new ArrayList<AccountOperation>();\r\n\t\t\tif (aosByCA.containsKey(ca)) {\r\n\t\t\t\taosForCA = aosByCA.get(ca);\r\n\t\t\t}\r\n\t\t\taosForCA.add(ao);\r\n\t\t\taosByCA.put(ca, aosForCA);\r\n\t\t}\r\n\t\taos = new ArrayList<AccountOperation>();\r\n\t\tfor (Map.Entry<CustomerAccount, List<AccountOperation>> entry : aosByCA.entrySet()) {\r\n\t\t\tBigDecimal amountToPayByItem = BigDecimal.ZERO;\r\n\t\t\t\r\n\t\t\tCustomerAccount ca = entry.getKey();\r\n\t\t\t\r\n\t\t\tfor (AccountOperation ao : entry.getValue()) {\r\n\t\t\t\t\r\n\t\t\t\t\tamountToPayByItem = amountToPayByItem.add(ao.getUnMatchingAmount());\r\n\t\t\t\t\r\n\t\t\t}\r\n\t\t\tif(amountToPayByItem.compareTo(BigDecimal.valueOf(paymentThreshold))>=0) {\r\n\t\t\t\taos.addAll(entry.getValue());\r\n\t\t\t}\r\n\r\n\t\t\t\r\n\t\t}\r\n\t\tlog.info(\"findListAoToPay return aos:{}\",aos);\r\n\t\treturn aos;\t\t\r\n\t}\r\n\t\r\n\tprivate boolean isDirectDebitOrder(AccountOperation ao) {\r\n\t\tlog.info(\"checking paymentMethodType for AO id:\"+ao.getId());\r\n\t\tif(ao.getTransactionCategory() == OperationCategoryEnum.CREDIT) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\tif(ao.getSubscription() != null) {\r\n\t\t\tSubscription sub = subscriptionService.refreshOrRetrieve(ao.getSubscription());\r\n\t\t\tString orderPayMethod = (String)sub.getCfValue(CF_SUB_PAY_METHOD) ;\r\n\t\t\tlog.info(\"orderPayMethod:\"+orderPayMethod);\r\n\t\t\tif(PaymentMethodEnum.CARD.name().equals(orderPayMethod)) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\r\n}\r\n\r\n    ]]></script>\r\n</ScriptInstance>"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								},
								"description": "A Custom script to compute CUrrent Month Date range."
							},
							"response": []
						},
						{
							"name": "Create SepaDDRequestBuilderScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Proxy-Authorization",
										"value": "{{proxy.auth}}"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.payment.SepaDDRequestBuilderScript\" description=\"Ekko Sepa Pain08 ,Pain01 et camt54 Script\">\r\n    <type>JAVA</type>\r\n    <reuse>true</reuse>\r\n    <script><![CDATA[package com.opencellsoft.service.ekko.payment;\r\n\r\nimport java.io.File;\r\nimport java.math.BigDecimal;\r\nimport java.math.RoundingMode;\r\nimport java.util.ArrayList;\r\nimport java.util.Arrays;\r\nimport java.util.Date;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.regex.Pattern;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.admin.sepa.DDRejectFileInfos;\r\nimport org.meveo.admin.sepa.jaxb.camt054.AccountNotification2;\r\nimport org.meveo.admin.sepa.jaxb.camt054.BankToCustomerDebitCreditNotificationV02;\r\nimport org.meveo.admin.sepa.jaxb.pain001.AmountType3Choice;\r\nimport org.meveo.admin.sepa.jaxb.pain001.CreditTransferTransactionInformation10;\r\nimport org.meveo.admin.sepa.jaxb.pain001.CustomerCreditTransferInitiationV03;\r\nimport org.meveo.admin.sepa.jaxb.pain001.GroupHeader32;\r\nimport org.meveo.admin.sepa.jaxb.pain001.PaymentInstructionInformation3;\r\nimport org.meveo.admin.sepa.jaxb.pain001.PaymentMethod3Code;\r\nimport org.meveo.admin.sepa.jaxb.pain001.PaymentTypeInformation19;\r\nimport org.meveo.admin.sepa.jaxb.pain001.RemittanceInformation5;\r\nimport org.meveo.admin.sepa.jaxb.pain008.AccountIdentification4Choice;\r\nimport org.meveo.admin.sepa.jaxb.pain008.ActiveOrHistoricCurrencyAndAmount;\r\nimport org.meveo.admin.sepa.jaxb.pain008.BranchAndFinancialInstitutionIdentification4;\r\nimport org.meveo.admin.sepa.jaxb.pain008.CashAccount16;\r\nimport org.meveo.admin.sepa.jaxb.pain008.CustomerDirectDebitInitiationV02;\r\nimport org.meveo.admin.sepa.jaxb.pain008.DirectDebitTransaction6;\r\nimport org.meveo.admin.sepa.jaxb.pain008.DirectDebitTransactionInformation9;\r\nimport org.meveo.admin.sepa.jaxb.pain008.Document;\r\nimport org.meveo.admin.sepa.jaxb.pain008.FinancialInstitutionIdentification7;\r\nimport org.meveo.admin.sepa.jaxb.pain008.GenericFinancialIdentification1;\r\nimport org.meveo.admin.sepa.jaxb.pain008.GenericPersonIdentification1;\r\nimport org.meveo.admin.sepa.jaxb.pain008.GroupHeader39;\r\nimport org.meveo.admin.sepa.jaxb.pain008.LocalInstrument2Choice;\r\nimport org.meveo.admin.sepa.jaxb.pain008.MandateRelatedInformation6;\r\nimport org.meveo.admin.sepa.jaxb.pain008.Party6Choice;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PartyIdentification32;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PaymentIdentification1;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PaymentInstructionInformation4;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PaymentMethod2Code;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PaymentTypeInformation20;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PersonIdentification5;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PersonIdentificationSchemeName1Choice;\r\nimport org.meveo.admin.sepa.jaxb.pain008.SequenceType1Code;\r\nimport org.meveo.admin.sepa.jaxb.pain008.ServiceLevel8Choice;\r\nimport org.meveo.admin.util.ArConfig;\r\nimport org.meveo.commons.utils.EjbUtils;\r\nimport org.meveo.commons.utils.JAXBUtils;\r\nimport org.meveo.commons.utils.ParamBean;\r\nimport org.meveo.commons.utils.StringUtils;\r\nimport org.meveo.model.admin.Seller;\r\nimport org.meveo.model.billing.BankCoordinates;\r\nimport org.meveo.model.crm.Provider;\r\nimport org.meveo.model.payments.AccountOperation;\r\nimport org.meveo.model.payments.CustomerAccount;\r\nimport org.meveo.model.payments.DDPaymentMethod;\r\nimport org.meveo.model.payments.DDRequestItem;\r\nimport org.meveo.model.payments.DDRequestLOT;\r\nimport org.meveo.model.payments.OperationCategoryEnum;\r\nimport org.meveo.model.payments.PaymentGateway;\r\nimport org.meveo.model.payments.PaymentMethod;\r\nimport org.meveo.model.payments.PaymentMethodEnum;\r\nimport org.meveo.model.payments.RecordedInvoice;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.model.shared.Name;\r\nimport org.meveo.model.shared.Title;\r\nimport org.meveo.service.admin.impl.SellerService;\r\nimport org.meveo.service.billing.impl.SubscriptionService;\r\nimport org.meveo.service.catalog.impl.CalendarBankingService;\r\nimport org.meveo.service.catalog.impl.TitleService;\r\nimport org.meveo.service.payments.impl.AccountOperationService;\r\nimport org.meveo.service.payments.impl.CustomerAccountService;\r\nimport org.meveo.service.payments.impl.DDRequestItemService;\r\nimport org.meveo.service.payments.impl.DDRequestLOTService;\r\nimport org.meveo.service.payments.impl.PaymentGatewayService;\r\nimport org.meveo.service.payments.impl.PaymentMethodService;\r\nimport org.meveo.service.payments.impl.RecordedInvoiceService;\r\nimport org.meveo.service.script.payment.DDRequestBuilderScript;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n/**\r\n * The Class SepaDDRequestBuilderScript.\r\n *\r\n * @author anasseh\r\n * \r\n * 02/03/2022 supprimer le dossier 'EKKO'\r\n * 02/03/2022 fileName : from SDD.PRL.MYP1_EKKO_20210401XXXXXXXXX.xml to SDD.PRL.MPE.20210401XXXXXXXXX.xml\r\n * 03/10/22 add sepa refund\r\n * 31/05/2023 SUPS-2597\r\n * 16/06/2023 SUPS-2597(bis)\r\n * 21/06/2023 SUPS-2692\r\n */\r\n\r\npublic class SepaDDRequestBuilderScript extends DDRequestBuilderScript {\r\n\t/** The log. */\r\n\tprivate static Logger log = LoggerFactory.getLogger(SepaDDRequestBuilderScript.class);\r\n\r\n\t/** The location of SDD schema. */\r\n\tprivate static final String SDD_SCHEMA_LOCATION = \"https://github.com/w2c/sepa-sdd-xml-generator/blob/master/validation_schemes/pain.008.001.02.xsd\";\r\n\r\n\t   /** The location of SCT schema. */\r\n    private static final String SCT_SCHEMA_LOCATION = \"https://github.com/digitick/php-sepa-xml/blob/master/tests/pain.001.001.03.xsd\";\r\n    \r\n\t/** The Constant SIMPLE_DATE_PATTERN. */\r\n\tprivate static final String SIMPLE_DATE_PATTERN = \"yyyyMMdd\";\r\n\r\n\t/** The Constant EMPTY_STRING. */\r\n\tprivate static final String EMPTY_STRING = \"\";\r\n\r\n\t/** The Constant DASH_STRING. */\r\n\tprivate static final String DASH_STRING = \"-\";\r\n\r\n\t/** The Constant DOUBLE_POINT. */\r\n\tprivate static final String DOUBLE_POINT = \"\\\\..\";\r\n\r\n\t/** The underscore separator used at sepa file name. */\r\n\tprivate static final String UNDERSCORE_SEPARATOR = \"_\";\r\n\r\n\t/** The Constant EURO_CCY. */\r\n\tprivate static final String EURO_CCY = \"EUR\";\r\n\r\n\t/** The Constant SEPA_SERVICE_LEVEL_CD. */\r\n\tprivate static final String SEPA_SERVICE_LEVEL_CD = \"SEPA\";\r\n\r\n\t/** The Constant SEPA_LOCAL_INSTRUMENT_CODE. */\r\n\tprivate static final String SEPA_LOCAL_INSTRUMENT_CODE = \"CORE\";\r\n\t\r\n\t   /** The Constant COMMA_STRING. */\r\n    private static final String COMMA_STRING = \",\";\r\n    \r\n    /** The PATTERN that the IBAN should match. */\r\n    private static final String IBAN_PATTERN = \"[A-Z]{2,2}[0-9]{2,2}[a-zA-Z0-9]{1,30}\";\r\n    \r\n    /** The Constant NOTPROVIDED_BIC. */\r\n    private static final String NOTPROVIDED_BIC = \"NOTPROVIDED\";\r\n\r\n    /** The Constant CATEGORY_PURPOSE_CODE. */\r\n    private static final String CATEGORY_PURPOSE_CODE = \"SUPP\";\r\n    /** The Constant FR_COUNTRY. */\r\n    private static final String FR_COUNTRY = \"FR\";\r\n    private Pattern pattern = Pattern.compile(IBAN_PATTERN);\r\n\r\n\t/** The dd request item service. */\r\n\tprivate DDRequestItemService ddRequestItemService = (DDRequestItemService) EjbUtils.getServiceInterface(\"DDRequestItemService\");\r\n\r\n\t/** The dd request LOT service. */\r\n\tprivate DDRequestLOTService ddRequestLOTService = (DDRequestLOTService) EjbUtils.getServiceInterface(\"DDRequestLOTService\");\r\n\r\n\t/** The customer account service. */\r\n\tprivate CustomerAccountService customerAccountService = (CustomerAccountService) EjbUtils.getServiceInterface(\"CustomerAccountService\");\r\n\tprivate SubscriptionService subscriptionService = (SubscriptionService) EjbUtils.getServiceInterface(\"SubscriptionService\");\r\n\r\n\t/** The recorded invoice service. */\r\n\tprivate RecordedInvoiceService recordedInvoiceService = (RecordedInvoiceService) EjbUtils.getServiceInterface(\"RecordedInvoiceService\");\r\n\tprivate SellerService sellerService = (SellerService) EjbUtils.getServiceInterface(\"SellerService\");\r\n\tprivate TitleService titleService = (TitleService) EjbUtils.getServiceInterface(\"TitleService\");\r\n\tprivate CalendarBankingService calendarBankingService = (CalendarBankingService) getServiceInterface(\"CalendarBankingService\");\r\n\tprivate PaymentMethodService paymentMethodService = (PaymentMethodService) getServiceInterface(\"PaymentMethodService\");\r\n\tprivate AccountOperationService accountOperationService = (AccountOperationService) EjbUtils.getServiceInterface(\"AccountOperationService\");\r\n\t\r\n\t\r\n\t\r\n\t\r\n\r\n\t\r\n\t@Override\r\n\tpublic String getDDFileName(Map<String, Object> methodContext) throws BusinessException {\r\n\t\tDDRequestLOT ddRequestLOT = (DDRequestLOT) methodContext.get(DDRequestBuilderScript.DD_REQUEST_LOT);\r\n\t\tProvider appProvider = (Provider) methodContext.get(DDRequestBuilderScript.PROVIDER);\r\n\t\tif (ddRequestLOT.getPaymentOrRefundEnum().getOperationCategoryToProcess() == OperationCategoryEnum.DEBIT) {\r\n\t\t\treturn getFileName(ddRequestLOT, appProvider, \r\n\t\t\t    ParamBean.getInstance().getProperty(\"bayad.ddrequest.fileName.prefix\", \"SDD.PRL.MPE.\"), \r\n\t\t\t    ParamBean.getInstance().getProperty(\"bayad.ddrequest.fileName.extension\", \"xml\"),  \r\n\t\t\t    ParamBean.getInstance().getProperty(\"bayad.ddrequest.outputDir\", \"prelevement\"));\r\n\t\t} else {\r\n\t\t    return getFileName(ddRequestLOT, appProvider, \r\n\t\t        ParamBean.getInstance().getProperty(\"bayad.sctrequest.fileName.prefix\", \"SCT.VIR.MPE.\"), \r\n                ParamBean.getInstance().getProperty(\"bayad.sctrequest.fileName.extension\", \"xml\"),  \r\n                ParamBean.getInstance().getProperty(\"bayad.sctrequest.outputDir\", \"virement\"));\r\n\t\t}\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void generateDDRequestLotFile(Map<String, Object> methodContext) throws BusinessException {\r\n\r\n\t\tlog.info(\" >>> Starting generateDDRequestLotFile ... \");\r\n\t\tProvider appProvider = (Provider) methodContext.get(DDRequestBuilderScript.PROVIDER);\r\n\t\tDDRequestLOT ddRequestLOT = (DDRequestLOT) methodContext.get(DDRequestBuilderScript.DD_REQUEST_LOT);\r\n\t\tDDRequestLOTService ddRequestLotService = (DDRequestLOTService) getServiceInterface(\"DDRequestLOTService\");\r\n\t\tddRequestLOT = ddRequestLotService.findById(ddRequestLOT.getId(), Arrays.asList(\"ddrequestItems\", \"ddRequestBuilder\"));\r\n\t\tif (ddRequestLOT.getPaymentOrRefundEnum().getOperationCategoryToProcess() == OperationCategoryEnum.DEBIT) {\r\n\t\t\tgenerateDDRequestLotFileForSSD(ddRequestLOT, appProvider);\r\n\t\t} else {\r\n\t\t\t generateDDRequestLotFileForSCT(ddRequestLOT, appProvider);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the file name.\r\n\t *\r\n\t * @param ddRequestLot        the dd request lot\r\n\t * @param appProvider         the app provider\r\n\t * @param fileNamePrefix      the file name prefix\r\n\t * @param fileNameExtension   the file name extension\r\n\t * @param additionalOutputDir the additional output dir\r\n\t * @return the file name\r\n\t * @throws BusinessException the business exception\r\n\t */\r\n\tprivate String getFileName(DDRequestLOT ddRequestLot, Provider appProvider, String fileNamePrefix, String fileNameExtension, String additionalOutputDir)\r\n\t\t\tthrows BusinessException {\r\n\t\ttry {\r\n\t\t\t//SDD.PRL.MYP1_EKKO_20210401XXXXXXXXX.xml ==> debut projet\r\n\t\t\t//SDD.PRL.MPE.20210401XXXXXXXXX.xml ==> 02/03/2022 live test MEP\r\n\t\t\tParamBean paramBean = ParamBean.getInstanceByProvider(appProvider.getCode());\r\n\t\t\tString fileName = fileNamePrefix+DateUtils.formatDateWithPattern(new Date(), \"yyyyMMddhhmmssSSS\")+\".\"+fileNameExtension;\r\n\t\t\t\r\n\t\t\tString outputDir = paramBean.getChrootDir(appProvider.getCode());\r\n\r\n\t\t\toutputDir = outputDir + File.separator + additionalOutputDir;\r\n\t\t\toutputDir = outputDir.replaceAll(DOUBLE_POINT, EMPTY_STRING);\r\n\r\n\t\t\tlog.info(\"DDRequest output directory=\" + outputDir);\r\n\t\t\tFile dir = new File(outputDir);\r\n\t\t\tif (!dir.exists()) {\r\n\t\t\t\tdir.mkdirs();\r\n\t\t\t}\r\n\t\t\treturn outputDir + File.separator + fileName;\r\n\t\t} catch (Exception e) {\r\n\t\t\tlog.error(e.getMessage(), e);\r\n\t\t\tthrow new BusinessException(e.getMessage());\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Generate DD request lot file for SSD.\r\n\t *\r\n\t * @param ddRequestLot the dd request lot\r\n\t * @param appProvider  the app provider\r\n\t * @throws BusinessException the business exception\r\n\t */\r\n\tprivate void generateDDRequestLotFileForSSD(DDRequestLOT ddRequestLot, Provider appProvider) throws BusinessException {\r\n\t\ttry {\r\n\t\t\tParamBean paramBean = ParamBean.getInstanceByProvider(appProvider.getCode());\r\n\t\t\tDocument document = new Document();\r\n\t\t\tCustomerDirectDebitInitiationV02 message = new CustomerDirectDebitInitiationV02();\r\n\t\t\tdocument.setCstmrDrctDbtInitn(message);\r\n\t\t\taddHeader(message, ddRequestLot, appProvider);\r\n\r\n\t\t\tboolean isEmptyLot = addPaymentInformation(message, ddRequestLot, appProvider);\r\n\r\n\t\t\tif (isEmptyLot) {\r\n\t\t\t\tlog.warn(\"There no valid dd item, file will not created\");\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tString schemaLocation = paramBean.getProperty(\"sepa.schemaLocation.pain008\", SDD_SCHEMA_LOCATION);\r\n\t\t\tJAXBUtils.marshaller(document, new File(ddRequestLot.getFileName()), schemaLocation);\r\n\t\t} catch (Exception e) {\r\n\t\t\tlog.error(\"Error on generateDDRequestLotFileForSSD\", e);\r\n\t\t\tthrow new BusinessException(e.getMessage());\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Adds the header of SDD file.\r\n\t *\r\n\t * @param message      the SDD message\r\n\t * @param ddRequestLOT the dd request LOT\r\n\t * @param appProvider  the provider\r\n\t * @throws Exception the exception\r\n\t */\r\n\tprivate void addHeader(CustomerDirectDebitInitiationV02 message, DDRequestLOT ddRequestLOT, Provider appProvider) throws Exception {\r\n\r\n\t\tGroupHeader39 groupHeader = new GroupHeader39();\r\n\t\tmessage.setGrpHdr(groupHeader);\r\n\t\tgroupHeader.setMsgId(ArConfig.getDDRequestHeaderReference() + DASH_STRING + ddRequestLOT.getId());\r\n\t\tgroupHeader.setCreDtTm(DateUtils.dateToXMLGregorianCalendar(new Date()));\r\n\t\tgroupHeader.setNbOfTxs(String.valueOf(ddRequestLOT.getNbItemsOk()));\r\n\t\tBigDecimal total = BigDecimal.ZERO;\r\n\t\tfor (DDRequestItem item : ddRequestLOT.getDdrequestItems()) {\r\n\t\t\tif (!item.hasError()) {\r\n\t\t\t\ttotal = total.add(item.getAmount().setScale(2, RoundingMode.HALF_UP));\r\n\t\t\t}\r\n\t\t}\r\n\t\tddRequestLOT.setTotalAmount(total);\r\n\t\tddRequestLOTService.updateNoCheck(ddRequestLOT);\r\n\t\tgroupHeader.setCtrlSum(total.setScale(2, RoundingMode.HALF_UP));\r\n\t\tPartyIdentification32 initgPty = new PartyIdentification32();\r\n\t\tif (ddRequestLOT.getSeller() != null) {\t\t\t\r\n\t\t\tinitgPty.setNm(format(sellerService.refreshOrRetrieve(ddRequestLOT.getSeller()).getDescription()));\r\n\t\t} else {\r\n\t\t\tinitgPty.setNm(format(appProvider.getDescription()));\r\n\t\t}\r\n\r\n\t\tgroupHeader.setInitgPty(initgPty);\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Adds the payment information of SDD file.\r\n\t *\r\n\t * @param Message       the SDD message\r\n\t * @param dDRequestItem the dd request item\r\n\t * @param appProvider   the provider\r\n\t * @throws Exception the exception\r\n\t */\r\n\tprivate boolean addPaymentInformation(CustomerDirectDebitInitiationV02 Message, DDRequestLOT ddRequestLot, Provider appProvider) throws Exception {\r\n\t\tboolean isEmptyLot = true;\r\n\t\tlog.info(\"addPaymentInformation dDRequestLot id=\" + ddRequestLot.getId());\r\n\t\tParamBean paramBean = ParamBean.getInstanceByProvider(appProvider.getCode());\r\n\t\tPaymentInstructionInformation4 paymentInformation = new PaymentInstructionInformation4();\r\n\t\tMessage.getPmtInf().add(paymentInformation);\r\n\t\tpaymentInformation.setPmtInfId(ArConfig.getDDRequestHeaderReference() + DASH_STRING + ddRequestLot.getId());\r\n\t\tpaymentInformation.setPmtMtd(PaymentMethod2Code.DD);\r\n\t\tpaymentInformation.setNbOfTxs(\"\" + ddRequestLot.getNbItemsOk());\r\n\t\tpaymentInformation.setCtrlSum(ddRequestLot.getTotalAmount().setScale(2, RoundingMode.HALF_UP));\r\n\t\tPaymentTypeInformation20 paymentTypeInformation = new PaymentTypeInformation20();\r\n\t\tpaymentInformation.setPmtTpInf(paymentTypeInformation);\r\n\t\tServiceLevel8Choice serviceLevel = new ServiceLevel8Choice();\r\n\t\tpaymentTypeInformation.setSvcLvl(serviceLevel);\r\n\t\tserviceLevel.setCd(SEPA_SERVICE_LEVEL_CD);\r\n\t\tLocalInstrument2Choice localInstrument = new LocalInstrument2Choice();\r\n\t\tpaymentTypeInformation.setLclInstrm(localInstrument);\r\n\t\tlocalInstrument.setCd(paramBean.getProperty(\"sepa.LclInstrm\", SEPA_LOCAL_INSTRUMENT_CODE));\r\n\t\tpaymentTypeInformation.setSeqTp(SequenceType1Code.RCUR);\r\n\t\t\r\n\t\t\r\n\t\tSeller seller = sellerService.findByCode(\"EKKO\");\r\n\t\t\r\n\t\tLong nbDaysPay = (Long) seller.getCfValue(\"CF_SEL_PAY_NB_BUSI_DAYS\");\r\n\t\tLong nbDaysToAdd = nbDaysPay;\r\n\t\t\r\n\t\tDate customerRequestedDate = addBusinessDays(new Date(), nbDaysToAdd);\r\n\t\tlog.info(\"customerRequestedDate business day:\" + customerRequestedDate);\r\n\r\n\t\tpaymentInformation.setReqdColltnDt(DateUtils.dateToXMLGregorianCalendarFieldUndefined(customerRequestedDate));\r\n\r\n\t\tBankCoordinates bankCoordinates = getBankCoordinates(ddRequestLot, appProvider);\r\n\r\n\t\tif (bankCoordinates == null) {\r\n\t\t\tthrow new BusinessException(\"Missing bank information on provider or seller\");\r\n\t\t}\r\n\t\tPartyIdentification32 creditor = new PartyIdentification32();\r\n\t\tif (ddRequestLot.getSeller() != null) {\r\n\t\t\tcreditor.setNm(format(sellerService.refreshOrRetrieve(ddRequestLot.getSeller()).getDescription()));\r\n\t\t} else {\r\n\t\t\tcreditor.setNm(format(appProvider.getDescription()));\r\n\t\t}\r\n\r\n\t\tpaymentInformation.setCdtr(creditor);\r\n\r\n\t\tCashAccount16 creditorAccount = new CashAccount16();\r\n\t\tpaymentInformation.setCdtrAcct(creditorAccount);\r\n\t\tAccountIdentification4Choice identification = new AccountIdentification4Choice();\r\n\t\tcreditorAccount.setId(identification);\r\n\t\tidentification.setIBAN(format(bankCoordinates.getIban()));\r\n\r\n\t\tBranchAndFinancialInstitutionIdentification4 creditorAgent = new BranchAndFinancialInstitutionIdentification4();\r\n\t\tpaymentInformation.setCdtrAgt(creditorAgent);\r\n\t\tFinancialInstitutionIdentification7 financialInstitutionIdentification = new FinancialInstitutionIdentification7();\r\n\t\tcreditorAgent.setFinInstnId(financialInstitutionIdentification);\r\n\t\tfinancialInstitutionIdentification.setBIC(bankCoordinates.getBic());\r\n\t\tPartyIdentification32 creditorSchemeIdentification = new PartyIdentification32();\r\n\t\tpaymentInformation.setCdtrSchmeId(creditorSchemeIdentification);\r\n\t\tParty6Choice cdtrSchmeId = new Party6Choice();\r\n\t\tcreditorSchemeIdentification.setId(cdtrSchmeId);\r\n\t\tPersonIdentification5 privateidentifier = new PersonIdentification5();\r\n\t\tcdtrSchmeId.setPrvtId(privateidentifier);\r\n\t\tGenericPersonIdentification1 other = new GenericPersonIdentification1();\r\n\t\tprivateidentifier.getOthr().add(other);\r\n\t\tother.setId(bankCoordinates.getIcs());\r\n\t\tPersonIdentificationSchemeName1Choice schemeName = new PersonIdentificationSchemeName1Choice();\r\n\t\tother.setSchmeNm(schemeName);\r\n\t\tschemeName.setPrtry(SEPA_SERVICE_LEVEL_CD);\r\n\r\n\t\tfor (DDRequestItem ddrequestItem : ddRequestLot.getDdrequestItems()) {\r\n\t\t\tddrequestItem = ddRequestItemService.findById(ddrequestItem.getId(), Arrays.asList(\"accountOperations\"));\r\n\t\t\tif (!ddrequestItem.hasError()) {\r\n\t\t\t\taddTransaction(ddrequestItem, paymentInformation);\r\n\t\t\t\tisEmptyLot = false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn isEmptyLot;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Adds the transaction of SDD file.\r\n\t *\r\n\t * @param dDRequestItem      the dd request item\r\n\t * @param paymentInformation the payment information of SDD file\r\n\t * @throws Exception the exception\r\n\t */\r\n\tprivate void addTransaction(DDRequestItem dDRequestItem, PaymentInstructionInformation4 paymentInformation) throws Exception {\r\n\t\tCustomerAccount ca = customerAccountService.findById(dDRequestItem.getAccountOperations().get(0).getCustomerAccount().getId(), Arrays.asList(\"paymentMethods\"));\r\n\r\n\t\tPaymentMethod preferedPaymentMethod = customerAccountService.getPreferredPaymentMethod(dDRequestItem.getAccountOperations().get(0).getCustomerAccount().getId());\r\n\t\tif (preferedPaymentMethod == null || !(preferedPaymentMethod instanceof DDPaymentMethod)) {\r\n\t\t\tthrow new BusinessException(\"Payment method not valid!\");\r\n\t\t}\r\n\t\tBankCoordinates bankCoordinates = ((DDPaymentMethod) preferedPaymentMethod).getBankCoordinates();\r\n\r\n\t\tif (bankCoordinates == null) {\r\n\t\t\tthrow new BusinessException(\"Bank Coordinate is absent for Payment method \" + ((DDPaymentMethod) preferedPaymentMethod).getAlias());\r\n\t\t}\r\n\r\n\t\tDirectDebitTransactionInformation9 directDebitTransactionInformation = new DirectDebitTransactionInformation9();\r\n\t\tpaymentInformation.getDrctDbtTxInf().add(directDebitTransactionInformation);\r\n\t\tPaymentIdentification1 PaymentIdentification = new PaymentIdentification1();\r\n\t\tdirectDebitTransactionInformation.setPmtId(PaymentIdentification);\r\n\t\tPaymentIdentification.setInstrId(getCorrelationId(ca, dDRequestItem.getAccountOperations().get(0), dDRequestItem.getId()));\r\n\t\tPaymentIdentification.setEndToEndId(getCorrelationId(ca, dDRequestItem.getAccountOperations().get(0), dDRequestItem.getId()));\r\n\t\tActiveOrHistoricCurrencyAndAmount instructedAmount = new ActiveOrHistoricCurrencyAndAmount();\r\n\t\tdirectDebitTransactionInformation.setInstdAmt(instructedAmount);\r\n\t\tinstructedAmount.setValue(dDRequestItem.getAmount().setScale(2, RoundingMode.HALF_UP));\r\n\t\tinstructedAmount.setCcy(EURO_CCY);\r\n\t\tDirectDebitTransaction6 directDebitTransaction = new DirectDebitTransaction6();\r\n\t\tdirectDebitTransactionInformation.setDrctDbtTx(directDebitTransaction);\r\n\t\tMandateRelatedInformation6 mandateRelatedInformation = new MandateRelatedInformation6();\r\n\t\tdirectDebitTransaction.setMndtRltdInf(mandateRelatedInformation);\r\n\r\n\t\tmandateRelatedInformation.setMndtId(((DDPaymentMethod) preferedPaymentMethod).getMandateIdentification());\r\n\t\tmandateRelatedInformation.setDtOfSgntr(DateUtils.dateToXMLGregorianCalendarFieldUndefined(((DDPaymentMethod) preferedPaymentMethod).getMandateDate()));\r\n\t\tBranchAndFinancialInstitutionIdentification4 debtorAgent = new BranchAndFinancialInstitutionIdentification4();\r\n\t\tdirectDebitTransactionInformation.setDbtrAgt(debtorAgent);\r\n\t\tFinancialInstitutionIdentification7 financialInstitutionIdentification = new FinancialInstitutionIdentification7();\r\n\t\tGenericFinancialIdentification1 bicInfo = new GenericFinancialIdentification1();\r\n\t\tbicInfo.setId(\"NOTPROVIDED\");\r\n\t\tfinancialInstitutionIdentification.setOthr(bicInfo);\r\n\t\tdebtorAgent.setFinInstnId(financialInstitutionIdentification);\r\n\r\n\t\tPartyIdentification32 debtor = new PartyIdentification32();\r\n\t\tdirectDebitTransactionInformation.setDbtr(debtor);\r\n\t\tdebtor.setNm(format(getDebtorFullName(ca)));\r\n\r\n\t\tCashAccount16 debtorAccount = new CashAccount16();\r\n\t\tdirectDebitTransactionInformation.setDbtrAcct(debtorAccount);\r\n\t\tAccountIdentification4Choice identification = new AccountIdentification4Choice();\r\n\t\tidentification.setIBAN(bankCoordinates.getIban());\r\n\t\tdebtorAccount.setId(identification);\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the correlation id.\r\n\t *\r\n\t * @param ca               the ca\r\n\t * @param accountOperation the account operation\r\n\t * @param ddReqItemId      the dd req item id\r\n\t * @return the correlation id\r\n\t */\r\n\tprivate String getCorrelationId(CustomerAccount ca, AccountOperation accountOperation, Long ddReqItemId) {\r\n\r\n\t\treturn accountOperation.getId() + \"_\" + ca.getCode() + \"_\" + ddReqItemId;\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the debtor full name.\r\n\t *\r\n\t * @param ca the ca\r\n\t * @return the debtor full name\r\n\t */\r\n\tprivate String getDebtorFullName(CustomerAccount ca) {\r\n\t\tString fullName = \"\";\r\n\t\tName name = ca.getName();\r\n\t\tif (name != null) {\t\t\r\n\t\t\tfullName = geFullName(name);\r\n\t\t} else {\r\n\t\t\tfullName = geFullName(ca.getCustomer().getName());\r\n\t\t}\r\n\t\treturn fullName;\r\n\t}\r\n\t\r\n\tprivate String geFullName(Name name) {\r\n\t\tTitle title = titleService.refreshOrRetrieve(name.getTitle());\r\n\t\treturn   title.getCode()+\" \"+name.getFirstName()+\" \"+name.getLastName();\r\n\t\t\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the bank coordinates.\r\n\t *\r\n\t * @param ddRequestLOT the dd request LOT\r\n\t * @param appProvider  the app provider\r\n\t * @return the bank coordinates\r\n\t * @throws BusinessException the business exception\r\n\t */\r\n\tprivate BankCoordinates getBankCoordinates(DDRequestLOT ddRequestLOT, Provider appProvider) throws BusinessException {\r\n\t\tif (ddRequestLOT.getSeller() != null) {\r\n\t\t\tPaymentGatewayService paymentGatewayService = (PaymentGatewayService) getServiceInterface(\"PaymentGatewayService\");\r\n\t\t\tPaymentGateway paymentGateway = paymentGatewayService.getPaymentGateway(ddRequestLOT.getSeller(), PaymentMethodEnum.DIRECTDEBIT);\r\n\t\t\tif (paymentGateway == null) {\r\n\t\t\t\tthrow new BusinessException(\"Cant find payment gateway for seller : \" + ddRequestLOT.getSeller());\r\n\t\t\t}\r\n\t\t\treturn paymentGateway.getBankCoordinates();\r\n\t\t} else {\r\n\t\t\treturn appProvider.getBankCoordinates();\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the end to end id.\r\n\t *\r\n\t * @param accountNotification2 the account notification 2\r\n\t * @return the end to end id\r\n\t */\r\n\tprivate String getEndToEndId(AccountNotification2 accountNotification2) {\r\n\t\tString endToEndId = null;\r\n\t\ttry {\r\n\t\t\tendToEndId = accountNotification2.getNtry().get(0).getNtryDtls().get(0).getTxDtls().get(0).getRefs().getEndToEndId();\r\n\t\t\treturn endToEndId;\r\n\t\t} catch (Exception e) {\r\n\t\t\tthrow new BusinessException(\"Can't found END_TO_END \");\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the dd item id from end to end.\r\n\t *\r\n\t * @param endToEnd the end to end\r\n\t * @return the dd item id from end to end\r\n\t */\r\n\tprivate Long getDdItemIdFromEndToEnd(String endToEnd) {\r\n\t\tif (StringUtils.isBlank(endToEnd) || endToEnd.indexOf(\"_\") == -1) {\r\n\t\t\tthrow new BusinessException(\"Invalid format END_TO_END :\" + endToEnd);\r\n\t\t}\r\n\t\ttry {\r\n\r\n\t\t\treturn Long.valueOf(endToEnd.substring(endToEnd.lastIndexOf(\"_\") + 1, endToEnd.length()));\r\n\t\t} catch (Exception e) {\r\n\t\t\tthrow new BusinessException(\"Invalid type END_TO_END :\" + endToEnd);\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the a id from end to end.\r\n\t *\r\n\t * @param endToEnd the end to end\r\n\t * @return the a id from end to end\r\n\t */\r\n\tprivate Long getAIdFromEndToEnd(String endToEnd) {\r\n\t\tif (StringUtils.isBlank(endToEnd) || endToEnd.indexOf(\"_\") == -1) {\r\n\t\t\tthrow new BusinessException(\"Invalid format END_TO_END :\" + endToEnd);\r\n\t\t}\r\n\t\ttry {\r\n\r\n\t\t\treturn Long.valueOf(endToEnd.substring(0, endToEnd.indexOf(\"_\")));\r\n\t\t} catch (Exception e) {\r\n\t\t\tthrow new BusinessException(\"Invalid type END_TO_END :\" + endToEnd);\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tpublic DDRejectFileInfos processSDDRejectedFile(Map<String, Object> methodContext) throws BusinessException {\r\n\t\tFile sepaRejectedFile = (File) methodContext.get(DDRequestBuilderScript.DD_REJECT_FILE);\r\n\t\tif (sepaRejectedFile == null) {\r\n\t\t\tthrow new BusinessException(\"sepaRejectedFile is null\");\r\n\t\t}\r\n\t\tlog.info(\"processSDDRejectedFile:\" + sepaRejectedFile.getName());\r\n\t\tDDRejectFileInfos ddRejectFileInfos = new DDRejectFileInfos();\r\n\t\ttry {\r\n\t\t\tddRejectFileInfos.setFileName(sepaRejectedFile.getName());\r\n\t\t\torg.meveo.admin.sepa.jaxb.camt054.Document camt54 = (org.meveo.admin.sepa.jaxb.camt054.Document) JAXBUtils\r\n\t\t\t\t\t.unmarshaller(org.meveo.admin.sepa.jaxb.camt054.Document.class, sepaRejectedFile);\r\n\r\n\t\t\tBankToCustomerDebitCreditNotificationV02 bkToCstmrDbtCdtNtfctn = camt54.getBkToCstmrDbtCdtNtfctn();\r\n\r\n\t\t\tList<AccountNotification2> listNtfctn = bkToCstmrDbtCdtNtfctn.getNtfctn();\r\n\t\t\tfor (AccountNotification2 accountNotification2 : listNtfctn) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tString endToEnd = getEndToEndId(accountNotification2);\r\n\t\t\t\t\tString rejectReason = getRejectReason(accountNotification2);\r\n\t\t\t\t\tddRejectFileInfos.getListInvoiceRefsRejected().put(getDdItemIdFromEndToEnd(endToEnd), rejectReason);\r\n\t\t\t\t\tddRequestLOTService.rejectPayment(ddRequestItemService.findById(getDdItemIdFromEndToEnd(endToEnd)), rejectReason, sepaRejectedFile.getName());\r\n\t\t\t\t\tddRejectFileInfos.addItemOk();\r\n\r\n\t\t\t\t\tRecordedInvoice ri = recordedInvoiceService.findById(getAIdFromEndToEnd(endToEnd));\r\n\t\t\t\t\tri.setPaymentInfo6(\"NotAllowed\");\r\n\t\t\t\t\trecordedInvoiceService.updateNoCheck(ri);\r\n\r\n\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\tddRejectFileInfos.addItemKo();\r\n\t\t\t\t\tlog.error(\"Error on processSDDRejectedFile :\", e);\r\n\t\t\t\t\tddRejectFileInfos.getListErrors().add(e.getMessage());\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t} catch (Exception e) {\r\n\t\t\tthrow new BusinessException(e.getMessage());\r\n\t\t}\r\n\t\treturn ddRejectFileInfos;\r\n\t}\r\n\r\n\t/**\r\n\t * Format.\r\n\t *\r\n\t * @param valueStr the value str\r\n\t * @return the string\r\n\t */\r\n\tprivate String format(String valueStr) {\r\n\t\tif (valueStr == null) {\r\n\t\t\treturn \"\";\r\n\t\t}\r\n\t\treturn StringUtils.enleverAccent(valueStr);\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the reject reason.\r\n\t *\r\n\t * @param accountNotification2 the account notification 2\r\n\t * @return the reject reason\r\n\t */\r\n\tprivate String getRejectReason(AccountNotification2 accountNotification2) {\r\n\t\tString rejectReason = null;\r\n\t\ttry {\r\n\t\t\trejectReason = accountNotification2.getNtry().get(0).getNtryDtls().get(0).getTxDtls().get(0).getRtrInf().getRsn().getCd();\r\n\t\t\tif (\"AC01\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"IBAN incorrect ou inconnu\";\r\n\t\t\tif (\"AC04\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Le titulaire a ferm\\u00E9 son compte\";\r\n\t\t\tif (\"AC06\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Compte bloqu\\u00E9 pour pr\\u00E9l\\u00e8vement automatique\";\r\n\t\t\tif (\"AG02\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Information incorrecte\";\r\n\t\t\tif (\"AM04\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Fonds insuffisants\";\r\n\t\t\tif (\"MD01\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Mandat non valide\";\r\n\t\t\tif (\"MD06\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"R\\u00E9tro-facturation du paiement\";\r\n\t\t\tif (\"MD07\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Le client est d\\u00E9c\\u00E9d\\u00E9\";\r\n\t\t\tif (\"MS02\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Transaction refus\\u00E9e\";\r\n\t\t\tif (\"MS03\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Autre raison\";\r\n\t\t\tif (\"SL01\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Refus\\u00E9 par la banque d\\u00E9bitrice\";\r\n\t\t\treturn rejectReason;\r\n\t\t} catch (Exception e) {\r\n\t\t\tthrow new BusinessException(\"Can't found rejectReason \");\r\n\t\t}\r\n\t}\r\n\t\r\n\tprivate Date addBusinessDays(Date dateStart, Long nbDays) {\t\r\n\t\tif(nbDays == null || nbDays.intValue() < 0) {\r\n\t\t\tnbDays = 0L;\r\n\t\t}\r\n\t\tint daysAdded = 0;\r\n\t\tDate endDate = dateStart;\r\n\t\twhile (daysAdded < nbDays.intValue()) {\r\n\t\t\tendDate = DateUtils.addDaysToDate(endDate, 1);\r\n\t\t\tif (calendarBankingService.isBankWorkingDate(endDate)) {\r\n\t\t\t\tdaysAdded++;\r\n\t\t\t}\r\n\t\t\tlog.info(\"daysAdded:\"+daysAdded);\r\n\t\t}\r\n\t\treturn DateUtils.setDateToEndOfDay(endDate);\r\n\t}\r\n\t\r\n\t/**\r\n     * Generate DD request lot file for SCT.\r\n     *\r\n     * @param ddRequestLot the dd request lot\r\n     * @param appProvider  the app provider\r\n     * @throws BusinessException the business exception\r\n     */\r\n    private void generateDDRequestLotFileForSCT(DDRequestLOT ddRequestLot, Provider appProvider) throws BusinessException {\r\n        ParamBean paramBean = ParamBean.getInstanceByProvider(appProvider.getCode());\r\n   \t\r\n        org.meveo.admin.sepa.jaxb.pain001.Document document;\r\n        CustomerCreditTransferInitiationV03 message;\r\n        List<DDRequestItem> ddrequestItems = ddRequestLot.getDdrequestItems();\r\n        DDRequestItem ddrequestItem;\r\n        Long operationsByFile = ddRequestLot.getDdRequestBuilder().getNbOperationPerFile();\r\n        long ddRequestItemSize = ddrequestItems.size();\r\n        if (operationsByFile == null || operationsByFile <= 0) {\r\n            operationsByFile = ddRequestItemSize;\r\n        }\r\n        int filesToGenerate = ddrequestItems.isEmpty() ? 0 : (int) Math.ceil(ddRequestItemSize / (double) operationsByFile);\r\n        int opToGenerateByFile;\r\n        int generatedOps = 0;\r\n        int opWithErrorsByFile;\r\n        BigDecimal totalAmount;\r\n        List<String> generatedFilesNames = new ArrayList<String>();\r\n        String fileName;\r\n        for (int fileNumber = 1; fileNumber <= filesToGenerate; fileNumber++) {\r\n            try {\r\n                fileName = ddRequestLot.getFileName();//getDDFileName(ddRequestLot, appProvider);\r\n                document = new org.meveo.admin.sepa.jaxb.pain001.Document();\r\n                message = new CustomerCreditTransferInitiationV03();\r\n                document.setCstmrCdtTrfInitn(message);\r\n                addSctHeader(message, ddRequestLot, appProvider, fileNumber);\r\n                totalAmount = BigDecimal.ZERO;\r\n                opToGenerateByFile = 0;\r\n                opWithErrorsByFile = 0;\r\n                while (generatedOps < ddRequestItemSize && opToGenerateByFile < operationsByFile) {\r\n                    ddrequestItem = ddrequestItems.get(generatedOps);\r\n                    totalAmount = totalAmount.add(ddrequestItem.getAmount());\r\n                    if (!ddrequestItem.hasError()) {\r\n                        addSctPaymentInformation(message, ddrequestItem, appProvider);\r\n                    } else {\r\n                        log.error(\"ddrequestItem with id ={} has Errors :{} . The file {} will not contain all payment informations.\", ddrequestItem.getId(), ddrequestItem.getErrorMsg(), fileName);\r\n                        opWithErrorsByFile++;\r\n                    }\r\n                    opToGenerateByFile++;\r\n                    generatedOps++;\r\n                }\r\n                if (opToGenerateByFile > opWithErrorsByFile) { // The file is generated only if it contains at least one operation without\r\n                                                                // errors\r\n                    message.getGrpHdr().setCtrlSum(totalAmount.setScale(2, RoundingMode.HALF_UP));\r\n                    message.getGrpHdr().setNbOfTxs(String.valueOf(opToGenerateByFile));\r\n                    // the Pain001 jaxb classes are generated from the xsd located at:\r\n                    // https://www.iso20022.org/documents/messages/1_0_version/pain/schemas/pain.001.001.03.zip\r\n                    JAXBUtils.marshaller(document, new File(fileName),\r\n                            paramBean.getProperty(\"sepa.schemaLocation.pain001\", SCT_SCHEMA_LOCATION));\r\n                    generatedFilesNames.add(fileName);\r\n                }\r\n            } catch (Exception e) {\r\n                log.error(e.getMessage(), e);\r\n                throw new BusinessException(e.getMessage());\r\n            }\r\n\r\n        }\r\n        ddRequestLot.setFileName(String.join(COMMA_STRING, generatedFilesNames));\r\n    }\r\n    \r\n    /**\r\n     * Adds the header for SCT file.\r\n     *\r\n     * @param message      the SCT message\r\n     * @param ddRequestLot the dd request lot\r\n     * @param appProvider  the provider\r\n     * @param fileNumber   the file number: used when generatin severals files for\r\n     *                     one ddRequest lot\r\n     * @throws Exception the exception\r\n     */\r\n    private void addSctHeader(CustomerCreditTransferInitiationV03 message, DDRequestLOT ddRequestLot, Provider appProvider, int fileNumber) {\r\n        GroupHeader32 groupHeader = new GroupHeader32();\r\n        message.setGrpHdr(groupHeader);\r\n        groupHeader.setMsgId(ArConfig.getSCTRequestHeaderRefrence() + DASH_STRING + ddRequestLot.getId() + DASH_STRING + fileNumber);\r\n        try{\r\n            groupHeader.setCreDtTm(DateUtils.dateToXMLGregorianCalendar(new Date()));\r\n        }\r\n        catch(Exception e){\r\n            throw new BusinessException(e);\r\n        }\r\n        org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32 initgPty = new org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32();\r\n        initgPty.setNm(appProvider.getDescription());\r\n        groupHeader.setInitgPty(initgPty);\r\n\r\n    }\r\n    /**\r\n     * Adds the payment information for SCT file.\r\n     *\r\n     * @param message       the SCT message\r\n     * @param ddrequestItem the ddrequest item\r\n     * @param appProvider   the provider\r\n     * @throws Exception the exception\r\n     */\r\n    private void addSctPaymentInformation(CustomerCreditTransferInitiationV03 message, DDRequestItem ddrequestItem, Provider appProvider) {\r\n\r\n        log.info(\"addSctPaymentInformation dDRequestItem id={} \", ddrequestItem.getId());\r\n        ddrequestItem = ddRequestItemService.findById(ddrequestItem.getId(), Arrays.asList(\"accountOperations\"));\r\n        PaymentInstructionInformation3 paymentInformation = new PaymentInstructionInformation3();\r\n        message.getPmtInf().add(paymentInformation);\r\n        paymentInformation.setPmtInfId(ArConfig.getDDRequestHeaderReference() + DASH_STRING + ddrequestItem.getId());\r\n        paymentInformation.setPmtMtd(PaymentMethod3Code.TRF);\r\n        paymentInformation.setBtchBookg(true);\r\n        paymentInformation.setNbOfTxs(String.valueOf(ddrequestItem.getAccountOperations().size()));\r\n        paymentInformation.setCtrlSum(ddrequestItem.getAmount().setScale(2, RoundingMode.HALF_UP));\r\n        PaymentTypeInformation19 paymentTypeInformation = new PaymentTypeInformation19();\r\n        paymentInformation.setPmtTpInf(paymentTypeInformation);\r\n        org.meveo.admin.sepa.jaxb.pain001.ServiceLevel8Choice serviceLevel = new org.meveo.admin.sepa.jaxb.pain001.ServiceLevel8Choice();\r\n        paymentTypeInformation.setSvcLvl(serviceLevel);\r\n        serviceLevel.setCd(SEPA_SERVICE_LEVEL_CD);\r\n        org.meveo.admin.sepa.jaxb.pain001.CategoryPurpose1Choice ctgyPurp = new org.meveo.admin.sepa.jaxb.pain001.CategoryPurpose1Choice();\r\n        paymentTypeInformation.setCtgyPurp(ctgyPurp);\r\n        ctgyPurp.setCd(CATEGORY_PURPOSE_CODE);\r\n        \r\n    \tSeller seller = sellerService.findByCode(\"EKKO\");\r\n\t\tLong nbDaysSepa = (Long) seller.getCfValue(\"CF_SEL_SEPA_NB_BUSI_DAYS\");\r\n\t\t\r\n\t\t\r\n\t\tDate customerRequestedDate = addBusinessDays(new Date(), nbDaysSepa);\r\n\t\tlog.info(\"customerRequestedDate business day:\" + customerRequestedDate);\r\n        \r\n        try{\r\n            paymentInformation.setReqdExctnDt(DateUtils.dateToXMLGregorianCalendarFieldUndefined(customerRequestedDate));\r\n        }\r\n        catch (Exception e) {\r\n            throw new BusinessException(e);\r\n        }\r\n\r\n        org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32 dbtr = new org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32();\r\n        if (ddrequestItem.getDdRequestLOT().getSeller() != null) {\r\n            dbtr.setNm(ddrequestItem.getDdRequestLOT().getSeller().getDescription());\r\n        } else {\r\n            dbtr.setNm(appProvider.getDescription());\r\n        }\r\n\r\n        paymentInformation.setDbtr(dbtr);\r\n\r\n        org.meveo.admin.sepa.jaxb.pain001.CashAccount16 dbtrAccount = new org.meveo.admin.sepa.jaxb.pain001.CashAccount16();\r\n        paymentInformation.setDbtrAcct(dbtrAccount);\r\n        org.meveo.admin.sepa.jaxb.pain001.AccountIdentification4Choice identification = new org.meveo.admin.sepa.jaxb.pain001.AccountIdentification4Choice();\r\n        dbtrAccount.setId(identification);\r\n\r\n        BankCoordinates bankCoordinates = getBankCoordinates(ddrequestItem.getDdRequestLOT(), appProvider);\r\n\r\n        if (bankCoordinates == null) {\r\n            throw new BusinessException(\"Missing bank information on provider\");\r\n        }\r\n       \r\n        identification.setIBAN(bankCoordinates.getIban());\r\n\r\n        dbtrAccount.setCcy(EURO_CCY);\r\n        org.meveo.admin.sepa.jaxb.pain001.BranchAndFinancialInstitutionIdentification4 dbtrAgent = new org.meveo.admin.sepa.jaxb.pain001.BranchAndFinancialInstitutionIdentification4();\r\n        paymentInformation.setDbtrAgt(dbtrAgent);\r\n        org.meveo.admin.sepa.jaxb.pain001.FinancialInstitutionIdentification7 financialInstitutionIdentification = new org.meveo.admin.sepa.jaxb.pain001.FinancialInstitutionIdentification7();\r\n        dbtrAgent.setFinInstnId(financialInstitutionIdentification);\r\n        if (StringUtils.isBlank(bankCoordinates.getBic())) {\r\n            org.meveo.admin.sepa.jaxb.pain001.GenericFinancialIdentification1 othr = new org.meveo.admin.sepa.jaxb.pain001.GenericFinancialIdentification1();\r\n            othr.setId(NOTPROVIDED_BIC);\r\n            financialInstitutionIdentification.setOthr(othr);\r\n        }\r\n\r\n        financialInstitutionIdentification.setBIC(bankCoordinates.getBic());\r\n        paymentInformation.setChrgBr(org.meveo.admin.sepa.jaxb.pain001.ChargeBearerType1Code.SLEV);\r\n        addSctTransaction(ddrequestItem, paymentInformation);\r\n    }\r\n   \r\n    /**\r\n     * Adds the transaction for SCT file.\r\n     *\r\n     * @param paymentInformation the payment information of SCT file\r\n     */\r\n    private void addSctTransaction(DDRequestItem dDRequestItem, PaymentInstructionInformation3 paymentInformation) {\r\n        Object[] paymentInformations = getPreferredPaymentMethod(dDRequestItem.getId());\r\n        if (!paymentInformations[3].equals(\"DIRECTDEBIT\")) {\r\n            throw new BusinessException(\"Payment method not valid!\");\r\n        }\r\n\r\n        if (paymentInformations[4] == null && paymentInformations[5] == null) {\r\n            throw new BusinessException(\"Bank Coordinate is absent for Payment method \" + paymentInformations[6]);\r\n        }\r\n\r\n        CreditTransferTransactionInformation10 cdtTrfTxInf = new CreditTransferTransactionInformation10();\r\n        paymentInformation.getCdtTrfTxInf().add(cdtTrfTxInf);\r\n        org.meveo.admin.sepa.jaxb.pain001.PaymentIdentification1 paymentIdentification = new org.meveo.admin.sepa.jaxb.pain001.PaymentIdentification1();\r\n        cdtTrfTxInf.setPmtId(paymentIdentification);\r\n        paymentIdentification.setInstrId(String.valueOf(dDRequestItem.getDdRequestLOT().getId()));\r\n        paymentIdentification.setEndToEndId(String.valueOf(dDRequestItem.getId()));\r\n\r\n        AmountType3Choice amt = new AmountType3Choice();\r\n        cdtTrfTxInf.setAmt(amt);\r\n        org.meveo.admin.sepa.jaxb.pain001.ActiveOrHistoricCurrencyAndAmount instdAmt = new org.meveo.admin.sepa.jaxb.pain001.ActiveOrHistoricCurrencyAndAmount();\r\n\r\n        instdAmt.setValue(dDRequestItem.getAmount().setScale(2, RoundingMode.HALF_UP));\r\n        instdAmt.setCcy(EURO_CCY);\r\n        amt.setInstdAmt(instdAmt);\r\n\r\n        org.meveo.admin.sepa.jaxb.pain001.BranchAndFinancialInstitutionIdentification4 cdtrAgent = new org.meveo.admin.sepa.jaxb.pain001.BranchAndFinancialInstitutionIdentification4();\r\n        cdtTrfTxInf.setCdtrAgt(cdtrAgent);\r\n        org.meveo.admin.sepa.jaxb.pain001.FinancialInstitutionIdentification7 finInstnId = new org.meveo.admin.sepa.jaxb.pain001.FinancialInstitutionIdentification7();\r\n        finInstnId.setBIC((String) paymentInformations[4]);\r\n        cdtrAgent.setFinInstnId(finInstnId);\r\n        org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32 cdtr = new org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32();\r\n        cdtTrfTxInf.setCdtr(cdtr);\r\n        cdtr.setNm((String) paymentInformations[2]);\r\n        cdtr.setCtryOfRes(FR_COUNTRY);\r\n        org.meveo.admin.sepa.jaxb.pain001.CashAccount16 cdtrAccount = new org.meveo.admin.sepa.jaxb.pain001.CashAccount16();\r\n        cdtTrfTxInf.setCdtrAcct(cdtrAccount);\r\n        org.meveo.admin.sepa.jaxb.pain001.AccountIdentification4Choice identification = new org.meveo.admin.sepa.jaxb.pain001.AccountIdentification4Choice();\r\n        String iban = (String) paymentInformations[5];\r\n        \r\n        identification.setIBAN(iban);\r\n        cdtrAccount.setId(identification);\r\n\r\n        RemittanceInformation5 rmtInf = new RemittanceInformation5();\r\n        cdtTrfTxInf.setRmtInf(rmtInf);\r\n        rmtInf.getUstrd().add(\"Remboursement \" + getReference(dDRequestItem));\r\n    }\r\n    private Object[] getPreferredPaymentMethod(Long ddRequestItemID) {\r\n        return (Object[]) paymentMethodService.getEntityManager()\r\n                .createNamedQuery(\"PaymentMethod.getPreferredPaymentMethodForDDRequestItem\")\r\n                .setParameter(\"id\", ddRequestItemID)\r\n                .setMaxResults(1)\r\n                .getSingleResult();\r\n    }\r\n    \r\n    private String getReference(DDRequestItem dDRequestItem) {\r\n        String references = \"\";\r\n       List<AccountOperation> aos =  dDRequestItem.getAccountOperations();\r\n        if(aos != null && !aos.isEmpty()) {\r\n            for(AccountOperation ao : aos) {\r\n                if(!ao.getReference().startsWith(\"ddItem\")) {\r\n                    references += \" \"+ao.getReference(); \r\n                }\r\n            }\r\n        }\r\n        return references;\r\n    }\r\n}\r\n\r\n    ]]></script>\r\n</ScriptInstance>"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								},
								"description": "A Custom script to compute CUrrent Month Date range."
							},
							"response": []
						},
						{
							"name": "Create PaymentEkkoDateRangeScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Status code is 200\", function () {",
											"    pm.response.to.have.status(200);",
											"});"
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"auth": {
									"type": "basic",
									"basic": [
										{
											"key": "username",
											"value": "{{opencell.username}}",
											"type": "string"
										},
										{
											"key": "password",
											"value": "{{opencell.password}}",
											"type": "string"
										}
									]
								},
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Proxy-Authorization",
										"value": "{{proxy.auth}}"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.payment.PaymentEkkoDateRangeScript\" description=\"Range date payment EKKO\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.payment;\r\n\r\nimport java.util.Date;\r\nimport java.util.Map;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.admin.job.DateRange;\r\nimport org.meveo.model.admin.Seller;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.service.admin.impl.SellerService;\r\nimport org.meveo.service.catalog.impl.CalendarBankingService;\r\nimport org.meveo.service.script.payment.DateRangeScript;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n/**\r\n * \r\n * @author anasseh\r\n *  03/04/2022 fix ENG382-102\r\n *  21/06/2023 SUPS-2692\r\n */\r\n\r\npublic class PaymentEkkoDateRangeScript extends DateRangeScript {\r\n\tprivate Logger log = LoggerFactory.getLogger(PaymentEkkoDateRangeScript.class);\r\n\r\n\tprivate CalendarBankingService calendarBankingService = (CalendarBankingService) getServiceInterface(\"CalendarBankingService\");\r\n\tprivate SellerService sellerService = (SellerService) getServiceInterface(\"SellerService\");\r\n\r\n\t\r\n\tprivate static final String CF_SEL_SEPA_NB_BUSI_DAYS = \"CF_SEL_SEPA_NB_BUSI_DAYS\";\r\n\t\r\n\t@Override\r\n\tpublic DateRange computeDateRange(Map<String, Object> methodContext) throws BusinessException {\r\n\t\t\r\n\t\tlog.info(\"Execute context : {} \",methodContext);\r\n\t\t\r\n\t\tSeller seller = sellerService.findByCode(\"EKKO\");\r\n\t\tLong nbDaysSepa = (Long) seller.getCfValue(CF_SEL_SEPA_NB_BUSI_DAYS);\r\n\r\n\t\tDateRange dateRange = new DateRange(DateUtils.setDateToStartOfDay(new Date(1)), DateUtils.addDaysToDate(addBusinessDays(new Date(),nbDaysSepa),1));\r\n\r\n\t\tlog.info(\"sysdate:{} startDate:{} endDate:{}\", new Date(), dateRange.getFrom(), dateRange.getTo());\r\n\t\treturn dateRange;\r\n\t}\r\n\r\n\tprivate Date addBusinessDays(Date dateStart, Long nbDays) {\r\n\t\tif(nbDays == null || nbDays.intValue() < 0) {\r\n\t\t\tnbDays = 0L;\r\n\t\t}\r\n\t\tint daysAdded = 0;\r\n\t\tDate endDate = dateStart;\r\n\t\twhile (daysAdded < nbDays.intValue()) {\r\n\t\t\tendDate = DateUtils.addDaysToDate(endDate, 1);\r\n\t\t\tif (calendarBankingService.isBankWorkingDate(endDate)) {\r\n\t\t\t\tdaysAdded++;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn DateUtils.setDateToEndOfDay(endDate);\r\n\t}\r\n}\r\n]]>\r\n            </script>\r\n</ScriptInstance>\r\n\r\n"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								},
								"description": "A Custom script to compute CUrrent Month Date range."
							},
							"response": []
						}
					]
				},
				{
					"name": "util",
					"item": [
						{
							"name": "AnonymizeScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"var data = JSON.parse(responseBody);",
											"tests[\"is.success\"] = data.actionStatus.status === \"SUCCESS\";"
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.util.AnonymizeScript\" description=\"Script AnonymizeScript\">\n    <type>JAVA</type>\n    <reuse>true</reuse>\n    <script><![CDATA[\n    package com.opencellsoft.service.ekko.util;\n\nimport org.meveo.admin.exception.BusinessException;\nimport org.meveo.model.AccountEntity;\nimport org.meveo.model.billing.BillingAccount;\nimport org.meveo.model.billing.UserAccount;\nimport org.meveo.model.crm.Customer;\nimport org.meveo.model.payments.CustomerAccount;\nimport org.meveo.service.crm.impl.CustomerService;\nimport org.meveo.service.script.Script;\n\nimport javax.persistence.EntityManager;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.UUID;\n\npublic class AnonymizeScript extends Script {\n\n    private int anonymizationSeq = 0;\n    private CustomerService customerService = (CustomerService) getServiceInterface(\"CustomerService\");\n    @Override\n    public void execute(Map<String, Object> context) throws BusinessException {\n\n        EntityManager em = customerService.getEntityManager();\n        // Get list ids of all customers\n        List<Long> ids = em.createQuery(\"select c.id from Customer c\", Long.class)\n                .getResultList();\n        String randomCode;\n        for (int i = 0; i < ids.size(); i++) {\n            Long id = ids.get(i);\n            randomCode = UUID.randomUUID().toString();\n            //log.info(\"dd\");\n            Customer customer = customerService.findById(id);\n            customer.anonymize(randomCode);\n\n            anonymizeDescription(customer);\n            for (CustomerAccount ca : customer.getCustomerAccounts()) {\n                anonymizeDescription(ca);\n                for (BillingAccount ba : ca.getBillingAccounts()) {\n                    anonymizeDescription(ba);\n                    for (UserAccount userAccount : ba.getUsersAccounts()) {\n                        anonymizeDescription(userAccount);\n                    }\n                }\n            }\n            anonymizationSeq++;\n\n            if (i > 0 && i % 500 == 0) {\n                // flush a batch of updates and release memory\n                em.flush();\n                em.clear();\n            }\n        }\n    }\n\n    private void anonymizeDescription(AccountEntity ae) {\n        ae.setDescription(\"Anonym_\" + anonymizationSeq);\n    }\n}\n]]></script>\n</ScriptInstance>"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "SetPatchInfoScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"var data = JSON.parse(responseBody);",
											"tests[\"is.success\"] = data.actionStatus.status === \"SUCCESS\";"
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.SetPatchInfoScript\" description=\"SetPatchInfoScript\">\n    <type>JAVA</type>\n    <reuse>true</reuse>\n    <script><![CDATA[\n    package com.opencellsoft.service.ekko;\n\nimport java.util.Date;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.meveo.admin.exception.BusinessException;\nimport org.meveo.api.ProviderApi;\nimport org.meveo.api.dto.CustomFieldDto;\nimport org.meveo.api.dto.CustomFieldValueDto;\nimport org.meveo.api.dto.CustomFieldsDto;\nimport org.meveo.api.dto.ProviderDto;\nimport org.meveo.model.crm.Provider;\nimport org.meveo.model.shared.DateUtils;\nimport org.meveo.service.crm.impl.ProviderService;\nimport org.meveo.service.script.Script;\n\npublic class SetPatchInfoScript extends Script {\n\n\tprivate ProviderService providerService = (ProviderService) getServiceInterface(\"ProviderService\");\n\tprivate ProviderApi providerApi = (ProviderApi) getServiceInterface(\"ProviderApi\");\n\tprivate static final String CF_PROV_VERSION = \"CF_PROV_VERSION\";\n\n\t/**\n\t * Script execute method\n\t *\n\t * @param context execution context\n\t * @throws BusinessException Business Exception\n\t */\n\t@Override\n\tpublic void execute(Map<String, Object> context) throws BusinessException {\n\n\tlog.info(\"EXECUT...\");\n\tString patchName = \"{{request.label}}\";\n\t\t\n\t\tProviderDto providerDto = providerApi.findProviderCF();\n\t\t\n\t\tlog.info(\"providerDto: {}\",providerDto);\n\t\tCustomFieldsDto cfs =  providerDto.getCustomFields();\t\n\t\tCustomFieldDto cf = null;\n\t\tif(cfs == null ) {\n\t\t\tproviderDto.setCustomFields(new CustomFieldsDto());\n\t\t\tcfs =  providerDto.getCustomFields();\n\t\t\tcf = new CustomFieldDto();\n\t\t\tcf.setCode(CF_PROV_VERSION);\n\t\t\tcf.setMapValue(new  LinkedHashMap<String, CustomFieldValueDto>());\n\t\t\tcfs.getCustomField().add(cf);\n\t\t}\n\t\tList<CustomFieldDto> listCf = cfs.getCustomField();\n\t\t\n\t\t cf = cfs.getCF(CF_PROV_VERSION);\n\t\tint  i =0;\n\t\tfor(CustomFieldDto c : listCf) {\n\t\t\tif(CF_PROV_VERSION.equals(c.getCode())) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\ti++;\n\t\t}\n\t\tlistCf.remove(i);\n\t\tMap<String,CustomFieldValueDto> val = cf.getMapValue();\n\t\tlog.info(\"val: {}\",val);\n\t\tLinkedHashMap<String, CustomFieldValueDto> newCfmap = null;\n\t\tif(val == null) {\n\t\t\t newCfmap = new  LinkedHashMap<String, CustomFieldValueDto>();\n\t\t}else {\n\t\t\tnewCfmap = (LinkedHashMap<String, CustomFieldValueDto>) val;\n\t\t}\n\t\t\n\t\tCustomFieldValueDto newVal = new CustomFieldValueDto();\n\t\tnewVal.setValue(patchName);\n\t\t\n\t\tnewCfmap.put(DateUtils.formatAsTime(new Date()), newVal);\n\t\t\n\t\t\n\t\tcf.setMapValue(newCfmap);\n\t\t\n\t\tlistCf.add(cf);\n\t\tcfs.setCustomField(listCf);\n\t\t\n\t\tproviderDto.setCustomFields(cfs);\n\t\tlog.info(\"the list:{}\",providerDto.getCustomFields().getCustomField());\t\t\n\t\tproviderApi.update(providerDto);\n\t\t//workarround\n\t\tProvider prov = providerService.getProvider();\t\t\n\t\tproviderService.update(prov);\n\t\t\n\t}\n}\n\n\n]]></script>\n</ScriptInstance>"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						}
					]
				}
			]
		},
		{
			"name": "Settings",
			"item": [
				{
					"name": "AccountingCodes",
					"item": [
						{
							"name": "706260",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\r\n  \"code\": \"706260\",\r\n  \"description\": \"706260\",\r\n  \"chartOfAccountTypeEnum\" : \"ASSETS\",\r\n  \"chartOfAccountViewTypeEnum\" : \"VIEW\"\r\n  \r\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/billing/accountingCode/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"billing",
										"accountingCode",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "709300",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\r\n  \"code\": \"709300\",\r\n  \"description\": \"709300\",\r\n  \"chartOfAccountTypeEnum\" : \"EXPENSE\",\r\n  \"chartOfAccountViewTypeEnum\" : \"VIEW\"\r\n  \r\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/billing/accountingCode/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"billing",
										"accountingCode",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "706800",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\r\n  \"code\": \"706800\",\r\n  \"description\": \"706800\",\r\n  \"chartOfAccountTypeEnum\" : \"ASSETS\",\r\n  \"chartOfAccountViewTypeEnum\" : \"VIEW\"\r\n  \r\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/billing/accountingCode/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"billing",
										"accountingCode",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "445710",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\r\n  \"code\": \"445710\",\r\n  \"description\": \"445710\",\r\n  \"chartOfAccountTypeEnum\" : \"LIABILITIES\",\r\n  \"chartOfAccountViewTypeEnum\" : \"REGULAR\"\r\n  \r\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/billing/accountingCode/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"billing",
										"accountingCode",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "411120",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\r\n  \"code\": \"411120\",\r\n  \"description\": \"411120\",\r\n  \"chartOfAccountTypeEnum\" : \"LIABILITIES\",\r\n  \"chartOfAccountViewTypeEnum\" : \"REGULAR\"\r\n  \r\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/billing/accountingCode/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"billing",
										"accountingCode",
										"createOrUpdate"
									]
								}
							},
							"response": []
						}
					]
				},
				{
					"name": "customer",
					"item": [
						{
							"name": "Titles",
							"item": [
								{
									"name": "title M",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "test",
												"value": "test"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"code\": \"Monsieur\",\n    \"description\": \"Monsieur\",\n    \"languageDescriptions\" : [ \n        { \"languageCode\" : \"ENG\", \"description\" : \"Monsieur\" },\n        { \"languageCode\" : \"FRA\", \"description\" : \"Monsieur\" }\n    ]\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/account/title/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"account",
												"title",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "title MME",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "test",
												"value": "test"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"code\": \"MME\",\n    \"description\": \"Madame\",\n    \"languageDescriptions\" : [ \n        { \"languageCode\" : \"ENG\", \"description\" : \"Madame\" },\n        { \"languageCode\" : \"FRA\", \"description\" : \"Madame\" }\n    ]\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/account/title/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"account",
												"title",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "title Madame",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript",
												"packages": {}
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "test",
												"value": "test"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"code\": \"Madame\",\n    \"description\": \"Madame\",\n    \"languageDescriptions\" : [ \n        { \"languageCode\" : \"ENG\", \"description\" : \"Madame\" },\n        { \"languageCode\" : \"FRA\", \"description\" : \"Madame\" }\n    ]\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/account/title/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"account",
												"title",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "title Mlle",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "test",
												"value": "test"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"code\": \"Mlle\",\n    \"description\": \"Mademoiselle\",\n    \"isCompany\": false\n   \n}"
										},
										"url": {
											"raw": "{{opencell.url}}/account/title/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"account",
												"title",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "title CIE",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "test",
												"value": "test"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"code\": \"CIE\",\n    \"description\": \"Sté\",\n    \"isCompany\": true\n   \n}"
										},
										"url": {
											"raw": "{{opencell.url}}/account/title/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"account",
												"title",
												"createOrUpdate"
											]
										}
									},
									"response": []
								}
							]
						},
						{
							"name": "Currencies",
							"item": [
								{
									"name": "code=EUR|desc=Euro",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "PUT",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{ \n  \"code\": \"{{code}}\",\n  \"description\": \"{{desc}}\"\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/currency",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"currency"
											]
										}
									},
									"response": []
								}
							]
						},
						{
							"name": "Countries",
							"item": [
								{
									"name": "code=FR|name=France|currency=EUR",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{ \n  \"countryCode\": \"{{code}}\",\n  \"name\": \"{{name}}\",\n  \"currencyCode\":\"{{currency}}\"\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/country/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"country",
												"createOrUpdate"
											]
										}
									},
									"response": []
								}
							]
						},
						{
							"name": "Languages",
							"item": [
								{
									"name": "code=FRA|desc=Français",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{ \n  \"code\": \"{{code}}\",\n  \"description\": \"{{desc}}\"\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/language/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"language",
												"createOrUpdate"
											]
										}
									},
									"response": []
								}
							]
						}
					]
				},
				{
					"name": "Taxes",
					"item": [
						{
							"name": "Tax categories",
							"item": [
								{
									"name": "taxCat|code=STANDARD|desc=Comptes standards",
									"event": [
										{
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											},
											"listen": "test"
										},
										{
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											},
											"listen": "prerequest"
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"code\": \"{{code}}\",\n    \"description\": \"{{desc}}\",\n    \"descriptionI18n\": [\n        {\n            \"languageCode\": \"FRA\",\n            \"description\": \"{{desc}}\"\n        }\n    ]\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/taxCategory/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"taxCategory",
												"createOrUpdate"
											]
										}
									},
									"response": []
								}
							]
						},
						{
							"name": "Rate",
							"item": [
								{
									"name": "20% BF",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										},
										{
											"listen": "prerequest",
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n  \"code\": \"BF\",\n  \"description\": \"Coll. 20,0% - FR Opérations taxables\",\n  \"percent\": \"20\",\n  \"accountingCode\": \"445710\",\n  \"languageDescriptions\": [\n  {\n    \"languageCode\": \"FRA\",\n    \"description\": \"Coll. 20,0% - FR Opérations taxables\"\n  }\n  ]\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/tax/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"tax",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "10% BE",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										},
										{
											"listen": "prerequest",
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n  \"code\": \"BE\",\n  \"description\": \"Coll. 10,0% - FR Opérations taxables\",\n  \"percent\": \"10\",\n  \"accountingCode\": \"445710\",\n  \"languageDescriptions\": [\n  {\n    \"languageCode\": \"FRA\",\n    \"description\": \"Coll. 10,0% - FR Opérations taxables\"\n  }\n  ]\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/tax/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"tax",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "5.5% B2",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										},
										{
											"listen": "prerequest",
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n  \"code\": \"B2\",\n  \"description\": \"Coll. 5,5% - FR Opérations taxables\",\n  \"percent\": \"5.5\",\n  \"accountingCode\": \"445710\",\n  \"languageDescriptions\": [\n  {\n    \"languageCode\": \"FRA\",\n    \"description\": \"Coll. 5,5% - FR Opérations taxables\"\n  }\n  ]\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/tax/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"tax",
												"createOrUpdate"
											]
										}
									},
									"response": []
								}
							]
						},
						{
							"name": "Tax classes (charge)",
							"item": [
								{
									"name": "TVA_20",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										},
										{
											"listen": "prerequest",
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"code\": \"TVA_20\",\n    \"description\": \"Tva standard 20\"\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/taxClass/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"taxClass",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "TVA_10",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										},
										{
											"listen": "prerequest",
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"code\": \"TVA_10\",\n    \"description\": \"Tva standard 10\"\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/taxClass/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"taxClass",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "TVA_5.5",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										},
										{
											"listen": "prerequest",
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"code\": \"TVA_55\",\n    \"description\": \"Tva standard 5.5\"\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/taxClass/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"taxClass",
												"createOrUpdate"
											]
										}
									},
									"response": []
								}
							]
						},
						{
							"name": "Tax mapping",
							"item": [
								{
									"name": "TVA_20_FR",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										},
										{
											"listen": "prerequest",
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"accountTaxCategoryCode\": \"STANDARD\",\n    \"chargeTaxClassCode\": \"TVA_20\",\n    \"buyerCountryCode\": \"FR\",\n    \"taxCode\": \"BF\",\n    \"priority\": 0\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/taxMapping/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"taxMapping",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "TVA_10_FR",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										},
										{
											"listen": "prerequest",
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"accountTaxCategoryCode\": \"STANDARD\",\n    \"chargeTaxClassCode\": \"TVA_10\",\n    \"buyerCountryCode\": \"FR\",\n    \"taxCode\": \"BE\",\n    \"priority\": 0\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/taxMapping/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"taxMapping",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "TVA_55_FR",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										},
										{
											"listen": "prerequest",
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"accountTaxCategoryCode\": \"STANDARD\",\n    \"chargeTaxClassCode\": \"TVA_55\",\n    \"buyerCountryCode\": \"FR\",\n    \"taxCode\": \"B2\",\n    \"priority\": 0\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/taxMapping/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"taxMapping",
												"createOrUpdate"
											]
										}
									},
									"response": []
								}
							]
						},
						{
							"name": "CLIENT",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"var jsonData = JSON.parse(responseBody);",
											"tests[\"is.success\"] = jsonData.status === \"SUCCESS\";"
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": " {\n    \"code\": \"CLIENT\",\n    \"description\": \"Client\",\n    \"exoneratedFromTaxes\": \"false\",\n    \"taxCategoryCode\": \"STANDARD\",\n    \"accountingCode\": null\n }"
								},
								"url": {
									"raw": "{{opencell.url}}/account/customer/createOrUpdateCategory",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"account",
										"customer",
										"createOrUpdateCategory"
									]
								}
							},
							"response": []
						}
					],
					"event": [
						{
							"listen": "prerequest",
							"script": {
								"type": "text/javascript",
								"exec": [
									""
								]
							}
						},
						{
							"listen": "test",
							"script": {
								"type": "text/javascript",
								"exec": [
									""
								]
							}
						}
					]
				},
				{
					"name": "CFs",
					"item": [
						{
							"name": "CF_SEL_INV_NB_BUSI_DAYS",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n            \"code\":\"CF_SEL_INV_NB_BUSI_DAYS\",\n            \"description\":\"Nombre de jours aprés facturation upFront\",\n            \"appliesTo\": \"Seller\",\n            \"fieldType\":\"LONG\",\n            \"storageType\":\"SINGLE\",\n            \"valueRequired\":false,\n            \"versionable\":false,\n            \"allowEdit\":true,\n            \"hideOnNew\":false,\n            \"guiPosition\": \"tab:Facturation;field:1\"\n         }"
								},
								"url": {
									"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"customFieldTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CF_SEL_INV_USE_SIMU_BUSINES_DAY",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n            \"code\":\"CF_SEL_INV_USE_SIMU_BUSINES_DAY\",\n            \"description\":\"Ignorer le jour ouvrable pour la génération REC\",\n            \"appliesTo\": \"Seller\",\n            \"fieldType\":\"BOOLEAN\",\n            \"storageType\":\"SINGLE\",\n            \"valueRequired\":false,\n            \"versionable\":false,\n            \"allowEdit\":true,\n            \"hideOnNew\":false,\n            \"guiPosition\": \"tab:Facturation;field:1\"\n         }"
								},
								"url": {
									"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"customFieldTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CF_SEL_SEPA_NB_BUSI_DAYS",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n            \"code\":\"CF_SEL_SEPA_NB_BUSI_DAYS\",\n            \"description\":\"Nombre de jours ouvrable pour la génération Sepa\",\n            \"appliesTo\": \"Seller\",\n            \"fieldType\":\"LONG\",\n            \"storageType\":\"SINGLE\",\n            \"valueRequired\":false,\n            \"versionable\":false,\n            \"allowEdit\":true,\n            \"hideOnNew\":false,\n            \"guiPosition\": \"tab:Paiement;field:0\"\n         }"
								},
								"url": {
									"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"customFieldTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CF_SEL_PAY_NB_BUSI_DAYS",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n            \"code\":\"CF_SEL_PAY_NB_BUSI_DAYS\",\n            \"description\":\"Nombre de jours ouvrable pour la date de paiement\",\n            \"appliesTo\": \"Seller\",\n            \"fieldType\":\"LONG\",\n            \"storageType\":\"SINGLE\",\n            \"valueRequired\":false,\n            \"versionable\":false,\n            \"allowEdit\":true,\n            \"hideOnNew\":false,\n            \"guiPosition\": \"tab:Paiement;field:0\"\n         }"
								},
								"url": {
									"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"customFieldTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CF_SEL_PAY_AMOUNT_THRESHOLD",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n            \"code\":\"CF_SEL_PAY_AMOUNT_THRESHOLD\",\n            \"description\":\"Seuil de prélèvementt\",\n            \"appliesTo\": \"Seller\",\n            \"fieldType\":\"DOUBLE\",\n            \"storageType\":\"SINGLE\",\n            \"valueRequired\":false,\n            \"versionable\":false,\n            \"allowEdit\":true,\n            \"hideOnNew\":false,\n            \"guiPosition\": \"tab:Paiement;field:0\"\n         }"
								},
								"url": {
									"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"customFieldTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CF_SUB_SF_DATA",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript",
										"packages": {}
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n            \"code\":\"CF_SUB_SF_DATA\",\n            \"description\":\"Données contrat sur salesForce\",\n            \"appliesTo\": \"Subscription\",\n            \"fieldType\":\"STRING\",\n            \"storageType\":\"MAP\",\n            \"valueRequired\":false,\n            \"versionable\":false,\n            \"allowEdit\":false,\n            \"hideOnNew\":false,\n            \"guiPosition\": \"tab:SalesForce;field:0\",\n             \"maxValue\" : 1000\n         }"
								},
								"url": {
									"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"customFieldTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CF_SUB_DATE_INSTALL",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n            \"code\":\"CF_SUB_DATE_INSTALL\",\n            \"description\":\"Date installation\",\n            \"appliesTo\": \"Subscription\",\n            \"fieldType\":\"DATE\",\n            \"storageType\":\"SINGLE\",\n            \"valueRequired\":false,\n            \"versionable\":false,\n            \"allowEdit\":false,\n            \"hideOnNew\":false,\n            \"guiPosition\": \"tab:SalesForce;field:0\"\n         }"
								},
								"url": {
									"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"customFieldTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CF_SEL_INV_NO_REC_INVOICES",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n            \"code\":\"CF_SEL_INV_NO_REC_INVOICES\",\n            \"description\":\"Bloquer la facturation des abonnements en masse\",\n            \"appliesTo\": \"Seller\",\n            \"fieldType\":\"BOOLEAN\",\n            \"storageType\":\"SINGLE\",\n            \"valueRequired\":false,\n            \"versionable\":false,\n            \"allowEdit\":true,\n            \"hideOnNew\":false,\n            \"defaultValue\":\"true\",\n            \"guiPosition\": \"tab:Facturation;field:0\"\n         }"
								},
								"url": {
									"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"customFieldTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CF_SUB_PAY_METHOD",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n            \"code\":\"CF_SUB_PAY_METHOD\",\n            \"description\":\"Mode de paiement\",\n            \"appliesTo\": \"Subscription\",\n            \"fieldType\":\"STRING\",\n            \"storageType\":\"SINGLE\",\n            \"valueRequired\":false,\n            \"versionable\":false,\n            \"allowEdit\":false,\n            \"hideOnNew\":false,\n            \"guiPosition\": \"tab:SalesForce;field:0\"\n         }"
								},
								"url": {
									"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"customFieldTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CF_PROV_VERSION",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n            \"code\":\"CF_PROV_VERSION\",\n            \"description\":\"Liste patch postman\",\n            \"appliesTo\": \"Provider\",\n            \"fieldType\":\"STRING\",\n            \"mapKeyType\":\"STRING\",\n            \"maxValue\":265,\n            \"storageType\":\"MAP\",\n            \"valueRequired\":false,\n            \"versionable\":false,\n            \"allowEdit\":true,\n            \"hideOnNew\":false,\n            \"guiPosition\": \"tab:Version;field:0\"\n         }"
								},
								"url": {
									"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"customFieldTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CF_SUB_REF_MATS",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n            \"code\":\"CF_SUB_REF_MATS\",\n            \"description\":\"Référence matériels\",\n            \"appliesTo\": \"Subscription\",\n            \"fieldType\":\"STRING\",\n            \"storageType\":\"MAP\",\n            \"valueRequired\":false,\n            \"versionable\":false,\n            \"allowEdit\":false,\n            \"hideOnNew\":false,\n            \"guiPosition\": \"tab:SalesForce;field:1\"\n         }"
								},
								"url": {
									"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"customFieldTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CF_SUB_CPT_REMISE",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n            \"code\":\"CF_SUB_CPT_REMISE\",\n            \"description\":\"Compteur occurence remise\",\n            \"appliesTo\": \"Subscription\",\n            \"fieldType\":\"LONG\",\n            \"storageType\":\"SINGLE\",\n            \"valueRequired\":false,\n            \"versionable\":false,\n            \"allowEdit\":false,\n            \"hideOnNew\":false,\n            \"guiPosition\": \"tab:SalesForce;field:0\"\n         }"
								},
								"url": {
									"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"customFieldTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CF_SUB_DATE_INSTALL",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n            \"code\":\"CF_SUB_DATE_INSTALL\",\n            \"description\":\"Date installation\",\n            \"appliesTo\": \"Subscription\",\n            \"fieldType\":\"DATE\",\n            \"storageType\":\"SINGLE\",\n            \"valueRequired\":false,\n            \"versionable\":false,\n            \"allowEdit\":true,\n            \"hideOnNew\":false,\n            \"guiPosition\": \"tab:SalesForce;field:0\"\n         }"
								},
								"url": {
									"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"customFieldTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CF_SUB_PAY_METHOD",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n            \"code\":\"CF_SUB_PAY_METHOD\",\n            \"description\":\"Mode de paiement\",\n            \"appliesTo\": \"Subscription\",\n            \"fieldType\":\"STRING\",\n            \"storageType\":\"SINGLE\",\n            \"valueRequired\":false,\n            \"versionable\":false,\n            \"allowEdit\":true,\n            \"hideOnNew\":false,\n            \"guiPosition\": \"tab:SalesForce;field:0\"\n         }"
								},
								"url": {
									"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"customFieldTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CF_SUB_REF_MATS",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n            \"code\":\"CF_SUB_REF_MATS\",\n            \"description\":\"Référence matériels\",\n            \"appliesTo\": \"Subscription\",\n            \"fieldType\":\"STRING\",\n            \"storageType\":\"MAP\",\n            \"valueRequired\":false,\n            \"versionable\":false,\n            \"allowEdit\":true,\n            \"hideOnNew\":false,\n            \"guiPosition\": \"tab:SalesForce;field:1\"\n         }"
								},
								"url": {
									"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"customFieldTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CF_SUB_PRICES",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n            \"code\":\"CF_SUB_PRICES\",\n            \"description\":\"Prices\",\n            \"appliesTo\": \"Subscription\",\n            \"fieldType\":\"DOUBLE\",\n            \"storageType\":\"MAP\",\n            \"valueRequired\":false,\n            \"versionable\":false,\n            \"allowEdit\":true,\n            \"hideOnNew\":false,\n            \"guiPosition\": \"tab:Prix;field:1\"\n         }"
								},
								"url": {
									"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"customFieldTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CF_SUB_LABELS",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n            \"code\":\"CF_SUB_LABELS\",\n            \"description\":\"Labels\",\n            \"appliesTo\": \"Subscription\",\n            \"fieldType\":\"STRING\",\n            \"storageType\":\"MAP\",\n            \"valueRequired\":false,\n            \"versionable\":false,\n            \"allowEdit\":true,\n            \"hideOnNew\":false,\n            \"guiPosition\": \"tab:Prix;field:1\"\n         }"
								},
								"url": {
									"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"customFieldTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						}
					]
				},
				{
					"name": "Sellers",
					"item": [
						{
							"name": "EKKO",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n  \"code\": \"EKKO\",\n  \"description\": \"Mon Pilotage Elec\",\n  \"currencyCode\": \"EUR\",\n  \"countryCode\": \"FR\",\n  \"languageCode\": \"FRA\",\n  \"address\": {\n    \"address1\": \"1 Place Samuel Champlain\",\n    \"address2\": \"Paris La Défense Cedex\",\n    \"zipCode\": 92930,\n    \"city\": \"Courbevoie\",\n    \"country\": \"FR\"\n  }\n,\n\t\"customFields\": {\n\t\t\"customField\": [\t\t\t\n\t\t\t{\n\t\t\t\t\"code\": \"CF_SEL_INV_NB_BUSI_DAYS\",\n\t\t\t\t\"longValue\": 5\n\t\t\t},\n            {\n\t\t\t\t\"code\": \"CF_SEL_PAY_NB_BUSI_DAYS\",\n\t\t\t\t\"longValue\": 10\n\t\t\t},\n            {\n\t\t\t\t\"code\": \"CF_SEL_SEPA_NB_BUSI_DAYS\",\n\t\t\t\t\"longValue\": 5\n\t\t\t},\n            {\n\t\t\t\t\"code\": \"CF_SEL_PAY_AMOUNT_THRESHOLD\",\n\t\t\t\t\"doubleValue\": 1\n\t\t\t}\n\n            \n\n\t\t]\n\t}\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/seller/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"seller",
										"createOrUpdate"
									]
								}
							},
							"response": []
						}
					]
				},
				{
					"name": "Calendars",
					"item": [
						{
							"name": "MENSUEL",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n    \"code\": \"MENSUEL\",\n    \"description\": \"1St Monthly\",\n    \"calendarType\":\"YEARLY\",\n    \"days\":[\n        {\"day\":1,\"month\":\"JANUARY\"},\n        {\"day\":1,\"month\":\"FEBRUARY\"},\n        {\"day\":1,\"month\":\"MARCH\"},\n        {\"day\":1,\"month\":\"APRIL\"},\n        {\"day\":1,\"month\":\"MAY\"},\n        {\"day\":1,\"month\":\"JUNE\"},\n        {\"day\":1,\"month\":\"JULY\"},\n        {\"day\":1,\"month\":\"AUGUST\"},\n        {\"day\":1,\"month\":\"SEPTEMBER\"},\n        {\"day\":1,\"month\":\"OCTOBER\"},\n         {\"day\":1,\"month\":\"NOVEMBER\"},\n          {\"day\":1,\"month\":\"DECEMBER\"}\n    ]\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/calendar/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"calendar",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "FR_BANKING_2021",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n    \"code\": \"FR_BANKING_2021\",\n    \"description\": \"Jours Fériés France 2021\",\n    \"calendarType\":\"BANKING\",\n    \"startDate\":\"2021-01-01\",\n    \"endDate\":\"2021-12-31\",\n    \"weekendBegin\":6,\n    \"weekendEnd\" : 7,\n    \"holidays\":[\n        {\"holidayBegin\":101,\"holidayEnd\":101},\n        {\"holidayBegin\":405,\"holidayEnd\":405},\n         {\"holidayBegin\":501,\"holidayEnd\":501},\n         {\"holidayBegin\":508,\"holidayEnd\":508},\n         {\"holidayBegin\":513,\"holidayEnd\":513},\n         {\"holidayBegin\":524,\"holidayEnd\":524},\n         {\"holidayBegin\":714,\"holidayEnd\":714},\n         {\"holidayBegin\":815,\"holidayEnd\":815},\n         {\"holidayBegin\":1101,\"holidayEnd\":1101},\n         {\"holidayBegin\":1111,\"holidayEnd\":1111},\n         {\"holidayBegin\":1225,\"holidayEnd\":1225}\n\n    ]\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/calendar/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"calendar",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "FR_BANKING_2022",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n    \"code\": \"FR_BANKING_2022\",\n    \"description\": \"Jours Fériés France 2022\",\n    \"calendarType\":\"BANKING\",\n    \"startDate\":\"2022-01-01\",\n    \"endDate\":\"2022-12-31\",\n    \"weekendBegin\":6,\n    \"weekendEnd\" : 7,\n    \"holidays\":[\n        {\"holidayBegin\":101,\"holidayEnd\":101},\n        {\"holidayBegin\":418,\"holidayEnd\":418},\n         {\"holidayBegin\":501,\"holidayEnd\":501},\n         {\"holidayBegin\":508,\"holidayEnd\":508},\n         {\"holidayBegin\":526,\"holidayEnd\":526},\n         {\"holidayBegin\":606,\"holidayEnd\":606},\n         {\"holidayBegin\":714,\"holidayEnd\":714},\n         {\"holidayBegin\":815,\"holidayEnd\":815},\n         {\"holidayBegin\":1101,\"holidayEnd\":1101},\n         {\"holidayBegin\":1111,\"holidayEnd\":1111},\n         {\"holidayBegin\":1225,\"holidayEnd\":1225}\n\n    ]\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/calendar/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"calendar",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "FR_BANKING_2023",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n    \"code\": \"FR_BANKING_2023\",\n    \"description\": \"Jours Fériés France 2023\",\n    \"calendarType\":\"BANKING\",\n    \"startDate\":\"2023-01-01\",\n    \"endDate\":\"2023-12-31\",\n    \"weekendBegin\":6,\n    \"weekendEnd\" : 7,\n    \"holidays\":[\n        {\"holidayBegin\":101,\"holidayEnd\":101},\n        {\"holidayBegin\":410,\"holidayEnd\":410},\n         {\"holidayBegin\":501,\"holidayEnd\":501},\n         {\"holidayBegin\":508,\"holidayEnd\":508},\n         {\"holidayBegin\":518,\"holidayEnd\":518},\n         {\"holidayBegin\":529,\"holidayEnd\":529},\n         {\"holidayBegin\":714,\"holidayEnd\":714},\n         {\"holidayBegin\":815,\"holidayEnd\":815},\n         {\"holidayBegin\":1101,\"holidayEnd\":1101},\n         {\"holidayBegin\":1111,\"holidayEnd\":1111},\n         {\"holidayBegin\":1225,\"holidayEnd\":1225}\n\n    ]\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/calendar/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"calendar",
										"createOrUpdate"
									]
								}
							},
							"response": []
						}
					]
				},
				{
					"name": "Billing",
					"item": [
						{
							"name": "AOsTemplate",
							"item": [
								{
									"name": "INV_STD",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "test",
												"value": "test"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"code\": \"INV_STD\",\n    \"description\": \"Standard invoice sub-item\",\n    \"occCategory\": \"DEBIT\",\n    \"accountingCode\": \"411120\"\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/occTemplate/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"occTemplate",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "PAY_DDT",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "test",
												"value": "test"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"code\": \"PAY_DDT\",\n    \"description\": \"Payment DirectDebit\",\n    \"occCategory\": \"CREDIT\",\n    \"accountingCode\": \"445710\"\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/occTemplate/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"occTemplate",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "REJ_DDT",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "test",
												"value": "test"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"code\": \"REJ_DDT\",\n    \"description\": \"Rejected payment - direct debit\",\n    \"occCategory\": \"DEBIT\",\n    \"accountingCode\": \"706800\"\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/occTemplate/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"occTemplate",
												"createOrUpdate"
											]
										}
									},
									"response": []
								}
							]
						},
						{
							"name": "Invoice types",
							"item": [
								{
									"name": "REC_SEQ",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "test",
												"value": "test"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"code\": \"REC_SEQ\",\n    \"description\": \"Ekko séquence facture récurrente\",\n    \"sequenceSize\": 11,\n    \"currentInvoiceNb\": 0\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/invoiceSequence/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"invoiceSequence",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "UPF_SEQ",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "test",
												"value": "test"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"code\": \"UPF_SEQ\",\n    \"description\": \"Ekko séquence facture Upfront\",\n    \"sequenceSize\": 11,\n    \"currentInvoiceNb\": 0\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/invoiceSequence/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"invoiceSequence",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "REC",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "test",
												"value": "test"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"code\": \"REC\",\n    \"description\": \"Ekko facture récurrente\",\n    \"occTemplateCode\": \"INV_STD\",\n    \"occTemplateNegativeCode\": \"INV_CRN\",\n      \"billingTemplateName\":\"REC\",\n    \"customInvoiceXmlScriptInstanceCode\":\"com.opencellsoft.service.ekko.invoicing.InvoiceXmlScript\",\n    \"sequenceDto\": {\n    \t\"prefixEL\": \"5\",    \n        \"invoiceSequenceCode\": \"REC_SEQ\"\n    },\n    \"matchingAuto\": false,\n    \"billingTemplateNameEL\": \"\",\n    \"useSelfSequence\": false,\n    \"sellerSequence\": {}\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/invoiceType/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"invoiceType",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "UPF",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "test",
												"value": "test"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n    \"code\": \"UPF\",\n    \"description\": \"Ekko facture Upfront\",\n    \"occTemplateCode\": \"INV_STD\",\n    \"occTemplateNegativeCode\": \"INV_CRN\",\n    \"billingTemplateName\":\"UPF\",\n     \"customInvoiceXmlScriptInstanceCode\":\"com.opencellsoft.service.ekko.invoicing.InvoiceXmlScript\",\n    \"sequenceDto\": {\n    \t\"prefixEL\": \"5\",    \n        \"invoiceSequenceCode\": \"REC_SEQ\"\n    },\n    \"matchingAuto\": false,\n    \"billingTemplateNameEL\": \"\",\n    \"useSelfSequence\": false,\n    \"sellerSequence\": {}\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/invoiceType/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"invoiceType",
												"createOrUpdate"
											]
										}
									},
									"response": []
								}
							]
						},
						{
							"name": "Billing cycles",
							"item": [
								{
									"name": "MENSUEL",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n  \"code\": \"MENSUEL\",\n  \"type\": \"SUBSCRIPTION\",\n  \"description\": \"Mensuel\",\n  \"invoiceDateDelay\": \"0\",\n  \"dueDateDelayEL\": \"#{mv:executeScript(entity, 'com.opencellsoft.service.ekko.invoicing.DueDateScript', '')}\",\n  \"invoiceDateProductionDelay\": \"0\",\n  \"calendar\": \"MENSUEL\",  \n  \"scriptInstanceCode\":\"com.opencellsoft.service.ekko.invoicing.EkkoBillingCycleScript\"\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/billingCycle/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"billingCycle",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "NO INVOICING",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\n  \"code\": \"NO_INVOICING\",\n  \"type\": \"SUBSCRIPTION\",\n  \"description\": \"Pas de facturation\",\n  \"invoiceDateDelay\": \"0\",\n  \"dueDateDelayEL\": \"0\",\n  \"invoiceDateProductionDelay\": \"0\",\n  \"calendar\": \"MENSUEL\"\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/billingCycle/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"billingCycle",
												"createOrUpdate"
											]
										}
									},
									"response": []
								}
							]
						},
						{
							"name": "Categories",
							"item": [
								{
									"name": "ICAT_EKKO_INSTALL",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{ \n  \"code\": \"ICAT_EKKO_INSTALL\",\n  \"description\": \"Instalation\"\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/invoiceCategory/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"invoiceCategory",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "ICAT_EKKO_MATERIEL",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{ \n  \"code\": \"ICAT_EKKO_MATERIEL\",\n  \"description\": \"Vente\"\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/invoiceCategory/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"invoiceCategory",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "ICAT_EKKO_ABO",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{ \n  \"code\": \"ICAT_EKKO_ABO\",\n  \"description\": \"Abonnement\"\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/invoiceCategory/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"invoiceCategory",
												"createOrUpdate"
											]
										}
									},
									"response": []
								}
							]
						},
						{
							"name": "Sub categories",
							"item": [
								{
									"name": "ISCAT_EKKO_INSTALL",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n\t\"code\": \"ISCAT_EKKO_INSTALL\",\r\n\t\"description\": \"Instalation\",\r\n\t\"invoiceCategory\": \"ICAT_EKKO_INSTALL\",\r\n\t\"accountingCode\": \"706260\"\r\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/invoiceSubCategory/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"invoiceSubCategory",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "ISCAT_EKKO_INSTALL_REMISE",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n\t\"code\": \"ISCAT_EKKO_INSTALL_REMISE\",\r\n\t\"description\": \"Instalation Remise\",\r\n\t\"invoiceCategory\": \"ICAT_EKKO_INSTALL\",\r\n\t\"accountingCode\": \"709300\"\r\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/invoiceSubCategory/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"invoiceSubCategory",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "ISCAT_EKKO_INSTALL_GEST",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n\t\"code\": \"ISCAT_EKKO_INSTALL_GEST\",\r\n\t\"description\": \"Geste commercial\",\r\n\t\"invoiceCategory\": \"ICAT_EKKO_INSTALL\",\r\n\t\"accountingCode\": \"709300\"\r\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/invoiceSubCategory/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"invoiceSubCategory",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "ISCAT_EKKO_MAT_VENTE",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n\t\"code\": \"ISCAT_EKKO_MAT_VENTE\",\r\n\t\"description\": \"Vente matériel\",\r\n\t\"invoiceCategory\": \"ICAT_EKKO_MATERIEL\",\r\n\t\"accountingCode\": \"706260\"\r\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/invoiceSubCategory/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"invoiceSubCategory",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "ISCAT_EKKO_MAT_REMISE",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n\t\"code\": \"ISCAT_EKKO_MAT_REMISE\",\r\n\t\"description\": \"Remise matériel\",\r\n\t\"invoiceCategory\": \"ICAT_EKKO_MATERIEL\",\r\n\t\"accountingCode\": \"709300\"\r\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/invoiceSubCategory/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"invoiceSubCategory",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "ISCAT_EKKO_DEEE",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n\t\"code\": \"ISCAT_EKKO_DEEE\",\r\n\t\"description\": \"Eco-participations DEEE\",\r\n\t\"invoiceCategory\": \"ICAT_EKKO_MATERIEL\",\r\n\t\"accountingCode\": \"706260\"\r\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/invoiceSubCategory/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"invoiceSubCategory",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "ISCAT_EKKO_DEEE_REMISE",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n\t\"code\": \"ISCAT_EKKO_DEEE_REMISE\",\r\n\t\"description\": \"Remise eco-participations DEEE\",\r\n\t\"invoiceCategory\": \"ICAT_EKKO_MATERIEL\",\r\n\t\"accountingCode\": \"709300\"\r\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/invoiceSubCategory/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"invoiceSubCategory",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "ISCAT_EKKO_ABO",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n\t\"code\": \"ISCAT_EKKO_ABO\",\r\n\t\"description\": \"Abonnement EKKO\",\r\n\t\"invoiceCategory\": \"ICAT_EKKO_ABO\",\r\n\t\"accountingCode\": \"706800\"\r\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/invoiceSubCategory/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"invoiceSubCategory",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "ISCAT_EKKO_ABO_REMISE",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n\t\"code\": \"ISCAT_EKKO_ABO_REMISE\",\r\n\t\"description\": \"Remise abonnement EKKO\",\r\n\t\"invoiceCategory\": \"ICAT_EKKO_ABO\",\r\n\t\"accountingCode\": \"709300\"\r\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/invoiceSubCategory/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"invoiceSubCategory",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "ISCAT_EKKO_ABO_GEST",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n\t\"code\": \"ISCAT_EKKO_ABO_GEST\",\r\n\t\"description\": \"Geste commercial abonnement\",\r\n\t\"invoiceCategory\": \"ICAT_EKKO_ABO\",\r\n\t\"accountingCode\": \"709300\"\r\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/invoiceSubCategory/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"invoiceSubCategory",
												"createOrUpdate"
											]
										}
									},
									"response": []
								}
							]
						}
					]
				},
				{
					"name": "Provider",
					"item": [
						{
							"name": "EKKO",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											""
										],
										"type": "text/javascript",
										"packages": {}
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n\t\"code\": \"EKKO\",\n\t\"description\": \"Mon Pilotage Elec\",\n\t\"enterprise\": \"true\",\n\t\"rounding\": \"2\",\n\t\"invoiceRounding\": \"2\",\n    \"invoiceRoundingMode\":\"NEAREST\",\n\t\"invoiceConfiguration\": {\n\t\t\"displaySubscriptions\": \"true\",\n\t\t\"displayServices\": \"true\",\n\t\t\"displayOffers\": \"true\",\n\t\t\"displayEdrs\": \"false\",\n\t\t\"displayProvider\": \"true\",\n\t\t\"displayCfAsXML\": \"true\",\n\t\t\"displayPricePlans\": \"true\",\n\t\t\"displayDetail\": \"true\",\n\t\t\"displayChargesPeriods\": \"true\",\n\t\t\"displayFreeTransacInInvoice\": \"false\",\n\t\t\"displayBillingCycle\": \"false\",\n\t\t\"displayOrders\": \"false\"\n\t},\n    \"bankCoordinates\":{\n        \"iban\":\"FR7630004013280001323623704\",\n        \"bic\" :\"BNPAFRPPXXX\",\n        \"ics\":\"FRXXZZZ123456\",\n        \"bankId\":\"BNP\",\n        \"bankCode\":\"\",\n        \"accountNumber\":\"\",\n        \"issuerNumber\":\"\"\n\n    }\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/provider/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"provider",
										"createOrUpdate"
									]
								}
							},
							"response": []
						}
					]
				},
				{
					"name": "Termination reasons",
					"item": [
						{
							"name": "RETRACTATION",
							"request": {
								"auth": {
									"type": "basic",
									"basic": [
										{
											"key": "password",
											"value": "opencell.admin",
											"type": "string"
										},
										{
											"key": "username",
											"value": "opencell.admin",
											"type": "string"
										}
									]
								},
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\r\n    \"code\": \"RETRACT\",\r\n    \"description\": \"Rétractaction\",\r\n    \"applyAgreement\": false,\r\n    \"applyReimbursment\": false,\r\n    \"applyTerminationCharges\": false,\r\n    \"overrideProrata\": \"NO_OVERRIDE\",\r\n    \"reimburseOneshots\": false\r\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/terminationReason",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"terminationReason"
									]
								}
							},
							"response": []
						},
						{
							"name": "RESILIATION",
							"request": {
								"auth": {
									"type": "basic",
									"basic": [
										{
											"key": "password",
											"value": "opencell.admin",
											"type": "string"
										},
										{
											"key": "username",
											"value": "opencell.admin",
											"type": "string"
										}
									]
								},
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\r\n    \"code\": \"RESIL\",\r\n    \"description\": \"Résiliation\",\r\n    \"applyAgreement\": false,\r\n    \"applyReimbursment\": false,\r\n    \"applyTerminationCharges\": false,\r\n    \"overrideProrata\": \"NO_OVERRIDE\",\r\n    \"reimburseOneshots\": false\r\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/terminationReason",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"terminationReason"
									]
								}
							},
							"response": []
						}
					]
				}
			],
			"event": [
				{
					"listen": "prerequest",
					"script": {
						"type": "text/javascript",
						"exec": [
							""
						]
					}
				},
				{
					"listen": "test",
					"script": {
						"type": "text/javascript",
						"exec": [
							""
						]
					}
				}
			]
		},
		{
			"name": "Catalog",
			"item": [
				{
					"name": "Charges",
					"item": [
						{
							"name": "OneShot",
							"item": [
								{
									"name": "CH_OS_EKKO_INSTALL",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n    \"code\": \"CH_OS_EKKO_INSTALL\",\r\n    \"description\": \"Installation\",\r\n    \"disabled\": false,\r\n    \"invoiceSubCategory\": \"ISCAT_EKKO_INSTALL\",\r\n    \"amountEditable\": true,\r\n    \"unitNbDecimal\": 12,\r\n    \"roundingModeDtoEnum\": \"NEAREST\",\r\n    \"taxClassCode\": \"TVA_55\",\r\n    \"dropZeroWo\": false,\r\n    \"oneShotChargeTemplateType\": \"OTHER\",\r\n    \"immediateInvoicing\": false\r\n}"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/oneShotChargeTemplate/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"oneShotChargeTemplate",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "CH_OS_EKKO_REM_INST",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "\r\n{\r\n    \"code\": \"CH_OS_EKKO_REM_INST\",\r\n    \"description\": \"Remise sur installation\",\r\n    \"disabled\": false,\r\n    \"invoiceSubCategory\": \"ISCAT_EKKO_INSTALL_REMISE\",\r\n    \"amountEditable\": true,\r\n    \"unitNbDecimal\": 12,\r\n    \"roundingModeDtoEnum\": \"NEAREST\",\r\n    \"taxClassCode\": \"TVA_55\",\r\n    \"dropZeroWo\": false,\r\n    \"oneShotChargeTemplateType\": \"OTHER\",\r\n    \"immediateInvoicing\": false\r\n}\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/oneShotChargeTemplate/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"oneShotChargeTemplate",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "CH_OS_EKKO_GEST_INST",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n    \"code\": \"CH_OS_EKKO_GEST_INST\",\r\n    \"description\": \"Geste commercial suite à pb à l’installation\",\r\n    \"disabled\": false,\r\n    \"invoiceSubCategory\": \"ISCAT_EKKO_INSTALL_GEST\",\r\n    \"amountEditable\": true,\r\n    \"unitNbDecimal\": 12,\r\n    \"roundingModeDtoEnum\": \"NEAREST\",\r\n    \"taxClassCode\": \"TVA_55\",\r\n    \"dropZeroWo\": false,\r\n    \"oneShotChargeTemplateType\": \"OTHER\",\r\n    \"immediateInvoicing\": false\r\n}\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/oneShotChargeTemplate/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"oneShotChargeTemplate",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "CH_OS_EKKO_DEEE",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n    \"code\": \"CH_OS_EKKO_DEEE\",\r\n    \"description\": \"Eco-participation DEEE\",\r\n    \"disabled\": false,\r\n    \"invoiceSubCategory\": \"ISCAT_EKKO_DEEE\",\r\n    \"amountEditable\": true,\r\n    \"unitNbDecimal\": 12,\r\n    \"roundingModeDtoEnum\": \"NEAREST\",\r\n    \"taxClassCode\": \"TVA_20\",\r\n    \"dropZeroWo\": false,\r\n    \"oneShotChargeTemplateType\": \"OTHER\",\r\n    \"immediateInvoicing\": false\r\n}\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/oneShotChargeTemplate/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"oneShotChargeTemplate",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "CF_OS_EKKO_REM_DEEE",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n    \"code\": \"CH_OS_EKKO_REM_DEEE\",\r\n    \"description\": \"Remise sur Eco-participation DEEE\",\r\n    \"disabled\": false,\r\n    \"invoiceSubCategory\": \"ISCAT_EKKO_DEEE_REMISE\",\r\n    \"amountEditable\": true,\r\n    \"unitNbDecimal\": 12,\r\n    \"roundingModeDtoEnum\": \"NEAREST\",\r\n    \"taxClassCode\": \"TVA_20\",\r\n    \"dropZeroWo\": false,\r\n    \"oneShotChargeTemplateType\": \"OTHER\",\r\n    \"immediateInvoicing\": false\r\n}\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/oneShotChargeTemplate/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"oneShotChargeTemplate",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "CH_OS_EKKO_MATERIEL",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n    \"code\": \"CH_OS_EKKO_MATERIEL\",\r\n    \"description\": \"Materiel\",\r\n    \"disabled\": false,\r\n    \"invoiceSubCategory\": \"ISCAT_EKKO_MAT_VENTE\",\r\n    \"amountEditable\": true,\r\n    \"unitNbDecimal\": 12,\r\n    \"roundingModeDtoEnum\": \"NEAREST\",\r\n    \"taxClassCode\": \"TVA_55\",\r\n    \"dropZeroWo\": false,\r\n    \"oneShotChargeTemplateType\": \"OTHER\",\r\n    \"immediateInvoicing\": false\r\n}\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/oneShotChargeTemplate/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"oneShotChargeTemplate",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "CH_OS_EKKO_REM_MAT",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n    \"code\": \"CH_OS_EKKO_REM_MAT\",\r\n    \"description\": \"Remise sur materiel\",\r\n    \"disabled\": false,\r\n    \"invoiceSubCategory\": \"ISCAT_EKKO_MAT_REMISE\",\r\n    \"amountEditable\": true,\r\n    \"unitNbDecimal\": 12,\r\n    \"roundingModeDtoEnum\": \"NEAREST\",\r\n    \"taxClassCode\": \"TVA_55\",\r\n    \"dropZeroWo\": false,\r\n    \"oneShotChargeTemplateType\": \"OTHER\",\r\n    \"immediateInvoicing\": false\r\n}\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/oneShotChargeTemplate/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"oneShotChargeTemplate",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "CH_OS_EKKO_GEST_ABO",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n    \"code\": \"CH_OS_EKKO_GEST_ABO\",\r\n    \"description\": \"Geste commercial abonnement\",\r\n    \"disabled\": false,\r\n    \"invoiceSubCategory\": \"ISCAT_EKKO_ABO_GEST\",\r\n    \"amountEditable\": true,\r\n    \"unitNbDecimal\": 12,\r\n    \"roundingModeDtoEnum\": \"NEAREST\",\r\n    \"taxClassCode\": \"TVA_20\",\r\n    \"dropZeroWo\": false,\r\n    \"oneShotChargeTemplateType\": \"OTHER\",\r\n    \"immediateInvoicing\": false\r\n}\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/oneShotChargeTemplate/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"oneShotChargeTemplate",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "CH_OS_EKKO_RESIL",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n    \"code\": \"CH_OS_EKKO_RESIL\",\r\n    \"description\": \"FRAIS DE RESIL\",\r\n    \"disabled\": false,\r\n    \"invoiceSubCategory\": \"ISCAT_EKKO_ABO\",\r\n    \"amountEditable\": true,\r\n    \"unitNbDecimal\": 12,\r\n    \"roundingModeDtoEnum\": \"NEAREST\",\r\n    \"taxClassCode\": \"TVA_20\",\r\n    \"dropZeroWo\": false,\r\n    \"oneShotChargeTemplateType\": \"TERMINATION\",\r\n    \"immediateInvoicing\": false\r\n}\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/oneShotChargeTemplate/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"oneShotChargeTemplate",
												"createOrUpdate"
											]
										}
									},
									"response": []
								}
							]
						},
						{
							"name": "Recurring",
							"item": [
								{
									"name": "CH_REC_EKKO_ABO",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n\t\"code\": \"CH_REC_EKKO_ABO\",\r\n\t\"description\": \"Service Abonnement\",\r\n\t\"invoiceSubCategory\": \"ISCAT_EKKO_ABO\",\r\n\t\"disabled\": false,\r\n    \"amountEditable\": true,\r\n\t\"unitNbDecimal\": 12,\r\n\t\"roundingModeDtoEnum\": \"NEAREST\",\r\n\t\"calendar\": \"MENSUEL\",\r\n\t\"subscriptionProrata\": false,\r\n\t\"terminationProrata\": false,\r\n\t\"applyInAdvance\": true,\r\n\t\"taxClassCode\": \"TVA_20\"\r\n\t}\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/recurringChargeTemplate/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"recurringChargeTemplate",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "CH_REC_EKKO_ABO_REM",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n\t\"code\": \"CH_REC_EKKO_ABO_REM\",\r\n\t\"description\": \"Prestation de services Remises\",\r\n\t\"invoiceSubCategory\": \"ISCAT_EKKO_ABO_REMISE\",\r\n\t\"disabled\": false,\r\n    \"amountEditable\": true,\r\n\t\"unitNbDecimal\": 12,\r\n\t\"roundingModeDtoEnum\": \"NEAREST\",\r\n\t\"calendar\": \"MENSUEL\",\r\n\t\"subscriptionProrata\": false,\r\n\t\"terminationProrata\": false,\r\n\t\"applyInAdvance\": true,\r\n\t\"taxClassCode\": \"TVA_20\"\r\n\t}\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/recurringChargeTemplate/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"recurringChargeTemplate",
												"createOrUpdate"
											]
										}
									},
									"response": []
								}
							]
						}
					]
				},
				{
					"name": "PricesPlans",
					"item": [
						{
							"name": "OneShot",
							"item": [
								{
									"name": "PP_CH_OS_EKKO_INSTALL",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n  \"code\": \"PP_CH_OS_EKKO_INSTALL\",\r\n  \"eventCode\": \"CH_OS_EKKO_INSTALL\",\r\n  \"amountWithoutTax\": -1,\r\n  \"priority\": 1,\r\n  \"criteriaEL\" : null\r\n}\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/pricePlan/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"pricePlan",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "PP_ CH_OS_EKKO_REM_INST",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n  \"code\": \"PP_CH_OS_EKKO_REM_INST\",\r\n  \"eventCode\": \"CH_OS_EKKO_REM_INST\",\r\n  \"amountWithoutTax\": -1,\r\n  \"priority\": 1,\r\n  \"criteriaEL\" : null\r\n}\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/pricePlan/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"pricePlan",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "PP_CH_OS_EKKO_DEEE",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n  \"code\": \"PP_CH_OS_EKKO_DEEE\",\r\n  \"eventCode\": \"CH_OS_EKKO_DEEE\",\r\n  \"amountWithoutTax\": -1,\r\n  \"priority\": 1,\r\n  \"criteriaEL\" : null\r\n}\r\n\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/pricePlan/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"pricePlan",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "PP_CH_OS_EKKO_REM_DEEE",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n  \"code\": \"PP_CH_OS_EKKO_REM_DEEE\",\r\n  \"eventCode\": \"CH_OS_EKKO_REM_DEEE\",\r\n  \"amountWithoutTax\": -1,\r\n  \"priority\": 1,\r\n  \"criteriaEL\" : null\r\n}\r\n\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/pricePlan/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"pricePlan",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "PP_CH_OS_EKKO_MATERIEL",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n  \"code\": \"PP_CH_OS_EKKO_MATERIEL\",\r\n  \"eventCode\": \"CH_OS_EKKO_MATERIEL\",\r\n  \"amountWithoutTax\": -1,\r\n  \"priority\": 1,\r\n  \"criteriaEL\" : null\r\n}\r\n\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/pricePlan/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"pricePlan",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "PP_CH_OS_EKKO_GEST",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n  \"code\": \"PP_CH_OS_EKKO_GEST_INST\",\r\n  \"eventCode\": \"CH_OS_EKKO_GEST_INST\",\r\n  \"amountWithoutTax\": -1,\r\n  \"priority\": 1,\r\n  \"criteriaEL\" : null\r\n}\r\n\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/pricePlan/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"pricePlan",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "PP_CH_OS_EKKO_REM_MAT",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n  \"code\": \"PP_CH_OS_EKKO_REM_MAT\",\r\n  \"eventCode\": \"CH_OS_EKKO_REM_MAT\",\r\n  \"amountWithoutTax\": -1, \r\n  \"priority\": 1,\r\n  \"criteriaEL\" : null\r\n}\r\n\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/pricePlan/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"pricePlan",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "PP_CH_OS_EKKO_GEST_ABO",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n  \"code\": \"PP_CH_OS_EKKO_GEST_ABO\",\r\n  \"eventCode\": \"CH_OS_EKKO_GEST_ABO\",\r\n  \"amountWithoutTax\": -1, \r\n  \"priority\": 1,\r\n  \"criteriaEL\" : null\r\n}\r\n\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/pricePlan/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"pricePlan",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "PP_CH_OS_EKKO_RESIL",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n  \"code\": \"PP_CH_OS_EKKO_RESIL\",\r\n  \"eventCode\": \"CH_OS_EKKO_RESIL\",\r\n  \"amountWithoutTax\": 15, \r\n  \"priority\": 1,\r\n  \"criteriaEL\" : null\r\n}\r\n\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/pricePlan/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"pricePlan",
												"createOrUpdate"
											]
										}
									},
									"response": []
								}
							]
						},
						{
							"name": "Recurring",
							"item": [
								{
									"name": "PP_CH_REC_EKKO_ABO",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n  \"code\": \"PP_CH_REC_EKKO_ABO\",\r\n  \"eventCode\": \"CH_REC_EKKO_ABO\",\r\n  \"amountWithoutTax\": 1\r\n}\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/pricePlan/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"pricePlan",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "PP_CH_REC_EKKO_ABO_REM",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n  \"code\": \"PP_CH_REC_EKKO_ABO_REM\",\r\n  \"eventCode\": \"CH_REC_EKKO_ABO_REM\",\r\n  \"amountWithoutTax\": -0.5,\r\n  \"criteriaEL\" : null\r\n}\r\n"
										},
										"url": {
											"raw": "{{opencell.url}}/catalog/pricePlan/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"catalog",
												"pricePlan",
												"createOrUpdate"
											]
										}
									},
									"response": []
								}
							]
						}
					]
				},
				{
					"name": "Services",
					"item": [
						{
							"name": "CFs",
							"item": [
								{
									"name": "CF_SUB_PRICES",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n            \"code\":\"CF_SUB_PRICES\",\r\n            \"description\":\"Prices\",\r\n            \"appliesTo\": \"Subscription\",\r\n            \"fieldType\":\"DOUBLE\",\r\n            \"storageType\":\"MAP\",\r\n            \"valueRequired\":false,\r\n            \"versionable\":false,\r\n            \"allowEdit\":false,\r\n            \"hideOnNew\":false,\r\n            \"guiPosition\": \"tab:Prix;field:1\"\r\n         }"
										},
										"url": {
											"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"customFieldTemplate",
												"createOrUpdate"
											]
										}
									},
									"response": []
								},
								{
									"name": "CF_SUB_LABELS",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													"pm.test(\"Successful request\", () => {",
													"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
													"});",
													"",
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "POST",
										"header": [
											{
												"key": "Content-Type",
												"value": "application/json"
											},
											{
												"key": "Authorization",
												"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
											}
										],
										"body": {
											"mode": "raw",
											"raw": "{\r\n            \"code\":\"CF_SUB_LABELS\",\r\n            \"description\":\"Labels\",\r\n            \"appliesTo\": \"Subscription\",\r\n            \"fieldType\":\"STRING\",\r\n            \"storageType\":\"MAP\",\r\n            \"valueRequired\":false,\r\n            \"versionable\":false,\r\n            \"allowEdit\":false,\r\n            \"hideOnNew\":false,\r\n            \"guiPosition\": \"tab:Prix;field:2\"\r\n         }"
										},
										"url": {
											"raw": "{{opencell.url}}/customFieldTemplate/createOrUpdate",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"customFieldTemplate",
												"createOrUpdate"
											]
										}
									},
									"response": []
								}
							]
						},
						{
							"name": "SE_EKKO_ABO",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n    \"code\": \"SE_EKKO_ABO\",\n    \"description\": \"Service abonnement EKKO\",\n    \"mandatory\": false,\t\n    \"serviceChargeTemplateRecurrings\": {\n        \"serviceChargeTemplateRecurring\": [\n            {\n                \"code\": \"CH_REC_EKKO_ABO\"\n            }\n        ]\n    },\n    \"serviceChargeTemplateTerminations\": {\n        \"serviceChargeTemplateTermination\": [\n            {\n                \"code\": \"CH_OS_EKKO_RESIL\"\n            }\n        ]\n    }\n}\n\n"
								},
								"url": {
									"raw": "{{opencell.url}}/catalog/serviceTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"catalog",
										"serviceTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "SE_EKKO_ABO_REM",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\n    \"code\": \"SE_EKKO_ABO_REM\",\n    \"description\": \"Service abonnement remise EKKO\",\n    \"mandatory\": false,\t\n    \"serviceChargeTemplateRecurrings\": {\n        \"serviceChargeTemplateRecurring\": [\n            {\n                \"code\": \"CH_REC_EKKO_ABO_REM\"\n            }\n        ]\n    }\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/catalog/serviceTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"catalog",
										"serviceTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						}
					]
				},
				{
					"name": "Offers",
					"item": [
						{
							"name": "OF_EKKO",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46aFViNTJBTTNDZSEh"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\r\n    \"code\": \"OF_EKKO\",\r\n    \"description\": \"Engie EKKO\",\r\n    \"lifeCycleStatus\": \"ACTIVE\",\t\r\n    \"globalRatingScriptInstance\":\"com.opencellsoft.service.ekko.rating.EkkoRatingScript\",\r\n    \"seller\": [\r\n            \"EKKO\"\r\n    ],\r\n    \"offerServiceTemplate\": [\r\n        {\"serviceTemplate\":{\"code\": \"SE_EKKO_ABO\" }},\r\n        {\"serviceTemplate\":{\"code\": \"SE_EKKO_ABO_REM\" }}]\t\r\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/catalog/offerTemplate/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"catalog",
										"offerTemplate",
										"createOrUpdate"
									]
								}
							},
							"response": []
						}
					]
				}
			]
		},
		{
			"name": "Sepa_Pain08_Camt54",
			"item": [
				{
					"name": "Create Sepa DDRequestBuilder",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript",
								"packages": {}
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"code\": \"EKKO_Sepa_Pain08_Camt54\",\r\n    \"description\": \"Ekko Format sepa Pain08 and Camt54\",\r\n    \"type\" : \"CUSTOM\" , \r\n    \"scriptInstanceCode\" : \"com.opencellsoft.service.ekko.payment.SepaDDRequestBuilderScript\", \r\n    \"paymentLevel\" : \"SUB\"\r\n    \r\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/payment/ddRequestBuilder/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"payment",
								"ddRequestBuilder",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "Create DDRequestLotOp",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"recurrent\": true,\r\n    \"fromDueDate\" : \"2000-01-01\",\r\n    \"toDueDate\" : \"2999-01-01\",\r\n    \"ddRequestBuilderCode\" : \"EKKO_Sepa_Pain08_Camt54\",\r\n    \"dueDateRageScriptCode\" : \"com.opencellsoft.service.ekko.payment.PaymentEkkoDateRangeScript\"\r\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/payment/ddrequestLotOp",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"payment",
								"ddrequestLotOp"
							]
						}
					},
					"response": []
				},
				{
					"name": "Create SEPA_CAMT54_JOB",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"code\": \"EKKO_Reject_SDD_JOB\",\r\n    \"description\": \"EKKO Camt054 Reject Sepa DD Job\",\r\n    \"jobCategory\": \"PAYMENT\",\r\n    \"jobTemplate\": \"SepaRejectedTransactionsJob\" , \r\n    \"customFields\" : {\r\n    \t\"customField\": [ \r\n    \t\t{ \"code\":\"RejectSepaJob_ddRequestBuilder\", \r\n    \t\t   \"entityReferenceValue\" : {\r\n    \t\t        \"classname\" : \"org.meveo.model.payments.DDRequestBuilder\" ,\r\n    \t\t        \"code\" : \"EKKO_Sepa_Pain08_Camt54\"\r\n    \t\t   }\r\n    \t\t},\r\n            { \"code\":\"RejectSepaJob_inputDir\", \r\n    \t\t   \"stringValue\" : \"/bcom/ekko/in/pre\"\r\n    \t\t},\r\n            { \"code\":\"RejectSepaJob_fileNameExtension\", \r\n    \t\t   \"stringValue\" : \"xml\"\r\n    \t\t},\r\n            { \"code\":\"RejectSepaJob_fileNamePrefix\", \r\n    \t\t   \"stringValue\" : \"GSZMPE_REJSDD\"\r\n    \t\t}\r\n\r\n    \t] \r\n    }\r\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "Create SEPA_PAIN08_JOB",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"code\": \"EKKO_SDD_JOB\",\r\n    \"description\": \"EKKO Pain08 Payment Sepa DD Job\",\r\n    \"jobCategory\": \"PAYMENT\",\r\n    \"jobTemplate\": \"SepaDirectDebitJob\" , \r\n    \"followingJob\": \"EKKO_Reject_SDD_JOB\",\r\n    \"customFields\" : {\r\n    \t\"customField\": [ \r\n    \t\t{ \"code\":\"SepaJob_ddRequestBuilder\", \r\n    \t\t   \"entityReferenceValue\" : {\r\n    \t\t        \"classname\" : \"org.meveo.model.payments.DDRequestBuilder\" ,\r\n    \t\t        \"code\" : \"EKKO_Sepa_Pain08_Camt54\"\r\n    \t\t   }\r\n    \t\t},\r\n            { \"code\":\"SepaJob_aoFilterScript\", \r\n    \t\t   \"entityReferenceValue\" : {\r\n    \t\t        \"classname\" : \"org.meveo.model.scripts.ScriptInstance\" ,\r\n    \t\t        \"code\" : \"com.opencellsoft.service.ekko.payment.AOFilterScript\"\r\n    \t\t   }\r\n    \t\t}\r\n    \t] \r\n    }\r\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "Remboursement",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"code\": \"Remboursement\",\r\n    \"description\": \"Lancement du PAIN001 + AO type ARF\",\r\n    \"jobCategory\": \"PAYMENT\",\r\n    \"jobTemplate\": \"SepaDirectDebitJob\" , \r\n    \"customFields\" : {\r\n    \t\"customField\": [ \r\n    \t\t{ \"code\":\"SepaJob_ddRequestBuilder\", \r\n    \t\t   \"entityReferenceValue\" : {\r\n    \t\t        \"classname\" : \"org.meveo.model.payments.DDRequestBuilder\" ,\r\n    \t\t        \"code\" : \"EKKO_Sepa_Pain08_Camt54\"\r\n    \t\t   }\r\n    \t\t},\r\n            { \"code\":\"SepaJob_aoFilterScript\", \r\n    \t\t   \"entityReferenceValue\" : {\r\n    \t\t        \"classname\" : \"org.meveo.model.scripts.ScriptInstance\" ,\r\n    \t\t        \"code\" : \"com.opencellsoft.service.ekko.payment.AOFilterScript\"\r\n    \t\t   }\r\n    \t\t},\r\n            { \"code\":\"SepaJob_paymentOrRefund\", \r\n    \t\t   \"stringValue\" : \"REFUND\"\r\n    \t\t}\r\n    \t] \r\n    }\r\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				}
			]
		},
		{
			"name": "Sepa_Pain01",
			"item": [
				{
					"name": "Update SepaDDRequestBuilderScript",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/xml"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.payment.SepaDDRequestBuilderScript\" description=\"Ekko Sepa Pain08 ,Pain01 et camt54 Script\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.payment;\r\n\r\nimport java.io.File;\r\nimport java.math.BigDecimal;\r\nimport java.math.RoundingMode;\r\nimport java.util.ArrayList;\r\nimport java.util.Arrays;\r\nimport java.util.Date;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.regex.Matcher;\r\nimport java.util.regex.Pattern;\r\nimport java.util.stream.Collectors;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.admin.sepa.DDRejectFileInfos;\r\nimport org.meveo.admin.sepa.jaxb.camt054.AccountNotification2;\r\nimport org.meveo.admin.sepa.jaxb.camt054.BankToCustomerDebitCreditNotificationV02;\r\nimport org.meveo.admin.sepa.jaxb.pain001.AmountType3Choice;\r\nimport org.meveo.admin.sepa.jaxb.pain001.CreditTransferTransactionInformation10;\r\nimport org.meveo.admin.sepa.jaxb.pain001.CustomerCreditTransferInitiationV03;\r\nimport org.meveo.admin.sepa.jaxb.pain001.GroupHeader32;\r\nimport org.meveo.admin.sepa.jaxb.pain001.PaymentInstructionInformation3;\r\nimport org.meveo.admin.sepa.jaxb.pain001.PaymentMethod3Code;\r\nimport org.meveo.admin.sepa.jaxb.pain001.PaymentTypeInformation19;\r\nimport org.meveo.admin.sepa.jaxb.pain001.RemittanceInformation5;\r\nimport org.meveo.admin.sepa.jaxb.pain008.AccountIdentification4Choice;\r\nimport org.meveo.admin.sepa.jaxb.pain008.ActiveOrHistoricCurrencyAndAmount;\r\nimport org.meveo.admin.sepa.jaxb.pain008.BranchAndFinancialInstitutionIdentification4;\r\nimport org.meveo.admin.sepa.jaxb.pain008.CashAccount16;\r\nimport org.meveo.admin.sepa.jaxb.pain008.CustomerDirectDebitInitiationV02;\r\nimport org.meveo.admin.sepa.jaxb.pain008.DirectDebitTransaction6;\r\nimport org.meveo.admin.sepa.jaxb.pain008.DirectDebitTransactionInformation9;\r\nimport org.meveo.admin.sepa.jaxb.pain008.Document;\r\nimport org.meveo.admin.sepa.jaxb.pain008.FinancialInstitutionIdentification7;\r\nimport org.meveo.admin.sepa.jaxb.pain008.GenericFinancialIdentification1;\r\nimport org.meveo.admin.sepa.jaxb.pain008.GenericPersonIdentification1;\r\nimport org.meveo.admin.sepa.jaxb.pain008.GroupHeader39;\r\nimport org.meveo.admin.sepa.jaxb.pain008.LocalInstrument2Choice;\r\nimport org.meveo.admin.sepa.jaxb.pain008.MandateRelatedInformation6;\r\nimport org.meveo.admin.sepa.jaxb.pain008.Party6Choice;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PartyIdentification32;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PaymentIdentification1;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PaymentInstructionInformation4;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PaymentMethod2Code;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PaymentTypeInformation20;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PersonIdentification5;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PersonIdentificationSchemeName1Choice;\r\nimport org.meveo.admin.sepa.jaxb.pain008.SequenceType1Code;\r\nimport org.meveo.admin.sepa.jaxb.pain008.ServiceLevel8Choice;\r\nimport org.meveo.admin.util.ArConfig;\r\nimport org.meveo.commons.utils.EjbUtils;\r\nimport org.meveo.commons.utils.JAXBUtils;\r\nimport org.meveo.commons.utils.ParamBean;\r\nimport org.meveo.commons.utils.StringUtils;\r\nimport org.meveo.model.admin.Seller;\r\nimport org.meveo.model.billing.BankCoordinates;\r\nimport org.meveo.model.billing.Subscription;\r\nimport org.meveo.model.crm.Provider;\r\nimport org.meveo.model.payments.AccountOperation;\r\nimport org.meveo.model.payments.CustomerAccount;\r\nimport org.meveo.model.payments.DDPaymentMethod;\r\nimport org.meveo.model.payments.DDRequestItem;\r\nimport org.meveo.model.payments.DDRequestLOT;\r\nimport org.meveo.model.payments.OperationCategoryEnum;\r\nimport org.meveo.model.payments.PaymentGateway;\r\nimport org.meveo.model.payments.PaymentMethod;\r\nimport org.meveo.model.payments.PaymentMethodEnum;\r\nimport org.meveo.model.payments.RecordedInvoice;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.model.shared.Name;\r\nimport org.meveo.model.shared.Title;\r\nimport org.meveo.service.admin.impl.SellerService;\r\nimport org.meveo.service.billing.impl.SubscriptionService;\r\nimport org.meveo.service.catalog.impl.CalendarBankingService;\r\nimport org.meveo.service.catalog.impl.TitleService;\r\nimport org.meveo.service.payments.impl.AccountOperationService;\r\nimport org.meveo.service.payments.impl.CustomerAccountService;\r\nimport org.meveo.service.payments.impl.DDRequestItemService;\r\nimport org.meveo.service.payments.impl.DDRequestLOTService;\r\nimport org.meveo.service.payments.impl.PaymentGatewayService;\r\nimport org.meveo.service.payments.impl.PaymentMethodService;\r\nimport org.meveo.service.payments.impl.RecordedInvoiceService;\r\nimport org.meveo.service.script.payment.DDRequestBuilderScript;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n/**\r\n * The Class SepaDDRequestBuilderScript.\r\n *\r\n * @author anasseh\r\n * \r\n * 02/03/2022 supprimer le dossier 'EKKO'\r\n * 02/03/2022 fileName : from SDD.PRL.MYP1_EKKO_20210401XXXXXXXXX.xml to SDD.PRL.MPE.20210401XXXXXXXXX.xml\r\n * 03/10/22 add sepa refund\r\n */\r\n\r\npublic class SepaDDRequestBuilderScript extends DDRequestBuilderScript {\r\n\t/** The log. */\r\n\tprivate static Logger log = LoggerFactory.getLogger(SepaDDRequestBuilderScript.class);\r\n\r\n\t/** The location of SDD schema. */\r\n\tprivate static final String SDD_SCHEMA_LOCATION = \"https://github.com/w2c/sepa-sdd-xml-generator/blob/master/validation_schemes/pain.008.001.02.xsd\";\r\n\r\n\t   /** The location of SCT schema. */\r\n    private static final String SCT_SCHEMA_LOCATION = \"https://github.com/digitick/php-sepa-xml/blob/master/tests/pain.001.001.03.xsd\";\r\n    \r\n\t/** The Constant SIMPLE_DATE_PATTERN. */\r\n\tprivate static final String SIMPLE_DATE_PATTERN = \"yyyyMMdd\";\r\n\r\n\t/** The Constant EMPTY_STRING. */\r\n\tprivate static final String EMPTY_STRING = \"\";\r\n\r\n\t/** The Constant DASH_STRING. */\r\n\tprivate static final String DASH_STRING = \"-\";\r\n\r\n\t/** The Constant DOUBLE_POINT. */\r\n\tprivate static final String DOUBLE_POINT = \"\\\\..\";\r\n\r\n\t/** The underscore separator used at sepa file name. */\r\n\tprivate static final String UNDERSCORE_SEPARATOR = \"_\";\r\n\r\n\t/** The Constant EURO_CCY. */\r\n\tprivate static final String EURO_CCY = \"EUR\";\r\n\r\n\t/** The Constant SEPA_SERVICE_LEVEL_CD. */\r\n\tprivate static final String SEPA_SERVICE_LEVEL_CD = \"SEPA\";\r\n\r\n\t/** The Constant SEPA_LOCAL_INSTRUMENT_CODE. */\r\n\tprivate static final String SEPA_LOCAL_INSTRUMENT_CODE = \"CORE\";\r\n\t\r\n\t   /** The Constant COMMA_STRING. */\r\n    private static final String COMMA_STRING = \",\";\r\n    \r\n    /** The PATTERN that the IBAN should match. */\r\n    private static final String IBAN_PATTERN = \"[A-Z]{2,2}[0-9]{2,2}[a-zA-Z0-9]{1,30}\";\r\n    \r\n    /** The Constant NOTPROVIDED_BIC. */\r\n    private static final String NOTPROVIDED_BIC = \"NOTPROVIDED\";\r\n\r\n    /** The Constant CATEGORY_PURPOSE_CODE. */\r\n    private static final String CATEGORY_PURPOSE_CODE = \"SUPP\";\r\n    /** The Constant FR_COUNTRY. */\r\n    private static final String FR_COUNTRY = \"FR\";\r\n    private Pattern pattern = Pattern.compile(IBAN_PATTERN);\r\n\r\n\t/** The dd request item service. */\r\n\tprivate DDRequestItemService ddRequestItemService = (DDRequestItemService) EjbUtils.getServiceInterface(\"DDRequestItemService\");\r\n\r\n\t/** The dd request LOT service. */\r\n\tprivate DDRequestLOTService ddRequestLOTService = (DDRequestLOTService) EjbUtils.getServiceInterface(\"DDRequestLOTService\");\r\n\r\n\t/** The customer account service. */\r\n\tprivate CustomerAccountService customerAccountService = (CustomerAccountService) EjbUtils.getServiceInterface(\"CustomerAccountService\");\r\n\tprivate SubscriptionService subscriptionService = (SubscriptionService) EjbUtils.getServiceInterface(\"SubscriptionService\");\r\n\r\n\t/** The recorded invoice service. */\r\n\tprivate RecordedInvoiceService recordedInvoiceService = (RecordedInvoiceService) EjbUtils.getServiceInterface(\"RecordedInvoiceService\");\r\n\tprivate SellerService sellerService = (SellerService) EjbUtils.getServiceInterface(\"SellerService\");\r\n\tprivate TitleService titleService = (TitleService) EjbUtils.getServiceInterface(\"TitleService\");\r\n\tprivate CalendarBankingService calendarBankingService = (CalendarBankingService) getServiceInterface(\"CalendarBankingService\");\r\n\tprivate PaymentMethodService paymentMethodService = (PaymentMethodService) getServiceInterface(\"PaymentMethodService\");\r\n\tprivate AccountOperationService accountOperationService = (AccountOperationService) EjbUtils.getServiceInterface(\"AccountOperationService\");\r\n\tprivate static final String CF_SUB_PAY_METHOD = \"CF_SUB_PAY_METHOD\";\r\n\t\r\n\t\r\n\t\r\n\r\n\t@Override\r\n\tpublic List<AccountOperation> findListAoToPay(Map<String, Object> methodContext) throws BusinessException {\r\n\t\tlog.info(\"findListAoToPay methodContext:{}\",methodContext);\r\n\t\tList<AccountOperation> aos = (List<AccountOperation>) methodContext.get(DDRequestBuilderScript.DD_REQUEST_LIST_AO);\r\n\t\tif (aos == null || aos.isEmpty()) {\r\n\t\t\treturn aos;\r\n\t\t}\r\n\t\taos = aos.stream().filter(ao -> (isDirectDebitOrder(ao))).collect(Collectors.toList());\r\n\t\tSeller seller = sellerService.findByCode(\"EKKO\");\r\n\t\tDouble paymentThreshold = (Double) seller.getCfValue(\"CF_SEL_PAY_AMOUNT_THRESHOLD\");\r\n\t\tif(paymentThreshold == null) {\r\n\t\t\tpaymentThreshold = 1d;\r\n\t\t}\r\n\r\n\t\tMap<CustomerAccount, List<AccountOperation>> aosByCA = new HashMap<CustomerAccount, List<AccountOperation>>();\r\n\t\tfor (AccountOperation ao : aos) {\r\n\t\t\tao = accountOperationService.refreshOrRetrieve(ao);\r\n\t\t\tCustomerAccount ca = customerAccountService.refreshOrRetrieve(ao.getCustomerAccount());\r\n\t\t\tList<AccountOperation> aosForCA = new ArrayList<AccountOperation>();\r\n\t\t\tif (aosByCA.containsKey(ca)) {\r\n\t\t\t\taosForCA = aosByCA.get(ca);\r\n\t\t\t}\r\n\t\t\taosForCA.add(ao);\r\n\t\t\taosByCA.put(ca, aosForCA);\r\n\t\t}\r\n\t\taos = new ArrayList<AccountOperation>();\r\n\t\tfor (Map.Entry<CustomerAccount, List<AccountOperation>> entry : aosByCA.entrySet()) {\r\n\t\t\tBigDecimal amountToPayByItem = BigDecimal.ZERO;\r\n\t\t\t\r\n\t\t\tCustomerAccount ca = entry.getKey();\r\n\t\t\t\r\n\t\t\tfor (AccountOperation ao : entry.getValue()) {\r\n\t\t\t\t\r\n\t\t\t\t\tamountToPayByItem = amountToPayByItem.add(ao.getUnMatchingAmount());\r\n\t\t\t\t\r\n\t\t\t}\r\n\t\t\tif(amountToPayByItem.compareTo(BigDecimal.valueOf(paymentThreshold))>=0) {\r\n\t\t\t\taos.addAll(entry.getValue());\r\n\t\t\t}\r\n\r\n\t\t\t\r\n\t\t}\r\n\r\n\t\tlog.info(\"findListAoToPay return aos:{}\",aos);\r\n\t\treturn aos;\r\n\t}\r\n\r\n\tprivate boolean isDirectDebitOrder(AccountOperation ao) {\r\n\t\tlog.info(\"checking paymentMethodType for AO id:\"+ao.getId());\r\n\t\tif(ao.getSubscription() != null) {\r\n\t\t\tSubscription sub = subscriptionService.refreshOrRetrieve(ao.getSubscription());\r\n\t\t\tString orderPayMethod = (String)sub.getCfValue(CF_SUB_PAY_METHOD) ;\r\n\t\t\tlog.info(\"orderPayMethod:\"+orderPayMethod);\r\n\t\t\tif(PaymentMethodEnum.CARD.name().equals(orderPayMethod)) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\t@Override\r\n\tpublic String getDDFileName(Map<String, Object> methodContext) throws BusinessException {\r\n\t\tDDRequestLOT ddRequestLOT = (DDRequestLOT) methodContext.get(DDRequestBuilderScript.DD_REQUEST_LOT);\r\n\t\tProvider appProvider = (Provider) methodContext.get(DDRequestBuilderScript.PROVIDER);\r\n\t\tif (ddRequestLOT.getPaymentOrRefundEnum().getOperationCategoryToProcess() == OperationCategoryEnum.DEBIT) {\r\n\t\t\treturn getFileName(ddRequestLOT, appProvider, \r\n\t\t\t    ParamBean.getInstance().getProperty(\"bayad.ddrequest.fileName.prefix\", \"SDD.PRL.MPE.\"), \r\n\t\t\t    ParamBean.getInstance().getProperty(\"bayad.ddrequest.fileName.extension\", \"xml\"),  \r\n\t\t\t    ParamBean.getInstance().getProperty(\"bayad.ddrequest.outputDir\", \"prelevement\"));\r\n\t\t} else {\r\n\t\t    return getFileName(ddRequestLOT, appProvider, \r\n\t\t        ParamBean.getInstance().getProperty(\"bayad.sctrequest.fileName.prefix\", \"SCT.VIR.MPE.\"), \r\n                ParamBean.getInstance().getProperty(\"bayad.sctrequest.fileName.extension\", \"xml\"),  \r\n                ParamBean.getInstance().getProperty(\"bayad.sctrequest.outputDir\", \"virement\"));\r\n\t\t}\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void generateDDRequestLotFile(Map<String, Object> methodContext) throws BusinessException {\r\n\r\n\t\tlog.info(\" >>> Starting generateDDRequestLotFile ... \");\r\n\t\tProvider appProvider = (Provider) methodContext.get(DDRequestBuilderScript.PROVIDER);\r\n\t\tDDRequestLOT ddRequestLOT = (DDRequestLOT) methodContext.get(DDRequestBuilderScript.DD_REQUEST_LOT);\r\n\t\tDDRequestLOTService ddRequestLotService = (DDRequestLOTService) getServiceInterface(\"DDRequestLOTService\");\r\n\t\tddRequestLOT = ddRequestLotService.findById(ddRequestLOT.getId(), Arrays.asList(\"ddrequestItems\", \"ddRequestBuilder\"));\r\n\t\tif (ddRequestLOT.getPaymentOrRefundEnum().getOperationCategoryToProcess() == OperationCategoryEnum.DEBIT) {\r\n\t\t\tgenerateDDRequestLotFileForSSD(ddRequestLOT, appProvider);\r\n\t\t} else {\r\n\t\t\t generateDDRequestLotFileForSCT(ddRequestLOT, appProvider);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the file name.\r\n\t *\r\n\t * @param ddRequestLot        the dd request lot\r\n\t * @param appProvider         the app provider\r\n\t * @param fileNamePrefix      the file name prefix\r\n\t * @param fileNameExtension   the file name extension\r\n\t * @param additionalOutputDir the additional output dir\r\n\t * @return the file name\r\n\t * @throws BusinessException the business exception\r\n\t */\r\n\tprivate String getFileName(DDRequestLOT ddRequestLot, Provider appProvider, String fileNamePrefix, String fileNameExtension, String additionalOutputDir)\r\n\t\t\tthrows BusinessException {\r\n\t\ttry {\r\n\t\t\t//SDD.PRL.MYP1_EKKO_20210401XXXXXXXXX.xml ==> debut projet\r\n\t\t\t//SDD.PRL.MPE.20210401XXXXXXXXX.xml ==> 02/03/2022 live test MEP\r\n\t\t\tParamBean paramBean = ParamBean.getInstanceByProvider(appProvider.getCode());\r\n\t\t\tString fileName = fileNamePrefix+DateUtils.formatDateWithPattern(new Date(), \"yyyyMMddhhmmssSSS\")+\".\"+fileNameExtension;\r\n\t\t\t\r\n\t\t\tString outputDir = paramBean.getChrootDir(appProvider.getCode());\r\n\r\n\t\t\toutputDir = outputDir + File.separator + additionalOutputDir;\r\n\t\t\toutputDir = outputDir.replaceAll(DOUBLE_POINT, EMPTY_STRING);\r\n\r\n\t\t\tlog.info(\"DDRequest output directory=\" + outputDir);\r\n\t\t\tFile dir = new File(outputDir);\r\n\t\t\tif (!dir.exists()) {\r\n\t\t\t\tdir.mkdirs();\r\n\t\t\t}\r\n\t\t\treturn outputDir + File.separator + fileName;\r\n\t\t} catch (Exception e) {\r\n\t\t\tlog.error(e.getMessage(), e);\r\n\t\t\tthrow new BusinessException(e.getMessage());\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Generate DD request lot file for SSD.\r\n\t *\r\n\t * @param ddRequestLot the dd request lot\r\n\t * @param appProvider  the app provider\r\n\t * @throws BusinessException the business exception\r\n\t */\r\n\tprivate void generateDDRequestLotFileForSSD(DDRequestLOT ddRequestLot, Provider appProvider) throws BusinessException {\r\n\t\ttry {\r\n\t\t\tParamBean paramBean = ParamBean.getInstanceByProvider(appProvider.getCode());\r\n\t\t\tDocument document = new Document();\r\n\t\t\tCustomerDirectDebitInitiationV02 message = new CustomerDirectDebitInitiationV02();\r\n\t\t\tdocument.setCstmrDrctDbtInitn(message);\r\n\t\t\taddHeader(message, ddRequestLot, appProvider);\r\n\r\n\t\t\tboolean isEmptyLot = addPaymentInformation(message, ddRequestLot, appProvider);\r\n\r\n\t\t\tif (isEmptyLot) {\r\n\t\t\t\tlog.warn(\"There no valid dd item, file will not created\");\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tString schemaLocation = paramBean.getProperty(\"sepa.schemaLocation.pain008\", SDD_SCHEMA_LOCATION);\r\n\t\t\tJAXBUtils.marshaller(document, new File(ddRequestLot.getFileName()), schemaLocation);\r\n\t\t} catch (Exception e) {\r\n\t\t\tlog.error(\"Error on generateDDRequestLotFileForSSD\", e);\r\n\t\t\tthrow new BusinessException(e.getMessage());\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Adds the header of SDD file.\r\n\t *\r\n\t * @param message      the SDD message\r\n\t * @param ddRequestLOT the dd request LOT\r\n\t * @param appProvider  the provider\r\n\t * @throws Exception the exception\r\n\t */\r\n\tprivate void addHeader(CustomerDirectDebitInitiationV02 message, DDRequestLOT ddRequestLOT, Provider appProvider) throws Exception {\r\n\r\n\t\tGroupHeader39 groupHeader = new GroupHeader39();\r\n\t\tmessage.setGrpHdr(groupHeader);\r\n\t\tgroupHeader.setMsgId(ArConfig.getDDRequestHeaderReference() + DASH_STRING + ddRequestLOT.getId());\r\n\t\tgroupHeader.setCreDtTm(DateUtils.dateToXMLGregorianCalendar(new Date()));\r\n\t\tgroupHeader.setNbOfTxs(String.valueOf(ddRequestLOT.getNbItemsOk()));\r\n\t\tBigDecimal total = BigDecimal.ZERO;\r\n\t\tfor (DDRequestItem item : ddRequestLOT.getDdrequestItems()) {\r\n\t\t\tif (!item.hasError()) {\r\n\t\t\t\ttotal = total.add(item.getAmount().setScale(2, RoundingMode.HALF_UP));\r\n\t\t\t}\r\n\t\t}\r\n\t\tddRequestLOT.setTotalAmount(total);\r\n\t\tddRequestLOTService.updateNoCheck(ddRequestLOT);\r\n\t\tgroupHeader.setCtrlSum(total.setScale(2, RoundingMode.HALF_UP));\r\n\t\tPartyIdentification32 initgPty = new PartyIdentification32();\r\n\t\tif (ddRequestLOT.getSeller() != null) {\t\t\t\r\n\t\t\tinitgPty.setNm(format(sellerService.refreshOrRetrieve(ddRequestLOT.getSeller()).getDescription()));\r\n\t\t} else {\r\n\t\t\tinitgPty.setNm(format(appProvider.getDescription()));\r\n\t\t}\r\n\r\n\t\tgroupHeader.setInitgPty(initgPty);\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Adds the payment information of SDD file.\r\n\t *\r\n\t * @param Message       the SDD message\r\n\t * @param dDRequestItem the dd request item\r\n\t * @param appProvider   the provider\r\n\t * @throws Exception the exception\r\n\t */\r\n\tprivate boolean addPaymentInformation(CustomerDirectDebitInitiationV02 Message, DDRequestLOT ddRequestLot, Provider appProvider) throws Exception {\r\n\t\tboolean isEmptyLot = true;\r\n\t\tlog.info(\"addPaymentInformation dDRequestLot id=\" + ddRequestLot.getId());\r\n\t\tParamBean paramBean = ParamBean.getInstanceByProvider(appProvider.getCode());\r\n\t\tPaymentInstructionInformation4 paymentInformation = new PaymentInstructionInformation4();\r\n\t\tMessage.getPmtInf().add(paymentInformation);\r\n\t\tpaymentInformation.setPmtInfId(ArConfig.getDDRequestHeaderReference() + DASH_STRING + ddRequestLot.getId());\r\n\t\tpaymentInformation.setPmtMtd(PaymentMethod2Code.DD);\r\n\t\tpaymentInformation.setNbOfTxs(\"\" + ddRequestLot.getNbItemsOk());\r\n\t\tpaymentInformation.setCtrlSum(ddRequestLot.getTotalAmount().setScale(2, RoundingMode.HALF_UP));\r\n\t\tPaymentTypeInformation20 paymentTypeInformation = new PaymentTypeInformation20();\r\n\t\tpaymentInformation.setPmtTpInf(paymentTypeInformation);\r\n\t\tServiceLevel8Choice serviceLevel = new ServiceLevel8Choice();\r\n\t\tpaymentTypeInformation.setSvcLvl(serviceLevel);\r\n\t\tserviceLevel.setCd(SEPA_SERVICE_LEVEL_CD);\r\n\t\tLocalInstrument2Choice localInstrument = new LocalInstrument2Choice();\r\n\t\tpaymentTypeInformation.setLclInstrm(localInstrument);\r\n\t\tlocalInstrument.setCd(paramBean.getProperty(\"sepa.LclInstrm\", SEPA_LOCAL_INSTRUMENT_CODE));\r\n\t\tpaymentTypeInformation.setSeqTp(SequenceType1Code.RCUR);\r\n\t\t\r\n\t\t\r\n\t\tSeller seller = sellerService.findByCode(\"EKKO\");\r\n\t\tLong nbDaysSepa = (Long) seller.getCfValue(\"CF_SEL_SEPA_NB_BUSI_DAYS\");\r\n\t\tLong nbDaysPay = (Long) seller.getCfValue(\"CF_SEL_PAY_NB_BUSI_DAYS\");\r\n\t\tLong nbDaysToAdd = nbDaysPay - nbDaysSepa;\r\n\t\t\r\n\t\tDate customerRequestedDate = addBusinessDays(new Date(), nbDaysToAdd);\r\n\t\tlog.info(\"customerRequestedDate business day:\" + customerRequestedDate);\r\n\r\n\t\tlog.info(\"customerRequestedDate business day:\" + customerRequestedDate);\r\n\t\tpaymentInformation.setReqdColltnDt(DateUtils.dateToXMLGregorianCalendarFieldUndefined(customerRequestedDate));\r\n\r\n\t\tBankCoordinates bankCoordinates = getBankCoordinates(ddRequestLot, appProvider);\r\n\r\n\t\tif (bankCoordinates == null) {\r\n\t\t\tthrow new BusinessException(\"Missing bank information on provider or seller\");\r\n\t\t}\r\n\t\tPartyIdentification32 creditor = new PartyIdentification32();\r\n\t\tif (ddRequestLot.getSeller() != null) {\r\n\t\t\tcreditor.setNm(format(sellerService.refreshOrRetrieve(ddRequestLot.getSeller()).getDescription()));\r\n\t\t} else {\r\n\t\t\tcreditor.setNm(format(appProvider.getDescription()));\r\n\t\t}\r\n\r\n\t\tpaymentInformation.setCdtr(creditor);\r\n\r\n\t\tCashAccount16 creditorAccount = new CashAccount16();\r\n\t\tpaymentInformation.setCdtrAcct(creditorAccount);\r\n\t\tAccountIdentification4Choice identification = new AccountIdentification4Choice();\r\n\t\tcreditorAccount.setId(identification);\r\n\t\tidentification.setIBAN(format(bankCoordinates.getIban()));\r\n\r\n\t\tBranchAndFinancialInstitutionIdentification4 creditorAgent = new BranchAndFinancialInstitutionIdentification4();\r\n\t\tpaymentInformation.setCdtrAgt(creditorAgent);\r\n\t\tFinancialInstitutionIdentification7 financialInstitutionIdentification = new FinancialInstitutionIdentification7();\r\n\t\tcreditorAgent.setFinInstnId(financialInstitutionIdentification);\r\n\t\tfinancialInstitutionIdentification.setBIC(bankCoordinates.getBic());\r\n\t\tPartyIdentification32 creditorSchemeIdentification = new PartyIdentification32();\r\n\t\tpaymentInformation.setCdtrSchmeId(creditorSchemeIdentification);\r\n\t\tParty6Choice cdtrSchmeId = new Party6Choice();\r\n\t\tcreditorSchemeIdentification.setId(cdtrSchmeId);\r\n\t\tPersonIdentification5 privateidentifier = new PersonIdentification5();\r\n\t\tcdtrSchmeId.setPrvtId(privateidentifier);\r\n\t\tGenericPersonIdentification1 other = new GenericPersonIdentification1();\r\n\t\tprivateidentifier.getOthr().add(other);\r\n\t\tother.setId(bankCoordinates.getIcs());\r\n\t\tPersonIdentificationSchemeName1Choice schemeName = new PersonIdentificationSchemeName1Choice();\r\n\t\tother.setSchmeNm(schemeName);\r\n\t\tschemeName.setPrtry(SEPA_SERVICE_LEVEL_CD);\r\n\r\n\t\tfor (DDRequestItem ddrequestItem : ddRequestLot.getDdrequestItems()) {\r\n\t\t\tddrequestItem = ddRequestItemService.findById(ddrequestItem.getId(), Arrays.asList(\"accountOperations\"));\r\n\t\t\tif (!ddrequestItem.hasError()) {\r\n\t\t\t\taddTransaction(ddrequestItem, paymentInformation);\r\n\t\t\t\tisEmptyLot = false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn isEmptyLot;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Adds the transaction of SDD file.\r\n\t *\r\n\t * @param dDRequestItem      the dd request item\r\n\t * @param paymentInformation the payment information of SDD file\r\n\t * @throws Exception the exception\r\n\t */\r\n\tprivate void addTransaction(DDRequestItem dDRequestItem, PaymentInstructionInformation4 paymentInformation) throws Exception {\r\n\t\tCustomerAccount ca = customerAccountService.findById(dDRequestItem.getAccountOperations().get(0).getCustomerAccount().getId(), Arrays.asList(\"paymentMethods\"));\r\n\r\n\t\tPaymentMethod preferedPaymentMethod = customerAccountService.getPreferredPaymentMethod(dDRequestItem.getAccountOperations().get(0).getCustomerAccount().getId());\r\n\t\tif (preferedPaymentMethod == null || !(preferedPaymentMethod instanceof DDPaymentMethod)) {\r\n\t\t\tthrow new BusinessException(\"Payment method not valid!\");\r\n\t\t}\r\n\t\tBankCoordinates bankCoordinates = ((DDPaymentMethod) preferedPaymentMethod).getBankCoordinates();\r\n\r\n\t\tif (bankCoordinates == null) {\r\n\t\t\tthrow new BusinessException(\"Bank Coordinate is absent for Payment method \" + ((DDPaymentMethod) preferedPaymentMethod).getAlias());\r\n\t\t}\r\n\r\n\t\tDirectDebitTransactionInformation9 directDebitTransactionInformation = new DirectDebitTransactionInformation9();\r\n\t\tpaymentInformation.getDrctDbtTxInf().add(directDebitTransactionInformation);\r\n\t\tPaymentIdentification1 PaymentIdentification = new PaymentIdentification1();\r\n\t\tdirectDebitTransactionInformation.setPmtId(PaymentIdentification);\r\n\t\tPaymentIdentification.setInstrId(getCorrelationId(ca, dDRequestItem.getAccountOperations().get(0), dDRequestItem.getId()));\r\n\t\tPaymentIdentification.setEndToEndId(getCorrelationId(ca, dDRequestItem.getAccountOperations().get(0), dDRequestItem.getId()));\r\n\t\tActiveOrHistoricCurrencyAndAmount instructedAmount = new ActiveOrHistoricCurrencyAndAmount();\r\n\t\tdirectDebitTransactionInformation.setInstdAmt(instructedAmount);\r\n\t\tinstructedAmount.setValue(dDRequestItem.getAmount().setScale(2, RoundingMode.HALF_UP));\r\n\t\tinstructedAmount.setCcy(EURO_CCY);\r\n\t\tDirectDebitTransaction6 directDebitTransaction = new DirectDebitTransaction6();\r\n\t\tdirectDebitTransactionInformation.setDrctDbtTx(directDebitTransaction);\r\n\t\tMandateRelatedInformation6 mandateRelatedInformation = new MandateRelatedInformation6();\r\n\t\tdirectDebitTransaction.setMndtRltdInf(mandateRelatedInformation);\r\n\r\n\t\tmandateRelatedInformation.setMndtId(((DDPaymentMethod) preferedPaymentMethod).getMandateIdentification());\r\n\t\tmandateRelatedInformation.setDtOfSgntr(DateUtils.dateToXMLGregorianCalendarFieldUndefined(((DDPaymentMethod) preferedPaymentMethod).getMandateDate()));\r\n\t\tBranchAndFinancialInstitutionIdentification4 debtorAgent = new BranchAndFinancialInstitutionIdentification4();\r\n\t\tdirectDebitTransactionInformation.setDbtrAgt(debtorAgent);\r\n\t\tFinancialInstitutionIdentification7 financialInstitutionIdentification = new FinancialInstitutionIdentification7();\r\n\t\tGenericFinancialIdentification1 bicInfo = new GenericFinancialIdentification1();\r\n\t\tbicInfo.setId(\"NOTPROVIDED\");\r\n\t\tfinancialInstitutionIdentification.setOthr(bicInfo);\r\n\t\tdebtorAgent.setFinInstnId(financialInstitutionIdentification);\r\n\r\n\t\tPartyIdentification32 debtor = new PartyIdentification32();\r\n\t\tdirectDebitTransactionInformation.setDbtr(debtor);\r\n\t\tdebtor.setNm(format(getDebtorFullName(ca)));\r\n\r\n\t\tCashAccount16 debtorAccount = new CashAccount16();\r\n\t\tdirectDebitTransactionInformation.setDbtrAcct(debtorAccount);\r\n\t\tAccountIdentification4Choice identification = new AccountIdentification4Choice();\r\n\t\tidentification.setIBAN(bankCoordinates.getIban());\r\n\t\tdebtorAccount.setId(identification);\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the correlation id.\r\n\t *\r\n\t * @param ca               the ca\r\n\t * @param accountOperation the account operation\r\n\t * @param ddReqItemId      the dd req item id\r\n\t * @return the correlation id\r\n\t */\r\n\tprivate String getCorrelationId(CustomerAccount ca, AccountOperation accountOperation, Long ddReqItemId) {\r\n\r\n\t\treturn accountOperation.getId() + \"_\" + ca.getCode() + \"_\" + ddReqItemId;\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the debtor full name.\r\n\t *\r\n\t * @param ca the ca\r\n\t * @return the debtor full name\r\n\t */\r\n\tprivate String getDebtorFullName(CustomerAccount ca) {\r\n\t\tString fullName = \"\";\r\n\t\tName name = ca.getName();\r\n\t\tif (name != null) {\t\t\r\n\t\t\tfullName = geFullName(name);\r\n\t\t} else {\r\n\t\t\tfullName = geFullName(ca.getCustomer().getName());\r\n\t\t}\r\n\t\treturn fullName;\r\n\t}\r\n\t\r\n\tprivate String geFullName(Name name) {\r\n\t\tTitle title = titleService.refreshOrRetrieve(name.getTitle());\r\n\t\treturn   title.getCode()+\" \"+name.getFirstName()+\" \"+name.getLastName();\r\n\t\t\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the bank coordinates.\r\n\t *\r\n\t * @param ddRequestLOT the dd request LOT\r\n\t * @param appProvider  the app provider\r\n\t * @return the bank coordinates\r\n\t * @throws BusinessException the business exception\r\n\t */\r\n\tprivate BankCoordinates getBankCoordinates(DDRequestLOT ddRequestLOT, Provider appProvider) throws BusinessException {\r\n\t\tif (ddRequestLOT.getSeller() != null) {\r\n\t\t\tPaymentGatewayService paymentGatewayService = (PaymentGatewayService) getServiceInterface(\"PaymentGatewayService\");\r\n\t\t\tPaymentGateway paymentGateway = paymentGatewayService.getPaymentGateway(ddRequestLOT.getSeller(), PaymentMethodEnum.DIRECTDEBIT);\r\n\t\t\tif (paymentGateway == null) {\r\n\t\t\t\tthrow new BusinessException(\"Cant find payment gateway for seller : \" + ddRequestLOT.getSeller());\r\n\t\t\t}\r\n\t\t\treturn paymentGateway.getBankCoordinates();\r\n\t\t} else {\r\n\t\t\treturn appProvider.getBankCoordinates();\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the end to end id.\r\n\t *\r\n\t * @param accountNotification2 the account notification 2\r\n\t * @return the end to end id\r\n\t */\r\n\tprivate String getEndToEndId(AccountNotification2 accountNotification2) {\r\n\t\tString endToEndId = null;\r\n\t\ttry {\r\n\t\t\tendToEndId = accountNotification2.getNtry().get(0).getNtryDtls().get(0).getTxDtls().get(0).getRefs().getEndToEndId();\r\n\t\t\treturn endToEndId;\r\n\t\t} catch (Exception e) {\r\n\t\t\tthrow new BusinessException(\"Can't found END_TO_END \");\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the dd item id from end to end.\r\n\t *\r\n\t * @param endToEnd the end to end\r\n\t * @return the dd item id from end to end\r\n\t */\r\n\tprivate Long getDdItemIdFromEndToEnd(String endToEnd) {\r\n\t\tif (StringUtils.isBlank(endToEnd) || endToEnd.indexOf(\"_\") == -1) {\r\n\t\t\tthrow new BusinessException(\"Invalid format END_TO_END :\" + endToEnd);\r\n\t\t}\r\n\t\ttry {\r\n\r\n\t\t\treturn Long.valueOf(endToEnd.substring(endToEnd.lastIndexOf(\"_\") + 1, endToEnd.length()));\r\n\t\t} catch (Exception e) {\r\n\t\t\tthrow new BusinessException(\"Invalid type END_TO_END :\" + endToEnd);\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the a id from end to end.\r\n\t *\r\n\t * @param endToEnd the end to end\r\n\t * @return the a id from end to end\r\n\t */\r\n\tprivate Long getAIdFromEndToEnd(String endToEnd) {\r\n\t\tif (StringUtils.isBlank(endToEnd) || endToEnd.indexOf(\"_\") == -1) {\r\n\t\t\tthrow new BusinessException(\"Invalid format END_TO_END :\" + endToEnd);\r\n\t\t}\r\n\t\ttry {\r\n\r\n\t\t\treturn Long.valueOf(endToEnd.substring(0, endToEnd.indexOf(\"_\")));\r\n\t\t} catch (Exception e) {\r\n\t\t\tthrow new BusinessException(\"Invalid type END_TO_END :\" + endToEnd);\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tpublic DDRejectFileInfos processSDDRejectedFile(Map<String, Object> methodContext) throws BusinessException {\r\n\t\tFile sepaRejectedFile = (File) methodContext.get(DDRequestBuilderScript.DD_REJECT_FILE);\r\n\t\tif (sepaRejectedFile == null) {\r\n\t\t\tthrow new BusinessException(\"sepaRejectedFile is null\");\r\n\t\t}\r\n\t\tlog.info(\"processSDDRejectedFile:\" + sepaRejectedFile.getName());\r\n\t\tDDRejectFileInfos ddRejectFileInfos = new DDRejectFileInfos();\r\n\t\ttry {\r\n\t\t\tddRejectFileInfos.setFileName(sepaRejectedFile.getName());\r\n\t\t\torg.meveo.admin.sepa.jaxb.camt054.Document camt54 = (org.meveo.admin.sepa.jaxb.camt054.Document) JAXBUtils\r\n\t\t\t\t\t.unmarshaller(org.meveo.admin.sepa.jaxb.camt054.Document.class, sepaRejectedFile);\r\n\r\n\t\t\tBankToCustomerDebitCreditNotificationV02 bkToCstmrDbtCdtNtfctn = camt54.getBkToCstmrDbtCdtNtfctn();\r\n\r\n\t\t\tList<AccountNotification2> listNtfctn = bkToCstmrDbtCdtNtfctn.getNtfctn();\r\n\t\t\tfor (AccountNotification2 accountNotification2 : listNtfctn) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tString endToEnd = getEndToEndId(accountNotification2);\r\n\t\t\t\t\tString rejectReason = getRejectReason(accountNotification2);\r\n\t\t\t\t\tddRejectFileInfos.getListInvoiceRefsRejected().put(getDdItemIdFromEndToEnd(endToEnd), rejectReason);\r\n\t\t\t\t\tddRequestLOTService.rejectPayment(ddRequestItemService.findById(getDdItemIdFromEndToEnd(endToEnd)), rejectReason, sepaRejectedFile.getName());\r\n\t\t\t\t\tddRejectFileInfos.addItemOk();\r\n\r\n\t\t\t\t\tRecordedInvoice ri = recordedInvoiceService.findById(getAIdFromEndToEnd(endToEnd));\r\n\t\t\t\t\tri.setPaymentInfo6(\"NotAllowed\");\r\n\t\t\t\t\trecordedInvoiceService.updateNoCheck(ri);\r\n\r\n\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\tddRejectFileInfos.addItemKo();\r\n\t\t\t\t\tlog.error(\"Error on processSDDRejectedFile :\", e);\r\n\t\t\t\t\tddRejectFileInfos.getListErrors().add(e.getMessage());\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t} catch (Exception e) {\r\n\t\t\tthrow new BusinessException(e.getMessage());\r\n\t\t}\r\n\t\treturn ddRejectFileInfos;\r\n\t}\r\n\r\n\t/**\r\n\t * Format.\r\n\t *\r\n\t * @param valueStr the value str\r\n\t * @return the string\r\n\t */\r\n\tprivate String format(String valueStr) {\r\n\t\tif (valueStr == null) {\r\n\t\t\treturn \"\";\r\n\t\t}\r\n\t\treturn StringUtils.enleverAccent(valueStr);\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the reject reason.\r\n\t *\r\n\t * @param accountNotification2 the account notification 2\r\n\t * @return the reject reason\r\n\t */\r\n\tprivate String getRejectReason(AccountNotification2 accountNotification2) {\r\n\t\tString rejectReason = null;\r\n\t\ttry {\r\n\t\t\trejectReason = accountNotification2.getNtry().get(0).getNtryDtls().get(0).getTxDtls().get(0).getRtrInf().getRsn().getCd();\r\n\t\t\tif (\"AC01\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"IBAN incorrect ou inconnu\";\r\n\t\t\tif (\"AC04\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Le titulaire a ferm\\u00E9 son compte\";\r\n\t\t\tif (\"AC06\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Compte bloqu\\u00E9 pour pr\\u00E9l\\u00e8vement automatique\";\r\n\t\t\tif (\"AG02\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Information incorrecte\";\r\n\t\t\tif (\"AM04\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Fonds insuffisants\";\r\n\t\t\tif (\"MD01\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Mandat non valide\";\r\n\t\t\tif (\"MD06\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"R\\u00E9tro-facturation du paiement\";\r\n\t\t\tif (\"MD07\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Le client est d\\u00E9c\\u00E9d\\u00E9\";\r\n\t\t\tif (\"MS02\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Transaction refus\\u00E9e\";\r\n\t\t\tif (\"MS03\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Autre raison\";\r\n\t\t\tif (\"SL01\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Refus\\u00E9 par la banque d\\u00E9bitrice\";\r\n\t\t\treturn rejectReason;\r\n\t\t} catch (Exception e) {\r\n\t\t\tthrow new BusinessException(\"Can't found rejectReason \");\r\n\t\t}\r\n\t}\r\n\t\r\n\tprivate Date addBusinessDays(Date dateStart, Long nbDays) {\r\n\r\n\t\tint daysAdded = 0;\r\n\t\tDate endDate = dateStart;\r\n\t\twhile (daysAdded != nbDays.intValue()) {\r\n\t\t\tendDate = DateUtils.addDaysToDate(endDate, 1);\r\n\t\t\tif (calendarBankingService.isBankWorkingDate(endDate)) {\r\n\t\t\t\tdaysAdded++;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn DateUtils.setDateToEndOfDay(endDate);\r\n\t}\r\n\t\r\n\t/**\r\n     * Generate DD request lot file for SCT.\r\n     *\r\n     * @param ddRequestLot the dd request lot\r\n     * @param appProvider  the app provider\r\n     * @throws BusinessException the business exception\r\n     */\r\n    private void generateDDRequestLotFileForSCT(DDRequestLOT ddRequestLot, Provider appProvider) throws BusinessException {\r\n        ParamBean paramBean = ParamBean.getInstanceByProvider(appProvider.getCode());\r\n\r\n        org.meveo.admin.sepa.jaxb.pain001.Document document;\r\n        CustomerCreditTransferInitiationV03 message;\r\n        List<DDRequestItem> ddrequestItems = ddRequestLot.getDdrequestItems();\r\n        DDRequestItem ddrequestItem;\r\n        Long operationsByFile = ddRequestLot.getDdRequestBuilder().getNbOperationPerFile();\r\n        long ddRequestItemSize = ddrequestItems.size();\r\n        if (operationsByFile == null || operationsByFile <= 0) {\r\n            operationsByFile = ddRequestItemSize;\r\n        }\r\n        int filesToGenerate = ddrequestItems.isEmpty() ? 0 : (int) Math.ceil(ddRequestItemSize / (double) operationsByFile);\r\n        int opToGenerateByFile;\r\n        int generatedOps = 0;\r\n        int opWithErrorsByFile;\r\n        BigDecimal totalAmount;\r\n        List<String> generatedFilesNames = new ArrayList<String>();\r\n        String fileName;\r\n        for (int fileNumber = 1; fileNumber <= filesToGenerate; fileNumber++) {\r\n            try {\r\n                fileName = ddRequestLot.getFileName();//getDDFileName(ddRequestLot, appProvider);\r\n                document = new org.meveo.admin.sepa.jaxb.pain001.Document();\r\n                message = new CustomerCreditTransferInitiationV03();\r\n                document.setCstmrCdtTrfInitn(message);\r\n                addSctHeader(message, ddRequestLot, appProvider, fileNumber);\r\n                totalAmount = BigDecimal.ZERO;\r\n                opToGenerateByFile = 0;\r\n                opWithErrorsByFile = 0;\r\n                while (generatedOps < ddRequestItemSize && opToGenerateByFile < operationsByFile) {\r\n                    ddrequestItem = ddrequestItems.get(generatedOps);\r\n                    totalAmount = totalAmount.add(ddrequestItem.getAmount());\r\n                    if (!ddrequestItem.hasError()) {\r\n                        addSctPaymentInformation(message, ddrequestItem, appProvider);\r\n                    } else {\r\n                        log.error(\"ddrequestItem with id ={} has Errors :{} . The file {} will not contain all payment informations.\", ddrequestItem.getId(), ddrequestItem.getErrorMsg(), fileName);\r\n                        opWithErrorsByFile++;\r\n                    }\r\n                    opToGenerateByFile++;\r\n                    generatedOps++;\r\n                }\r\n                if (opToGenerateByFile > opWithErrorsByFile) { // The file is generated only if it contains at least one operation without\r\n                                                                // errors\r\n                    message.getGrpHdr().setCtrlSum(totalAmount.setScale(2, RoundingMode.HALF_UP));\r\n                    message.getGrpHdr().setNbOfTxs(String.valueOf(opToGenerateByFile));\r\n                    // the Pain001 jaxb classes are generated from the xsd located at:\r\n                    // https://www.iso20022.org/documents/messages/1_0_version/pain/schemas/pain.001.001.03.zip\r\n                    JAXBUtils.marshaller(document, new File(fileName),\r\n                            paramBean.getProperty(\"sepa.schemaLocation.pain001\", SCT_SCHEMA_LOCATION));\r\n                    generatedFilesNames.add(fileName);\r\n                }\r\n            } catch (Exception e) {\r\n                log.error(e.getMessage(), e);\r\n                throw new BusinessException(e.getMessage());\r\n            }\r\n\r\n        }\r\n        ddRequestLot.setFileName(String.join(COMMA_STRING, generatedFilesNames));\r\n    }\r\n    \r\n    /**\r\n     * Adds the header for SCT file.\r\n     *\r\n     * @param message      the SCT message\r\n     * @param ddRequestLot the dd request lot\r\n     * @param appProvider  the provider\r\n     * @param fileNumber   the file number: used when generatin severals files for\r\n     *                     one ddRequest lot\r\n     * @throws Exception the exception\r\n     */\r\n    private void addSctHeader(CustomerCreditTransferInitiationV03 message, DDRequestLOT ddRequestLot, Provider appProvider, int fileNumber) {\r\n        GroupHeader32 groupHeader = new GroupHeader32();\r\n        message.setGrpHdr(groupHeader);\r\n        groupHeader.setMsgId(ArConfig.getSCTRequestHeaderRefrence() + DASH_STRING + ddRequestLot.getId() + DASH_STRING + fileNumber);\r\n        try{\r\n            groupHeader.setCreDtTm(DateUtils.dateToXMLGregorianCalendar(new Date()));\r\n        }\r\n        catch(Exception e){\r\n            throw new BusinessException(e);\r\n        }\r\n        org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32 initgPty = new org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32();\r\n        initgPty.setNm(appProvider.getDescription());\r\n        groupHeader.setInitgPty(initgPty);\r\n\r\n    }\r\n    /**\r\n     * Adds the payment information for SCT file.\r\n     *\r\n     * @param message       the SCT message\r\n     * @param ddrequestItem the ddrequest item\r\n     * @param appProvider   the provider\r\n     * @throws Exception the exception\r\n     */\r\n    private void addSctPaymentInformation(CustomerCreditTransferInitiationV03 message, DDRequestItem ddrequestItem, Provider appProvider) {\r\n\r\n        log.info(\"addSctPaymentInformation dDRequestItem id={} \", ddrequestItem.getId());\r\n        ddrequestItem = ddRequestItemService.findById(ddrequestItem.getId(), Arrays.asList(\"accountOperations\"));\r\n        PaymentInstructionInformation3 paymentInformation = new PaymentInstructionInformation3();\r\n        message.getPmtInf().add(paymentInformation);\r\n        paymentInformation.setPmtInfId(ArConfig.getDDRequestHeaderReference() + DASH_STRING + ddrequestItem.getId());\r\n        paymentInformation.setPmtMtd(PaymentMethod3Code.TRF);\r\n        paymentInformation.setBtchBookg(true);\r\n        paymentInformation.setNbOfTxs(String.valueOf(ddrequestItem.getAccountOperations().size()));\r\n        paymentInformation.setCtrlSum(ddrequestItem.getAmount().setScale(2, RoundingMode.HALF_UP));\r\n        PaymentTypeInformation19 paymentTypeInformation = new PaymentTypeInformation19();\r\n        paymentInformation.setPmtTpInf(paymentTypeInformation);\r\n        org.meveo.admin.sepa.jaxb.pain001.ServiceLevel8Choice serviceLevel = new org.meveo.admin.sepa.jaxb.pain001.ServiceLevel8Choice();\r\n        paymentTypeInformation.setSvcLvl(serviceLevel);\r\n        serviceLevel.setCd(SEPA_SERVICE_LEVEL_CD);\r\n        org.meveo.admin.sepa.jaxb.pain001.CategoryPurpose1Choice ctgyPurp = new org.meveo.admin.sepa.jaxb.pain001.CategoryPurpose1Choice();\r\n        paymentTypeInformation.setCtgyPurp(ctgyPurp);\r\n        ctgyPurp.setCd(CATEGORY_PURPOSE_CODE);\r\n\r\n        try{\r\n            paymentInformation.setReqdExctnDt(DateUtils.dateToXMLGregorianCalendarFieldUndefined(calendarBankingService.getNextBankWorkingDate(new Date())));\r\n        }\r\n        catch (Exception e) {\r\n            throw new BusinessException(e);\r\n        }\r\n\r\n        org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32 dbtr = new org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32();\r\n        if (ddrequestItem.getDdRequestLOT().getSeller() != null) {\r\n            dbtr.setNm(ddrequestItem.getDdRequestLOT().getSeller().getDescription());\r\n        } else {\r\n            dbtr.setNm(appProvider.getDescription());\r\n        }\r\n\r\n        paymentInformation.setDbtr(dbtr);\r\n\r\n        org.meveo.admin.sepa.jaxb.pain001.CashAccount16 dbtrAccount = new org.meveo.admin.sepa.jaxb.pain001.CashAccount16();\r\n        paymentInformation.setDbtrAcct(dbtrAccount);\r\n        org.meveo.admin.sepa.jaxb.pain001.AccountIdentification4Choice identification = new org.meveo.admin.sepa.jaxb.pain001.AccountIdentification4Choice();\r\n        dbtrAccount.setId(identification);\r\n\r\n        BankCoordinates bankCoordinates = getBankCoordinates(ddrequestItem.getDdRequestLOT(), appProvider);\r\n\r\n        if (bankCoordinates == null) {\r\n            throw new BusinessException(\"Missing bank information on provider\");\r\n        }\r\n       \r\n        identification.setIBAN(bankCoordinates.getIban());\r\n\r\n        dbtrAccount.setCcy(EURO_CCY);\r\n        org.meveo.admin.sepa.jaxb.pain001.BranchAndFinancialInstitutionIdentification4 dbtrAgent = new org.meveo.admin.sepa.jaxb.pain001.BranchAndFinancialInstitutionIdentification4();\r\n        paymentInformation.setDbtrAgt(dbtrAgent);\r\n        org.meveo.admin.sepa.jaxb.pain001.FinancialInstitutionIdentification7 financialInstitutionIdentification = new org.meveo.admin.sepa.jaxb.pain001.FinancialInstitutionIdentification7();\r\n        dbtrAgent.setFinInstnId(financialInstitutionIdentification);\r\n        if (StringUtils.isBlank(bankCoordinates.getBic())) {\r\n            org.meveo.admin.sepa.jaxb.pain001.GenericFinancialIdentification1 othr = new org.meveo.admin.sepa.jaxb.pain001.GenericFinancialIdentification1();\r\n            othr.setId(NOTPROVIDED_BIC);\r\n            financialInstitutionIdentification.setOthr(othr);\r\n        }\r\n\r\n        financialInstitutionIdentification.setBIC(bankCoordinates.getBic());\r\n        paymentInformation.setChrgBr(org.meveo.admin.sepa.jaxb.pain001.ChargeBearerType1Code.SLEV);\r\n        addSctTransaction(ddrequestItem, paymentInformation);\r\n    }\r\n   \r\n    /**\r\n     * Adds the transaction for SCT file.\r\n     *\r\n     * @param paymentInformation the payment information of SCT file\r\n     */\r\n    private void addSctTransaction(DDRequestItem dDRequestItem, PaymentInstructionInformation3 paymentInformation) {\r\n        Object[] paymentInformations = getPreferredPaymentMethod(dDRequestItem.getId());\r\n        if (!paymentInformations[3].equals(\"DIRECTDEBIT\")) {\r\n            throw new BusinessException(\"Payment method not valid!\");\r\n        }\r\n\r\n        if (paymentInformations[4] == null && paymentInformations[5] == null) {\r\n            throw new BusinessException(\"Bank Coordinate is absent for Payment method \" + paymentInformations[6]);\r\n        }\r\n\r\n        CreditTransferTransactionInformation10 cdtTrfTxInf = new CreditTransferTransactionInformation10();\r\n        paymentInformation.getCdtTrfTxInf().add(cdtTrfTxInf);\r\n        org.meveo.admin.sepa.jaxb.pain001.PaymentIdentification1 paymentIdentification = new org.meveo.admin.sepa.jaxb.pain001.PaymentIdentification1();\r\n        cdtTrfTxInf.setPmtId(paymentIdentification);\r\n        paymentIdentification.setInstrId(String.valueOf(dDRequestItem.getDdRequestLOT().getId()));\r\n        paymentIdentification.setEndToEndId(String.valueOf(dDRequestItem.getId()));\r\n\r\n        AmountType3Choice amt = new AmountType3Choice();\r\n        cdtTrfTxInf.setAmt(amt);\r\n        org.meveo.admin.sepa.jaxb.pain001.ActiveOrHistoricCurrencyAndAmount instdAmt = new org.meveo.admin.sepa.jaxb.pain001.ActiveOrHistoricCurrencyAndAmount();\r\n\r\n        instdAmt.setValue(dDRequestItem.getAmount().setScale(2, RoundingMode.HALF_UP));\r\n        instdAmt.setCcy(EURO_CCY);\r\n        amt.setInstdAmt(instdAmt);\r\n\r\n        org.meveo.admin.sepa.jaxb.pain001.BranchAndFinancialInstitutionIdentification4 cdtrAgent = new org.meveo.admin.sepa.jaxb.pain001.BranchAndFinancialInstitutionIdentification4();\r\n        cdtTrfTxInf.setCdtrAgt(cdtrAgent);\r\n        org.meveo.admin.sepa.jaxb.pain001.FinancialInstitutionIdentification7 finInstnId = new org.meveo.admin.sepa.jaxb.pain001.FinancialInstitutionIdentification7();\r\n        finInstnId.setBIC((String) paymentInformations[4]);\r\n        cdtrAgent.setFinInstnId(finInstnId);\r\n        org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32 cdtr = new org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32();\r\n        cdtTrfTxInf.setCdtr(cdtr);\r\n        cdtr.setNm((String) paymentInformations[2]);\r\n        cdtr.setCtryOfRes(FR_COUNTRY);\r\n        org.meveo.admin.sepa.jaxb.pain001.CashAccount16 cdtrAccount = new org.meveo.admin.sepa.jaxb.pain001.CashAccount16();\r\n        cdtTrfTxInf.setCdtrAcct(cdtrAccount);\r\n        org.meveo.admin.sepa.jaxb.pain001.AccountIdentification4Choice identification = new org.meveo.admin.sepa.jaxb.pain001.AccountIdentification4Choice();\r\n        String iban = (String) paymentInformations[5];\r\n        \r\n        identification.setIBAN(iban);\r\n        cdtrAccount.setId(identification);\r\n\r\n        RemittanceInformation5 rmtInf = new RemittanceInformation5();\r\n        cdtTrfTxInf.setRmtInf(rmtInf);\r\n        rmtInf.getUstrd().add(\"Remboursement \" + getReference(dDRequestItem));\r\n    }\r\n    private Object[] getPreferredPaymentMethod(Long ddRequestItemID) {\r\n        return (Object[]) paymentMethodService.getEntityManager()\r\n                .createNamedQuery(\"PaymentMethod.getPreferredPaymentMethodForDDRequestItem\")\r\n                .setParameter(\"id\", ddRequestItemID)\r\n                .setMaxResults(1)\r\n                .getSingleResult();\r\n    }\r\n    \r\n    private String getReference(DDRequestItem dDRequestItem) {\r\n        String references = \"\";\r\n       List<AccountOperation> aos =  dDRequestItem.getAccountOperations();\r\n        if(aos != null && !aos.isEmpty()) {\r\n            for(AccountOperation ao : aos) {\r\n                if(!ao.getReference().startsWith(\"ddItem\")) {\r\n                    references += \" \"+ao.getReference(); \r\n                }\r\n            }\r\n        }\r\n        return references;\r\n    }\r\n}\r\n\r\n\r\n ]]>\r\n            </script>\r\n</ScriptInstance>"
						},
						"url": {
							"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"scriptInstance",
								"createOrUpdate"
							]
						},
						"description": "A Custom script to compute CUrrent Month Date range."
					},
					"response": []
				},
				{
					"name": "Create Sepa DDRequestBuilder",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"code\": \"EKKO_Sepa_Pain08_Camt54\",\r\n    \"description\": \"Ekko Format sepa Pain08 ,Pain01 and Camt54\",\r\n    \"type\" : \"CUSTOM\" , \r\n    \"scriptInstanceCode\" : \"com.opencellsoft.service.ekko.payment.SepaDDRequestBuilderScript\", \r\n    \"paymentLevel\" : \"CA\"\r\n    \r\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/payment/ddRequestBuilder/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"payment",
								"ddRequestBuilder",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "Create DDRequestLotOp",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{   \r\n\t\"paymentOrRefundEnum\":\"REFUND\",\r\n    \"recurrent\": true,\r\n    \"fromDueDate\" : \"2000-01-01\",\r\n    \"toDueDate\" : \"2999-01-01\",\r\n    \"ddRequestBuilderCode\" : \"EKKO_Sepa_Pain08_Camt54\"\r\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/payment/ddrequestLotOp",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"payment",
								"ddrequestLotOp"
							]
						}
					},
					"response": []
				},
				{
					"name": "Create SEPA_PAIN01_JOB",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"code\": \"Remboursement\",\r\n    \"description\": \"Lancement du PAIN001 + AO type ARF\",\r\n    \"jobCategory\": \"PAYMENT\",\r\n    \"jobTemplate\": \"SepaDirectDebitJob\" , \r\n    \"customFields\" : {\r\n    \t\"customField\": [ \r\n    \t\t{ \"code\":\"SepaJob_ddRequestBuilder\", \r\n    \t\t   \"entityReferenceValue\" : {\r\n    \t\t        \"classname\" : \"org.meveo.model.payments.DDRequestBuilder\" ,\r\n    \t\t        \"code\" : \"EKKO_Sepa_Pain08_Camt54\"\r\n    \t\t   }\r\n    \t\t},\r\n    \t\t{\r\n    \t\t\t\"code\":\"SepaJob_paymentOrRefund\",\r\n    \t\t\t\"stringValue\":\"REFUND\"\r\n    \t\t}\r\n    \t] \r\n    }\r\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "Update following SEPA_CAMT54_JOB",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"code\": \"EKKO_Reject_SDD_JOB\",\r\n    \"description\": \"EKKO Camt054 Reject Sepa DD Job\",\r\n    \"jobCategory\": \"PAYMENT\",\r\n    \"jobTemplate\": \"SepaRejectedTransactionsJob\" , \r\n    \"followingJob\":\"Remboursement\"\r\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "setProperty sdd prefix",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"property\": \"bayad.ddrequest.fileName.prefix\",\r\n    \"value\": \"SDD.PRL.MPE.\"\r\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/configurations",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"configurations"
							]
						}
					},
					"response": []
				},
				{
					"name": "setProperty sdd extension",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"property\": \"bayad.ddrequest.fileName.extension\",\r\n    \"value\": \"xml\"\r\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/configurations",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"configurations"
							]
						}
					},
					"response": []
				},
				{
					"name": "setProperty sdd output",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"property\": \"bayad.ddrequest.outputDir\",\r\n    \"value\": \"tmp\"\r\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/configurations",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"configurations"
							]
						}
					},
					"response": []
				},
				{
					"name": "setProperty sct prefix",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"property\": \"bayad.sctrequest.fileName.prefix\",\r\n    \"value\": \"SCT.VIR.MPE.\"\r\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/configurations",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"configurations"
							]
						}
					},
					"response": []
				},
				{
					"name": "setProperty sct extension",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"property\": \"bayad.sctrequest.fileName.extension\",\r\n    \"value\": \"xml\"\r\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/configurations",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"configurations"
							]
						}
					},
					"response": []
				},
				{
					"name": "setProperty sct output",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"property\": \"bayad.sctrequest.outputDir\",\r\n    \"value\": \"SCT\"\r\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/configurations",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"configurations"
							]
						}
					},
					"response": []
				}
			]
		},
		{
			"name": "jobs flow",
			"item": [
				{
					"name": "Timer Daily-2H",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n    \"code\": \"Daily-2H\",\n    \"hour\": \"2\",\n    \"minute\": \"0\",\n    \"second\": \"0\"\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/timerEntity/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"timerEntity",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "eachMinute",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n    \"code\": \"eachMinute\",\n    \"minute\": \"*\",\n    \"second\": \"30\"\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/timerEntity/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"timerEntity",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "RecurringRatingJob",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n\t\"code\": \"RR_Job\",\n\t\"jobTemplate\": \"RecurringRatingJob\",\t\n\t\"timerCode\": \"Daily-2H\"\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "REC_RatedTransactionsJob",
					"event": [
						{
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							},
							"listen": "test"
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n\t\"code\": \"REC_RT_Job\",\n    \"description\": \"Ekko Recurring RT JOB\",\n    \"jobCategory\": \"INVOICING\",\n\t\"jobTemplate\": \"EkkoRatedTransactionsJob\",\n\t\"followingJob\": \"RT_JOB\"\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "RatedTransactionsJob",
					"event": [
						{
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							},
							"listen": "test"
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n\t\"code\": \"RT_Job\",\n\t\"jobTemplate\": \"RatedTransactionsJob\",\n\t\"followingJob\": \"BillingRunJob\"\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "BillingRunJob",
					"event": [
						{
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							},
							"listen": "test"
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n\t\"code\": \"BillingRunJob\",\n\t\"jobTemplate\": \"BillingRunJob\",\n\t\"followingJob\": \"Inv_Job\",\n\t\"customFields\": {\n\t\t\"customField\": [\n\t\t\t{\n\t\t\t\t\"code\": \"BillingRunJob_billingRun_Process\",\n\t\t\t\t\"stringValue\": \"3\"\n\t\t\t},\n\t\t\t{\n\t\t\t\t\"code\": \"BillingRunJob_billingCycle\",\n\t\t\t\t\"fieldType\": \"ENTITY\",\n\t\t\t\t\"value\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"value\": {\n\t\t\t\t\t\t\t\"entityReferenceValue\": {\n\t\t\t\t\t\t\t\t\"classname\": \"org.meveo.model.billing.BillingCycle\",\n\t\t\t\t\t\t\t\t\"code\": \"MENSUEL\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t]\n\t}\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "InvoicingJob",
					"event": [
						{
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							},
							"listen": "test"
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n\t\"code\": \"Inv_Job\",\n\t\"jobTemplate\": \"InvoicingJob\",\n\t\"followingJob\": \"XML_Job\"\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "PDFInvoiceGenerationJob",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n\t\"code\": \"PDF_Job\",\n\t\"jobTemplate\": \"PDFInvoiceGenerationJob\",\n    \"followingJob\": \"AO_Job\"\n\n\t\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "PDF_WRJob",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n\t\"code\": \"PDF_WRJob\",\n\t\"jobTemplate\": \"PDFInvoiceGenerationJob\"\n\t\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "XMLInvoiceGenerationJob",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n\t\"code\": \"XML_Job\",\n\t\"jobTemplate\": \"XMLInvoiceGenerationJob\",\n\t\"followingJob\": \"PDF_Job\"\n    \n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "XML_WRJob",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n\t\"code\": \"XML_WRJob\",\n\t\"jobTemplate\": \"XMLInvoiceGenerationJob\",\n\t\"followingJob\": \"PDF_WRJob\",\n    \"timerCode\": \"eachMinute\"\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "enable XMLInvoiceGenerationJob",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": ""
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/XML_WRJob/enable",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"XML_WRJob",
								"enable"
							]
						}
					},
					"response": []
				},
				{
					"name": "AccountOperationsGenerationJob",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n\t\"code\": \"AO_Job\",\n\t\"jobTemplate\": \"AccountOperationsGenerationJob\",\n\t\"followingJob\": \"EKKO_SDD_JOB\"\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "Export Rapsodie",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n    \"code\": \"EkkoExportRapsodieJob\",\n    \"description\": \"Ekko export Rapsodie Job\",\n    \"jobCategory\": \"MEDIATION\",\n    \"jobTemplate\": \"ScriptingJob\",\n    \"customFields\": {\n        \"customField\": [\n            {\n                \"code\": \"ScriptingJob_script\",\n                \"entityReferenceValue\": {\n                    \"classname\": \"org.meveo.model.scripts.ScriptInstance\",\n                    \"code\": \"com.opencellsoft.service.ekko.compta.ExportRapsodieScript\"\n                }\n            },\n            {\n                \"code\": \"ScriptingJob_variables\",\n                \"mapValue\": {\n                    \"outputDir\": {\n                        \"value\": \"/ekko/octopus/rapsodie/out\"\n                    },\n                    \"archivedDir\": {\n                        \"value\": \"/ekko/octopus/rapsodie/archived\"\n                    }\n                }\n            }\n        ]\n    }\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "MercanetPaymentJob",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n    \"code\": \"EkkoMercanetPaymentJob\",\n    \"description\": \"Ekko MercanetPaymentJob\",\n    \"jobCategory\": \"MEDIATION\",\n    \"jobTemplate\": \"ScriptingJob\",\n    \"customFields\": {\n        \"customField\": [\n            {\n                \"code\": \"ScriptingJob_script\",\n                \"entityReferenceValue\": {\n                    \"classname\": \"org.meveo.model.scripts.ScriptInstance\",\n                    \"code\": \"com.opencellsoft.service.ekko.payment.MercanetIntegrationScript\"\n                }\n            },\n            {\n                \"code\": \"ScriptingJob_variables\",\n                \"mapValue\": {\n                    \"MERCANET_INPUT_DIR\": {\n                        \"value\": \"/ekko/octopus/cb/in\"\n                    },\n                    \"MERCANET_ARCH_DIR\": {\n                        \"value\": \"/ekko/octopus/cb/archived\"\n                    },\n                    \"MERCANET_ERR_DIR\": {\n                        \"value\": \"/ekko/octopus/cb/errord\"\n                    },\n                    \"MERCANET_WARN_DIR\": {\n                        \"value\": \"/ekko/octopus/cb/warn\"\n                    },\n                    \"MERCANET_REPORT_DIR\": {\n                        \"value\": \"/ekko/octopus/cb/report\"\n                    },\n                    \"MERCANET_FILE_EXT\": {\n                        \"value\": \"txt\"\n                    },\n                    \"MERCANET_DELIMITER\": {\n                        \"value\": \"\\t\"\n                    }\n                }\n            }\n        ]\n    }\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "PatchJOB",
					"event": [
						{
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							},
							"listen": "test"
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n\t\"code\": \"PatchJOB\",\n    \"description\": \"PatchJOB\",\n    \"jobCategory\": \"MEDIATION\",\n\t\"jobTemplate\": \"ScriptingJob\",\n     \"customFields\": {\n                    \"customField\": [\n                       \n                       \n                        {\n                            \"code\": \"ScriptingJob_script\",\n                            \"entityReferenceValue\": {\n                                \"classname\": \"org.meveo.model.scripts.ScriptInstance\",\n                                \"code\": \"com.opencellsoft.service.ekko.SetPatchInfoScript\"\n                            }\n                        }\n                    ]\n                }\n\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "RecurringRatingJob",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n\t\"code\": \"RR_Job\",\n\t\"jobTemplate\": \"RecurringRatingJob\",\n\t\"followingJob\": \"REC_RT_Job\",    \n\t\"timerCode\": \"Daily-2H\"\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "REC_RatedTransactionsJob",
					"event": [
						{
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							},
							"listen": "test"
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n\t\"code\": \"REC_RT_Job\",\n    \"description\": \"Ekko Recurring RT JOB\",\n    \"jobCategory\": \"INVOICING\",\n\t\"jobTemplate\": \"EkkoRatedTransactionsJob\",\n\t\"followingJob\": \"RT_JOB\"\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "Anonymize_JOB",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"var data = JSON.parse(responseBody);",
									"tests[\"is.success\"] = data.status === \"SUCCESS\";"
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Authorization",
								"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n    \"code\": \"Anonymize_JOB\",\n    \"jobCategory\": \"MEDIATION\",\n    \"jobTemplate\": \"ScriptingJob\",\n    \"customFields\": {\n        \"customField\": [\n            {\n                \"code\": \"ScriptingJob_script\",\n                \"entityReferenceValue\": {\n                    \"classname\": \"org.meveo.model.scripts.ScriptInstance\",\n                    \"code\": \"com.opencellsoft.service.ekko.util.AnonymizeScript\"\n                }\n            },\n            {\n                \"code\": \"ScriptingJob_TransactionType\",\n                \"stringValue\": \"REQUIRES_NEW\"\n            },\n            {\n                \"code\": \"ScriptingJob_variables\",\n                \"mapValue\": {\n                    \"eventId\": {\n                        \"value\": \"\"\n                    },\n                    \"countryCode\": {\n                        \"value\": \"\"\n                    }\n                }\n            }\n        ]\n    },\n    \"limitToSingleNode\": true\n}",
							"options": {
								"raw": {
									"language": "json"
								}
							}
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "Remboursement",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"code\": \"Remboursement\",\r\n    \"description\": \"Lancement du PAIN001 + AO type ARF\",\r\n    \"jobCategory\": \"PAYMENT\",\r\n    \"jobTemplate\": \"SepaDirectDebitJob\" , \r\n    \"customFields\" : {\r\n    \t\"customField\": [ \r\n    \t\t{ \"code\":\"SepaJob_ddRequestBuilder\", \r\n    \t\t   \"entityReferenceValue\" : {\r\n    \t\t        \"classname\" : \"org.meveo.model.payments.DDRequestBuilder\" ,\r\n    \t\t        \"code\" : \"EKKO_Sepa_Pain08_Camt54\"\r\n    \t\t   }\r\n    \t\t},\r\n            { \"code\":\"SepaJob_aoFilterScript\", \r\n    \t\t   \"entityReferenceValue\" : {\r\n    \t\t        \"classname\" : \"org.meveo.model.scripts.ScriptInstance\" ,\r\n    \t\t        \"code\" : \"com.opencellsoft.service.ekko.payment.AOFilterScript\"\r\n    \t\t   }\r\n    \t\t},\r\n            { \"code\":\"SepaJob_paymentOrRefund\", \r\n    \t\t   \"stringValue\" : \"REFUND\"\r\n    \t\t}\r\n    \t] \r\n    }\r\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "FixInvoicesAmountsScript_JOB",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"var data = JSON.parse(responseBody);",
									"tests[\"is.success\"] = data.status === \"SUCCESS\";"
								],
								"type": "text/javascript",
								"packages": {}
							}
						}
					],
					"request": {
						"auth": {
							"type": "basic",
							"basic": [
								{
									"key": "username",
									"value": "{{opencell.username}}",
									"type": "string"
								},
								{
									"key": "password",
									"value": "{{opencell.password}}",
									"type": "string"
								},
								{
									"key": "saveHelperData",
									"value": true,
									"type": "boolean"
								},
								{
									"key": "showPassword",
									"value": false,
									"type": "boolean"
								}
							]
						},
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Authorization",
								"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n    \"code\": \"FixInvoicesAmountsScript_JOB\",\n    \"jobCategory\": \"MEDIATION\",\n    \"jobTemplate\": \"ScriptingJob\",\n    \"customFields\": {\n        \"customField\": [\n            {\n                \"code\": \"ScriptingJob_script\",\n                \"entityReferenceValue\": {\n                    \"classname\": \"org.meveo.model.scripts.ScriptInstance\",\n                    \"code\": \"com.opencellsoft.service.ekko.compta.FixInvoicesAmountsScript\"\n                }\n            },\n            {\n                \"code\": \"ScriptingJob_TransactionType\",\n                \"stringValue\": \"REQUIRES_NEW\"\n            },\n            {\n                \"code\": \"ScriptingJob_variables\",\n                \"mapValue\": {\n                    \"eventId\": {\n                        \"value\": \"\"\n                    },\n                    \"countryCode\": {\n                        \"value\": \"\"\n                    }\n                }\n            }\n        ]\n    },\n    \"limitToSingleNode\": true\n}",
							"options": {
								"raw": {
									"language": "json"
								}
							}
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "Subscription status job timer",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"var data = JSON.parse(responseBody);",
									"tests[\"status test\"] = data.status === \"SUCCESS\";",
									"tests[\"message test\"] = data.message === \"\";"
								],
								"type": "text/javascript",
								"packages": {}
							}
						}
					],
					"request": {
						"auth": {
							"type": "basic",
							"basic": [
								{
									"key": "password",
									"value": "opencell.admin",
									"type": "string"
								},
								{
									"key": "username",
									"value": "opencell.admin",
									"type": "string"
								}
							]
						},
						"method": "PUT",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Authorization",
								"value": "{{opencell.token}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n  \"code\": \"Sub_Status_Job\",\r\n  \"timerCode\": \"Daily-midnight\",\r\n  \"jobTemplate\": \"SubscriptionStatusJob\"\r\n\r\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/jobInstance",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"jobInstance"
							]
						}
					},
					"response": []
				}
			]
		},
		{
			"name": "SFDC Connector",
			"item": [
				{
					"name": "Modules",
					"item": [
						{
							"name": "clean up",
							"item": [
								{
									"name": "Client",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											}
										},
										{
											"listen": "prerequest",
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "DELETE",
										"header": [],
										"body": {
											"mode": "raw",
											"raw": ""
										},
										"url": {
											"raw": "{{opencell.url}}/account/businessAccountModel/{{request.label}}",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"account",
												"businessAccountModel",
												"{{request.label}}"
											]
										}
									},
									"response": []
								},
								{
									"name": "SalesforceConnectorModule",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											}
										},
										{
											"listen": "prerequest",
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "DELETE",
										"header": [],
										"body": {
											"mode": "raw",
											"raw": ""
										},
										"url": {
											"raw": "{{opencell.url}}/module/{{request.label}}",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"module",
												"{{request.label}}"
											]
										}
									},
									"response": []
								},
								{
									"name": "BusinessAccountModelModule",
									"event": [
										{
											"listen": "test",
											"script": {
												"exec": [
													""
												],
												"type": "text/javascript"
											}
										}
									],
									"request": {
										"method": "DELETE",
										"header": [],
										"body": {
											"mode": "raw",
											"raw": ""
										},
										"url": {
											"raw": "{{opencell.url}}/module/{{request.label}}",
											"host": [
												"{{opencell.url}}"
											],
											"path": [
												"module",
												"{{request.label}}"
											]
										}
									},
									"response": []
								}
							],
							"event": [
								{
									"listen": "prerequest",
									"script": {
										"type": "text/javascript",
										"exec": [
											"pm.collectionVariables.set('skipTest', true);"
										]
									}
								},
								{
									"listen": "test",
									"script": {
										"type": "text/javascript",
										"exec": [
											""
										]
									}
								}
							]
						},
						{
							"name": "Client",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											""
										],
										"type": "text/javascript"
									}
								},
								{
									"listen": "prerequest",
									"script": {
										"exec": [
											"pm.collectionVariables.unset('skipTest');"
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\r\n    \"code\": \"{{request.label}}\",\r\n    \"license\": \"COM\",\r\n    \"description\": \"SFDC customer\",\r\n\t\"hierarchyType\": \"C_UA\",\r\n\t \"moduleItems\": []\r\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/account/businessAccountModel",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"account",
										"businessAccountModel"
									]
								}
							},
							"response": []
						},
						{
							"name": "SalesforceConnectorModule",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											""
										],
										"type": "text/javascript",
										"packages": {}
									}
								}
							],
							"request": {
								"method": "PUT",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\r\n    \"code\": \"{{request.label}}\",\r\n    \"description\": \"Salesforce Object Syncing\",\r\n    \"license\": \"COM\",\r\n    \"moduleItems\": [\r\n    \t{\r\n    \t\t\"script\": {\r\n                \"description\": \"Salesforce object syncing script\",\r\n                \"script\": \"package org.opencell.eeko.service.script.syncing;\\n\\nimport java.text.MessageFormat;\\nimport java.util.ArrayList;\\nimport java.util.Date;\\nimport java.util.HashMap;\\nimport java.util.List;\\nimport java.util.Map;\\nimport java.util.Base64;\\nimport javax.persistence.Query;\\nimport javax.persistence.EntityManager;\\nimport javax.ws.rs.HttpMethod;\\nimport javax.ws.rs.ProcessingException;\\nimport javax.ws.rs.client.Entity;\\nimport javax.ws.rs.client.Invocation;\\nimport javax.ws.rs.core.Form;\\nimport javax.ws.rs.core.HttpHeaders;\\nimport javax.ws.rs.core.MultivaluedMap;\\nimport javax.ws.rs.core.Response;\\n\\nimport org.apache.commons.lang3.builder.ToStringBuilder;\\nimport org.apache.commons.lang3.builder.ToStringStyle;\\nimport org.hibernate.proxy.HibernateProxy;\\nimport org.jboss.resteasy.client.jaxrs.ResteasyClient;\\nimport org.meveo.commons.utils.ResteasyClientProxyBuilder;\\nimport org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;\\nimport org.json.simple.JSONArray;\\nimport org.meveo.admin.exception.BusinessException;\\nimport org.meveo.api.exception.MeveoApiException;\\nimport org.meveo.commons.utils.JsonUtils;\\nimport org.meveo.commons.utils.ParamBean;\\nimport org.meveo.commons.utils.ParamBeanFactory;\\nimport org.meveo.commons.utils.ReflectionUtils;\\nimport org.meveo.commons.utils.StringUtils;\\nimport org.meveo.model.BaseEntity;\\nimport org.meveo.model.BusinessEntity;\\nimport org.meveo.model.ICustomFieldEntity;\\nimport org.meveo.model.IEntity;\\nimport org.meveo.model.billing.Invoice;\\nimport org.meveo.model.billing.Subscription;\\nimport org.meveo.model.payments.AccountOperation;\\nimport org.meveo.model.payments.MatchingAmount;\\nimport org.meveo.model.payments.MatchingCode;\\nimport org.meveo.model.payments.OtherCreditAndCharge;\\nimport org.meveo.model.payments.Payment;\\nimport org.meveo.model.payments.RecordedInvoice;\\nimport org.meveo.model.payments.RejectedPayment;\\nimport org.meveo.model.shared.DateUtils;\\nimport org.meveo.service.base.BaseEntityService;\\nimport org.meveo.service.billing.impl.InvoiceService;\\nimport org.meveo.service.billing.impl.SubscriptionService;\\nimport org.meveo.service.script.Script;\\nimport org.slf4j.Logger;\\nimport org.slf4j.LoggerFactory;\\n\\nimport com.google.gson.JsonObject;\\nimport com.google.gson.annotations.SerializedName;\\n\\n/**\\n * \\n * This script allows to send the object available in the context param to its equivalent on the SFDC side The process is using the oauth2 with refresh based on the global system\\n * properties provided by the SFDC env\\n * \\n * @author Youssef IZEM\\n * @lastModifiedVersion 1.0\\n */\\npublic class SObjectSyncingScript extends Script {\\n\\n\\tprivate static final long serialVersionUID = 1L;\\n\\n\\t/**\\n\\t * Salesforce resources path\\n\\t */\\n\\tprivate static final String END_POINT_API_VERSION = \\\"v50.0\\\";\\n\\tprivate static final String END_POINT_TOKEN_REQUEST = \\\"/services/oauth2/token\\\";\\n\\tprivate static final String END_POINT_SOBJECT_INVOICE = \\\"/services/data/{{version}}/sobjects/opencell__invoice__c\\\";\\n\\tprivate static final String END_POINT_SOBJECT_ATTACHMENT = \\\"/services/data/{{version}}/sobjects/Attachment\\\";\\n\\tprivate static final String END_POINT_RESOURCE_COMPOSITE = \\\"/services/data/{{version}}/composite/\\\";\\n\\tprivate static final String END_POINT_SOBJECT_SUBSCRIPTION = \\\"/services/data/{{version}}/sobjects/opencell__Subscription__c\\\";\\n\\tprivate static final String END_POINT_SOBJECT_ACCOUNT_OPERATION = \\\"/services/data/{{version}}/sobjects/opencell__AccountOperation__c\\\";\\n\\n\\t/**\\n\\t * Global properties credentials for Salesforce authent\\n\\t */\\n\\tprivate static final String PROPERTY_KEY_SALESFORCE_URL = \\\"salesforce.url\\\";\\n\\tprivate static final String PROPERTY_KEY_SALESFORCE_USERNAME = \\\"salesforce.username\\\";\\n\\tprivate static final String PROPERTY_KEY_SALESFORCE_PASSWORD = \\\"salesforce.password\\\";\\n\\tprivate static final String PROPERTY_KEY_SALESFORCE_CLIENT_ID = \\\"salesforce.clientId\\\";\\n\\tprivate static final String PROPERTY_KEY_SALESFORCE_CLIENT_SECRET = \\\"salesforce.clientSecret\\\";\\n\\n\\t/**\\n\\t * Salesforce oAuth2 request params\\n\\t */\\n\\tprivate static final String TOKEN_REQUEST_PARAM_USERNAME = \\\"username\\\";\\n\\tprivate static final String TOKEN_REQUEST_PARAM_PASSWORD = \\\"password\\\";\\n\\tprivate static final String TOKEN_REQUEST_PARAM_CLIENT_ID = \\\"client_id\\\";\\n\\tprivate static final String TOKEN_REQUEST_PARAM_GRANT_TYPE = \\\"grant_type\\\";\\n\\tprivate static final String TOKEN_REQUEST_PARAM_CLIENT_SECRET = \\\"client_secret\\\";\\n\\tprivate static final String TOKEN_REQUEST_PARAM_REFRESH_TOKEN = \\\"refresh_token\\\";\\n\\tprivate static final String TOKEN_REQUEST_PARAM_GRANT_TYPE_REFRESH = \\\"refresh_token\\\";\\n\\tprivate static final String TOKEN_REQUEST_PARAM_GRANT_TYPE_PASSWORD = \\\"password\\\";\\n\\n\\t/**\\n\\t * Salesforce oAuth2 timeout\\n\\t */\\n\\tpublic static final Integer OAUTH_TOKEN_RETRY_TIMES = 3;\\n\\tpublic static final Integer OAUTH_TOKEN_REFRESH_IN_MINUTES = 15;\\n\\tpublic static final Integer OAUTH_READ_TIMEOUT_IN_SECONDS = 10;\\n\\tpublic static final Integer OAUTH_SOCKET_TIMEOUT_IN_SECONDS = 5;\\n\\tpublic static final Integer OAUTH_CONNECT_TIMEOUT_IN_SECONDS = 5;\\n\\n\\t/**\\n\\t * Constants\\n\\t */\\n\\tprivate static final String SFDC_REFERENCE_ID = \\\"referenceId\\\";\\n\\tprivate static final String CF_IS_SYNCED_NAME = \\\"CF_ENTITY_IS_SYNCED\\\";\\n\\tprivate static final String CF_SFDC_INVOICE_ID = \\\"CF_SFDC_INVOICE_ID\\\";\\n\\tprivate static final String CF_SFDC_ATTACHMENT_ID = \\\"CF_SFDC_ATTACHMENT_ID\\\";\\n\\n\\t/**\\n\\t * Syncing erros custom table SQL requests\\n\\t */\\n\\tprivate static final String DELETE_ERRORS_QUERY = \\\"DELETE FROM SYNCING_ERRORS WHERE entity_type='%s' AND entity_id = '%s'\\\";\\n\\tprivate static final String INSERT_ERRORS_QUERY = \\\"INSERT INTO SYNCING_ERRORS (entity_id, entity_code, entity_type, syncing_date, request_path_info, request_body, response_status, response_message, response_body) \\\"\\n\\t\\t\\t+ \\\"VALUES ('%s','%s', '%s', '%s','%s', '%s','%s','%s', '%s');\\\";\\n\\n\\t/**\\n\\t * Salesforce oAuth2 token\\n\\t */\\n\\tprivate static Token token;\\n\\n\\t/**\\n\\t * All core services used in the syncing process\\n\\t */\\n\\tprivate transient ParamBean paramBean = ((ParamBeanFactory) getServiceInterface(\\\"ParamBeanFactory\\\")).getInstance();\\n\\tprivate transient InvoiceService invoiceService = (InvoiceService) getServiceInterface(\\\"InvoiceService\\\");\\n\\tprivate transient SubscriptionService subscriptionService = (SubscriptionService) getServiceInterface(\\\"SubscriptionService\\\");\\n\\tprivate transient BaseEntityService baseEntityService = (BaseEntityService) getServiceInterface(\\\"BaseEntityService\\\");\\n\\tprivate transient EntityManager em = invoiceService.getEntityManager();\\n\\tprivate static final ResteasyClient client = new ResteasyClientProxyBuilder().build();\\n\\n\\t/**\\n\\t * The main method called by the object updating/creating notifications\\n\\t */\\n\\t@Override\\n\\tpublic void execute(Map<String, Object> context) {\\n\\t\\tObject object = context.get(Script.CONTEXT_ENTITY);\\n\\t\\tif (!(object instanceof IEntity)) {\\n\\t\\t\\tlog.warn(\\\"<======== This object isn't configured to be synced : {}\\\", object);\\n\\t\\t\\treturn;\\n\\t\\t}\\n\\t\\tIEntity entity = (IEntity) object;\\n\\t\\tClass clazz = ReflectionUtils.getClassBySimpleNameAndParentClass(entity.getClass().getSimpleName(), BaseEntity.class);\\n\\t\\tbaseEntityService.setEntityClass(clazz);\\n\\t\\t\\n\\t\\tentity = baseEntityService.retrieveIfNotManaged(entity);\\n\\t\\tlog.info(\\\"========> Start syncing the entity : {}[id={}]  ...............\\\", entity.getClass().getSimpleName(), ((IEntity) entity).getId());\\n\\n\\t\\ttry {\\n\\t\\t\\tif (entity instanceof Invoice) {\\n\\t\\t\\t\\tsendInvoice((Invoice) entity);\\n\\t\\t\\t\\tsendPDF((Invoice) entity);\\n\\t\\t\\t} else if (entity instanceof Subscription) {\\n\\t\\t\\t\\tsendSubscription((Subscription) entity);\\n\\t\\t\\t} else if (entity instanceof MatchingCode) {\\n\\t\\t\\t\\tsendMatchingCode((MatchingCode) entity);\\n\\t\\t\\t} else if (entity instanceof AccountOperation) {\\n\\t\\t\\t\\tsendAccountOperation((AccountOperation) entity);\\n\\t\\t\\t} else {\\n\\t\\t\\t\\tlog.warn(\\\"<======== This entity isn't configured to be synced : {}\\\", entity);\\n\\t\\t\\t\\treturn;\\n\\t\\t\\t}\\n\\t\\t\\tlog.info(\\\"<======== This entity has successfully been synced : {}\\\", entity);\\n\\n\\t\\t} catch (SObjectSyncingException ex) {\\n\\t\\t\\tlog.error(\\\"<======== \\\" + ex.getMessage());\\n\\t\\t} catch (Exception ex) {\\n\\t\\t\\tregisterResult(entity, null, null, null, ex.getMessage(), false);\\n\\t\\t\\tlog.error(\\\"<======== Generic error thrown during entity sending : {} => {} \\\", entity, ex.getMessage());\\n\\t\\t} finally {\\n\\t\\t\\tentity = this.baseEntityService.updateNoCheck(entity);\\n\\t\\t}\\n\\n\\t}\\n\\n\\t/**\\n\\t * Sends Subscription object to SFDC\\n\\t * \\n\\t * @param subscription\\n\\t */\\n\\tprivate void sendSubscription(Subscription subscription) {\\n\\n\\t\\tCompositeSubRequestDto subscriptionReq = new CompositeSubRequestDto();\\n\\t\\tsubscriptionReq.setMethod(HttpMethod.PATCH);\\n\\t\\tsubscriptionReq.setReferenceId(SFDC_REFERENCE_ID);\\n\\t\\tsubscriptionReq.setBody(toSubscriptionJson(subscription));\\n\\t\\tsubscriptionReq.setUrl(getEndPoint(END_POINT_SOBJECT_SUBSCRIPTION, \\\"OCCode\\\", subscription.getCode()));\\n\\n\\t\\tCompositeRequestDto request = new CompositeRequestDto();\\n\\t\\trequest.setAllOrNone(true);\\n\\t\\trequest.addSubRequest(subscriptionReq);\\n\\t\\trequest.setCollateSubrequests(true);\\n\\n\\t\\tsendRequest(request, subscription, null);\\n\\t}\\n\\n\\t/**\\n\\t * Sends invoice object to SFDC\\n\\t * \\n\\t * @param invoice\\n\\t */\\n\\tprivate void sendInvoice(Invoice invoice) {\\n\\n\\t\\tCompositeSubRequestDto invoiceReq = new CompositeSubRequestDto();\\n\\t\\tinvoiceReq.setMethod(HttpMethod.PATCH);\\n\\t\\tinvoiceReq.setReferenceId(SFDC_REFERENCE_ID);\\n\\t\\tinvoiceReq.setBody(toInvoiceJson(invoice));\\n\\t\\tinvoiceReq.setUrl(getEndPoint(END_POINT_SOBJECT_INVOICE, \\\"Id\\\", invoice.getId()));\\n\\n\\t\\tCompositeRequestDto request = new CompositeRequestDto();\\n\\t\\trequest.setAllOrNone(true);\\n\\t\\trequest.addSubRequest(invoiceReq);\\n\\t\\trequest.setCollateSubrequests(false);\\n\\n\\t\\tsendRequest(request, invoice, CF_SFDC_INVOICE_ID);\\n\\t}\\n\\n\\t/**\\n\\t * Sends invoice pdf to SFDC, we start by deleting old pdf because the patch based on the external id is not working with the attachment object\\n\\t * \\n\\t * @param invoice\\n\\t */\\n\\tprivate void sendPDF(Invoice invoice) {\\n\\n\\t\\tif (invoiceService.isInvoicePdfExist(invoice)) {\\n\\t\\t\\tCompositeRequestDto request = new CompositeRequestDto();\\n\\t\\t\\tObject invoiceId = invoice.getCfValue(CF_SFDC_INVOICE_ID);\\n\\t\\t\\tif (invoiceId instanceof String) {\\n\\t\\t\\t\\tObject attachmentId = invoice.getCfValue(CF_SFDC_ATTACHMENT_ID);\\n\\t\\t\\t\\tif (attachmentId instanceof String) {\\n\\t\\t\\t\\t\\tCompositeSubRequestDto delAttachmentReq = new CompositeSubRequestDto();\\n\\t\\t\\t\\t\\tdelAttachmentReq.setMethod(HttpMethod.DELETE);\\n\\t\\t\\t\\t\\tdelAttachmentReq.setReferenceId(\\\"refDelAttachment\\\");\\n\\t\\t\\t\\t\\tdelAttachmentReq.setUrl(getEndPoint(END_POINT_SOBJECT_ATTACHMENT) + \\\"/\\\" + attachmentId);\\n\\t\\t\\t\\t\\trequest.addSubRequest(delAttachmentReq);\\n\\t\\t\\t\\t}\\n\\n\\t\\t\\t\\tCompositeSubRequestDto attachmentReq = new CompositeSubRequestDto();\\n\\t\\t\\t\\tattachmentReq.setMethod(HttpMethod.POST);\\n\\t\\t\\t\\tattachmentReq.setReferenceId(SFDC_REFERENCE_ID);\\n\\t\\t\\t\\tattachmentReq.setUrl(getEndPoint(END_POINT_SOBJECT_ATTACHMENT));\\n\\t\\t\\t\\tattachmentReq.setBody(toAttachmentJson(invoice, (String) invoiceId));\\n\\t\\t\\t\\trequest.addSubRequest(attachmentReq);\\n\\t\\t\\t}\\n\\n\\t\\t\\trequest.setAllOrNone(false);\\n\\t\\t\\trequest.setCollateSubrequests(false);\\n\\n\\t\\t\\tsendRequest(request, invoice, CF_SFDC_ATTACHMENT_ID);\\n\\t\\t}\\n\\t}\\n\\n\\t/**\\n\\t * Sends an accountOperation object to SFDC\\n\\t * \\n\\t * @param accountOperation\\n\\t */\\n\\tprivate void sendAccountOperation(AccountOperation accountOperation) {\\n\\n\\t\\tCompositeSubRequestDto paymentReq = new CompositeSubRequestDto();\\n\\t\\tpaymentReq.setUrl(getEndPoint(END_POINT_SOBJECT_ACCOUNT_OPERATION, \\\"Id\\\", accountOperation.getId()));\\n\\t\\tpaymentReq.setMethod(HttpMethod.PATCH);\\n\\t\\tpaymentReq.setReferenceId(SFDC_REFERENCE_ID);\\n\\t\\tpaymentReq.setBody(toAccountOperationJson(accountOperation));\\n\\n\\t\\tCompositeRequestDto request = new CompositeRequestDto();\\n\\t\\trequest.setAllOrNone(true);\\n\\t\\trequest.addSubRequest(paymentReq);\\n\\t\\trequest.setCollateSubrequests(true);\\n\\n\\t\\tsendRequest(request, accountOperation, null);\\n\\t}\\n\\n\\t/**\\n\\t * Updates the AO already sent to SFDC after been matched on OC\\n\\t * \\n\\t * @param matchingCode\\n\\t */\\n\\tprivate void sendMatchingCode(MatchingCode matchingCode) {\\n\\t\\tif (matchingCode.getMatchingAmounts() != null && !matchingCode.getMatchingAmounts().isEmpty()) {\\n\\t\\t\\tfor (MatchingAmount matchingAmount : matchingCode.getMatchingAmounts()) {\\n\\t\\t\\t\\tif (matchingAmount != null && matchingAmount.getAccountOperation() != null) {\\n\\t\\t\\t\\t\\tAccountOperation accountOperation = matchingAmount.getAccountOperation();\\n\\t\\t\\t\\t\\taccountOperation = (AccountOperation) baseEntityService.retrieveIfNotManaged(accountOperation);\\n\\t\\t\\t\\t\\tlog.info(\\\" --- [MatchingCode] : syncing the AO : {}  ...............\\\", accountOperation);\\n\\t\\t\\t\\t\\tsendAccountOperation(accountOperation);\\n\\t\\t\\t\\t\\tif (accountOperation instanceof RecordedInvoice && ((RecordedInvoice) accountOperation).getInvoice() != null) {\\n\\t\\t\\t\\t\\t\\tInvoice invoice = ((RecordedInvoice) accountOperation).getInvoice();\\n\\t\\t\\t\\t\\t\\tinvoice = (Invoice) baseEntityService.retrieveIfNotManaged(invoice);\\n\\t\\t\\t\\t\\t\\tlog.info(\\\" --- [Matched invoice] : syncing the matched invoice : {}  ...............\\\", invoice);\\n\\t\\t\\t\\t\\t\\tsendInvoice(invoice);\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t}\\n\\t}\\n\\n\\t/**\\n\\t * Send composite request to salesforce\\n\\t * \\n\\t * @param request\\n\\t * @param entity\\n\\t * @param cfName\\n\\t */\\n\\tprivate void sendRequest(CompositeRequestDto request, IEntity entity, String cfName) {\\n\\n\\t\\tint cp = 1;\\n\\t\\tString targetUri = \\\"\\\";\\n\\t\\tString instanceUrl = \\\"\\\";\\n\\t\\tString authorization = \\\"\\\";\\n\\t\\tResponse response = null;\\n\\t\\tboolean isAuthenticated = false;\\n\\t\\tString exceptionMessage = \\\"\\\";\\n\\n\\t\\tdo {\\n\\t\\t\\ttry {\\n\\t\\t\\t\\tif (token == null) {\\n\\t\\t\\t\\t\\tisAuthenticated = this.authenticate();\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tif (token != null) {\\n\\t\\t\\t\\t\\tinstanceUrl = token.getInstanceUrl();\\n\\t\\t\\t\\t\\tauthorization = token.getAuth();\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\ttargetUri = instanceUrl + getEndPoint(END_POINT_RESOURCE_COMPOSITE);\\n\\t\\t\\t\\tlogRequest(targetUri, request);\\n\\t\\t\\t\\tResteasyWebTarget target = client.target(targetUri);\\n\\t\\t\\t\\tInvocation.Builder requestBuilder = target.request();\\n\\t\\t\\t\\trequestBuilder = requestBuilder.header(HttpHeaders.AUTHORIZATION, authorization);\\n\\t\\t\\t\\tresponse = requestBuilder.post((Entity.json(JsonUtils.toJson(request, false))));\\n\\t\\t\\t\\tprocessResponse(entity, cfName, request, response);\\n\\t\\t\\t\\tisAuthenticated = true;\\n\\t\\t\\t} catch (ProcessingException ex) {\\n\\t\\t\\t\\texceptionMessage = ex.getMessage();\\n\\t\\t\\t\\tlog.error(\\\"Error invoking target {} with request {} =>  {}\\\", targetUri, request, exceptionMessage);\\n\\t\\t\\t\\tisAuthenticated = this.authenticate();\\n\\t\\t\\t} catch (SObjectSyncingException ex) {\\n\\t\\t\\t\\tif (ErrorMessage.AUTHENTICATION_ERROR.equals(ex.getMessage()) ||\\n\\t\\t\\t\\t\\t\\tErrorMessage.AUTHENTICATION_ERROR_UNKNOWN.equals(ex.getMessage())) {\\n\\t\\t\\t\\t\\ttoken = null;\\n\\t\\t\\t\\t\\tcontinue;\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\tthrow ex;\\n\\t\\t\\t} catch (Exception ex) {\\n\\t\\t\\t\\tlog.error(\\\"Error invoking target {} with request {} =>  {}\\\", targetUri, request, ex.getMessage());\\n\\t\\t\\t\\tregisterResult(entity, request, null, response, ex.getMessage(), false);\\n\\t\\t\\t\\tthrow new SObjectSyncingException(ErrorMessage.ENTITY_SYNCING_ERROR, entity, ex.getMessage());\\n\\t\\t\\t}\\n\\n\\t\\t} while (!isAuthenticated && cp++ < OAUTH_TOKEN_RETRY_TIMES);\\n\\n\\t\\tif (!isAuthenticated) {\\n\\t\\t\\tlog.error(\\\"Failed to invoke target {} with request {} After {} attempts  =>  {}\\\", targetUri, request, OAUTH_TOKEN_RETRY_TIMES, exceptionMessage);\\n\\t\\t\\tregisterResult(entity, request, null, response, exceptionMessage, false);\\n\\t\\t\\tthrow new SObjectSyncingException(ErrorMessage.ENTITY_SYNCING_ERROR, entity, exceptionMessage);\\n\\t\\t}\\n\\t}\\n\\n\\t/**\\n\\t * Process the Salesforce syncing response\\n\\t * \\n\\t * @param entity\\n\\t * @param cfName to store the SF id on Opencell\\n\\t * @param request\\n\\t * @param response\\n\\t */\\n\\tprivate void processResponse(IEntity entity, String cfName, CompositeRequestDto request, Response response) {\\n\\n\\t\\tString jsonResponse = response.readEntity(String.class);\\n\\t\\tif (log.isDebugEnabled()) {\\n\\t\\t\\tlog.debug(\\\"Json Response : [{}:{}] => {}\\\", response.getStatus(), response.getStatusInfo().getReasonPhrase(), jsonResponse);\\n\\t\\t}\\n\\n\\t\\tif (isSuccessResponse(response)) {\\n\\t\\t\\tResponseDto result = JsonUtils.toObject(jsonResponse, ResponseDto.class);\\n\\t\\t\\tboolean isSuccess = result.isRequestSuccess(SFDC_REFERENCE_ID);\\n\\t\\t\\tregisterResult(entity, request, null, response, jsonResponse, isSuccess);\\n\\t\\t\\tif (!isSuccess) {\\n\\t\\t\\t\\tthrow new SObjectSyncingException(ErrorMessage.ENTITY_SYNCING_ERROR, entity, result);\\n\\t\\t\\t}\\n\\t\\t\\tif (cfName != null && entity instanceof ICustomFieldEntity) {\\n\\t\\t\\t\\t((ICustomFieldEntity) entity).setCfValue(cfName, result.getSObjectId(SFDC_REFERENCE_ID));\\n\\t\\t\\t}\\n\\t\\t} else {\\n\\t\\t\\tJSONArray errorResponse = JsonUtils.toObject(jsonResponse, JSONArray.class);\\n\\t\\t\\tregisterResult(entity, request, null, response, jsonResponse, false);\\n\\t\\t\\tthrow new SObjectSyncingException(ErrorMessage.ENTITY_SYNCING_ERROR, entity, errorResponse);\\n\\t\\t}\\n\\t}\\n\\n\\t/**\\n\\t * Allows to register the syncing process result on the system espacially the syncing status to avoid to resync the objects already synced next iteration.\\n\\t * \\n\\t * @param service\\n\\t * @param entity\\n\\t * @param isSynced\\n\\t */\\n\\tprivate void registerResult(IEntity entity, CompositeRequestDto request, String jsonRequest, Response response, String jsonResponse, boolean isSynced) {\\n\\n\\t\\tif (entity instanceof ICustomFieldEntity) {\\n\\t\\t\\t((ICustomFieldEntity) entity).setCfValue(CF_IS_SYNCED_NAME, isSynced);\\n\\t\\t}\\n\\n\\t\\tString entityId = \\\"-\\\";\\n\\t\\tString entityType = \\\"-\\\";\\n\\t\\tString queryToExecute = null;\\n\\t\\tString endPoint = (token != null ? token.getInstanceUrl() : \\\"\\\") + getEndPoint(END_POINT_RESOURCE_COMPOSITE);\\n\\n\\t\\tif (entity == null) { // Token case\\n\\t\\t\\tentityType = \\\"Token\\\";\\n\\t\\t} else {\\n\\t\\t\\tentityType = entity.getClass().getName();\\n\\t\\t\\tentityId = entity.getId() + \\\"\\\";\\n\\t\\t}\\n\\n\\t\\tif (isSynced) {\\n\\t\\t\\tqueryToExecute = String.format(DELETE_ERRORS_QUERY, entityType, entityId);\\n\\t\\t} else {\\n\\n\\t\\t\\tString entityCode = \\\"-\\\";\\n\\t\\t\\tString requestBody = \\\"-\\\";\\n\\t\\t\\tString responseBody = \\\"-\\\";\\n\\t\\t\\tString responseStatus = \\\"-\\\";\\n\\t\\t\\tString responseMessage = \\\"-\\\";\\n\\t\\t\\tString requestEndPoint = endPoint;\\n\\t\\t\\tString lastSyncingDate = this.formatAsTime(new Date());\\n\\n\\t\\t\\tif (entity instanceof BusinessEntity) {\\n\\t\\t\\t\\tentityCode = ((BusinessEntity) entity).getCode();\\n\\t\\t\\t}\\n\\t\\t\\tif (entity instanceof Invoice) {\\n\\t\\t\\t\\tentityCode = ((Invoice) entity).getInvoiceNumber();\\n\\t\\t\\t}\\n\\t\\t\\tif (request != null) {\\n\\t\\t\\t\\trequestBody = JsonUtils.toJson(request, false);\\n\\t\\t\\t}\\n\\t\\t\\tif (jsonRequest != null) {\\n\\t\\t\\t\\trequestBody = jsonRequest;\\n\\t\\t\\t}\\n\\t\\t\\tif (response != null) {\\n\\t\\t\\t\\tresponseStatus = response.getStatus() + \\\"\\\";\\n\\t\\t\\t\\tresponseMessage = response.getStatusInfo() == null ? responseMessage : response.getStatusInfo().getReasonPhrase();\\n\\t\\t\\t}\\n\\t\\t\\tif (jsonResponse != null) {\\n\\t\\t\\t\\tresponseBody = jsonResponse;\\n\\t\\t\\t}\\n\\n\\t\\t\\tqueryToExecute = String.format(INSERT_ERRORS_QUERY, entityId, entityCode, entityType, lastSyncingDate, requestEndPoint, requestBody, responseStatus, responseMessage,\\n\\t\\t\\t\\tresponseBody);\\n\\t\\t}\\n\\n\\t\\tif (queryToExecute != null) {\\n\\t\\t\\t/*Query query = em.createNativeQuery(queryToExecute);\\n\\t\\t\\tif (query != null) {\\n\\t\\t\\t\\tquery.executeUpdate();\\n\\t\\t\\t}*/\\n\\t\\t}\\n\\t}\\n\\n\\t/**\\n\\t * Logs the request sent to SFDC\\n\\t * \\n\\t * @param endPoint\\n\\t * @param request\\n\\t */\\n\\tprivate void logRequest(String endPoint, CompositeRequestDto request) {\\n\\t\\tif (log.isDebugEnabled()) {\\n\\t\\t\\tString jsonBody = JsonUtils.toJson(request, false);\\n\\t\\t\\tlog.debug(\\\"Calling target=[{}] with request=[{}]\\\", endPoint, jsonBody);\\n\\t\\t}\\n\\t}\\n\\n\\t/**\\n\\t * Checks if is success response.\\n\\t *\\n\\t * @param response the response\\n\\t * @return true, if is success response\\n\\t */\\n\\tprivate boolean isSuccessResponse(Response response) {\\n\\t\\treturn Response.Status.Family.SUCCESSFUL == response.getStatusInfo().getFamily();\\n\\t}\\n\\n\\t/**\\n\\t * Put the right version & the external ID in the endPoint param\\n\\t * \\n\\t * @param endPoint\\n\\t * @return\\n\\t */\\n\\tprivate String getEndPoint(String endPoint, String fieldName, Object fieldValue) {\\n\\t\\treturn this.getEndPoint(endPoint) + \\\"/opencell__\\\" + fieldName + \\\"__c/\\\" + fieldValue;\\n\\t}\\n\\n\\tprivate String getEndPoint(String endPoint) {\\n\\t\\treturn endPoint.replace(\\\"{{version}}\\\", END_POINT_API_VERSION);\\n\\t}\\n\\n\\t/**\\n\\t * All the oAuth2 process is done in this method\\n\\t */\\n\\tprivate boolean authenticate() {\\n\\t\\ttry {\\n\\t\\t\\tfinal String tokenRequetsUrl = this.getMandatoryParam(PROPERTY_KEY_SALESFORCE_URL) + END_POINT_TOKEN_REQUEST;\\n\\t\\t\\tResteasyWebTarget resourceTarget = client.target(tokenRequetsUrl);\\n\\n\\t\\t\\tForm form = buildTokenRequest();\\n\\t\\t\\tif (log.isDebugEnabled()) {\\n\\t\\t\\t\\tlog.debug(\\\"A token request will be sent... {}\\\", securedLog(form));\\n\\t\\t\\t}\\n\\n\\t\\t\\tResponse response = resourceTarget.request().post(Entity.form(form), Response.class);\\n\\t\\t\\tString jsonResponse = response.readEntity(String.class);\\n\\n\\t\\t\\tboolean isSuccess = isSuccessResponse(response);\\n\\t\\t\\tregisterResult(null, null, securedLog(form), response, jsonResponse, isSuccess);\\n\\t\\t\\tif (isSuccess) {\\n\\t\\t\\t\\ttoken = JsonUtils.toObject(jsonResponse, Token.class);\\n\\t\\t\\t\\tif (log.isDebugEnabled()) {\\n\\t\\t\\t\\t\\tlog.debug(\\\"A new token has successfully been obtained : {}\\\", token);\\n\\t\\t\\t\\t}\\n\\t\\t\\t\\treturn true;\\n\\t\\t\\t} else {\\n\\t\\t\\t\\tthrow new SObjectSyncingException(ErrorMessage.AUTHENTICATION_ERROR, response.getStatus(), response.getStatusInfo().getReasonPhrase(), jsonResponse);\\n\\t\\t\\t}\\n\\n\\t\\t} catch (SObjectSyncingException e) {\\n\\t\\t\\tthrow e;\\n\\t\\t} catch (Exception e) {\\n\\t\\t\\tregisterResult(null, null, null, null, e.getMessage(), false);\\n\\t\\t\\tthrow new SObjectSyncingException(ErrorMessage.AUTHENTICATION_ERROR_UNKNOWN, e.getMessage());\\n\\t\\t}\\n\\t}\\n\\n\\t/**\\n\\t * Secures Request form params to log them\\n\\t * \\n\\t * @param form\\n\\t * @return\\n\\t */\\n\\tprivate String securedLog(Form form) {\\n\\t\\tif (form == null || form.asMap() == null) {\\n\\t\\t\\treturn \\\"\\\";\\n\\t\\t}\\n\\n\\t\\tMap<String, String> result = new HashMap<>();\\n\\t\\tMultivaluedMap<String, String> map = form.asMap();\\n\\t\\tfor (Map.Entry<String, List<String>> entry : map.entrySet()) {\\n\\t\\t\\tif (entry.getValue() != null && !entry.getValue().isEmpty()) {\\n\\t\\t\\t\\tresult.put(entry.getKey(), maskString(entry.getValue().get(0)));\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\treturn result.toString();\\n\\t}\\n\\n\\t/**\\n\\t * Masks a part of the string param\\n\\t * \\n\\t * @param stringToMask\\n\\t * @return\\n\\t */\\n\\tprivate static String maskString(String stringToMask) {\\n\\t\\tif (stringToMask != null && stringToMask.length() >= 8) {\\n\\t\\t\\treturn new StringBuilder(stringToMask.substring(0, 4)).append(org.apache.commons.lang3.StringUtils.repeat('*', stringToMask.length() - 8))\\n\\t\\t\\t\\t.append(stringToMask.substring(stringToMask.length() - 4)).toString();\\n\\t\\t}\\n\\t\\treturn \\\"\\\";\\n\\t}\\n\\n\\t/**\\n\\t * Reads the configuration from the system properties and builds the token request based on.\\n\\t * \\n\\t * @return\\n\\t */\\n\\tprivate Form buildTokenRequest() {\\n\\t\\tfinal String username = this.getMandatoryParam(PROPERTY_KEY_SALESFORCE_USERNAME);\\n\\t\\tfinal String password = this.getMandatoryParam(PROPERTY_KEY_SALESFORCE_PASSWORD);\\n\\t\\tfinal String clientId = this.getMandatoryParam(PROPERTY_KEY_SALESFORCE_CLIENT_ID);\\n\\t\\tfinal String clientSecret = this.getMandatoryParam(PROPERTY_KEY_SALESFORCE_CLIENT_SECRET);\\n\\n\\t\\tForm request = new Form();\\n\\t\\trequest.param(TOKEN_REQUEST_PARAM_USERNAME, username);\\n\\t\\trequest.param(TOKEN_REQUEST_PARAM_PASSWORD, password);\\n\\t\\trequest.param(TOKEN_REQUEST_PARAM_CLIENT_ID, clientId);\\n\\t\\trequest.param(TOKEN_REQUEST_PARAM_CLIENT_SECRET, clientSecret);\\n\\t\\trequest.param(TOKEN_REQUEST_PARAM_GRANT_TYPE, TOKEN_REQUEST_PARAM_GRANT_TYPE_PASSWORD);\\n\\n\\t\\treturn request;\\n\\t}\\n\\n\\t/**\\n\\t * Reads the configuration from the system properties and builds the refresh token request based on. NOT SUPPORTED YET BY SFDC\\n\\t * \\n\\t * @return\\n\\t */\\n\\tprivate Form buildTokenRefresh() {\\n\\t\\tfinal String clientId = this.getMandatoryParam(PROPERTY_KEY_SALESFORCE_CLIENT_ID);\\n\\t\\tfinal String clientSecret = this.getMandatoryParam(PROPERTY_KEY_SALESFORCE_CLIENT_SECRET);\\n\\n\\t\\tForm request = new Form();\\n\\t\\trequest.param(TOKEN_REQUEST_PARAM_CLIENT_ID, clientId);\\n\\t\\trequest.param(TOKEN_REQUEST_PARAM_CLIENT_SECRET, clientSecret);\\n\\t\\trequest.param(TOKEN_REQUEST_PARAM_REFRESH_TOKEN, token.getAccessToken());\\n\\t\\trequest.param(TOKEN_REQUEST_PARAM_GRANT_TYPE, TOKEN_REQUEST_PARAM_GRANT_TYPE_REFRESH);\\n\\n\\t\\treturn request;\\n\\t}\\n\\n\\t/**\\n\\t * Build the subscription json to send to SFDC\\n\\t * \\n\\t * @param subscription\\n\\t * @return\\n\\t */\\n\\tprivate JsonObject toSubscriptionJson(Subscription subscription) {\\n\\n\\t\\tJsonObject subscriptionJson = new JsonObject();\\n\\t\\tsubscriptionJson.addProperty(\\\"opencell__Id__c\\\", subscription.getId());\\n\\t\\tsubscriptionJson.addProperty(\\\"opencell__Code__c\\\", subscription.getCode());\\n\\t\\tsubscriptionJson.addProperty(\\\"opencell__Description__c\\\", subscription.getDescription());\\n\\n\\t\\tif (subscription.getOffer() != null) {\\n\\t\\t\\tsubscriptionJson.addProperty(\\\"opencell__OfferCode__c\\\", subscription.getOffer().getCode());\\n\\t\\t\\tsubscriptionJson.addProperty(\\\"opencell__OfferDescription__c\\\", subscription.getOffer().getDescription());\\n\\t\\t}\\n\\t\\tif (subscription.getStatus() != null) {\\n\\t\\t\\tsubscriptionJson.addProperty(\\\"opencell__Status__c\\\", subscription.getStatus().name());\\n\\t\\t}\\n\\t\\tif (subscription.getUserAccount() != null) {\\n\\t\\t\\tsubscriptionJson.addProperty(\\\"opencell__AccountID__c\\\", subscription.getUserAccount().getCode());\\n\\t\\t}\\n\\t\\tif (subscription.getStatusDate() != null) {\\n\\t\\t\\tsubscriptionJson.addProperty(\\\"opencell__StatusDate__c\\\", this.formatAsDate(subscription.getStatusDate()));\\n\\t\\t}\\n\\t\\tif (subscription.getSubscriptionDate() != null) {\\n\\t\\t\\tsubscriptionJson.addProperty(\\\"opencell__subscriptionDate__c\\\", this.formatAsDate(subscription.getSubscriptionDate()));\\n\\t\\t}\\n\\t\\tif (subscription.getTerminationDate() != null) {\\n\\t\\t\\tsubscriptionJson.addProperty(\\\"opencell__TerminationDate__c\\\", this.formatAsDate(subscription.getTerminationDate()));\\n\\t\\t}\\n\\t\\tif (subscription.getEndAgreementDate() != null) {\\n\\t\\t\\tsubscriptionJson.addProperty(\\\"opencell__EndAgreementDate__c\\\", this.formatAsDate(subscription.getEndAgreementDate()));\\n\\t\\t}\\n\\t\\tif (subscription.getSubscribedTillDate() != null) {\\n\\t\\t\\tsubscriptionJson.addProperty(\\\"opencell__SubscribedTillDate__c\\\", this.formatAsDate(subscription.getSubscribedTillDate()));\\n\\t\\t}\\n\\t\\tif (subscription.getSubscriptionTerminationReason() != null) {\\n\\t\\t\\tsubscriptionJson.addProperty(\\\"opencell__SubscriptionTerminationReason__c\\\", subscription.getSubscriptionTerminationReason().getCode());\\n\\t\\t}\\n\\n\\t\\treturn subscriptionJson;\\n\\t}\\n\\n\\t/**\\n\\t * Build the invoice json to send to SFDC\\n\\t * \\n\\t * @param invoice\\n\\t * @return\\n\\t */\\n\\tprivate JsonObject toInvoiceJson(Invoice invoice) {\\n\\n\\t\\tJsonObject invoiceJson = new JsonObject();\\n\\t\\tinvoiceJson.addProperty(\\\"opencell__DueBalance__c\\\", invoice.getDueBalance());\\n\\t\\tinvoiceJson.addProperty(\\\"opencell__AmountTax__c\\\", invoice.getAmountTax());\\n\\t\\tinvoiceJson.addProperty(\\\"opencell__Amount_With_Tax__c\\\", invoice.getAmountWithTax());\\n\\t\\tinvoiceJson.addProperty(\\\"opencell__Amount_Without_Tax__c\\\", invoice.getAmountWithoutTax());\\n\\t\\tinvoiceJson.addProperty(\\\"opencell__InvoiceNumber__c\\\", invoice.getInvoiceNumber());\\n\\t\\t// Deprecated\\n\\t\\tinvoiceJson.addProperty(\\\"opencell__Invoice_Number_del__c\\\", invoice.getInvoiceNumber());\\n\\t\\tif (invoice.getStatus() != null) {\\n\\t\\t\\tinvoiceJson.addProperty(\\\"opencell__Status__c\\\", invoice.getStatus().name());\\n\\t\\t}\\n\\t\\tif (invoice.getSubscription() != null) {\\n\\t\\t\\tinvoiceJson.addProperty(\\\"opencell__SubscriptionId__c\\\", invoice.getSubscription().getId());\\n\\t\\t\\tinvoiceJson.addProperty(\\\"opencell__ExternalRef__c\\\", invoice.getSubscription().getCode());\\n\\t\\t}\\n\\t\\tif (invoice.getPaymentMethodType() != null) {\\n\\t\\t\\tinvoiceJson.addProperty(\\\"opencell__PaymentMethod__c\\\", invoice.getPaymentMethodType().name());\\n\\t\\t}\\n\\t\\tif (invoice.getBillingAccount() != null) {\\n\\t\\t\\tinvoiceJson.addProperty(\\\"opencell__Account_Name__c\\\", invoice.getBillingAccount().getCode());\\n\\t\\t}\\n\\t\\tif (invoice.getDueDate() != null) {\\n\\t\\t\\tinvoiceJson.addProperty(\\\"opencell__DueDate__c\\\", this.formatAsDate(invoice.getDueDate()));\\n\\t\\t}\\n\\t\\tif (invoice.getInvoiceDate() != null) {\\n\\t\\t\\tinvoiceJson.addProperty(\\\"opencell__Invoice_Date__c\\\", this.formatAsDate(invoice.getInvoiceDate()));\\n\\t\\t}\\n\\t\\tif (invoice.getInvoiceType() != null) {\\n\\t\\t\\tinvoiceJson.addProperty(\\\"opencell__InvoiceType__c\\\", invoice.getInvoiceType().getCode());\\n\\t\\t}\\n\\t\\tif (invoice.getCfValue(\\\"CF_COMMENT\\\") instanceof String) {\\n\\t\\t\\tinvoiceJson.addProperty(\\\"opencell__Comment__c\\\", (String) invoice.getCfValue(\\\"CF_COMMENT\\\"));\\n\\t\\t}\\n\\n\\t\\treturn invoiceJson;\\n\\t}\\n\\n\\t/**\\n\\t * Build the accountOperation json to send to SFDC\\n\\t * \\n\\t * @param accountOperation\\n\\t * @return\\n\\t */\\n\\tprivate JsonObject toAccountOperationJson(AccountOperation accountOperation) {\\n\\n\\t\\tJsonObject accountOperationJson = new JsonObject();\\n\\t\\taccountOperationJson.addProperty(\\\"opencell__Code__c\\\", accountOperation.getCode());\\n\\t\\taccountOperationJson.addProperty(\\\"opencell__Type__c\\\", accountOperation.getType());\\n\\t\\taccountOperationJson.addProperty(\\\"opencell__Amount__c\\\", accountOperation.getAmount());\\n\\t\\taccountOperationJson.addProperty(\\\"opencell__BankLot__c\\\", accountOperation.getBankLot());\\n\\t\\taccountOperationJson.addProperty(\\\"opencell__Reference__c\\\", accountOperation.getReference());\\n\\t\\taccountOperationJson.addProperty(\\\"opencell__TaxAmount__c\\\", accountOperation.getTaxAmount());\\n\\t\\taccountOperationJson.addProperty(\\\"opencell__Description__c\\\", accountOperation.getDescription());\\n\\t\\taccountOperationJson.addProperty(\\\"opencell__BankReference__c\\\", accountOperation.getBankReference());\\n\\t\\taccountOperationJson.addProperty(\\\"opencell__MatchedAmount__c\\\", accountOperation.getMatchingAmount());\\n\\t\\taccountOperationJson.addProperty(\\\"opencell__UnmatchedAmount__c\\\", accountOperation.getUnMatchingAmount());\\n\\t\\taccountOperationJson.addProperty(\\\"opencell__AmountWithoutTax__c\\\", accountOperation.getAmountWithoutTax());\\n\\t\\tif (accountOperation.getDueDate() != null) {\\n\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__DueDate__c\\\", this.formatAsDate(accountOperation.getDueDate()));\\n\\t\\t}\\n\\t\\tif (accountOperation.getDepositDate() != null) {\\n\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__DepositDate__c\\\", this.formatAsDate(accountOperation.getDepositDate()));\\n\\t\\t}\\n\\t\\tif (accountOperation.getTransactionDate() != null) {\\n\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__TransactionDate__c\\\", this.formatAsDate(accountOperation.getTransactionDate()));\\n\\t\\t}\\n\\t\\tif (accountOperation.getBankCollectionDate() != null) {\\n\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__BankCollectionDate__c\\\", this.formatAsDate(accountOperation.getBankCollectionDate()));\\n\\t\\t}\\n\\t\\tif (accountOperation.getPaymentMethod() != null) {\\n\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__PaymentMethod__c\\\", accountOperation.getPaymentMethod().name());\\n\\t\\t}\\n\\t\\tif (accountOperation.getAccountingCode() != null) {\\n\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__AccountingCode__c\\\", accountOperation.getAccountingCode().getCode());\\n\\t\\t}\\n\\t\\tif (accountOperation.getMatchingStatus() != null) {\\n\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__MatchingStatus__c\\\", accountOperation.getMatchingStatus().name());\\n\\t\\t}\\n\\t\\tif (accountOperation.getCustomerAccount() != null) {\\n\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__AccountId__c\\\", accountOperation.getCustomerAccount().getCode());\\n\\t\\t}\\n\\t\\tif (accountOperation.getTransactionCategory() != null) {\\n\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__Category__c\\\", accountOperation.getTransactionCategory().name());\\n\\t\\t}\\n\\n\\t\\tif (accountOperation instanceof Payment) {\\n\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__Fees__c\\\", ((Payment) accountOperation).getFees());\\n\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__Comment__c\\\", ((Payment) accountOperation).getComment());\\n\\t\\t}\\n\\t\\tif (accountOperation instanceof RejectedPayment) {\\n\\t\\t\\tRejectedPayment rejectedPayment = (RejectedPayment) accountOperation;\\n\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__RejectedCode__c\\\", rejectedPayment.getRejectedCode());\\n\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__RejectedDescription__c\\\", rejectedPayment.getRejectedDescription());\\n\\t\\t\\tif (rejectedPayment.getRejectedType() != null) {\\n\\t\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__RejectedType__c\\\", rejectedPayment.getRejectedType().name());\\n\\t\\t\\t}\\n\\t\\t\\tif (rejectedPayment.getRejectedDate() != null) {\\n\\t\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__RejectedDate__c\\\", this.formatAsDate(rejectedPayment.getRejectedDate()));\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\tif (accountOperation instanceof RecordedInvoice) {\\n\\t\\t\\tRecordedInvoice recordedInvoice = (RecordedInvoice) accountOperation;\\n\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__NetToPay__c\\\", recordedInvoice.getNetToPay());\\n\\t\\t\\tif (recordedInvoice.getInvoiceDate() != null) {\\n\\t\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__InvoiceDate__c\\\", this.formatAsDate(recordedInvoice.getInvoiceDate()));\\n\\t\\t\\t}\\n\\t\\t\\tif (recordedInvoice.getProductionDate() != null) {\\n\\t\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__ProductionDate__c\\\", this.formatAsDate(recordedInvoice.getProductionDate()));\\n\\t\\t\\t}\\n\\t\\t\\tif (recordedInvoice.getInvoice() != null) {\\n\\t\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__InvoiceId__c\\\", recordedInvoice.getInvoice().getId());\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\tif (accountOperation instanceof OtherCreditAndCharge) {\\n\\t\\t\\tOtherCreditAndCharge occ = (OtherCreditAndCharge) accountOperation;\\n\\t\\t\\tif (occ.getOperationDate() != null) {\\n\\t\\t\\t\\taccountOperationJson.addProperty(\\\"opencell__OperationDate__c\\\", this.formatAsDate(occ.getOperationDate()));\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\treturn accountOperationJson;\\n\\t}\\n\\n\\t/**\\n\\t * Build the invoice pdf json to send to SFDC\\n\\t * \\n\\t * @param invoice\\n\\t * @param invoiceId\\n\\t * @return\\n\\t */\\n\\tprivate JsonObject toAttachmentJson(Invoice invoice, String invoiceId) {\\n\\t\\tJsonObject invoiceJson = new JsonObject();\\n\\t\\tinvoiceJson.addProperty(\\\"Name\\\", invoice.getInvoiceNumber() + \\\"_PDF\\\");\\n\\t\\tinvoiceJson.addProperty(\\\"ParentId\\\", invoiceId);\\n\\t\\tinvoiceJson.addProperty(\\\"Description\\\", \\\"INVOICE\\\");\\n\\t\\tinvoiceJson.addProperty(\\\"ContentType\\\", \\\"application/pdf\\\");\\n\\t\\tinvoiceJson.addProperty(\\\"Body\\\", Base64.getEncoder().encodeToString(invoiceService.getInvoicePdf(invoice)));\\n\\t\\t//invoiceJson.addProperty(\\\"Body\\\", Base64.encodeBase64String(invoiceService.getInvoicePdf(invoice)));\\n\\t\\treturn invoiceJson;\\n\\t}\\n\\n\\t/**\\n\\t * Format date to yyyy-MM-dd pattern\\n\\t * \\n\\t * @param date Date to format\\n\\t * @return Date as yyyy-MM-dd string\\n\\t */\\n\\tprivate String formatAsDate(Date date) {\\n\\t\\treturn DateUtils.formatDateWithPattern(date, DateUtils.DATE_PATTERN);\\n\\t}\\n\\n\\t/**\\n\\t * Format date to yyyy-MM-dd'T'hh:mm:ssXXX pattern\\n\\t * \\n\\t * @param date Date to format\\n\\t * @return Date as yyyy-MM-dd'T'hh:mm:ssXXX string\\n\\t */\\n\\tprivate String formatAsTime(Date date) {\\n\\t\\treturn DateUtils.formatDateWithPattern(date, DateUtils.DATE_TIME_PATTERN);\\n\\t}\\n\\n\\t/**\\n\\t * Gets the mondatory param.\\n\\t *\\n\\t * @param paramKey the param key\\n\\t * @return the mondatory yousign param\\n\\t * @throws MeveoApiException the meveo api exception\\n\\t */\\n\\tprivate String getMandatoryParam(String paramKey) throws MeveoApiException {\\n\\t\\treturn this.getParam(paramKey, true);\\n\\t}\\n\\n\\tprivate String getParam(String paramKey, boolean isMandatory) throws MeveoApiException {\\n\\t\\treturn this.getParam(paramKey, isMandatory, \\\"\\\");\\n\\t}\\n\\n\\tprivate String getParam(String paramKey, boolean isMandatory, String defaultValue) throws MeveoApiException {\\n\\t\\tString paramValue = paramBean.getProperty(paramKey, defaultValue);\\n\\t\\tif (isMandatory && StringUtils.isBlank(paramValue)) {\\n\\t\\t\\tthrow new MeveoApiException(\\\" Mandatory param not configured : \\\" + paramKey);\\n\\t\\t}\\n\\t\\treturn paramValue;\\n\\t}\\n\\n\\tpublic IEntity updateNoCheck(IEntity entity) throws BusinessException {\\n\\t\\tlog.info(\\\"start of update {} entity (id={}) ..\\\", entity.getClass().getSimpleName(), entity.getId());\\n\\t\\treturn em.merge(entity);\\n\\t}\\n\\n\\tprivate IEntity retrieveIfNotManaged(IEntity entity) {\\n\\n\\t\\tif (entity.getId() == null) {\\n\\t\\t\\treturn entity;\\n\\t\\t}\\n\\t\\t// Entity is managed already\\n\\t\\tif (!em.contains(entity)) {\\n\\t\\t\\tClass<? extends IEntity> entityClass = entity.getClass();\\n\\t\\t\\tlog.trace(\\\"Find {}/{} by id\\\", entityClass.getSimpleName(), entity.getId());\\n\\t\\t\\tentity = em.find(entityClass, entity.getId());\\n\\t\\t}\\n\\t\\tif (entity instanceof HibernateProxy) {\\n\\t\\t\\tentity = (IEntity) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();\\n\\t\\t}\\n\\n\\t\\treturn entity;\\n\\t}\\n\\n\\t/**********************************************************************************\\n\\t * \\n\\t * \\n\\t * All The composite request/response classes to interact with salesforce\\n\\t * \\n\\t * @author Youssef IZEM\\n\\t * @lastModifiedVersion 1.0\\n\\t **********************************************************************************/\\n\\n\\tclass CompositeRequestDto {\\n\\n\\t\\tprivate boolean allOrNone = true;\\n\\t\\tprivate boolean collateSubrequests = true;\\n\\t\\tprivate List<CompositeSubRequestDto> compositeRequest = new ArrayList<>();\\n\\n\\t\\tpublic boolean isAllOrNone() {\\n\\t\\t\\treturn allOrNone;\\n\\t\\t}\\n\\n\\t\\tpublic void setAllOrNone(boolean allOrNone) {\\n\\t\\t\\tthis.allOrNone = allOrNone;\\n\\t\\t}\\n\\n\\t\\tpublic boolean isCollateSubrequests() {\\n\\t\\t\\treturn collateSubrequests;\\n\\t\\t}\\n\\n\\t\\tpublic void setCollateSubrequests(boolean collateSubrequests) {\\n\\t\\t\\tthis.collateSubrequests = collateSubrequests;\\n\\t\\t}\\n\\n\\t\\tpublic List<CompositeSubRequestDto> getCompositeRequest() {\\n\\t\\t\\treturn compositeRequest;\\n\\t\\t}\\n\\n\\t\\tpublic void addSubRequest(CompositeSubRequestDto subRequest) {\\n\\t\\t\\tthis.compositeRequest.add(subRequest);\\n\\t\\t}\\n\\n\\t\\tpublic CompositeSubRequestDto getSubRequest(String reference) {\\n\\t\\t\\tif (compositeRequest == null || reference == null) {\\n\\t\\t\\t\\treturn null;\\n\\t\\t\\t}\\n\\t\\t\\tfor (CompositeSubRequestDto request : compositeRequest) {\\n\\t\\t\\t\\tif (reference.equals(request.getReferenceId())) {\\n\\t\\t\\t\\t\\treturn request;\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t\\treturn null;\\n\\t\\t}\\n\\n\\t\\t@Override\\n\\t\\tpublic String toString() {\\n\\t\\t\\treturn ToStringBuilder.reflectionToString(this, ToStringStyle.NO_CLASS_NAME_STYLE);\\n\\t\\t}\\n\\t}\\n\\n\\tclass CompositeSubRequestDto {\\n\\n\\t\\tprivate String url;\\n\\t\\tprivate JsonObject body;\\n\\t\\tprivate String method;\\n\\t\\tprivate String referenceId;\\n\\n\\t\\tpublic String getUrl() {\\n\\t\\t\\treturn url;\\n\\t\\t}\\n\\n\\t\\tpublic void setUrl(String url) {\\n\\t\\t\\tthis.url = url;\\n\\t\\t}\\n\\n\\t\\tpublic JsonObject getBody() {\\n\\t\\t\\treturn body;\\n\\t\\t}\\n\\n\\t\\tpublic void setBody(JsonObject body) {\\n\\t\\t\\tthis.body = body;\\n\\t\\t}\\n\\n\\t\\tpublic String getMethod() {\\n\\t\\t\\treturn method;\\n\\t\\t}\\n\\n\\t\\tpublic void setMethod(String method) {\\n\\t\\t\\tthis.method = method;\\n\\t\\t}\\n\\n\\t\\tpublic String getReferenceId() {\\n\\t\\t\\treturn referenceId;\\n\\t\\t}\\n\\n\\t\\tpublic void setReferenceId(String referenceId) {\\n\\t\\t\\tthis.referenceId = referenceId;\\n\\t\\t}\\n\\n\\t\\t@Override\\n\\t\\tpublic String toString() {\\n\\t\\t\\treturn ToStringBuilder.reflectionToString(this, ToStringStyle.NO_CLASS_NAME_STYLE);\\n\\t\\t}\\n\\t}\\n\\n\\tclass ResponseDto {\\n\\n\\t\\tprivate List<CompositeSubRequestResponse> compositeResponse = new ArrayList<>();\\n\\n\\t\\tpublic List<CompositeSubRequestResponse> getSubCompositeResponse() {\\n\\t\\t\\treturn compositeResponse;\\n\\t\\t}\\n\\n\\t\\tpublic void setCompositeResponse(List<CompositeSubRequestResponse> compositeResponse) {\\n\\t\\t\\tthis.compositeResponse = compositeResponse;\\n\\t\\t}\\n\\n\\t\\t/**\\n\\t\\t * Get the id for the created SOBJECT\\n\\t\\t * \\n\\t\\t * @param reference\\n\\t\\t * @return\\n\\t\\t */\\n\\t\\tpublic Object getSObjectId(String reference) {\\n\\t\\t\\tif (compositeResponse == null || reference == null) {\\n\\t\\t\\t\\treturn null;\\n\\t\\t\\t}\\n\\t\\t\\tfor (CompositeSubRequestResponse response : compositeResponse) {\\n\\t\\t\\t\\tif (reference.equals(response.getReferenceId()) && response.getBody() instanceof Map) {\\n\\t\\t\\t\\t\\treturn ((Map) response.getBody()).get(\\\"id\\\");\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t\\treturn null;\\n\\t\\t}\\n\\n\\t\\t/**\\n\\t\\t * Get the subResponse for the created SOBJECT\\n\\t\\t * \\n\\t\\t * @param reference\\n\\t\\t * @return\\n\\t\\t */\\n\\t\\tpublic CompositeSubRequestResponse getSubResponse(String reference) {\\n\\t\\t\\tif (compositeResponse == null || reference == null) {\\n\\t\\t\\t\\treturn null;\\n\\t\\t\\t}\\n\\t\\t\\tfor (CompositeSubRequestResponse response : compositeResponse) {\\n\\t\\t\\t\\tif (reference.equals(response.getReferenceId())) {\\n\\t\\t\\t\\t\\treturn response;\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t\\treturn null;\\n\\t\\t}\\n\\n\\t\\t/**\\n\\t\\t * Get the Error code for specific request\\n\\t\\t * \\n\\t\\t * @param reference\\n\\t\\t * @return\\n\\t\\t */\\n\\t\\tpublic Object getErrorCode(String reference) {\\n\\t\\t\\tif (compositeResponse == null || reference == null) {\\n\\t\\t\\t\\treturn null;\\n\\t\\t\\t}\\n\\t\\t\\tfor (CompositeSubRequestResponse response : compositeResponse) {\\n\\t\\t\\t\\treturn response.getBody().getClass().getSimpleName();\\n\\t\\t\\t}\\n\\t\\t\\treturn null;\\n\\t\\t}\\n\\n\\t\\t/**\\n\\t\\t * Checks if all requests have successfully executed\\n\\t\\t * \\n\\t\\t * @return\\n\\t\\t */\\n\\t\\tprivate boolean areAllRequestsSuccess() {\\n\\t\\t\\tif (compositeResponse == null) {\\n\\t\\t\\t\\treturn false;\\n\\t\\t\\t}\\n\\n\\t\\t\\tfor (CompositeSubRequestResponse response : compositeResponse) {\\n\\t\\t\\t\\tif (!response.isSuccess()) {\\n\\t\\t\\t\\t\\treturn false;\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\n\\t\\t\\treturn true;\\n\\t\\t}\\n\\n\\t\\tprivate boolean isRequestSuccess(String referenceId) {\\n\\t\\t\\tif (compositeResponse == null || referenceId == null) {\\n\\t\\t\\t\\treturn false;\\n\\t\\t\\t}\\n\\n\\t\\t\\tfor (CompositeSubRequestResponse response : compositeResponse) {\\n\\t\\t\\t\\tif (referenceId.equals(response.getReferenceId()) && response.isSuccess()) {\\n\\t\\t\\t\\t\\treturn true;\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\n\\t\\t\\treturn false;\\n\\t\\t}\\n\\n\\t\\t@Override\\n\\t\\tpublic String toString() {\\n\\t\\t\\treturn ToStringBuilder.reflectionToString(this, ToStringStyle.NO_CLASS_NAME_STYLE);\\n\\t\\t}\\n\\t}\\n\\n\\tclass CompositeSubRequestResponse {\\n\\n\\t\\tprivate String referenceId;\\n\\t\\tprivate String httpStatusCode;\\n\\t\\tprivate Object body = new ArrayList<>();\\n\\t\\tprivate Map<String, String> httpHeaders = new HashMap<>();\\n\\n\\t\\tpublic String getReferenceId() {\\n\\t\\t\\treturn referenceId;\\n\\t\\t}\\n\\n\\t\\tpublic void setReferenceId(String referenceId) {\\n\\t\\t\\tthis.referenceId = referenceId;\\n\\t\\t}\\n\\n\\t\\tpublic String getHttpStatusCode() {\\n\\t\\t\\treturn httpStatusCode;\\n\\t\\t}\\n\\n\\t\\tpublic void setHttpStatusCode(String httpStatusCode) {\\n\\t\\t\\tthis.httpStatusCode = httpStatusCode;\\n\\t\\t}\\n\\n\\t\\tpublic boolean isSuccess() {\\n\\t\\t\\treturn Response.Status.Family.SUCCESSFUL == Response.Status.Family.familyOf(Integer.parseInt(httpStatusCode));\\n\\t\\t}\\n\\n\\t\\tpublic Object getBody() {\\n\\t\\t\\treturn body;\\n\\t\\t}\\n\\n\\t\\tpublic void setBody(List<Body> body) {\\n\\t\\t\\tthis.body = body;\\n\\t\\t}\\n\\n\\t\\tpublic void setBody(Body body) {\\n\\t\\t\\tthis.body = body;\\n\\t\\t}\\n\\n\\t\\tpublic Map<String, String> getHttpHeaders() {\\n\\t\\t\\treturn httpHeaders;\\n\\t\\t}\\n\\n\\t\\tpublic void setHttpHeaders(Map<String, String> httpHeaders) {\\n\\t\\t\\tthis.httpHeaders = httpHeaders;\\n\\t\\t}\\n\\n\\t\\t@Override\\n\\t\\tpublic String toString() {\\n\\t\\t\\treturn ToStringBuilder.reflectionToString(this, ToStringStyle.NO_CLASS_NAME_STYLE);\\n\\t\\t}\\n\\t}\\n\\n\\tclass Body {\\n\\t\\tprivate String id;\\n\\t\\tprivate String message;\\n\\t\\tprivate String errorCode;\\n\\t\\tprivate boolean success;\\n\\t\\tprivate List<String> erros;\\n\\t\\tprivate List<String> fields;\\n\\n\\t\\tpublic String getId() {\\n\\t\\t\\treturn id;\\n\\t\\t}\\n\\n\\t\\tpublic void setId(String id) {\\n\\t\\t\\tthis.id = id;\\n\\t\\t}\\n\\n\\t\\tpublic String getMessage() {\\n\\t\\t\\treturn message;\\n\\t\\t}\\n\\n\\t\\tpublic void setMessage(String message) {\\n\\t\\t\\tthis.message = message;\\n\\t\\t}\\n\\n\\t\\tpublic String getErrorCode() {\\n\\t\\t\\treturn errorCode;\\n\\t\\t}\\n\\n\\t\\tpublic void setErrorCode(String errorCode) {\\n\\t\\t\\tthis.errorCode = errorCode;\\n\\t\\t}\\n\\n\\t\\tpublic boolean isSuccess() {\\n\\t\\t\\treturn success;\\n\\t\\t}\\n\\n\\t\\tpublic void setSuccess(boolean success) {\\n\\t\\t\\tthis.success = success;\\n\\t\\t}\\n\\n\\t\\tpublic List<String> getErros() {\\n\\t\\t\\treturn erros;\\n\\t\\t}\\n\\n\\t\\tpublic void setErros(List<String> erros) {\\n\\t\\t\\tthis.erros = erros;\\n\\t\\t}\\n\\n\\t\\tpublic List<String> getFields() {\\n\\t\\t\\treturn fields;\\n\\t\\t}\\n\\n\\t\\tpublic void setFields(List<String> fields) {\\n\\t\\t\\tthis.fields = fields;\\n\\t\\t}\\n\\n\\t\\t@Override\\n\\t\\tpublic String toString() {\\n\\t\\t\\treturn ToStringBuilder.reflectionToString(this, ToStringStyle.NO_CLASS_NAME_STYLE);\\n\\t\\t}\\n\\n\\t}\\n\\n\\t/**\\n\\t * \\n\\t * Token class containing the access token infos got from SFDC\\n\\t * \\n\\t * @author Youssef IZEM\\n\\t * @lastModifiedVersion 1.0\\n\\t */\\n\\tstatic class Token {\\n\\t\\tprotected Logger log = LoggerFactory.getLogger(this.getClass());\\n\\n\\t\\t@SerializedName(value = \\\"issuedAt\\\", alternate = \\\"issued_at\\\")\\n\\t\\tprivate Date issuedAt;\\n\\t\\t@SerializedName(value = \\\"tokenType\\\", alternate = \\\"token_type\\\")\\n\\t\\tprivate String tokenType;\\n\\t\\t@SerializedName(value = \\\"accessToken\\\", alternate = \\\"access_token\\\")\\n\\t\\tprivate String accessToken;\\n\\t\\t@SerializedName(value = \\\"instanceUrl\\\", alternate = \\\"instance_url\\\")\\n\\t\\tprivate String instanceUrl;\\n\\n\\t\\tpublic void reset() {\\n\\t\\t\\tthis.issuedAt = new Date();\\n\\t\\t\\tthis.tokenType = StringUtils.EMPTY;\\n\\t\\t\\tthis.accessToken = StringUtils.EMPTY;\\n\\t\\t\\tthis.instanceUrl = StringUtils.EMPTY;\\n\\t\\t}\\n\\n\\t\\tpublic Date getIssuedAt() {\\n\\t\\t\\treturn issuedAt;\\n\\t\\t}\\n\\n\\t\\tpublic String getAuth() {\\n\\t\\t\\tif (StringUtils.isBlank(this.tokenType) || StringUtils.isBlank(this.accessToken)) {\\n\\t\\t\\t\\treturn StringUtils.EMPTY;\\n\\t\\t\\t}\\n\\t\\t\\treturn this.tokenType + \\\" \\\" + this.accessToken;\\n\\t\\t}\\n\\n\\t\\tpublic void setIssuedAt(String issuedAt) {\\n\\t\\t\\tthis.issuedAt = new Date(Long.parseLong(issuedAt));\\n\\t\\t}\\n\\n\\t\\tpublic String getTokenType() {\\n\\t\\t\\treturn tokenType;\\n\\t\\t}\\n\\n\\t\\tpublic void setTokenType(String tokenType) {\\n\\t\\t\\tthis.tokenType = tokenType;\\n\\t\\t}\\n\\n\\t\\tpublic String getAccessToken() {\\n\\t\\t\\treturn accessToken;\\n\\t\\t}\\n\\n\\t\\tpublic String getMaskedAccessToken() {\\n\\t\\t\\treturn SObjectSyncingScript.maskString(accessToken);\\n\\t\\t}\\n\\n\\t\\tpublic void setAccessToken(String accessToken) {\\n\\t\\t\\tthis.accessToken = accessToken;\\n\\t\\t}\\n\\n\\t\\tpublic String getInstanceUrl() {\\n\\t\\t\\treturn instanceUrl;\\n\\t\\t}\\n\\n\\t\\tpublic void setInstanceUrl(String instanceUrl) {\\n\\t\\t\\tthis.instanceUrl = instanceUrl;\\n\\t\\t}\\n\\n\\t\\t@Override\\n\\t\\tpublic String toString() {\\n\\t\\t\\treturn String.format(\\\"%s[instanceUrl=%s, tokenType=%s, issuedAt=%s, accessToken=%s]\\\", this.getClass().getSimpleName(), this.instanceUrl, this.tokenType, this.issuedAt,\\n\\t\\t\\t\\tthis.getMaskedAccessToken());\\n\\t\\t}\\n\\t}\\n\\n\\t/**********************************************************************************\\n\\t * \\n\\t * \\n\\t * All business error messages and exception for an object syncing\\n\\t * \\n\\t * @author Youssef IZEM\\n\\t * @lastModifiedVersion 1.0\\n\\t **********************************************************************************/\\n\\n\\t/**\\n\\t * \\n\\t * Keobiz business exception\\n\\t * \\n\\t * @author Youssef IZEM\\n\\t * @lastModifiedVersion 1.0\\n\\t */\\n\\tclass SObjectSyncingException extends BusinessException {\\n\\n\\t\\tprivate static final long serialVersionUID = 1L;\\n\\n\\t\\tprivate IEntity entity;\\n\\t\\tprivate CompositeRequestDto request;\\n\\t\\tprivate Response response;\\n\\t\\tprivate String jsonResponse;\\n\\t\\tprivate boolean isSynced;\\n\\n\\t\\tpublic SObjectSyncingException() {\\n\\t\\t\\tthis.entity = null;\\n\\t\\t\\tthis.request = null;\\n\\t\\t\\tthis.isSynced = false;\\n\\t\\t\\tthis.response = null;\\n\\t\\t\\tthis.jsonResponse = null;\\n\\t\\t}\\n\\n\\t\\tpublic SObjectSyncingException(ErrorMessage errorMessage, Object... args) {\\n\\t\\t\\tsuper(MessageFormat.format(errorMessage.getMessage(), args));\\n\\t\\t}\\n\\n\\t\\tpublic SObjectSyncingException(IEntity entity, CompositeRequestDto request, Response response, String jsonResponse, boolean isSynced, ErrorMessage errorMessage,\\n\\t\\t\\t\\tObject... args) {\\n\\t\\t\\tsuper(MessageFormat.format(errorMessage.getMessage(), args));\\n\\t\\t\\tthis.entity = entity;\\n\\t\\t\\tthis.entity = entity;\\n\\t\\t}\\n\\n\\t}\\n\\n\\t/**\\n\\t * Business Error message list\\n\\t * \\n\\t * @author Youssef IZEM\\n\\t * @lastModifiedVersion 1.0\\n\\t */\\n\\tenum ErrorMessage {\\n\\n\\t\\tENTITY_SYNCING_ERROR(\\\"Error occured during the syncing process of the {0} => {1}\\\"),\\n\\n\\t\\tAUTHENTICATION_ERROR(\\\"Error occured while requesting new token : [{0}:{1}] ==> Response got : {2}\\\"),\\n\\n\\t\\tAUTHENTICATION_ERROR_UNKNOWN(\\\"Unknown error occured while requesting new token : {0}\\\"),\\n\\n\\t\\tPAGE_NOT_FOUND(\\\"Target resource not found : {0}\\\"),\\n\\n\\t\\tMETHOD_NOT_ALLOWED(\\\"Method not supported by this API\\\");\\n\\n\\t\\tprivate final String message;\\n\\n\\t\\tErrorMessage(String message) {\\n\\t\\t\\tthis.message = message;\\n\\t\\t}\\n\\n\\t\\tpublic String getMessage(Object... args) {\\n\\t\\t\\treturn MessageFormat.format(message, args);\\n\\t\\t}\\n\\n\\t}\\n\\n}\\n\",\r\n                \"type\": \"JAVA\"\r\n            }\r\n        },\r\n        {\r\n        \t\"notification\" : {\r\n\t\t\t    \"code\": \"SalesforceInvoiceSyncing\",\r\n\t\t\t\t\"runAsync\": false,\r\n\t\t\t    \"description\": \"Invoice syncing with Salesforce\",\r\n\t\t\t    \"classNameFilter\": \"org.meveo.model.billing.Invoice\",\r\n\t\t\t    \"eventTypeFilter\": \"UPDATED\",\r\n\t\t\t\t\"elFilter\": \"#{event.invoiceNumber != null && event.recordedInvoice != null}\",\r\n\t\t\t\t\"disabled\": false,\r\n\t\t\t\t\"saveSuccessfulNotifications\": false,\r\n\t\t\t    \"scriptInstanceCode\": \"org.opencell.eeko.service.script.syncing.SObjectSyncingScript\"\r\n        \t}\r\n        },\r\n\t\t{\r\n        \t\"notification\" : {\r\n\t\t\t    \"code\": \"SalesforceAccountOperationSyncing\",\r\n\t\t\t\t\"runAsync\": false,\r\n\t\t\t    \"description\": \"AO syncing with Salesforce\",\r\n\t\t\t    \"classNameFilter\": \"org.meveo.model.payments.AccountOperation\",\r\n\t\t\t    \"eventTypeFilter\": \"CREATED\",\r\n\t\t\t\t\"disabled\": false,\r\n\t\t\t\t\"saveSuccessfulNotifications\": false,\r\n\t\t\t\t\"scriptInstanceCode\": \"org.opencell.eeko.service.script.syncing.SObjectSyncingScript\"\r\n        \t}\r\n        },\r\n\t\t{\r\n        \t\"notification\" : {\r\n\t\t\t    \"code\": \"SalesforceMatchedAccountOperationSyncing\",\r\n\t\t\t\t\"runAsync\": false,\r\n\t\t\t    \"description\": \"Update AO already sent to SFDC after being matched on OC\",\r\n\t\t\t    \"classNameFilter\": \"org.meveo.model.payments.MatchingCode\",\r\n\t\t\t    \"eventTypeFilter\": \"CREATED\",\r\n\t\t\t\t\"disabled\": false,\r\n\t\t\t\t\"saveSuccessfulNotifications\": false,\r\n\t\t\t    \"scriptInstanceCode\": \"org.opencell.eeko.service.script.syncing.SObjectSyncingScript\"\r\n        \t}\r\n        },\r\n\t\t{\r\n        \t\"notification\" : {\r\n\t\t\t    \"code\": \"SalesforceCreatedSubscriptionSyncing\",\r\n\t\t\t\t\"runAsync\": false,\r\n\t\t\t    \"description\": \"Subscription syncing with Salesforce\",\r\n\t\t\t    \"classNameFilter\": \"org.meveo.model.billing.Subscription\",\r\n\t\t\t    \"eventTypeFilter\": \"CREATED\",\r\n\t\t\t\t\"disabled\": false,\r\n\t\t\t\t\"saveSuccessfulNotifications\": false,\r\n\t\t\t\t\"scriptInstanceCode\": \"org.opencell.eeko.service.script.syncing.SObjectSyncingScript\"\r\n        \t}\r\n        },\r\n\t\t{\r\n        \t\"notification\" : {\r\n\t\t\t    \"code\": \"SalesforceUpdatedSubscriptionSyncing\",\r\n\t\t\t\t\"runAsync\": false,\r\n\t\t\t    \"description\": \"Subscription syncing with Salesforce\",\r\n\t\t\t    \"classNameFilter\": \"org.meveo.model.billing.Subscription\",\r\n\t\t\t    \"eventTypeFilter\": \"UPDATED\",\r\n\t\t\t\t\"disabled\": false,\r\n\t\t\t\t\"saveSuccessfulNotifications\": false,\r\n\t\t\t    \"scriptInstanceCode\": \"org.opencell.eeko.service.script.syncing.SObjectSyncingScript\"\r\n        \t}\r\n        },\r\n\t\t{\r\n            \"filter\": {\r\n                \"code\": \"SFDC_INVOICE_TO_SYNC_FILTER\",\r\n                \"disabled\": false,\r\n                \"shared\": false,\r\n\t\t\t\t\"pollingQuery\": \"select inv from Invoice inv where (inv.cfValues is not null and inv.cfValues like '%\\\"CF_ENTITY_IS_SYNCED\\\":[{\\\"boolean\\\":false}]%')\",\r\n                \"inputXml\": \"<filter>\\r\\n   <disabled>false<\\/disabled><secondarySelectors\\/><\\/filter>\"\r\n            }\r\n        },\r\n\t\t{\r\n            \"filter\": {\r\n                \"code\": \"SFDC_SUBSCRIPTION_TO_SYNC_FILTER\",\r\n                \"disabled\": false,\r\n                \"shared\": false,\r\n\t\t\t\t\"pollingQuery\": \"select sub from Subscription sub where (sub.cfValues is not null and sub.cfValues like '%\\\"CF_ENTITY_IS_SYNCED\\\":[{\\\"boolean\\\":true}]%') AND (ao.cfValues is not null and ao.cfValues like '%\\\"CF_ENTITY_IS_SYNCED\\\":[{\\\"boolean\\\":false}]%')\",\r\n                \"inputXml\": \"<filter>\\r\\n   <disabled>false<\\/disabled><secondarySelectors\\/><\\/filter>\"\r\n            }\r\n        },\t\t\r\n\t\t{\r\n            \"filter\": {\r\n                \"code\": \"SFDC_ACCOUNT_OPERATION_TO_SYNC_FILTER\",\r\n                \"disabled\": false,\r\n                \"shared\": false,\r\n\t\t\t\t\"pollingQuery\": \"select ao from AccountOperation ao where (ao.cfValues is not null and ao.cfValues like '%\\\"CF_ENTITY_IS_SYNCED\\\":[{\\\"boolean\\\":false}]%')\",\r\n                \"inputXml\": \"<filter>\\r\\n   <disabled>false<\\/disabled><secondarySelectors\\/><\\/filter>\"\r\n            }\r\n        },\r\n        {\r\n            \"jobInstance\": {\r\n                \"code\": \"SalesforceInvoiceSyncingJob\",\r\n                \"jobTemplate\": \"FilteringJob\",\r\n\t\t\t\t\"disabled\": true,\r\n                \"customFields\": {\r\n                    \"customField\": [\r\n                        {\r\n                            \"code\": \"FilteringJob_recordVariableName\",\r\n                            \"stringValue\": \"CONTEXT_ENTITY\"\r\n                        },\r\n                        {\r\n                            \"code\": \"FilteringJob_filter\",\r\n                            \"entityReferenceValue\": {\r\n                                \"classname\": \"org.meveo.model.filter.Filter\",\r\n                                \"code\": \"SFDC_INVOICE_TO_SYNC_FILTER\"\r\n                            }\r\n                        },\r\n                        {\r\n                            \"code\": \"FilteringJob_script\",\r\n                            \"entityReferenceValue\": {\r\n                                \"classname\": \"org.meveo.model.scripts.ScriptInstance\",\r\n                                \"code\": \"org.opencell.eeko.service.script.syncing.SObjectSyncingScript\"\r\n                            }\r\n                        }\r\n                    ]\r\n                },\r\n                \"limitToSingleNode\": true,\r\n                \"verboseReport\": true\r\n            }\r\n        },\r\n\t\t{\r\n            \"jobInstance\": {\r\n                \"code\": \"SalesforceSubscriptionSyncingJob\",\r\n                \"jobTemplate\": \"FilteringJob\",\r\n\t\t\t\t\"disabled\": true,\r\n                \"customFields\": {\r\n                    \"customField\": [\r\n                        {\r\n                            \"code\": \"FilteringJob_recordVariableName\",\r\n                            \"stringValue\": \"CONTEXT_ENTITY\"\r\n                        },\r\n                        {\r\n                            \"code\": \"FilteringJob_filter\",\r\n                            \"entityReferenceValue\": {\r\n                                \"classname\": \"org.meveo.model.filter.Filter\",\r\n                                \"code\": \"SFDC_SUBSCRIPTION_TO_SYNC_FILTER\"\r\n                            }\r\n                        },\r\n                        {\r\n                            \"code\": \"FilteringJob_script\",\r\n                            \"entityReferenceValue\": {\r\n                                \"classname\": \"org.meveo.model.scripts.ScriptInstance\",\r\n                                \"code\": \"org.opencell.eeko.service.script.syncing.SObjectSyncingScript\"\r\n                            }\r\n                        }\r\n                    ]\r\n                },\r\n                \"limitToSingleNode\": true,\r\n                \"verboseReport\": true\r\n            }\r\n\t\t},\r\n \t\t{\r\n            \"jobInstance\": {\r\n                \"code\": \"SalesforceAccountOperationSyncingJob\",\r\n                \"jobTemplate\": \"FilteringJob\",\r\n\t\t\t\t\"disabled\": true,\r\n                \"customFields\": {\r\n                    \"customField\": [\r\n                        {\r\n                            \"code\": \"FilteringJob_filter\",\r\n                            \"entityReferenceValue\": {\r\n                                \"classname\": \"org.meveo.model.filter.Filter\",\r\n                                \"code\": \"SFDC_ACCOUNT_OPERATION_TO_SYNC_FILTER\"\r\n                            }\r\n                        },\r\n                        {\r\n                            \"code\": \"FilteringJob_recordVariableName\",\r\n                            \"stringValue\": \"CONTEXT_ENTITY\"\r\n                        },\r\n                        {\r\n                            \"code\": \"FilteringJob_script\",\r\n                            \"entityReferenceValue\": {\r\n                                \"classname\": \"org.meveo.model.scripts.ScriptInstance\",\r\n                                \"code\": \"org.opencell.eeko.service.script.syncing.SObjectSyncingScript\"\r\n                            }\r\n                        }\r\n                    ]\r\n                },\r\n                \"limitToSingleNode\": true,\r\n                \"verboseReport\": true\r\n            }\r\n        },\r\n\t\t{\r\n            \"customFieldTemplate\": {\r\n                \"code\": \"CF_SFDC_ACCOUNT_FIELDS\",\r\n                \"description\": \"Salesforce account fields\",\r\n                \"disabled\": false,\r\n                \"fieldType\": \"STRING\",\r\n                \"appliesTo\": \"Customer\",\r\n                \"useInheritedAsDefaultValue\": false,\r\n                \"storageType\": \"MAP\",\r\n                \"valueRequired\": false,\r\n                \"uniqueConstraint\": false,\r\n                \"versionable\": false,\r\n                \"triggerEndPeriodEvent\": false,\r\n                \"allowEdit\": true,\r\n                \"hideOnNew\": false,\r\n                \"maxValue\": 200\r\n            }\r\n        },\r\n\t\t{\r\n            \"entityCustomAction\": {\r\n                \"code\": \"INOICE_SYNCING_ACTION\",\r\n                \"appliesTo\": \"Invoice\",\r\n                \"label\": \"Synchronizer\",\r\n\t\t\t\t\"labelsTranslated\": [\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t\"languageCode\": \"FRA\",\r\n\t\t\t\t\t\t\"description\": \"Synchronizer\"\r\n\t\t\t\t\t}\r\n\t\t\t\t],\r\n                \"script\": {\r\n                    \"code\": \"org.opencell.eeko.service.script.syncing.SObjectSyncingScript\"\r\n                }\r\n            }\r\n        },\r\n\t\t{\r\n\t\t\t\"customFieldTemplate\": {\r\n\t\t\t\t\"code\": \"CF_ENTITY_IS_SYNCED\",\r\n\t\t\t\t\"description\": \"Has this Subscription already been synced ?\",\r\n\t\t\t\t\"fieldType\": \"BOOLEAN\",\r\n\t\t\t\t\"appliesTo\": \"Subscription\",\r\n\t\t\t\t\"storageType\": \"SINGLE\",\r\n\t\t\t\t\"valueRequired\": \"false\",\r\n\t\t\t\t\"versionable\": \"false\",\r\n\t\t\t\t\"triggerEndPeriodEvent\": \"false\",\r\n\t\t\t\t\"allowEdit\": \"true\",\r\n\t\t\t\t\"hideOnNew\": \"true\",\r\n\t\t\t\t\"cacheValue\": \"false\"\r\n\t\t\t}\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"customFieldTemplate\": {\r\n\t\t\t\t\"code\": \"CF_ENTITY_IS_SYNCED\",\r\n\t\t\t\t\"description\": \"Has this AO already been synced ?\",\r\n\t\t\t\t\"fieldType\": \"BOOLEAN\",\r\n\t\t\t\t\"appliesTo\": \"AccountOperation\",\r\n\t\t\t\t\"storageType\": \"SINGLE\",\r\n\t\t\t\t\"valueRequired\": \"false\",\r\n\t\t\t\t\"versionable\": \"false\",\r\n\t\t\t\t\"triggerEndPeriodEvent\": \"false\",\r\n\t\t\t\t\"allowEdit\": \"true\",\r\n\t\t\t\t\"hideOnNew\": \"true\",\r\n\t\t\t\t\"cacheValue\": \"false\"\r\n\t\t\t}\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"customFieldTemplate\": {\r\n\t\t\t\t\"code\": \"CF_ENTITY_IS_SYNCED\",\r\n\t\t\t\t\"description\": \"Has this invoice already been synced ?\",\r\n\t\t\t\t\"fieldType\": \"BOOLEAN\",\r\n\t\t\t\t\"appliesTo\": \"Invoice\",\r\n\t\t\t\t\"storageType\": \"SINGLE\",\r\n\t\t\t\t\"valueRequired\": \"false\",\r\n\t\t\t\t\"versionable\": \"false\",\r\n\t\t\t\t\"triggerEndPeriodEvent\": \"false\",\r\n\t\t\t\t\"allowEdit\": \"true\",\r\n\t\t\t\t\"hideOnNew\": \"true\",\r\n\t\t\t\t\"cacheValue\": \"false\"\r\n\t\t\t}\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"customFieldTemplate\": {\r\n\t\t\t\t\"code\": \"CF_SFDC_INVOICE_ID\",\r\n\t\t\t\t\"description\": \"SFDC Invoice ID\",\r\n\t\t\t\t\"fieldType\": \"STRING\",\r\n\t\t\t\t\"appliesTo\": \"Invoice\",\r\n\t\t\t\t\"storageType\": \"SINGLE\",\r\n\t\t\t\t\"valueRequired\": \"false\",\r\n\t\t\t\t\"versionable\": \"false\",\r\n\t\t\t\t\"triggerEndPeriodEvent\": \"false\",\r\n\t\t\t\t\"allowEdit\": \"false\",\r\n\t\t\t\t\"hideOnNew\": \"false\",\r\n\t\t\t\t\"cacheValue\": \"false\"\r\n\t\t\t}\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"customFieldTemplate\": {\r\n\t\t\t\t\"code\": \"CF_SFDC_ATTACHMENT_ID\",\r\n\t\t\t\t\"description\": \"SFDC Attachment ID\",\r\n\t\t\t\t\"fieldType\": \"STRING\",\r\n\t\t\t\t\"appliesTo\": \"Invoice\",\r\n\t\t\t\t\"storageType\": \"SINGLE\",\r\n\t\t\t\t\"valueRequired\": \"false\",\r\n\t\t\t\t\"versionable\": \"false\",\r\n\t\t\t\t\"triggerEndPeriodEvent\": \"false\",\r\n\t\t\t\t\"allowEdit\": \"false\",\r\n\t\t\t\t\"hideOnNew\": \"false\",\r\n\t\t\t\t\"cacheValue\": \"false\"\r\n\t\t\t}\r\n\t\t},\r\n\t\t{\r\n\t\t\t\"customEntityTemplate\": {\r\n                \"code\": \"SYNCING_ERRORS\",\r\n                \"name\": \"SFDC Syncing errors\",\r\n                \"storeAsTable\": true,\r\n                \"fields\": [\r\n                    {\r\n                        \"code\": \"entity_id\",\r\n                        \"description\": \"Entity id\",\r\n                        \"fieldType\": \"STRING\",\r\n                        \"appliesTo\": \"CE_SYNCING_ERRORS\",\r\n                        \"storageType\": \"SINGLE\",\r\n                        \"allowEdit\": false,\r\n                        \"maxValue\": 50\r\n                    },\r\n                    {\r\n                        \"code\": \"entity_code\",\r\n                        \"description\": \"Entity code\",\r\n                        \"fieldType\": \"STRING\",\r\n                        \"appliesTo\": \"CE_SYNCING_ERRORS\",\r\n                        \"storageType\": \"SINGLE\",\r\n                        \"allowEdit\": false,\r\n                        \"maxValue\": 255\r\n                    },\r\n                    {\r\n                        \"code\": \"entity_type\",\r\n                        \"description\": \"Entity type\",\r\n                        \"fieldType\": \"STRING\",\r\n                        \"appliesTo\": \"CE_SYNCING_ERROS\",\r\n                        \"storageType\": \"SINGLE\",\r\n                        \"allowEdit\": false,\r\n                        \"maxValue\": 50\r\n                    },\r\n                    {\r\n                        \"code\": \"syncing_date\",\r\n                        \"description\": \"Syncing date\",\r\n                        \"fieldType\": \"STRING\",\r\n                        \"appliesTo\": \"CE_SYNCING_ERROS\",\r\n                        \"storageType\": \"SINGLE\",\r\n                        \"allowEdit\": false,\r\n                        \"maxValue\": 50\r\n                    },\r\n\t\t\t\t\t{\r\n                        \"code\": \"request_path_info\",\r\n                        \"description\": \"Request path info\",\r\n                        \"fieldType\": \"STRING\",\r\n                        \"appliesTo\": \"CE_SYNCING_ERROS\",\r\n                        \"storageType\": \"SINGLE\",\r\n                        \"allowEdit\": false,\r\n                        \"maxValue\": 255\r\n                    },\r\n\t\t\t\t\t{\r\n                        \"code\": \"request_body\",\r\n                        \"description\": \"Request body\",\r\n                        \"fieldType\": \"STRING\",\r\n                        \"appliesTo\": \"CE_SYNCING_ERROS\",\r\n                        \"storageType\": \"SINGLE\",\r\n                        \"allowEdit\": false,\r\n                        \"maxValue\": 1024\r\n                    },\r\n\t\t\t\t\t{\r\n                        \"code\": \"response_status\",\r\n                        \"description\": \"Response status\",\r\n                        \"fieldType\": \"STRING\",\r\n                        \"appliesTo\": \"CE_SYNCING_ERROS\",\r\n                        \"storageType\": \"SINGLE\",\r\n                        \"allowEdit\": false,\r\n                        \"maxValue\": 100\r\n                    },     \r\n\t\t\t\t\t{\r\n                        \"code\": \"response_message\",\r\n                        \"description\": \"Response message\",\r\n                        \"fieldType\": \"STRING\",\r\n                        \"appliesTo\": \"CE_SYNCING_ERROS\",\r\n                        \"storageType\": \"SINGLE\",\r\n                        \"allowEdit\": false,\r\n                        \"maxValue\": 255\r\n                    },  \r\n\t\t\t\t\t{\r\n                        \"code\": \"response_body\",\r\n                        \"description\": \"Response body\",\r\n                        \"fieldType\": \"STRING\",\r\n                        \"appliesTo\": \"CE_SYNCING_ERROS\",\r\n                        \"storageType\": \"SINGLE\",\r\n                        \"allowEdit\": false,\r\n                        \"maxValue\": 1024\r\n                    } \t\t\t\t\t                          \r\n                ]\r\n            }\r\n        }\r\n    ]\r\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/module/install",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"module",
										"install"
									]
								}
							},
							"response": []
						},
						{
							"name": "BusinessAccountModelModule",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											""
										],
										"type": "text/javascript",
										"packages": {}
									}
								}
							],
							"request": {
								"method": "PUT",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\r\n    \"code\": \"{{request.label}}\",\r\n    \"description\": \"Gets all BAM modules\",\r\n    \"license\": \"COM\",\r\n    \"moduleItems\": [\r\n    \t{\r\n    \t\t\"script\": {\r\n                \"description\": \"API allowing to get all BAM modules\",\r\n                \"script\": \"package org.opencell.eeko.service.script;\\n\\nimport java.util.ArrayList;\\nimport java.util.List;\\nimport java.util.Map;\\n\\nimport org.apache.http.HttpStatus;\\nimport org.meveo.api.dto.ActionStatus;\\nimport org.meveo.api.dto.ActionStatusEnum;\\nimport org.meveo.api.dto.account.BusinessAccountModelDto;\\nimport org.meveo.api.dto.module.MeveoModuleDto;\\nimport org.meveo.api.dto.response.module.MeveoModuleDtosResponse;\\nimport org.meveo.api.exception.MeveoApiException;\\nimport org.meveo.api.module.MeveoModuleApi;\\nimport org.meveo.commons.utils.MillisDate;\\nimport org.meveo.model.crm.BusinessAccountModel;\\nimport org.meveo.model.notification.InboundRequest;\\nimport org.meveo.service.script.Script;\\n\\nimport com.google.gson.Gson;\\nimport com.google.gson.GsonBuilder;\\nimport com.google.gson.JsonArray;\\nimport com.google.gson.JsonObject;\\n\\n\\/**\\n * Api permettant de récupérer la liste des BusinessAccountModel \\n * => En attendant de corriger le bug core #5203\\n * \\n * @author Youssef IZEM\\n * @lastModifiedVersion 1.0\\n *\\/\\npublic class BusinessAccountModelScript extends Script {\\n\\n\\tprivate static final long serialVersionUID = 1L;\\n\\n\\tprivate transient MeveoModuleApi meveoModuleApi = (MeveoModuleApi) getServiceInterface(\\\"MeveoModuleApi\\\");\\n\\n\\t@Override\\n\\tpublic void execute(Map<String, Object> context) {\\n\\n\\t\\tlog.info(\\\">>>>>  BusinessAccountModelScript is running <<<<<<<\\\");\\n\\n\\t\\tInboundRequest inboundRequest = (InboundRequest) context.get(\\\"entityOrEvent\\\");\\n\\t\\tString httpPath = inboundRequest.getPathInfo();\\n\\t\\tString httpMethod = inboundRequest.getMethod();\\n\\t\\tString jsonContent = inboundRequest.getBody();\\n\\t\\tMap<String, String> parameters = inboundRequest.getParameters();\\n\\n\\t\\tlog.info(\\\"Http Call Detail : [Method={}, path={},QueryParams={}, body={}]\\\", httpMethod, httpPath, parameters, jsonContent);\\n\\n\\t\\tint httpStatus = HttpStatus.SC_OK;\\n\\t\\tActionStatus actionStatus = new ActionStatus();\\n\\t\\tString jsonResponse = \\\"\\\";\\n\\n\\t\\ttry {\\n\\n\\t\\t\\tjsonResponse = listModules();\\n\\n\\t\\t} catch (Exception ex) {\\n\\t\\t\\thttpStatus = HttpStatus.SC_BAD_REQUEST;\\n\\t\\t\\tactionStatus.setStatus(ActionStatusEnum.FAIL);\\n\\t\\t\\tactionStatus.setMessage(ex.getMessage());\\n\\t\\t\\tif (ex instanceof MeveoApiException) {\\n\\t\\t\\t\\tactionStatus.setErrorCode(((MeveoApiException) ex).getErrorCode());\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\ttry {\\n\\t\\t\\tinboundRequest.setResponseStatus(httpStatus);\\n\\t\\t\\tinboundRequest.setResponseBody(jsonResponse);\\n\\n\\t\\t} catch (Exception e) {\\n\\t\\t\\tinboundRequest.setResponseStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);\\n\\t\\t\\tinboundRequest.setResponseBody(\\\"Error writing response to inboundRequest response. reason:\\\" + e.getMessage());\\n\\t\\t}\\n\\n\\t\\tlog.info(\\\">>>>>  BusinessAccountModelScript has been successfully completed <<<<<<<\\\");\\n\\t}\\n\\n\\t\\/**\\n\\t * Gets BAM modules list\\n\\t * \\n\\t * @return\\n\\t *\\/\\n\\tprivate String listModules() {\\n\\t\\tlog.info(\\\">>>>>>>  listModules method is running <<<<<<<\\\");\\n\\n\\t\\tMeveoModuleDtosResponse result = meveoModuleApi.list(BusinessAccountModel.class);\\n\\t\\tJsonArray jsonModules = new JsonArray();\\n\\n\\t\\tfor (MeveoModuleDto module : result.getModules()) {\\n\\t\\t\\tif (module instanceof BusinessAccountModelDto) {\\n\\t\\t\\t\\tJsonObject object = new JsonObject();\\n\\t\\t\\t\\tobject.add(\\\"businessAccountModel\\\", gson.toJsonTree(module));\\n\\t\\t\\t\\tjsonModules.add(object);\\n\\t\\t\\t}\\n\\t\\t}\\n\\t\\tJsonObject response = new JsonObject();\\n\\t\\tJsonObject status = new JsonObject();\\n\\n\\t\\tActionStatus actionStatus = new ActionStatus();\\n\\t\\tactionStatus.setStatus(ActionStatusEnum.SUCCESS);\\n\\t\\tstatus.add(\\\"status\\\", gson.toJsonTree(\\\"SUCCESS\\\"));\\n\\n\\t\\tresponse.add(\\\"actionStatus\\\", status);\\n\\t\\tresponse.add(\\\"modules\\\", jsonModules);\\n\\n\\t\\tlog.info(\\\">>>>>>>  findInvoice method  has been successfully completed <<<<<<<\\\");\\n\\t\\treturn gson.toJson(response);\\n\\t}\\n\\n\\t\\/**\\n\\t * Gets BAM modules list\\n\\t * \\n\\t * @return\\n\\t *\\/\\n\\tprivate List<MeveoModuleDto> listModules_v1() {\\n\\t\\tlog.info(\\\">>>>>>>  listModules method is running <<<<<<<\\\");\\n\\n\\t\\tList<MeveoModuleDto> modules = new ArrayList<>();\\n\\t\\tMeveoModuleDtosResponse result = meveoModuleApi.list(BusinessAccountModel.class);\\n\\n\\t\\tfor (MeveoModuleDto module : result.getModules()) {\\n\\t\\t\\tif (module instanceof BusinessAccountModelDto) {\\n\\t\\t\\t\\tmodules.add(module);\\n\\t\\t\\t}\\n\\t\\t}\\n\\n\\t\\tlog.info(\\\">>>>>>>  findInvoice method  has been successfully completed <<<<<<<\\\");\\n\\t\\treturn modules;\\n\\t}\\n\\n\\tstatic Gson gson = null;\\n\\tstatic {\\n\\t\\tGsonBuilder builder = new GsonBuilder();\\n\\t\\tbuilder.setVersion(1.0);\\n\\t\\tgson = builder.setPrettyPrinting().registerTypeAdapter(java.util.Date.class, new MillisDate()).create();\\n\\t}\\n\\n}\\n\",\r\n                \"type\": \"JAVA\"\r\n            }\r\n        },\r\n        {\r\n        \t\"notification\" : {\r\n\t\t\t    \"code\": \"BusinessAccountModelInbound\",\r\n\t\t\t    \"description\": \"API allowing to get all BAM modules\",\r\n\t\t\t    \"classNameFilter\": \"org.meveo.model.notification.InboundRequest\",\r\n\t\t\t    \"eventTypeFilter\": \"INBOUND_REQ\",\r\n\t\t\t    \"elFilter\": \"#{event.pathInfo.equals(\\\"/account/businessAccountModel/list\\\")}\",\r\n\t\t\t    \"scriptInstanceCode\": \"org.opencell.eeko.service.script.BusinessAccountModelScript\"\r\n        \t}\r\n        }\r\n        \r\n    ]\r\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/module/install",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"module",
										"install"
									]
								}
							},
							"response": []
						}
					]
				},
				{
					"name": "Global properties",
					"item": [
						{
							"name": "salesforce.url",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											""
										],
										"type": "text/javascript"
									}
								},
								{
									"listen": "prerequest",
									"script": {
										"exec": [
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\r\n  \t\"property\": \"{{request.label}}\",\r\n\t\"value\": \"https://test.salesforce.com\"\r\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/configurations",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"configurations"
									]
								}
							},
							"response": []
						},
						{
							"name": "salesforce.username",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											""
										],
										"type": "text/javascript"
									}
								},
								{
									"listen": "prerequest",
									"script": {
										"exec": [
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\r\n  \t\"property\": \"{{request.label}}\",\r\n\t\"value\": \"youssef.izem@opencellsoft.com.eeko.devsay\"\r\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/configurations",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"configurations"
									]
								}
							},
							"response": []
						},
						{
							"name": "salesforce.password",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											""
										],
										"type": "text/javascript"
									}
								},
								{
									"listen": "prerequest",
									"script": {
										"exec": [
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\r\n  \t\"property\": \"{{request.label}}\",\r\n\t\"value\": \"Douze=3fois4\"\r\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/configurations",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"configurations"
									]
								}
							},
							"response": []
						},
						{
							"name": "salesforce.clientId",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											""
										],
										"type": "text/javascript"
									}
								},
								{
									"listen": "prerequest",
									"script": {
										"exec": [
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\r\n  \t\"property\": \"{{request.label}}\",\r\n\t\"value\": \"3MVG9Lu3LaaTCEgJ1gvddPIi1TxGBBGjtTfWz_k.xPK_LqaJSQgtM4D9Pks0s.uC02FYNtAf3rmAgykwevYoO\"\r\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/configurations",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"configurations"
									]
								}
							},
							"response": []
						},
						{
							"name": "salesforce.clientSecret",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											""
										],
										"type": "text/javascript"
									}
								},
								{
									"listen": "prerequest",
									"script": {
										"exec": [
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/json"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "{\r\n  \t\"property\": \"{{request.label}}\",\r\n\t\"value\": \"2F3CAA6AF86A2096C4FD83B945F3EFEEADDCC232770567D47A4B7D93C7D50362\"\r\n}"
								},
								"url": {
									"raw": "{{opencell.url}}/configurations",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"configurations"
									]
								}
							},
							"response": []
						}
					]
				}
			]
		},
		{
			"name": "patchs",
			"item": [
				{
					"name": "CheckRoundingAmountsNotif",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"code\": \"CheckRoundingAmountsNotif\",\r\n    \"runAsync\": false,\r\n    \"description\": \"Check Rounding Amounts Notif\",\r\n    \"classNameFilter\": \"org.meveo.model.billing.Invoice\",\r\n    \"eventTypeFilter\": \"UPDATED\",\r\n    \"elFilter\": \"#{event.invoiceNumber != null && event.comment == null && event.invoiceType.code !='ADJ'}\",\r\n    \"disabled\": false,\r\n    \"saveSuccessfulNotifications\": false,\r\n    \"scriptInstanceCode\": \"com.opencellsoft.service.ekko.invoicing.CheckRoundingAmountsScript\"\r\n}",
							"options": {
								"raw": {
									"language": "json"
								}
							}
						},
						"url": {
							"raw": "{{opencell.url}}/notification/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"notification",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "FR_BANKING_2024",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n    \"code\": \"FR_BANKING_2024\",\n    \"description\": \"Jours Fériés France 2024\",\n    \"calendarType\":\"BANKING\",\n    \"startDate\":\"2024-01-01\",\n    \"endDate\":\"2024-12-31\",\n    \"weekendBegin\":6,\n    \"weekendEnd\" : 7,\n    \"holidays\":[\n        {\"holidayBegin\":101,\"holidayEnd\":101},\n        {\"holidayBegin\":401,\"holidayEnd\":401},\n         {\"holidayBegin\":501,\"holidayEnd\":501},\n         {\"holidayBegin\":508,\"holidayEnd\":508},\n         {\"holidayBegin\":509,\"holidayEnd\":509},\n         {\"holidayBegin\":520,\"holidayEnd\":520},\n         {\"holidayBegin\":714,\"holidayEnd\":714},\n         {\"holidayBegin\":815,\"holidayEnd\":815},\n         {\"holidayBegin\":1101,\"holidayEnd\":1101},\n         {\"holidayBegin\":1111,\"holidayEnd\":1111},\n         {\"holidayBegin\":1225,\"holidayEnd\":1225}\n\n    ]\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/calendar/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"calendar",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "BlankGatewayScript",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/xml"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.payment.BlankGatewayScript\" description=\"Ekko Blank gateway script\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.payment;\r\n\r\nimport java.util.Map;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.service.script.payment.PaymentScript;\r\n\r\npublic class BlankGatewayScript extends PaymentScript{\r\n\r\n\tprivate static final long serialVersionUID = 1L;\r\n\t\r\n\tpublic void createCardToken(Map<String, Object> methodContext) throws BusinessException {           \r\n        methodContext.put(PaymentScript.RESULT_TOKEN, \"7ced0000-3ab2-000d-6a50-08d4b8a6\"+(int )(Math.random() * 1000 + 1));\r\n    }\r\n    public void doPaymentToken(Map<String, Object> methodContext) throws BusinessException {\r\n       throw new BusinessException(\"There no gateway to process payment\");\r\n    }\r\n      public void doPaymentCard(Map<String, Object> methodContext) throws BusinessException {\r\n    \t  throw new BusinessException(\"There no gateway to process payment\");\r\n    }\r\n  \r\n    public void doRefundToken(Map<String, Object> methodContext) throws BusinessException {\r\n    \t throw new BusinessException(\"There no gateway to process refund\");\r\n    }\r\n   public void doRefundCard(Map<String, Object> methodContext) throws BusinessException {\r\n\t   throw new BusinessException(\"There no gateway to process refund\");\r\n    }\r\n     \r\n}\r\n ]]>\r\n            </script>\r\n</ScriptInstance>"
						},
						"url": {
							"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"scriptInstance",
								"createOrUpdate"
							]
						},
						"description": "A Custom script to compute CUrrent Month Date range."
					},
					"response": []
				},
				{
					"name": "ADJ",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "test",
								"value": "test"
							},
							{
								"key": "Authorization",
								"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n    \"code\": \"ADJ\",\n    \"description\": \"Adjustement\",\n    \"occTemplateCode\": \"INV_CRN\",\n    \"occTemplateNegativeCode\": \"INV_STD\",\n     \"customInvoiceXmlScriptInstanceCode\":\"com.opencellsoft.service.ekko.invoicing.InvoiceXmlScript\",\n    \"sequenceDto\": {\n    \t\"prefixEL\": \"4\",    \n        \"invoiceSequenceCode\": \"REC_SEQ\"\n    },\n    \"appliesTo\":[\"REC\",\"UPF\"]\n    ,\n    \"matchingAuto\": false,\n    \"billingTemplateNameEL\": \"#{mv:executeScript(invoice, 'com.opencellsoft.service.ekko.invoicing.TemplateNameScript', '')}\",\n    \"useSelfSequence\": false,\n    \"sellerSequence\": {}\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/invoiceType/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"invoiceType",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "blankGateway",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Authorization",
								"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"code\": \"BLANK_GATEWAY\",\r\n    \"description\": \"Empty gateway\",\r\n    \"paymentMethodType\": \"CARD\",\r\n    \"type\": \"CUSTOM\",\r\n    \"scriptInstanceCode\": \"com.opencellsoft.service.ekko.payment.BlankGatewayScript\",\r\n    \"sellerCode\":\"EKKO\"\r\n}",
							"options": {
								"raw": {
									"language": "json"
								}
							}
						},
						"url": {
							"raw": "{{opencell.url}}/payment/paymentGateway",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"payment",
								"paymentGateway"
							]
						}
					},
					"response": []
				},
				{
					"name": "delete pg1",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "DELETE",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Authorization",
								"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"code\": \"BLANK_GATEWAY\",\r\n    \"description\": \"Empty gateway\",\r\n    \"paymentMethodType\": \"CARD\",\r\n    \"type\": \"CUSTOM\",\r\n    \"scriptInstanceCode\": \"com.opencellsoft.service.ekko.payment.BlankGatewayScript\",\r\n    \"sellerCode\":\"EKKO\"\r\n}",
							"options": {
								"raw": {
									"language": "json"
								}
							}
						},
						"url": {
							"raw": "{{opencell.url}}/payment/paymentGateway?code=SLIMPAY_SEPA",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"payment",
								"paymentGateway"
							],
							"query": [
								{
									"key": "code",
									"value": "SLIMPAY_SEPA"
								}
							]
						}
					},
					"response": []
				},
				{
					"name": "delete pg2",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "DELETE",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Authorization",
								"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"code\": \"BLANK_GATEWAY\",\r\n    \"description\": \"Empty gateway\",\r\n    \"paymentMethodType\": \"CARD\",\r\n    \"type\": \"CUSTOM\",\r\n    \"scriptInstanceCode\": \"com.opencellsoft.service.ekko.payment.BlankGatewayScript\",\r\n    \"sellerCode\":\"EKKO\"\r\n}",
							"options": {
								"raw": {
									"language": "json"
								}
							}
						},
						"url": {
							"raw": "{{opencell.url}}/payment/paymentGateway?code=customGatewayDemo",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"payment",
								"paymentGateway"
							],
							"query": [
								{
									"key": "code",
									"value": "customGatewayDemo"
								}
							]
						}
					},
					"response": []
				},
				{
					"name": "delete pg3",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "DELETE",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Authorization",
								"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"code\": \"BLANK_GATEWAY\",\r\n    \"description\": \"Empty gateway\",\r\n    \"paymentMethodType\": \"CARD\",\r\n    \"type\": \"CUSTOM\",\r\n    \"scriptInstanceCode\": \"com.opencellsoft.service.ekko.payment.BlankGatewayScript\",\r\n    \"sellerCode\":\"EKKO\"\r\n}",
							"options": {
								"raw": {
									"language": "json"
								}
							}
						},
						"url": {
							"raw": "{{opencell.url}}/payment/paymentGateway?code=INGENICO_OGONE_CARD",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"payment",
								"paymentGateway"
							],
							"query": [
								{
									"key": "code",
									"value": "INGENICO_OGONE_CARD"
								}
							]
						}
					},
					"response": []
				},
				{
					"name": "delete pg4",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "DELETE",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Authorization",
								"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\r\n    \"code\": \"BLANK_GATEWAY\",\r\n    \"description\": \"Empty gateway\",\r\n    \"paymentMethodType\": \"CARD\",\r\n    \"type\": \"CUSTOM\",\r\n    \"scriptInstanceCode\": \"com.opencellsoft.service.ekko.payment.BlankGatewayScript\",\r\n    \"sellerCode\":\"EKKO\"\r\n}",
							"options": {
								"raw": {
									"language": "json"
								}
							}
						},
						"url": {
							"raw": "{{opencell.url}}/payment/paymentGateway?code=INGENICO_OGONE_SEPA",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"payment",
								"paymentGateway"
							],
							"query": [
								{
									"key": "code",
									"value": "INGENICO_OGONE_SEPA"
								}
							]
						}
					},
					"response": []
				},
				{
					"name": "TR_SIMPLE_REASON",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							},
							{
								"key": "Authorization",
								"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n    \"code\": \"SIMPLE_REASON\",\n    \"description\": \"Termination without fees\",\n    \"applyAgreement\": false,\n    \"applyReimbursment\": false,\n    \"applyTerminationCharges\": false,\n    \"reimburseOneshots\": false\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/terminationReason/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"terminationReason",
								"createOrUpdate"
							]
						}
					},
					"response": []
				},
				{
					"name": "MANUEL",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Successful request\", () => {",
									"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
									"});",
									"",
									""
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/json"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "{\n  \"code\": \"MANUEL\",\n  \"type\": \"SUBSCRIPTION\",\n  \"description\": \"Manuel\",\n  \"invoiceDateDelay\": \"0\",\n  \"dueDateDelayEL\": \"#{mv:executeScript(entity, 'com.opencellsoft.service.ekko.invoicing.DueDateScript', '')}\",\n  \"invoiceDateProductionDelay\": \"0\",\n  \"calendar\": \"MENSUEL\",  \n  \"scriptInstanceCode\":\"com.opencellsoft.service.ekko.invoicing.EkkoBillingCycleScript\"\n}"
						},
						"url": {
							"raw": "{{opencell.url}}/billingCycle/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"billingCycle",
								"createOrUpdate"
							]
						}
					},
					"response": []
				}
			]
		},
		{
			"name": "Last_Scripts",
			"item": [
				{
					"name": "Rating",
					"item": [
						{
							"name": "EkkoRatingScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript",
										"packages": {}
									}
								},
								{
									"listen": "prerequest",
									"script": {
										"exec": [
											""
										],
										"type": "text/javascript",
										"packages": {}
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.rating.EkkoRatingScript\" description=\"Ekko Rating Script\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.rating;\r\n\r\nimport java.math.BigDecimal;\r\nimport java.math.RoundingMode;\r\nimport java.util.HashMap;\r\nimport java.util.Map;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\n\r\nimport org.meveo.model.billing.Subscription;\r\nimport org.meveo.model.billing.Tax;\r\nimport org.meveo.model.billing.WalletOperation;\r\nimport org.meveo.model.billing.WalletOperationStatusEnum;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.model.tax.TaxClass;\r\nimport org.meveo.service.billing.impl.SubscriptionService;\r\nimport org.meveo.service.catalog.impl.TaxService;\r\nimport org.meveo.service.script.Script;\r\nimport org.meveo.service.tax.TaxClassService;\r\n\r\n/**\r\n * \r\n * @author anasseh\r\n * \r\n *   02/05/2022 : ENG382-84 occurence remise\r\n *\r\n */\r\npublic class EkkoRatingScript extends Script {\r\n\r\n\tprivate static final long serialVersionUID = 1L;\r\n\r\n\tprivate SubscriptionService subscriptionService = (SubscriptionService) getServiceInterface(\"SubscriptionService\");\r\n\r\n\tprivate TaxService taxService = (TaxService) getServiceInterface(\"TaxService\");\r\n\tprivate TaxClassService taxClassService = (TaxClassService) getServiceInterface(\"TaxClassService\");\r\n\r\n\tprivate static Map<BigDecimal, String> taxMapping = new HashMap<>();\r\n\r\n\t//mapping of taxPercent to tax code\r\n\tstatic {\r\n\t\ttaxMapping.put(new BigDecimal(\"20\"), \"TVA_20:BF\");\r\n\t\ttaxMapping.put(new BigDecimal(\"5.5\"), \"TVA_55:B2\");\r\n\t\ttaxMapping.put(new BigDecimal(\"10\"), \"TVA_10:BE\");\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void execute(Map<String, Object> context) throws BusinessException {\r\n\r\n\t\tWalletOperation wo = (WalletOperation) context.get(Script.CONTEXT_ENTITY);\r\n\r\n\t\tif (wo.getSubscription() == null) {\r\n\t\t\tthrow new BusinessException(\"wo.subscription is null\");\r\n\t\t}\r\n\t\tif(wo.getCode().equals(\"CH_OS_EKKO_RESIL\")) {\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tMap<String, Double> prices = (Map<String, Double>) wo.getSubscription().getCfValue(\"CF_SUB_PRICES\");\r\n\t\tMap<String, String> labels = (Map<String, String>) wo.getSubscription().getCfValue(\"CF_SUB_LABELS\");\r\n\r\n\t\tlog.info(\"woCode:{}, operationDate:{}, subscriptionDate:{}, CF prices:{} \", wo.getCode(), DateUtils.formatAsDate(wo.getOperationDate()),\r\n\t\t\t\tDateUtils.formatAsDate(wo.getSubscriptionDate()), prices);\r\n\r\n\r\n\t\two.setDescription(labels.get(wo.getCode()));\r\n\r\n\t\tif (wo.getCode().startsWith(\"CH_REC\") && DateUtils.getMonthFromDate(wo.getOperationDate()).intValue() == DateUtils.getMonthFromDate(wo.getSubscriptionDate()).intValue()\r\n\t\t\t\t&& DateUtils.getYearFromDate(wo.getOperationDate()).intValue() == DateUtils.getYearFromDate(wo.getSubscriptionDate()).intValue()) {\r\n\r\n\t\t\two.setAmountTax(BigDecimal.ZERO);\r\n\t\t\two.setAmountWithoutTax(BigDecimal.ZERO);\r\n\t\t\two.setAmountWithTax(BigDecimal.ZERO);\r\n\r\n\t\t\two.setUnitAmountTax(BigDecimal.ZERO);\r\n\t\t\two.setUnitAmountWithoutTax(BigDecimal.ZERO);\r\n\t\t\two.setUnitAmountWithTax(BigDecimal.ZERO);\r\n\t\t\two.setStatus(WalletOperationStatusEnum.CANCELED);\r\n\t\t} else {\r\n\t\t\tif(prices == null || prices.isEmpty() || !prices.containsKey(wo.getCode()+ \"_HT\")) {\r\n\t\t\t\tthrow new BusinessException(\"Prices for charge :\"+wo.getCode()+\" not found\");\r\n\t\t\t}\r\n\t\t\t\r\n\t\t\tcheckLineOrderAmounts(wo.getSubscription().getCode(), wo.getCode(), prices.get(wo.getCode() + \"_HT\"), prices.get(wo.getCode() + \"_T\"),\r\n\t\t\t\t\tprices.get(wo.getCode() + \"_TTC\"), prices.get(wo.getCode() + \"_TX\"));\r\n\r\n\t\t\two.setAmountTax(new BigDecimal(prices.get(wo.getCode() + \"_T\")));\r\n\t\t\two.setAmountWithoutTax(new BigDecimal(prices.get(wo.getCode() + \"_HT\")));\r\n\t\t\two.setAmountWithTax(new BigDecimal(prices.get(wo.getCode() + \"_TTC\")));\r\n\r\n\t\t\two.setUnitAmountTax(new BigDecimal(prices.get(wo.getCode() + \"_T\")));\r\n\t\t\two.setUnitAmountWithoutTax(new BigDecimal(prices.get(wo.getCode() + \"_HT\")));\r\n\t\t\two.setUnitAmountWithTax(new BigDecimal(prices.get(wo.getCode() + \"_TTC\")));\r\n\r\n\t\t\t// tax is optional in prices CF\r\n\t\t\tif (prices.get(wo.getCode() + \"_TX\") != null) {\r\n\t\t\t\tBigDecimal taxPercent = BigDecimal.valueOf(prices.get(wo.getCode() + \"_TX\"));\r\n\t\t\t\tTaxClass taxClass = null;\r\n\t\t\t\tTax tax = null;\r\n\t\t\t\tfor (BigDecimal key : taxMapping.keySet()) {\r\n\t\t\t\t\tif (taxPercent.compareTo(key) == 0) {\r\n\t\t\t\t\t\tString[] codes = taxMapping.get(key).split(\":\");\r\n\t\t\t\t\t\ttaxClass = taxClassService.findByCode(codes[0]);\r\n\t\t\t\t\t\ttax = taxService.findByCode(codes[1]);\r\n\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (taxClass == null || tax == null) {\r\n\t\t\t\t\tthrow new BusinessException(\"Tax not found for SF taxPercent \" + taxPercent.setScale(2));\r\n\t\t\t\t}\r\n\r\n\t\t\t\two.setTaxClass(taxClass);\r\n\t\t\t\two.setTax(tax);\r\n\t\t\t\two.setTaxPercent(tax.getPercent());\r\n\t\t\t}\r\n\r\n\t\t\t// if amounts of WO are zero then cancel it\r\n\t\t\tif (wo.getAmountWithoutTax().compareTo(BigDecimal.ZERO) == 0) {\r\n\t\t\t\two.setStatus(WalletOperationStatusEnum.CANCELED);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (wo.getCode().equals(\"CH_REC_EKKO_ABO_REM\")) {\r\n\t\t\t\tSubscription subscription = wo.getSubscription();\r\n\t\t\t\tLong cptRemise = (Long) subscription.getCfValue(\"CF_SUB_CPT_REMISE\");\r\n\t\t\t\tif (cptRemise == null) {\r\n\t\t\t\t\tcptRemise = 0L;\r\n\t\t\t\t}\r\n\t\t\t\tLong nbRemise = null;\r\n\t\t\t\tMap<String, Object> sfData = (Map<String, Object>) subscription.getCfValue(\"CF_SUB_SF_DATA\");\r\n\t\t\t\tif (sfData != null && sfData.get(\"EK_nb_rem_abt\") != null) {\r\n\t\t\t\t\ttry {\r\n\t\t\t\t\t\tnbRemise = Long.valueOf((String) sfData.get(\"EK_nb_rem_abt\"));\r\n\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\tlog.warn(\"EK_nb_rem_abt should be numeric\");\r\n\t\t\t\t\t}\r\n\t\t\t\t}\t\t\t\t\r\n\t\t\t\tif (nbRemise != null && nbRemise != 9999L) {\r\n\t\t\t\t\tif (cptRemise.intValue() >= nbRemise.intValue()) {\r\n\t\t\t\t\t\two.setStatus(WalletOperationStatusEnum.CANCELED);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tcptRemise = cptRemise + 1;\r\n\t\t\t\t\t\tsubscription.setCfValue(\"CF_SUB_CPT_REMISE\", cptRemise);\r\n\t\t\t\t\t\tsubscriptionService.updateNoCheck(subscription);\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t}\r\n\t\r\n\tprivate void checkLineOrderAmounts(String subCode, String chargeCode, Double amountWithoutTax, Double amountTax,\r\n\t\t\t\t\t\t\t\t\t   Double amountWithTax, Double taxPercent) throws BusinessException {\r\n\t\t\r\n\t\tBigDecimal ht;\r\n\t\tBigDecimal tva;\r\n\t\tBigDecimal ttc;\r\n\r\n\t\ttry {\r\n\t\t\tht = BigDecimal.valueOf(amountWithoutTax);\r\n\t\t\ttva = BigDecimal.valueOf(amountTax);\r\n\t\t\tttc = BigDecimal.valueOf(amountWithTax);\r\n\t\t} catch (NumberFormatException e) {\r\n\t\t\tthrow new BusinessException(\r\n\t\t\t\t\t\"Incoherent amounts for order line \" + chargeCode + \": Number format error!\");\r\n\t\t}\r\n\t\t\r\n\t\tif (Math.max(0, ht.stripTrailingZeros().scale()) > 2 || Math.max(0, tva.stripTrailingZeros().scale()) > 2\r\n\t\t\t\t|| Math.max(0, ttc.stripTrailingZeros().scale()) > 2) {\r\n\t\t\tthrow new BusinessException(\"Incoherent amounts for order line \" + chargeCode\r\n\t\t\t\t\t+ \": Amounts with more than 2 decimals!\");\r\n\t\t}\r\n\r\n\t\tif ((ht.add(tva)).compareTo(ttc) != 0) {\r\n\t\t\tthrow new BusinessException(\r\n\t\t\t\t\t\"Incoherent amounts for order line \" + chargeCode + \": HT+TVA != TTC\");\r\n\t\t}\r\n\r\n\t\t// tax percent is optional\r\n\t\tif (taxPercent != null) {\r\n\t\t\tBigDecimal tax = BigDecimal.valueOf(taxPercent).divide(BigDecimal.valueOf(100));\r\n\t\t\tif (tva.compareTo(tax.multiply(ht).setScale(2, RoundingMode.HALF_UP)) != 0) {\r\n\t\t\t\tlog.warn(\"Incoherent amounts for subCode \" + subCode + \" and charge \" + chargeCode + \": HTxTAX != TVA\");\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n\r\n\r\n]]>\r\n            </script>\r\n         </ScriptInstance>\r\n\r\n",
									"options": {
										"raw": {
											"language": "xml"
										}
									}
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						}
					]
				},
				{
					"name": "Invoicing",
					"item": [
						{
							"name": "EkkoBillingCycleScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript",
										"packages": {}
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.invoicing.EkkoBillingCycleScript\" description=\"Ekko Invoicing Script\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.invoicing;\r\n\r\nimport java.util.ArrayList;\r\nimport java.util.Calendar;\r\nimport java.util.Date;\r\nimport java.util.List;\r\nimport java.util.Map;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.model.billing.BillingAccount;\r\nimport org.meveo.model.billing.Invoice;\r\nimport org.meveo.model.billing.InvoiceType;\r\nimport org.meveo.model.billing.RatedTransaction;\r\nimport org.meveo.model.billing.RatedTransactionGroup;\r\nimport org.meveo.model.billing.Subscription;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.service.billing.impl.InvoiceTypeService;\r\nimport org.meveo.service.catalog.impl.CalendarBankingService;\r\nimport org.meveo.service.script.Script;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n/**\r\n * \r\n * @author anasseh \r\n *          26/01/2022 : invoice amount zero \r\n *          20/02/2022 : ENG382-64 Bloquer la facturation des abonnements en masse \r\n *          04/06/2022 : SUPS-1687 + use simu as CF \r\n *          06/07/2002 : last SUPS-1687\r\n *          16/03/2023 : SUPS-2261\r\n *          05/03/2024 : SUPS-1787\r\n *          19/05/2024 : ENG382-192\r\n */\r\npublic class EkkoBillingCycleScript extends Script {\r\n\r\n\tprivate static final long serialVersionUID = 1L;\r\n\tprivate static final String INV_TYPE_REC = \"REC\";\r\n\tprivate static final String INV_TYPE_UPF = \"UPF\";\r\n\tprivate static final String CF_SEL_INV_NB_BUSI_DAYS = \"CF_SEL_INV_NB_BUSI_DAYS\";\r\n\tprivate static final String CF_SEL_INV_NO_REC_INVOICES = \"CF_SEL_INV_NO_REC_INVOICES\";\r\n\tprivate static final String CF_SEL_INV_USE_SIMU_BUSINES_DAY = \"CF_SEL_INV_USE_SIMU_BUSINES_DAY\";\r\n\r\n\tprivate static final Logger log = LoggerFactory.getLogger(EkkoBillingCycleScript.class);\r\n\tprivate InvoiceTypeService invoiceTypeService = (InvoiceTypeService) getServiceInterface(\"InvoiceTypeService\");\r\n\tprivate CalendarBankingService calendarBankingService = (CalendarBankingService) getServiceInterface(\"CalendarBankingService\");\r\n\r\n\t@Override\r\n\tpublic void execute(Map<String, Object> context) throws BusinessException {\r\n\t\tlog.info(\"Execute context : {} \", context);\r\n\t\tList<RatedTransactionGroup> listGroupRts = new ArrayList<RatedTransactionGroup>();\r\n\r\n\t\tif (calendarBankingService.isBankWorkingDate(new Date())) {\r\n\t\t\tcontext.put(Script.RESULT_VALUE, listGroupRts);\r\n\t\t}\r\n\t\t\r\n\t\tSubscription subscription = (Subscription) context.get(\"CONTEXT_ENTITY\");\t\t\r\n\t\t\r\n\t\tif(subscription == null) {\r\n\t\t\tthrow new BusinessException(\"Subscription not found on EkkoBillingCycleScript\");\r\n\t\t}\r\n\t\tlog.info(\"isTheFirstbusinesDay(new Date())=\" + isTheFirstbusinesDay(new Date()));\r\n\r\n\t\tList<RatedTransaction> ratedTransactions = (List<RatedTransaction>) context.get(\"ratedTransactions\");\r\n\t\tRatedTransactionGroup rtGroupRec = new RatedTransactionGroup();\r\n\t\tRatedTransactionGroup rtGroupUpfront = new RatedTransactionGroup();\r\n\t\tInvoiceType recInvoiceType = invoiceTypeService.findByCode(INV_TYPE_REC);\r\n\t\tInvoiceType upfInvoiceType = invoiceTypeService.findByCode(INV_TYPE_UPF);\r\n\r\n\t\trtGroupRec.setInvoiceType(recInvoiceType);\r\n\t\trtGroupRec.setInvoiceKey(recInvoiceType.getCode());\r\n\t\trtGroupRec.setBillingAccount(subscription.getUserAccount().getBillingAccount());\r\n\t\trtGroupRec.setSeller(subscription.getSeller());\r\n\t\trtGroupRec.setBillingCycle(subscription.getBillingCycle());\r\n\r\n\t\trtGroupUpfront.setInvoiceType(upfInvoiceType);\r\n\t\trtGroupUpfront.setInvoiceKey(upfInvoiceType.getCode());\r\n\t\trtGroupUpfront.setBillingAccount(subscription.getUserAccount().getBillingAccount());\r\n\t\trtGroupUpfront.setSeller(subscription.getSeller());\r\n\t\trtGroupUpfront.setBillingCycle(subscription.getBillingCycle());\r\n\r\n\t\tboolean dontGenerateRecInvoices = true;\r\n\t\tboolean useSimuForFistBusinesDay = false;\r\n\t\tif (\"DRAFT\".equals(((InvoiceType) context.get(\"invoiceType\")).getCode())) {\t\t\t\r\n\t\t\tdontGenerateRecInvoices = false;\r\n\t\t} else {\r\n\t\t\tif (subscription.getSeller().getCfValue(CF_SEL_INV_NO_REC_INVOICES) != null) {\r\n\t\t\t\tdontGenerateRecInvoices = (Boolean) subscription.getSeller().getCfValue(CF_SEL_INV_NO_REC_INVOICES);\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (subscription.getSeller().getCfValue(CF_SEL_INV_USE_SIMU_BUSINES_DAY) != null) {\r\n\t\t\tuseSimuForFistBusinesDay = (Boolean) subscription.getSeller().getCfValue(CF_SEL_INV_USE_SIMU_BUSINES_DAY);\r\n\t\t}\r\n\r\n\t\tboolean isUpfInvoiceAlreadyGenerated = false;\r\n\t\tBillingAccount billingAccount = subscription.getUserAccount().getBillingAccount();\r\n\t\tList<Invoice> invoices = billingAccount.getInvoices();\r\n\t\tfor (Invoice invoice : invoices) {\r\n\t\t\tif (invoice.getInvoiceType().getCode().equals(INV_TYPE_UPF)\r\n\t\t\t\t\t&& invoice.getSubscription().getCode().equals(subscription.getCode()) &&\r\n\t\t\t\t\t(invoice.getLinkedInvoices() == null || invoice.getLinkedInvoices().isEmpty())) {\r\n\t\t\t\tisUpfInvoiceAlreadyGenerated = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlog.info(\"getFirstBusinessDayInMonth(new date)=\" + getFirstBusinessDayInMonth(new Date()));\r\n\r\n\t\tfor (RatedTransaction rt : ratedTransactions) {\r\n\t\t\tlog.info(\"rt id:{} Code:{} UsageDate:{} \", rt.getId(), rt.getCode(),\r\n\t\t\t\t\tDateUtils.formatAsDate(rt.getUsageDate()));\r\n\t\t\tboolean isAboCharge = isAboCharge(rt);\r\n\r\n\t\t\tif (isUpfInvoiceAlreadyGenerated || isAboCharge) {\r\n\t\t\t\t// La facture de récurrent est envoyée et reçue le 1er jour ouvré de chaque\r\n\t\t\t\t// mois.\r\n\t\t\t\tif (DateUtils.setDateToStartOfDay(rt.getUsageDate())\r\n\t\t\t\t\t\t.before(DateUtils.setDateToEndOfDay(getFirstBusinessDayInMonth(new Date())))\r\n\t\t\t\t\t\t|| useSimuForFistBusinesDay) {\r\n\t\t\t\t\trtGroupRec.getRatedTransactions().add(rt);\r\n\t\t\t\t\tlog.info(\"END rt id:{} Code:{} UsageDate:{} \", rt.getId(), rt.getCode(),\r\n\t\t\t\t\t\t\tDateUtils.formatAsDate(rt.getUsageDate()));\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (!isAboCharge && !isUpfInvoiceAlreadyGenerated) {\r\n\t\t\t\tif (DateUtils.getDayFromDate(rt.getUsageDate()) <= 25) {\r\n\t\t\t\t\tif ((addBusinessDays(DateUtils.setDateToStartOfDay(rt.getUsageDate()),\r\n\t\t\t\t\t\t\t(Long) subscription.getSeller().getCfValue(CF_SEL_INV_NB_BUSI_DAYS))\r\n\t\t\t\t\t\t\t.before(DateUtils.setDateToEndOfDay(new Date())))) {\r\n\t\t\t\t\t\tlog.info(\"RT upf taken2\");\r\n\t\t\t\t\t\trtGroupUpfront.getRatedTransactions().add(rt);\r\n\t\t\t\t\t\tlog.info(\"END rt id:{} Code:{} UsageDate:{} \", rt.getId(), rt.getCode(),\r\n\t\t\t\t\t\t\t\tDateUtils.formatAsDate(rt.getUsageDate()));\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t\tif (DateUtils.getDayFromDate(rt.getUsageDate()) > 25) {\r\n\t\t\t\t\tlog.info(\"isTheFirstbusinesDay(new Date())=\" + isTheFirstbusinesDay(new Date()));\r\n\t\t\t\t\tlog.info(\"getFirstBusinessDayInMonth(date)=\" + getFirstBusinessDayInMonth(new Date()));\r\n\r\n\t\t\t\t\tif (isTheFirstbusinesDay(new Date()) || useSimuForFistBusinesDay) {\r\n\t\t\t\t\t\tlog.info(\"RT taken1\");\r\n\t\t\t\t\t\trtGroupUpfront.getRatedTransactions().add(rt);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tlog.info(\"RT skiped1\");\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tlog.info(\"END rt id:{} Code:{} UsageDate:{} \", rt.getId(), rt.getCode(),\r\n\t\t\t\t\tDateUtils.formatAsDate(rt.getUsageDate()));\r\n\t\t}\r\n\t\t\r\n\t\tlog.info(\"before listGroupRts:\"+listGroupRts);\r\n\t\tif (!rtGroupUpfront.getRatedTransactions().isEmpty()) {\r\n\t\t\tlistGroupRts.add(rtGroupUpfront);\r\n\t\t}\r\n\t\tif (!rtGroupRec.getRatedTransactions().isEmpty() && !dontGenerateRecInvoices) {\r\n\t\t\tif (isTheFirstbusinesDay(new Date()) || useSimuForFistBusinesDay) {\r\n\t\t\t\tlistGroupRts.add(rtGroupRec);\r\n\t\t\t}\r\n\t\t}\r\n\t\tlog.info(\"after listGroupRts:\"+listGroupRts);\r\n\t\tcontext.put(Script.RESULT_VALUE, listGroupRts);\r\n\r\n\t}\r\n\r\n\tprivate boolean isAboCharge(RatedTransaction rt) {\r\n\t\treturn rt.getCode().startsWith(\"CH_REC\") || rt.getCode().indexOf(\"ABO\") > -1;\r\n\r\n\t}\r\n\r\n\tprivate boolean isTheFirstbusinesDay(Date date) {\r\n\r\n\t\tDate firstBusinessDay = getFirstBusinessDayInMonth(date);\r\n\t\tdate = DateUtils.setDateToStartOfDay(date);\r\n\t\tfirstBusinessDay = DateUtils.setDateToStartOfDay(firstBusinessDay);\r\n\r\n\t\tif (date.compareTo(firstBusinessDay) == 0) {\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\treturn false;\r\n\t}\r\n\r\n\tprivate Date getFirstBusinessDayInMonth(Date dateMonth) {\r\n\r\n\t\tCalendar calendar = Calendar.getInstance();\r\n\t\tcalendar.setTime(dateMonth);\r\n\t\tcalendar.set(Calendar.DAY_OF_MONTH, 2); // dont change this, because the rec charge whill produced at 1 , so\r\n\t\t\t\t\t\t\t\t\t\t\t\t// will not be\r\n\t\t\t\t\t\t\t\t\t\t\t\t// invoiced at 1\r\n\r\n\t\tDate firstBusinessDay = calendar.getTime();\r\n\t\tif (calendarBankingService.isBankWorkingDate(firstBusinessDay)) {\r\n\t\t\treturn firstBusinessDay;\r\n\r\n\t\t}\r\n\r\n\t\twhile (!calendarBankingService.isBankWorkingDate(firstBusinessDay)) {\r\n\t\t\tfirstBusinessDay = DateUtils.addDaysToDate(firstBusinessDay, 1);\r\n\t\t}\r\n\r\n\t\treturn firstBusinessDay;\r\n\t}\r\n\r\n\tprivate Date addBusinessDays(Date dateStart, Long nbDays) {\r\n\r\n\t\tint daysAdded = 0;\r\n\t\tDate endDate = dateStart;\r\n\t\twhile (daysAdded != nbDays.intValue()) {\r\n\t\t\tendDate = DateUtils.addDaysToDate(endDate, 1);\r\n\t\t\tif (calendarBankingService.isBankWorkingDate(endDate)) {\r\n\t\t\t\tdaysAdded++;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn DateUtils.setDateToEndOfDay(endDate);\r\n\t}\r\n\r\n}\r\n\r\n\r\n\r\n\r\n]]>\r\n            </script>\r\n</ScriptInstance>\r\n"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "InvoiceXmlScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript",
										"packages": {}
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.invoicing.InvoiceXmlScript\" description=\"Ekko Invoice Xml Script\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.invoicing;\r\n\r\nimport java.io.File;\r\nimport java.math.BigDecimal;\r\nimport java.math.RoundingMode;\r\nimport java.util.ArrayList;\r\nimport java.util.Comparator;\r\nimport java.util.Date;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.Set;\r\nimport java.util.regex.Matcher;\r\nimport java.util.regex.Pattern;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.commons.utils.StringUtils;\r\nimport org.meveo.model.billing.*;\r\nimport org.meveo.model.payments.AccountOperation;\r\nimport org.meveo.model.payments.OperationCategoryEnum;\r\nimport org.meveo.model.payments.PaymentMethod;\r\nimport org.meveo.model.payments.PaymentMethodEnum;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.service.billing.impl.EkkoXMLInvoiceCreator;\r\nimport org.meveo.service.billing.impl.InvoiceAgregateService;\r\nimport org.meveo.service.billing.impl.InvoiceService;\r\nimport org.meveo.service.billing.impl.RatedTransactionService;\r\nimport org.meveo.service.catalog.impl.CalendarBankingService;\r\nimport org.meveo.service.payments.impl.AccountOperationService;\r\nimport org.meveo.service.script.Script;\r\nimport org.w3c.dom.Document;\r\nimport org.w3c.dom.Element;\r\nimport org.w3c.dom.Text;\r\n\r\nimport static org.meveo.commons.utils.StringUtils.getDefaultIfNull;\r\n\r\n/**\r\n * Generate custom Xml Invoice Execute Context Variable :\r\n * <li>CONTEXT_ENTITY : the invoice\r\n * <li>isVirtual : invoicing mode\r\n * <li>XMLInvoiceCreator : XMLInvoiceCreator std service\r\n *\r\n * @author anasseh\r\n * <p>\r\n * 09/06/2022 SUPS-1686\r\n * 14/07/2022 SUPS-1765 (mounir)\r\n * 18/07/2022 SUPS-1734\r\n * 13/04/2023 SUPS-2447\r\n * 17/04/2023 SUPS-2365\r\n * 21/05/2024 ENG382-176\r\n */\r\npublic class InvoiceXmlScript extends Script {\r\n\r\n    private static final long serialVersionUID = 1L;\r\n    private EkkoXMLInvoiceCreator xmlInvoiceCreatorScript = (EkkoXMLInvoiceCreator) getServiceInterface(\"EkkoXMLInvoiceCreator\");\r\n    private InvoiceService invoiceService = (InvoiceService) getServiceInterface(\"InvoiceService\");\r\n    private RatedTransactionService ratedTransactionService = (RatedTransactionService) getServiceInterface(\"RatedTransactionService\");\r\n    private InvoiceAgregateService invoiceAgregateService = (InvoiceAgregateService) getServiceInterface(\"InvoiceAgregateService\");\r\n    private AccountOperationService accountOperationService = (AccountOperationService) getServiceInterface(\"AccountOperationService\");\r\n    private CalendarBankingService calendarBankingService = (CalendarBankingService) getServiceInterface(\"CalendarBankingService\");\r\n\r\n\r\n    private static final String CF_SUB_PAY_METHOD = \"CF_SUB_PAY_METHOD\";\r\n    private static final String SHIPPING_ADDRESS = \"ShippingAddress\";\r\n    private static final String CF_NbrOfRadiator = \"EK_OPP_NofRadiator__c\";\r\n    private static final String CF_NbrOfRooms = \"EK_OPP_Number_Rooms__c\";\r\n\r\n    private Long nbrOfRadiotor = 0L;\r\n    private Long nbrOfRooms = 0L;\r\n    List<RatedTransaction> rts = new ArrayList<RatedTransaction>();\r\n\r\n    @Override\r\n    public void execute(Map<String, Object> methodContext) throws BusinessException {\r\n        log.debug(\"EXECUTE methodContext {}\", methodContext);\r\n        try {\r\n\r\n            Invoice invoice = (Invoice) methodContext.get(Script.CONTEXT_ENTITY);\r\n            // SUPS-4245: workaround fix\r\n            if (invoice.getStatus().equals(InvoiceStatusEnum.DRAFT) && invoice.getBillingRun() != null\r\n                    && invoice.getBillingRun().getStatus().equals(BillingRunStatusEnum.VALIDATED)) {\r\n                invoiceService.validateAndAssignInvoiceNumberUnit(invoice);\r\n            }\r\n            rts = ratedTransactionService.getRatedTransactionsByInvoice(invoice, true);\r\n            String fullXmlFilePath = invoiceService.getFullXmlFilePath(invoice, true);\r\n            Boolean isVirtual = (Boolean) methodContext.get(\"isVirtual\");\r\n\r\n            // SUPS-2749\r\n            updateInvoiceDueDate(invoice);\r\n\r\n\r\n            Document document = xmlInvoiceCreatorScript.createDocument(invoice, isVirtual, true);\r\n            additionalInfos(document, invoice, \"CF_SUB_SF_DATA\");\r\n            String defaultTemplateName = \"\";\r\n            if (\"ADJ\".equals(invoice.getInvoiceType().getCode())) {\r\n                Set<Invoice> linkedInvoices = invoice.getLinkedInvoices();\r\n                if (linkedInvoices != null && !linkedInvoices.isEmpty()) {\r\n                    Invoice adjustedInvoice = linkedInvoices.iterator().next();\r\n                    defaultTemplateName = adjustedInvoice.getInvoiceType().getCode();\r\n                    document.getDocumentElement().setAttribute(\"adjustedInvoiceDate\",\r\n                            DateUtils.formatDateWithPattern(adjustedInvoice.getInvoiceDate(), \"dd/MM/yyyy\"));\r\n                    createSubscriptionsSection(document, adjustedInvoice);\r\n                } else {\r\n                    List<RatedTransaction> rts = ratedTransactionService.getRatedTransactionsByInvoice(invoice, true);\r\n                    for (RatedTransaction rt : rts) {\r\n                        if (isAboCharge(rt)) {\r\n                            defaultTemplateName = \"REC\";\r\n                        }\r\n                    }\r\n                    if (\"\".equals(defaultTemplateName)) {\r\n                        defaultTemplateName = \"UPF\";\r\n                    }\r\n                }\r\n            }\r\n            log.info(\"defaultTemplateName:\" + defaultTemplateName);\r\n            boolean isAdjInvoice = invoice.getInvoiceType().getCode().equals(\"ADJ\");\r\n            if (\"REC\".equals(invoice.getInvoiceType().getCode()) || \"REC\".equals(defaultTemplateName)) {\r\n                addDetailREC(document, invoice, isAdjInvoice);\r\n                addTotalLInesREC(document, invoice, isAdjInvoice);\r\n            }\r\n            if (\"UPF\".equals(invoice.getInvoiceType().getCode()) || \"UPF\".equals(defaultTemplateName)) {\r\n                addDetailUPF(document, invoice, isAdjInvoice);\r\n                addRefsMats(document);\r\n                addTotalLInesUPF(document, invoice, isAdjInvoice);\r\n            }\r\n\r\n            File file = xmlInvoiceCreatorScript.createFile(document, invoice, fullXmlFilePath);\r\n            methodContext.put(Script.RESULT_VALUE, file);\r\n        } catch (Exception e) {\r\n            log.error(\"Error on producing XML invoice\", e);\r\n            throw new BusinessException(e.getMessage());\r\n        }\r\n    }\r\n\r\n    // update invoice's due date. Mainly util for manuel invoices like of type ADJ\r\n    private void updateInvoiceDueDate(Invoice invoice) {\r\n        Long nbrJourDelay = (Long) invoice.getSubscription().getSeller().getCfValue(\"CF_SEL_PAY_NB_BUSI_DAYS\");\r\n        Date dueDate = addBusinessDays(invoice.getInvoiceDate(), nbrJourDelay);\r\n        invoice.setDueDate(dueDate);\r\n        if (invoice.getSubscription() != null && invoice.getSubscription().getPaymentMethod() != null) {\r\n            invoice.setPaymentMethodType(invoice.getSubscription().getPaymentMethod().getPaymentType());\r\n        }\r\n        invoiceService.updateNoCheck(invoice);\r\n    }\r\n\r\n    private Date addBusinessDays(Date dateStart, Long nbDays) {\r\n        int daysAdded = 0;\r\n        Date endDate = dateStart;\r\n        while (daysAdded != nbDays.intValue()) {\r\n            endDate = DateUtils.addDaysToDate(endDate, 1);\r\n            if (calendarBankingService.isBankWorkingDate(endDate)) {\r\n                daysAdded++;\r\n            }\r\n        }\r\n        return DateUtils.setDateToEndOfDay(endDate);\r\n    }\r\n\r\n    private void addTotalLInesREC(Document document, Invoice invoice, boolean isAdjInvoice) {\r\n        boolean isTotalHTEqualZero = round(invoice.getAmountWithoutTax()).equals(BigDecimal.ZERO);\r\n        Element totauxElement = document.createElement(\"totauxElement\");\r\n\r\n        BigDecimal totalTTC = !isAdjInvoice ? invoice.getAmountWithoutTax() : invoice.getAmountWithoutTax().negate();\r\n\r\n        Element totalHTLineElem = document.createElement(\"totalHT\");\r\n        totalHTLineElem.setAttribute(\"amount\",\r\n                roundFormat(!isAdjInvoice ? invoice.getAmountWithoutTax() : invoice.getAmountWithoutTax().negate()));\r\n        totauxElement.appendChild(totalHTLineElem);\r\n\r\n        List<TaxInvoiceAgregate> taxInvoiceAgregates = new ArrayList<TaxInvoiceAgregate>();\r\n        for (InvoiceAgregate invoiceAgregate : invoice.getInvoiceAgregates()) {\r\n            if (invoiceAgregate instanceof TaxInvoiceAgregate) {\r\n                taxInvoiceAgregates.add((TaxInvoiceAgregate) invoiceAgregate);\r\n            }\r\n        }\r\n        taxInvoiceAgregates.sort(Comparator.comparing(ta -> ta.getTax().getPercent()));\r\n        for (TaxInvoiceAgregate taxInvoiceAgregate : taxInvoiceAgregates) {\r\n\r\n            Element taxElem = document.createElement(\"tvaLine\");\r\n\r\n            taxElem.setAttribute(\"label\", \"TVA (\" + roundFormat(taxInvoiceAgregate.getTaxPercent(), true) + \"%)\");\r\n            BigDecimal amountTax = computeAmountsForTaxes(rts, taxInvoiceAgregate.getTaxPercent())[1];\r\n            amountTax = !isAdjInvoice ? amountTax : amountTax.negate();\r\n            taxElem.setAttribute(\"amount\",\r\n                    (isTotalHTEqualZero ? roundFormat(BigDecimal.ZERO) : roundFormat(amountTax)) + \" €\");\r\n            totauxElement.appendChild(taxElem);\r\n\r\n            totalTTC = totalTTC.add(isTotalHTEqualZero ? BigDecimal.ZERO : round(amountTax));\r\n        }\r\n\r\n        Element totalTTCLineElem = document.createElement(\"totalTTC\");\r\n        totalTTCLineElem.setAttribute(\"amount\", roundFormat(totalTTC));\r\n        totauxElement.appendChild(totalTTCLineElem);\r\n\r\n        // invoice.netToPay = invoice.TTC + totalUnpaidInvoices\r\n        BigDecimal totalUnpaidInvoices = getRappelSolde(invoice);\r\n        //BigDecimal totalUnpaidInvoices = invoice.getNetToPay().subtract(totalTTC);\r\n\r\n        // line rappel du solde\r\n        if (totalUnpaidInvoices.compareTo(BigDecimal.ZERO) != 0) {\r\n            Element totalLineElt = document.createElement(\"totalLine\");\r\n\r\n            totalLineElt.setAttribute(\"label\", \"Rappel du solde restant d\\u00FB\");\r\n            totalLineElt.setAttribute(\"amount\", roundFormat(totalUnpaidInvoices) + \" €\");\r\n            totauxElement.appendChild(totalLineElt);\r\n        }\r\n        // line net to pay\r\n        BigDecimal netToPay = !isAdjInvoice ? invoice.getAmountWithTax() : invoice.getAmountWithTax().negate();\r\n        netToPay = netToPay.add(round(totalUnpaidInvoices));\r\n        invoice.setNetToPay(netToPay);\r\n        Element totalNetToPayElem = document.createElement(\"netToPay\");\r\n        totalNetToPayElem.setAttribute(\"amount\", roundFormat(netToPay));\r\n        totauxElement.appendChild(totalNetToPayElem);\r\n\r\n        document.getElementsByTagName(\"invoice\").item(0).appendChild(totauxElement);\r\n\r\n    }\r\n\r\n    private BigDecimal getRappelSolde(Invoice invoice) {\r\n        Map<String, Object> params = new HashMap<>();\r\n        params.put(\"dueDateIN\", DateUtils.setDateToEndOfDay(DateUtils.addDaysToDate(new Date(), -1)));\r\n\r\n        List<AccountOperation> aos = (List<AccountOperation>) accountOperationService\r\n                .executeSelectQuery(\"select ao from AccountOperation ao where (ao.reference is null or ao.reference != '\" + invoice.getInvoiceNumber()\r\n                        + \"' )and ao.matchingStatus in ('O','P' ) and ao.dueDate < :dueDateIN and ao.subscription.id = \"\r\n                        + invoice.getSubscription().getId() + \" order by ao.id\", params);\r\n\r\n        BigDecimal totalUnpaidInvoices = BigDecimal.ZERO;\r\n        for (AccountOperation ao : aos) {\r\n            OperationCategoryEnum invOpCat = ao.getTransactionCategory();\r\n\r\n            totalUnpaidInvoices = totalUnpaidInvoices\r\n                    .add(invOpCat == OperationCategoryEnum.DEBIT ? ao.getUnMatchingAmount()\r\n                            : ao.getUnMatchingAmount().negate());\r\n\r\n        }\r\n        return totalUnpaidInvoices;\r\n    }\r\n\r\n    private void addTotalLInesUPF(Document document, Invoice invoice, boolean isAdjInvoice) {\r\n        Element totauxElement = document.createElement(\"totauxElement\");\r\n\r\n        BigDecimal totalTTC = !isAdjInvoice ? invoice.getAmountWithoutTax() : invoice.getAmountWithoutTax().negate();\r\n\r\n        Element totalHTLineElem = document.createElement(\"totalLine\");\r\n        totalHTLineElem.setAttribute(\"name\", \"Total HT\");\r\n        totalHTLineElem.setAttribute(\"amount\",\r\n                roundFormat(!isAdjInvoice ? invoice.getAmountWithoutTax() : invoice.getAmountWithoutTax().negate()));\r\n        totauxElement.appendChild(totalHTLineElem);\r\n\r\n        List<TaxInvoiceAgregate> taxInvoiceAgregates = new ArrayList<TaxInvoiceAgregate>();\r\n        for (InvoiceAgregate invoiceAgregate : invoice.getInvoiceAgregates()) {\r\n            if (invoiceAgregate instanceof TaxInvoiceAgregate) {\r\n                taxInvoiceAgregates.add((TaxInvoiceAgregate) invoiceAgregate);\r\n            }\r\n        }\r\n        taxInvoiceAgregates.sort(Comparator.comparing(ta -> ta.getTax().getPercent()));\r\n        for (TaxInvoiceAgregate taxInvoiceAgregate : taxInvoiceAgregates) {\r\n\r\n            Element taxElem = document.createElement(\"totalLine\");\r\n\r\n            taxElem.setAttribute(\"name\", \"TVA (\" + roundFormat(taxInvoiceAgregate.getTaxPercent(), true) + \"%)\");\r\n            BigDecimal amountTax = computeAmountsForTaxes(rts, taxInvoiceAgregate.getTaxPercent())[1];\r\n            amountTax = !isAdjInvoice ? amountTax : amountTax.negate();\r\n            taxElem.setAttribute(\"amount\", roundFormat(amountTax));\r\n            totauxElement.appendChild(taxElem);\r\n\r\n            totalTTC = totalTTC.add(round(amountTax));\r\n\r\n        }\r\n\r\n        Element totalTTCLineElem = document.createElement(\"totalLine\");\r\n        totalTTCLineElem.setAttribute(\"name\", \"Total facture TTC\");\r\n        totalTTCLineElem.setAttribute(\"amount\", roundFormat(totalTTC));\r\n        totauxElement.appendChild(totalTTCLineElem);\r\n\r\n        BigDecimal totalUnpaidInvoices = getRappelSolde(invoice);\r\n        //BigDecimal totalUnpaidInvoices = invoice.getNetToPay().subtract(totalTTC);\r\n\r\n        if (totalUnpaidInvoices.compareTo(BigDecimal.ZERO) != 0) {\r\n            Element totalLineElt = document.createElement(\"totalLine\");\r\n            // line rappel sold\r\n            totalLineElt.setAttribute(\"name\", \"Rappel du solde restant d\\u00FB\");\r\n            totalLineElt.setAttribute(\"amount\", roundFormat(totalUnpaidInvoices));\r\n            totauxElement.appendChild(totalLineElt);\r\n            // line net to pay\r\n            BigDecimal netToPay = !isAdjInvoice ? invoice.getAmountWithTax() : invoice.getAmountWithTax().negate();\r\n            netToPay = netToPay.add(round(totalUnpaidInvoices));\r\n            invoice.setNetToPay(netToPay);\r\n            Element totalLineElem = document.createElement(\"totalLine\");\r\n            totalLineElem.setAttribute(\"name\", netToPay.compareTo(BigDecimal.ZERO) >= 0 ? \"Total \\u00E0 payer TTC\" : \"Total en votre faveur TTC\");\r\n            totalLineElem.setAttribute(\"amount\", roundFormat(netToPay));\r\n            totauxElement.appendChild(totalLineElem);\r\n        }\r\n\r\n        document.getElementsByTagName(\"invoice\").item(0).appendChild(totauxElement);\r\n\r\n    }\r\n\r\n    private void addDetailREC(Document document, Invoice invoice, boolean isAdjInvoice) {\r\n\r\n        Element detailREC = document.createElement(\"detailREC\");\r\n        if (getPaymentMethodType(invoice) != null) {\r\n            detailREC.setAttribute(\"paymentMethod\", getPaymentMethodType(invoice).name());\r\n        }\r\n        List<RatedTransaction> rts = (List<RatedTransaction>) ratedTransactionService\r\n                .executeSelectQuery(\"select rt from RatedTransaction rt where rt.invoice.id=\" + invoice.getId()\r\n                        + \" and rt.amountWithTax != 0 order by rt.startDate asc, rt.description\", null);\r\n\r\n        // SUPS-SUPS-4241: Group RTs by concatenated periods\r\n        List<RatedTransaction> groupedRTs = new ArrayList<>();\r\n        RatedTransaction grpRT = null;\r\n        String grpRTKey;\r\n        String previousGrpRTKey = null;\r\n        String rtStartDate;\r\n        String previousGrpRTEndDate = null;\r\n\r\n        for (RatedTransaction rt : rts) {\r\n            grpRTKey = rt.getDescription() + roundFormat(rt.getUnitAmountWithoutTax()) + roundFormat(rt.getTaxPercent(), true);\r\n            rtStartDate = DateUtils.formatDateWithPattern(rt.getStartDate(), \"dd/MM/yyyy\");\r\n\r\n            if (!rt.getCode().startsWith(\"CH_REC\") || !grpRTKey.equals(previousGrpRTKey)\r\n                    || !rtStartDate.equals(previousGrpRTEndDate)) {\r\n                grpRT = new RatedTransaction();\r\n                grpRT.setCode(rt.getCode());\r\n                grpRT.setDescription(rt.getDescription());\r\n                grpRT.setStartDate(rt.getStartDate());\r\n                grpRT.setEndDate(rt.getEndDate());\r\n                grpRT.setUnitAmountWithoutTax(rt.getUnitAmountWithoutTax());\r\n                grpRT.setTaxPercent(rt.getTaxPercent());\r\n                grpRT.setUnitAmountWithTax(rt.getUnitAmountWithTax());\r\n                grpRT.setQuantity(rt.getQuantity());\r\n                grpRT.setAmountWithTax(rt.getAmountWithTax());\r\n                groupedRTs.add(grpRT);\r\n            } else {\r\n                grpRT.setEndDate(rt.getEndDate());\r\n                grpRT.setQuantity(grpRT.getQuantity().add(rt.getQuantity()));\r\n                grpRT.setAmountWithTax(grpRT.getAmountWithTax().add(rt.getAmountWithTax()));\r\n            }\r\n            previousGrpRTKey = grpRTKey;\r\n            previousGrpRTEndDate = DateUtils.formatDateWithPattern(grpRT.getEndDate(), \"dd/MM/yyyy\");\r\n        }\r\n\r\n        for (RatedTransaction rt : groupedRTs) {\r\n            Element linElem = document.createElement(\"lineREC\");\r\n            if (rt.getCode().startsWith(\"CH_REC\")) {\r\n                linElem.setAttribute(\"label1\", rt.getDescription() + \" du \");\r\n                linElem.setAttribute(\"label2\", DateUtils.formatDateWithPattern(rt.getStartDate(), \"dd/MM/yyyy\") + \" au \"\r\n                        + DateUtils.formatDateWithPattern(DateUtils.addDaysToDate(rt.getEndDate(), -1), \"dd/MM/yyyy\"));\r\n            } else {\r\n                linElem.setAttribute(\"label1\", rt.getDescription());\r\n            }\r\n            linElem.setAttribute(\"unitAmountWithoutTax\", roundFormat(rt.getUnitAmountWithoutTax()));\r\n            linElem.setAttribute(\"taxPercent\", roundFormat(rt.getTaxPercent(), true) + \" %\");\r\n            linElem.setAttribute(\"unitAmountWithTax\", roundFormat(rt.getUnitAmountWithTax()));\r\n            linElem.setAttribute(\"quantity\", roundFormat(!isAdjInvoice ? rt.getQuantity() : rt.getQuantity().negate()));\r\n            linElem.setAttribute(\"amountWithTax\",\r\n                    roundFormat(!isAdjInvoice ? rt.getAmountWithTax() : rt.getAmountWithTax().negate()));\r\n            detailREC.appendChild(linElem);\r\n        }\r\n\r\n        document.getElementsByTagName(\"invoice\").item(0).appendChild(detailREC);\r\n\r\n    }\r\n\r\n    private BigDecimal[] computeAmounts(List<RatedTransaction> rts, String subCatCode) {\r\n\r\n        BigDecimal[] amounts = new BigDecimal[3];\r\n        amounts[0] = BigDecimal.ZERO;\r\n        amounts[1] = BigDecimal.ZERO;\r\n        amounts[2] = BigDecimal.ZERO;\r\n\r\n        for (RatedTransaction rt : rts) {\r\n            if (subCatCode.equals(rt.getInvoiceSubCategory().getCode())) {\r\n                amounts[0] = amounts[0].add(round(rt.getAmountWithoutTax()));\r\n                amounts[1] = amounts[1].add(round(rt.getAmountTax()));\r\n                amounts[2] = amounts[2].add(round(rt.getAmountWithTax()));\r\n            }\r\n        }\r\n\r\n        return amounts;\r\n    }\r\n\r\n    private List<RatedTransaction> getRTsBySubCatCode(List<RatedTransaction> rts, String subCatCode) {\r\n\r\n        List<RatedTransaction> rtsBySubCat = new ArrayList<>();\r\n\r\n        for (RatedTransaction rt : rts) {\r\n            if (subCatCode.equals(rt.getInvoiceSubCategory().getCode())) {\r\n                rtsBySubCat.add(rt);\r\n            }\r\n        }\r\n        return rtsBySubCat;\r\n    }\r\n\r\n    private Element addLineUPF(Document document, String label, String taxPercent, BigDecimal unitHt,\r\n                               BigDecimal unitTtc, BigDecimal quantity, BigDecimal ttc, boolean isAdjInvoice) {\r\n        Element linElem = document.createElement(\"lineUPF\");\r\n\r\n        linElem.setAttribute(\"label\", label);\r\n\r\n        linElem.setAttribute(\"unitAmountWithoutTax\", unitHt == null ? \"-\" : roundFormat(unitHt));\r\n        linElem.setAttribute(\"taxPercent\", taxPercent == null ? \"-\" : (taxPercent + \" %\"));\r\n        linElem.setAttribute(\"unitAmountWithTax\", unitTtc == null ? \"-\" : roundFormat(unitTtc));\r\n        linElem.setAttribute(\"quantity\",\r\n                quantity == null ? \"-\" : roundFormat(!isAdjInvoice ? quantity : quantity.negate()));\r\n        linElem.setAttribute(\"amountWithTax\", ttc == null ? \"-\" : roundFormat(!isAdjInvoice ? ttc : ttc.negate()));\r\n        return linElem;\r\n\r\n    }\r\n\r\n    private void addDetailUPF(Document document, Invoice invoice, boolean isAdjInvoice) {\r\n        Element detailUPF = document.createElement(\"detailUPF\");\r\n        if (getPaymentMethodType(invoice) != null) {\r\n            detailUPF.setAttribute(\"paymentMethod\", getPaymentMethodType(invoice).name());\r\n        }\r\n        List<RatedTransaction> rts = ratedTransactionService.getRatedTransactionsByInvoice(invoice, true);\r\n\r\n        BigDecimal[] amountsMat = computeAmounts(rts, \"ISCAT_EKKO_MAT_VENTE\");\r\n        BigDecimal[] amountsDEEE = computeAmounts(rts, \"ISCAT_EKKO_DEEE\");\r\n        BigDecimal[] amountsInstall = computeAmounts(rts, \"ISCAT_EKKO_INSTALL\");\r\n        BigDecimal[] amountsDEEERemise = computeAmounts(rts, \"ISCAT_EKKO_DEEE_REMISE\");\r\n        BigDecimal[] amountsRemiseInstal = computeAmounts(rts, \"ISCAT_EKKO_INSTALL_REMISE\");\r\n        BigDecimal[] amountsRemiseMat = computeAmounts(rts, \"ISCAT_EKKO_MAT_REMISE\");\r\n        BigDecimal[] amountsGest = computeAmounts(rts, \"ISCAT_EKKO_INSTALL_GEST\");\r\n\r\n        BigDecimal total = round(amountsInstall[2]).add(round(amountsMat[2]).add(round(amountsDEEE[2])));\r\n        if (total.compareTo(BigDecimal.ZERO) != 0) {\r\n            detailUPF.appendChild(addLineUPF(document,\r\n                    \"Fourniture et pose de programmateurs d’intermittence de marque ENGIE sur \" + nbrOfRadiotor\r\n                            + \" radiateurs existants \",\r\n                    null, null, round(total), BigDecimal.ONE, round(total), isAdjInvoice));\r\n\r\n            for (RatedTransaction rt : getRTsBySubCatCode(rts, \"ISCAT_EKKO_MAT_VENTE\")) {\r\n                detailUPF.appendChild(\r\n                        addLineUPF(document, \"\\tdont \" + rt.getDescription(), roundFormat(rt.getTaxPercent(), true), rt.getUnitAmountWithoutTax(),\r\n                                rt.getUnitAmountWithTax(), rt.getQuantity(), rt.getAmountWithTax(), isAdjInvoice));\r\n            }\r\n            for (RatedTransaction rt : getRTsBySubCatCode(rts, \"ISCAT_EKKO_INSTALL\")) {\r\n                detailUPF.appendChild(\r\n                        addLineUPF(document, \"\\tdont \" + rt.getDescription(), roundFormat(rt.getTaxPercent(), true), rt.getUnitAmountWithoutTax(),\r\n                                rt.getUnitAmountWithTax(), rt.getQuantity(), rt.getAmountWithTax(), isAdjInvoice));\r\n            }\r\n            for (RatedTransaction rt : getRTsBySubCatCode(rts, \"ISCAT_EKKO_DEEE\")) {\r\n                detailUPF.appendChild(\r\n                        addLineUPF(document, \"\\tdont \" + rt.getDescription(), roundFormat(rt.getTaxPercent(), true), rt.getUnitAmountWithoutTax(),\r\n                                rt.getUnitAmountWithTax(), rt.getQuantity(), rt.getAmountWithTax(), isAdjInvoice));\r\n            }\r\n        }\r\n\r\n        BigDecimal totalRemise = round(amountsRemiseInstal[2]).add(round(amountsRemiseMat[2]))\r\n                .add(round(amountsDEEERemise[2]));\r\n        if (totalRemise.compareTo(BigDecimal.ZERO) != 0) {\r\n            detailUPF.appendChild(addLineUPF(document, \"Remise\", null, null, round(totalRemise), BigDecimal.ONE,\r\n                    round(totalRemise), isAdjInvoice));\r\n\r\n            for (RatedTransaction rt : getRTsBySubCatCode(rts, \"ISCAT_EKKO_MAT_REMISE\")) {\r\n                detailUPF.appendChild(\r\n                        addLineUPF(document, \"\\tdont \" + rt.getDescription(), roundFormat(rt.getTaxPercent(), true), rt.getUnitAmountWithoutTax(),\r\n                                rt.getUnitAmountWithTax(), rt.getQuantity(), rt.getAmountWithTax(), isAdjInvoice));\r\n            }\r\n            for (RatedTransaction rt : getRTsBySubCatCode(rts, \"ISCAT_EKKO_INSTALL_REMISE\")) {\r\n                detailUPF.appendChild(\r\n                        addLineUPF(document, \"\\tdont \" + rt.getDescription(), roundFormat(rt.getTaxPercent(), true), rt.getUnitAmountWithoutTax(),\r\n                                rt.getUnitAmountWithTax(), rt.getQuantity(), rt.getAmountWithTax(), isAdjInvoice));\r\n            }\r\n            for (RatedTransaction rt : getRTsBySubCatCode(rts, \"ISCAT_EKKO_DEEE_REMISE\")) {\r\n                detailUPF.appendChild(\r\n                        addLineUPF(document, \"\\tdont \" + rt.getDescription(), roundFormat(rt.getTaxPercent(), true), rt.getUnitAmountWithoutTax(),\r\n                                rt.getUnitAmountWithTax(), rt.getQuantity(), rt.getAmountWithTax(), isAdjInvoice));\r\n            }\r\n        }\r\n\r\n        if (amountsGest[0].compareTo(BigDecimal.ZERO) != 0) {\r\n            for (RatedTransaction rt : getRTsBySubCatCode(rts, \"ISCAT_EKKO_INSTALL_GEST\")) {\r\n                detailUPF.appendChild(addLineUPF(document, rt.getDescription(), roundFormat(rt.getTaxPercent(), true), rt.getUnitAmountWithoutTax(),\r\n                        rt.getUnitAmountWithTax(), rt.getQuantity(), rt.getAmountWithTax(), isAdjInvoice));\r\n            }\r\n        }\r\n\r\n        document.getElementsByTagName(\"invoice\").item(0).appendChild(detailUPF);\r\n\r\n    }\r\n\r\n    public Element addMaterielLine(Document document, String name, String reference) {\r\n        Element linElem = document.createElement(\"mat\");\r\n        linElem.setAttribute(\"name\", name);\r\n        linElem.setAttribute(\"reference\", reference);\r\n        return linElem;\r\n    }\r\n\r\n    private void addRefsMats(Document document) {\r\n        Element refsMats = document.createElement(\"refsMats\");\r\n        refsMats.appendChild(\r\n                addMaterielLine(document, \"1 prise communicante « Mbox »\", \"(référence K02-GM-01.0013E-C-ETH)\"));\r\n        refsMats.appendChild(addMaterielLine(document, nbrOfRadiotor + \" modules de pilotage « Dbox »\",\r\n                \"(référence K01-CDK-01.1016-01-P1/TIK)\"));\r\n        refsMats.appendChild(addMaterielLine(document, nbrOfRooms + \" capteurs de température « Sense-3 »\",\r\n                \"(référence K02-CASTH-01.1004-01/TIK-WH)\"));\r\n        refsMats.appendChild(addMaterielLine(document, \"1 câble Ethernet de longueur 5m\", \"(référence CA-ETHC2)\"));\r\n\r\n        document.getElementsByTagName(\"invoice\").item(0).appendChild(refsMats);\r\n    }\r\n\r\n    private void additionalInfos(Document document, Invoice invoice, String cfName) {\r\n\r\n        Element additionalFields = document.createElement(\"additionalFields\");\r\n\r\n        Subscription sub = invoice.getSubscription();\r\n        Map<String, String> sfDataMap = (Map<String, String>) sub.getCfValue(cfName);\r\n        if (sfDataMap != null) {\r\n            for (Map.Entry<String, String> entry : sfDataMap.entrySet()) {\r\n                if (SHIPPING_ADDRESS.equals(entry.getKey())) {\r\n                    extractShippingAddress(document, additionalFields, entry.getValue());\r\n                } else {\r\n                    Element entryElem = document.createElement(entry.getKey());\r\n                    entryElem.setTextContent(entry.getValue());\r\n                    additionalFields.appendChild(entryElem);\r\n                }\r\n            }\r\n            if (sfDataMap.get(CF_NbrOfRadiator) != null) {\r\n                nbrOfRadiotor = Long.valueOf(sfDataMap.get(CF_NbrOfRadiator));\r\n            }\r\n            if (sfDataMap.get(CF_NbrOfRooms) != null) {\r\n                nbrOfRooms = Long.valueOf(sfDataMap.get(CF_NbrOfRooms));\r\n            }\r\n        }\r\n        Element dateInsElem = document.createElement(\"CF_SUB_DATE_INSTALL\");\r\n        dateInsElem.setTextContent(\r\n                DateUtils.formatDateWithPattern((Date) sub.getCfValue(\"CF_SUB_DATE_INSTALL\"), \"dd/MM/yyyy\"));\r\n        additionalFields.appendChild(dateInsElem);\r\n\r\n        Element nbDaysElem = document.createElement(\"CF_SEL_PAY_NB_BUSI_DAYS\");\r\n        nbDaysElem.setTextContent(\"\" + (Long) sub.getSeller().getCfValue(\"CF_SEL_PAY_NB_BUSI_DAYS\"));\r\n        additionalFields.appendChild(nbDaysElem);\r\n\r\n        document.getElementsByTagName(\"invoice\").item(0).appendChild(additionalFields);\r\n    }\r\n\r\n    private BigDecimal round(BigDecimal amount) {\r\n        return round(amount, false);\r\n    }\r\n\r\n    private BigDecimal round(BigDecimal amount, boolean stripTrailingZeros) {\r\n        if (amount == null) {\r\n            amount = BigDecimal.ZERO;\r\n        }\r\n        int scale = 2;\r\n\r\n        amount = amount.setScale(scale, RoundingMode.HALF_UP);\r\n        if (stripTrailingZeros) {\r\n            amount = amount.stripTrailingZeros();\r\n        }\r\n        return amount;\r\n    }\r\n\r\n    private String roundFormat(BigDecimal amount) {\r\n        return String.valueOf(round(amount, false).toPlainString()).replaceAll(\"\\\\.\", \",\");\r\n    }\r\n\r\n    private String roundFormat(BigDecimal amount, boolean stripTrailingZeros) {\r\n        return String.valueOf(round(amount, stripTrailingZeros).toPlainString()).replaceAll(\"\\\\.\", \",\");\r\n    }\r\n\r\n    private PaymentMethodEnum getPaymentMethodType(Invoice invoice) {\r\n        String paymentMethod = (String) invoice.getSubscription().getCfValue(CF_SUB_PAY_METHOD);\r\n        PaymentMethodEnum paymentMethodEnumCommande = null;\r\n        if (paymentMethod != null) {\r\n            paymentMethodEnumCommande = PaymentMethodEnum.valueOf(paymentMethod);\r\n        }\r\n\r\n        //ENG382-176\r\n        boolean customerHasDDPayment = false;\r\n        for (PaymentMethod method : invoice.getBillingAccount().getCustomerAccount().getPaymentMethods()) {\r\n            if (method.getPaymentType().equals(PaymentMethodEnum.DIRECTDEBIT)) {\r\n                customerHasDDPayment = true;\r\n                break;\r\n            }\r\n        }\r\n\r\n        if (paymentMethodEnumCommande == PaymentMethodEnum.DIRECTDEBIT\r\n                && !customerHasDDPayment) {\r\n            return PaymentMethodEnum.CARD;\r\n        }\r\n        return paymentMethodEnumCommande;\r\n\r\n    }\r\n\r\n    private BigDecimal[] computeAmountsForTaxes(List<RatedTransaction> rts, BigDecimal taxPercent) {\r\n\r\n        BigDecimal[] amounts = new BigDecimal[3];\r\n        amounts[0] = BigDecimal.ZERO;\r\n        amounts[1] = BigDecimal.ZERO;\r\n        amounts[2] = BigDecimal.ZERO;\r\n\r\n        for (RatedTransaction rt : rts) {\r\n            if (taxPercent.compareTo(rt.getTaxPercent()) == 0) {\r\n                amounts[0] = amounts[0].add(round(rt.getAmountWithoutTax()));\r\n                amounts[1] = amounts[1].add(round(rt.getAmountTax()));\r\n                amounts[2] = amounts[2].add(round(rt.getAmountWithTax()));\r\n            }\r\n        }\r\n\r\n        return amounts;\r\n    }\r\n\r\n    private void extractShippingAddress(Document document, Element additionalFields, String shippingAddress) {\r\n\r\n        if (!StringUtils.isBlank(shippingAddress)) {\r\n            Matcher m = Pattern.compile(\"\\\\d{5}\").matcher(shippingAddress);\r\n            String zipCode = null;\r\n            String[] address = null;\r\n            if (m.find()) {\r\n                zipCode = m.group(0);\r\n            }\r\n            if (zipCode != null) {\r\n                address = shippingAddress.split(zipCode, shippingAddress.length());\r\n                Element addressElement = document.createElement(SHIPPING_ADDRESS);\r\n                addressElement.setTextContent(address[0]);\r\n                additionalFields.appendChild(addressElement);\r\n\r\n                Element zipCodeElement = document.createElement(\"zipCode\");\r\n                zipCodeElement.setTextContent(zipCode);\r\n                additionalFields.appendChild(zipCodeElement);\r\n\r\n                Element cityElement = document.createElement(\"city\");\r\n                cityElement.setTextContent(address[1]);\r\n                additionalFields.appendChild(cityElement);\r\n            } else {\r\n                Element shippingAddressElement = document.createElement(SHIPPING_ADDRESS);\r\n                shippingAddressElement.setTextContent(shippingAddress);\r\n                additionalFields.appendChild(shippingAddressElement);\r\n            }\r\n\r\n        }\r\n    }\r\n\r\n    private boolean isAboCharge(RatedTransaction rt) {\r\n        return rt.getCode().startsWith(\"CH_REC\") || rt.getCode().indexOf(\"ABO\") > -1;\r\n\r\n    }\r\n\r\n    private void createSubscriptionsSection(Document doc, Invoice adjustedInvoice) {\r\n        Element subscriptionsTag = doc.createElement(\"subscriptions\");\r\n        Subscription subscription = adjustedInvoice.getBillingAccount().getUsersAccounts().get(0).getSubscriptions()\r\n                .get(0);\r\n\r\n        Element subscriptionTag = doc.createElement(\"subscription\");\r\n        subscriptionTag.setAttribute(\"id\", subscription.getId() + \"\");\r\n        subscriptionTag.setAttribute(\"code\", subscription.getCode());\r\n        subscriptionTag.setAttribute(\"description\", getDefaultIfNull(subscription.getDescription(), \"\"));\r\n        subscriptionTag.setAttribute(\"offerCode\", subscription.getOffer().getCode());\r\n        Element subscriptionDateTag = doc.createElement(\"subscriptionDate\");\r\n        subscriptionDateTag.appendChild(\r\n                createTextNode(doc, DateUtils.formatDateWithPattern(subscription.getSubscriptionDate(), \"dd/MM/yyyy\")));\r\n        subscriptionTag.appendChild(subscriptionDateTag);\r\n        Element endAgreementTag = doc.createElement(\"endAgreementDate\");\r\n        endAgreementTag.appendChild(createTextNode(doc,\r\n                DateUtils.formatDateWithPattern(subscription.getEndAgreementDate(), \"yyyy-MM-dd'T'HH:mm:ss\")));\r\n        subscriptionTag.appendChild(endAgreementTag);\r\n        subscriptionsTag.appendChild(subscriptionTag);\r\n\r\n        doc.getElementsByTagName(\"userAccount\").item(0).appendChild(subscriptionsTag);\r\n    }\r\n\r\n    private Text createTextNode(Document doc, String data) {\r\n        if (data != null) {\r\n            return doc.createTextNode(data);\r\n        } else {\r\n            return doc.createTextNode(\"\");\r\n        }\r\n    }\r\n\r\n}\r\n]]>\r\n            </script>\r\n</ScriptInstance>\r\n\r\n"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "DueDateScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.invoicing.DueDateScript\" description=\"Ekko DueDateScript\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[ package com.opencellsoft.service.ekko.invoicing;\r\n\r\nimport java.util.Date;\r\n\r\nimport java.util.Map;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.model.admin.Seller;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.service.admin.impl.SellerService;\r\nimport org.meveo.service.catalog.impl.CalendarBankingService;\r\nimport org.meveo.service.script.Script;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n\r\n/**\r\n * \r\n * @author anasseh\r\n *\r\n */\r\n\r\npublic class DueDateScript extends Script {\r\n\r\n\tprivate static final long serialVersionUID = 1L;\r\n\tprivate static final String CF_SEL_PAY_NB_BUSI_DAYS = \"CF_SEL_PAY_NB_BUSI_DAYS\";\r\n\r\n\tprivate static final Logger log = LoggerFactory.getLogger(DueDateScript.class);\r\n\tprivate CalendarBankingService calendarBankingService = (CalendarBankingService) getServiceInterface(\"CalendarBankingService\");\r\n\tprivate SellerService sellerService = (SellerService) getServiceInterface(\"SellerService\");\r\n\r\n\t@Override\r\n\tpublic void execute(Map<String, Object> context) throws BusinessException {\r\n\t\tlog.info(\"Execute context : {} \", context);\r\n\t\tSeller seller = sellerService.findByCode(\"EKKO\");\r\n\t\tLong nbDaysDue = (Long) seller.getCfValue(CF_SEL_PAY_NB_BUSI_DAYS);\r\n\t\t\r\n\t\tDate dueDate = null;\r\n\t\tDate today = DateUtils.setDateToStartOfDay(new Date());\r\n\r\n\t\tdueDate = addBusinessDays(new Date(), nbDaysDue);\r\n\t\tDouble daysbetween = DateUtils.daysBetween(today, dueDate);\r\n\t\tlog.info(\"today:{} dueDate:{} \", today, dueDate, daysbetween.intValue());\r\n\r\n\t\tcontext.put(Script.RESULT_VALUE, daysbetween.intValue());\r\n\t}\r\n\r\n\tprivate Date addBusinessDays(Date dateStart, Long nbDays) {\r\n\r\n\t\tint daysAdded = 0;\r\n\t\tDate endDate = dateStart;\r\n\t\twhile (daysAdded != nbDays.intValue()) {\r\n\t\t\tendDate = DateUtils.addDaysToDate(endDate, 1);\r\n\t\t\tif (calendarBankingService.isBankWorkingDate(endDate)) {\r\n\t\t\t\tdaysAdded++;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn DateUtils.setDateToEndOfDay(endDate);\r\n\t}\r\n\r\n}\r\n\r\n]]>\r\n            </script>\r\n</ScriptInstance>\r\n\r\n"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CheckRoundingAmountsScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.invoicing.CheckRoundingAmountsScript\" description=\"CheckRoundingAmountsScript\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[             \r\npackage com.opencellsoft.service.ekko.invoicing;\r\n\r\nimport java.math.BigDecimal;\r\nimport java.math.RoundingMode;\r\nimport java.util.Date;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.commons.utils.StringUtils;\r\nimport org.meveo.model.billing.Invoice;\r\nimport org.meveo.model.billing.RatedTransaction;\r\nimport org.meveo.model.billing.SubCategoryInvoiceAgregate;\r\nimport org.meveo.model.payments.AccountOperation;\r\nimport org.meveo.model.payments.OperationCategoryEnum;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.service.billing.impl.InvoiceAgregateService;\r\nimport org.meveo.service.billing.impl.InvoiceService;\r\nimport org.meveo.service.billing.impl.RatedTransactionService;\r\nimport org.meveo.service.payments.impl.AccountOperationService;\r\nimport org.meveo.service.script.Script;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n/**\r\n *\r\n * \r\n * @author anasseh\r\n * \r\n * 02/05/2023 SUPS-2461\r\n * 01/02/2024 ENG382-122\r\n * 05/03/2024 : SUPS-1787\r\n *\r\n */\r\npublic class CheckRoundingAmountsScript extends Script {\r\n\r\n\tprivate static final long serialVersionUID = 1L;\r\n\tprivate static final Logger log = LoggerFactory.getLogger(CheckRoundingAmountsScript.class);\r\n\r\n\tprivate InvoiceService invoiceService = (InvoiceService) getServiceInterface(\"InvoiceService\");\r\n\tprivate RatedTransactionService ratedTransactionService = (RatedTransactionService) getServiceInterface(\"RatedTransactionService\");\t\r\n\tprivate InvoiceAgregateService invoiceAgregateService = (InvoiceAgregateService) getServiceInterface(\"InvoiceAgregateService\");\r\n\tprivate AccountOperationService accountOperationService = (AccountOperationService) getServiceInterface(\"AccountOperationService\");\r\n\t\r\n\t\r\n\t@Override\r\n\tpublic void execute(Map<String, Object> methodContext) throws BusinessException {\r\n\t\tlog.info(\"EXECUTE methodContext {}\", methodContext);\r\n\t\t\r\n\t\tInvoice invoice =(Invoice) methodContext.get(Script.CONTEXT_ENTITY);\r\n\t\tif (StringUtils.isBlank(invoice.getComment())) {\r\n\r\n\t\t\tList<RatedTransaction> rts = ratedTransactionService.getRatedTransactionsByInvoice(invoice, true);\r\n\t\t\tif(rts != null && !rts.isEmpty()) {\r\n\t\t\t\t\r\n\t\t\t\tBigDecimal[] amounts = computeAmounts(rts);\r\n\t\t\t\tinvoice.setAmountWithoutTax(amounts[0]);\r\n\t\t\t\tinvoice.setAmountTax(amounts[1]);\r\n\t\t\t\tinvoice.setAmountWithTax(amounts[2]);\r\n\t\t\t\tinvoice.setComment(\"Checked\");\r\n\t\t\t\tList<SubCategoryInvoiceAgregate> listAggregateSub =  (List<SubCategoryInvoiceAgregate>) invoiceAgregateService.listByInvoiceAndType(invoice, \"F\");\t\t\t\t\r\n\t\t\t\tfor(SubCategoryInvoiceAgregate aggragte : listAggregateSub) {\r\n\t\t\t\t\tBigDecimal[] amountsAggregate = computeAmountsBySubCat(rts, aggragte.getInvoiceSubCategory().getCode());\t\t\t\t\t\r\n\t\t\t\t\taggragte.setAmountWithoutTax(amountsAggregate[0]);\r\n\t\t\t\t\taggragte.setAmountTax(amountsAggregate[1]);\r\n\t\t\t\t\taggragte.setAmountWithTax(amountsAggregate[2]);\t\t\t\t\t\r\n\t\t\t\t\tinvoiceAgregateService.update(aggragte);\r\n\t\t\t\t}\r\n\t\t\t\tboolean isAdjInvoice = invoice.getInvoiceType().getCode().equals(\"ADJ\");\r\n\t\t\t\tBigDecimal netToPay = !isAdjInvoice ? invoice.getAmountWithTax() : invoice.getAmountWithTax().negate();\r\n\t\t\t\tBigDecimal totalUnpaidInvoices = getRappelSolde(invoice);\r\n\r\n\t\t\t\tnetToPay = netToPay.add(round(totalUnpaidInvoices));\r\n\t\t\t\tinvoice.setNetToPay(netToPay);\r\n\t\t\t\t\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t}\r\n\t\r\n\t\r\n\r\n\tprivate BigDecimal[] computeAmountsBySubCat(List<RatedTransaction> rts, String catCode) {\r\n\r\n        BigDecimal[] amounts = new BigDecimal[3];\r\n        amounts[0] = BigDecimal.ZERO;\r\n        amounts[1] = BigDecimal.ZERO;\r\n        amounts[2] = BigDecimal.ZERO;\r\n\r\n        for(RatedTransaction rt : rts) {\r\n            if(catCode.equals(rt.getInvoiceSubCategory().getCode())) {\r\n                amounts[0] = amounts[0].add(round(rt.getAmountWithoutTax()));\r\n                amounts[1] = amounts[1].add(round(rt.getAmountTax()));\r\n                amounts[2] = amounts[2].add(round(rt.getAmountWithTax()));\r\n            }\r\n        }\r\n\r\n        return amounts;\r\n    }\r\n\r\n\tprivate BigDecimal[] computeAmounts(List<RatedTransaction> rts) {\r\n\r\n\t\tBigDecimal[] amounts = new BigDecimal[3];\r\n\t\tamounts[0] = BigDecimal.ZERO;\r\n\t\tamounts[1] = BigDecimal.ZERO;\r\n\t\tamounts[2] = BigDecimal.ZERO;\r\n\r\n\t\tfor (RatedTransaction rt : rts) {\r\n\r\n\t\t\tamounts[0] = amounts[0].add(round(rt.getAmountWithoutTax()));\r\n\t\t\tamounts[1] = amounts[1].add(round(rt.getAmountTax()));\r\n\t\t\tamounts[2] = amounts[2].add(round(rt.getAmountWithTax()));\r\n\r\n\t\t}\r\n\r\n\t\treturn amounts;\r\n\t}\r\n\r\n\tprivate BigDecimal round(BigDecimal amount) {\r\n\t\treturn round(amount, false);\r\n\t}\r\n\r\n\tprivate BigDecimal round(BigDecimal amount, boolean stripTrailingZeros) {\r\n\t\tif (amount == null) {\r\n\t\t\tamount = BigDecimal.ZERO;\r\n\t\t}\r\n\t\tint scale = 2;\r\n\r\n\t\tamount = amount.setScale(scale, RoundingMode.HALF_UP);\r\n\t\tif (stripTrailingZeros) {\r\n\t\t\tamount = amount.stripTrailingZeros();\r\n\t\t}\r\n\t\treturn amount;\r\n\t}\r\n\tprivate BigDecimal getRappelSolde(Invoice invoice) {\r\n\t\tMap<String, Object> params = new HashMap<>();\r\n\t\tparams.put(\"dueDateIN\", DateUtils.setDateToEndOfDay(DateUtils.addDaysToDate(new Date(), -1)));\r\n\r\n\t\tList<AccountOperation> aos = (List<AccountOperation>) accountOperationService\r\n\t\t\t\t.executeSelectQuery(\"select ao from AccountOperation ao where (ao.reference is null or ao.reference != '\" + invoice.getInvoiceNumber()\r\n\t\t\t\t\t\t+ \"' )and ao.matchingStatus in ('O','P' ) and ao.dueDate < :dueDateIN and ao.customerAccount.id = \"\r\n\t\t\t\t\t\t+ invoice.getBillingAccount().getCustomerAccount().getId() + \" order by ao.id\", params);\r\n\r\n\t\tBigDecimal totalUnpaidInvoices = BigDecimal.ZERO;\r\n\t\tfor (AccountOperation ao : aos) {\t\t\t\r\n\t\t\tOperationCategoryEnum invOpCat = ao.getTransactionCategory();\r\n\r\n\t\t\ttotalUnpaidInvoices = totalUnpaidInvoices\r\n\t\t\t\t\t.add(invOpCat == OperationCategoryEnum.DEBIT ? ao.getUnMatchingAmount()\r\n\t\t\t\t\t\t\t: ao.getUnMatchingAmount().negate());\r\n\r\n\t\t}\r\n\t\treturn totalUnpaidInvoices;\r\n\t}\r\n\r\n}\r\n\r\n\r\n            \r\n]]>\r\n            </script>\r\n</ScriptInstance>\r\n\r\n"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "CancelRecInvoicesScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.invoicing.CancelRecInvoicesScript\" description=\"CancelRecInvoicesScript\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[ package com.opencellsoft.service.ekko.invoicing;\r\n\r\nimport java.util.Map;\r\n\r\nimport org.hibernate.SQLQuery;\r\nimport org.hibernate.Session;\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.model.billing.Invoice;\r\nimport org.meveo.model.payments.MatchingStatusEnum;\r\nimport org.meveo.service.billing.impl.InvoiceService;\r\nimport org.meveo.service.billing.impl.RatedTransactionService;\r\nimport org.meveo.service.script.Script;\r\n\r\n\r\npublic class CancelRecInvoicesScript extends Script {\r\n\r\n\tprivate InvoiceService invoiceService = (InvoiceService) getServiceInterface(\"InvoiceService\");\r\n\tprivate RatedTransactionService ratedTransactionService = (RatedTransactionService) getServiceInterface(\"RatedTransactionService\");\r\n\r\n\r\n\t/**\r\n\t * Script execute method\r\n\t * \r\n\t * @param methodContext execution context\r\n\t * @throws BusinessException Business Exception\r\n\t */\r\n\t@Override\r\n\tpublic void execute(Map<String, Object> methodContext) throws BusinessException {\r\n\t\tInvoice invoice = invoiceService.refreshOrRetrieve((Invoice) methodContext.get(\"inv\"));\r\n\t\t\r\n\t\t\r\n\t\tratedTransactionService.deleteSupplementalRTs(invoice);\r\n        ratedTransactionService.uninvoiceRTs(invoice);\r\n        Long aoid = null;\r\n        if(invoice.getRecordedInvoice() != null) {\r\n        \taoid = invoice.getRecordedInvoice().getId();\r\n        \t//invoice.getRecordedInvoice().setMatchingStatus(MatchingStatusEnum.C);\r\n        \tinvoice.getRecordedInvoice().setInvoice(null);\r\n        \t\r\n        }        \r\n        \r\n        invoiceService.remove(invoice);\r\n        if(aoid != null && invoice.getRecordedInvoice().getMatchingStatus() == MatchingStatusEnum.O) {\r\n        executeNativeSelectQuery(\"delete from  ar_account_operation where id=\"+aoid,null);\r\n        }\r\n\r\n\t}\r\n\t\r\n\t public void executeNativeSelectQuery(String query, Map<String, Object> params) {\r\n\t        Session session = invoiceService.getEntityManager().unwrap(Session.class);\r\n\t        SQLQuery q = session.createSQLQuery(query);\r\n\r\n\t      \r\n\r\n\t        if (params != null) {\r\n\t            for (Map.Entry<String, Object> entry : params.entrySet()) {\r\n\t                q.setParameter(entry.getKey(), entry.getValue());\r\n\t            }\r\n\t        }\r\n\t  q.executeUpdate();\r\n\r\n\t     \r\n\t    }\r\n}\r\n\r\n]]>\r\n            </script>\r\n</ScriptInstance>\r\n\r\n"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "TemplateNameScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.invoicing.TemplateNameScript\" description=\"TemplateNameScript\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[ package com.opencellsoft.service.ekko.invoicing;\r\n\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.Set;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.model.billing.Invoice;\r\nimport org.meveo.model.billing.RatedTransaction;\r\nimport org.meveo.service.billing.impl.RatedTransactionService;\r\nimport org.meveo.service.script.Script;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n/**\r\n * \r\n * @author anasseh\r\n *\r\n */\r\n\r\npublic class TemplateNameScript extends Script {\r\n\r\n    private static final long serialVersionUID = 1L;\r\n    \r\n\r\n    private static final Logger log = LoggerFactory.getLogger(TemplateNameScript.class);\r\n    private RatedTransactionService ratedTransactionService = (RatedTransactionService) getServiceInterface(\"RatedTransactionService\");\r\n   \r\n    @Override\r\n    public void execute(Map<String, Object> context) throws BusinessException {\r\n        log.info(\"Execute context : {} \", context);\r\n        String defaultTemplateName = \"UPF\";\r\n        Invoice invoice = (Invoice) context.get(Script.CONTEXT_ENTITY);\r\n        Set<Invoice> linkedInvoices = invoice.getLinkedInvoices();\r\n        if (linkedInvoices != null && !linkedInvoices.isEmpty()) {\r\n            defaultTemplateName =  linkedInvoices.iterator().next().getInvoiceType().getCode();\r\n        }else {\r\n            List<RatedTransaction> rts = ratedTransactionService.getRatedTransactionsByInvoice(invoice, true);\r\n            for(RatedTransaction rt : rts) {\r\n                if(isAboCharge( rt)) {\r\n                    defaultTemplateName = \"REC\";\r\n                }\r\n            }\r\n        }\r\n        log.info(\"defaultTemplateName:\"+defaultTemplateName);\r\n        context.put(Script.RESULT_VALUE, defaultTemplateName);\r\n    }\r\n    private boolean isAboCharge(RatedTransaction rt) {\r\n        return rt.getCode().startsWith(\"CH_REC\") || rt.getCode().indexOf(\"ABO\") > -1;\r\n\r\n    }\r\n}\r\n\r\n]]>\r\n            </script>\r\n</ScriptInstance>\r\n\r\n"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						}
					]
				},
				{
					"name": "compta",
					"item": [
						{
							"name": "ExportRapsodieScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript",
										"packages": {}
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.compta.ExportRapsodieScript\" description=\"Ekko Export Rapsodie Script\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.compta;\r\n\r\nimport com.google.common.base.Charsets;\r\nimport com.google.common.collect.Maps;\r\nimport com.google.common.io.Files;\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.commons.utils.ParamBean;\r\nimport org.meveo.commons.utils.QueryBuilder;\r\nimport org.meveo.commons.utils.StringUtils;\r\nimport org.meveo.model.billing.*;\r\nimport org.meveo.model.crm.Provider;\r\nimport org.meveo.model.finance.AccountingEntry;\r\nimport org.meveo.model.jobs.JobExecutionResultImpl;\r\nimport org.meveo.model.jobs.JobInstance;\r\nimport org.meveo.model.payments.*;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.service.billing.impl.AccountingCodeService;\r\nimport org.meveo.service.billing.impl.InvoiceService;\r\nimport org.meveo.service.billing.impl.RatedTransactionService;\r\nimport org.meveo.service.catalog.impl.InvoiceCategoryService;\r\nimport org.meveo.service.catalog.impl.InvoiceSubCategoryService;\r\nimport org.meveo.service.catalog.impl.TaxService;\r\nimport org.meveo.service.crm.impl.ProviderService;\r\nimport org.meveo.service.finance.AccountingWritingService;\r\nimport org.meveo.service.job.JobInstanceService;\r\nimport org.meveo.service.payments.impl.OCCTemplateService;\r\nimport org.meveo.service.script.Script;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\nimport javax.persistence.EntityManager;\r\nimport javax.persistence.NoResultException;\r\nimport javax.persistence.Query;\r\nimport javax.persistence.Tuple;\r\nimport java.io.File;\r\nimport java.io.IOException;\r\nimport java.math.BigDecimal;\r\nimport java.math.RoundingMode;\r\nimport java.text.DecimalFormat;\r\nimport java.time.LocalDate;\r\nimport java.util.*;\r\nimport java.util.Map.Entry;\r\nimport java.util.stream.Collectors;\r\n\r\nimport static org.apache.commons.lang.StringUtils.leftPad;\r\nimport static org.apache.commons.lang.StringUtils.rightPad;\r\n\r\n/**\r\n * /**\r\n *\r\n * @author myPower team , from dump PP 19/05/2021\r\n *\r\n * @author anasseh update for OC 11 and EKKO\r\n *\r\n * 16/05/2022 SUPS-1634\r\n *\r\n */\r\n\r\npublic class ExportRapsodieScript extends Script {\r\n\r\n\tprivate static final Logger log = LoggerFactory.getLogger(ExportRapsodieScript.class);\r\n\r\n\tprivate static final String JOB_CODE = \"EkkoExportRapsodieJob\";\r\n\tprivate static final String PREFIX = \"EKK\";\r\n\tprivate static final String FOLDER_ID = \"G\";\r\n\tprivate static final String ORGA_CODE = \"9856\";\r\n\tprivate static final String OC_CODE = \"OCE\";\r\n\tprivate static final String MANDANT = \"500\";\r\n\tprivate static final String DEBIT = \"40\";\r\n\tprivate static final String CREDIT = \"50\";\r\n\tprivate static final String CAT_VENDING_CODE = \"ICAT_EKKO_INSTALL\";\r\n\tprivate static final String CAT_VENDING_CODE_2 = \"ICAT_EKKO_ABO\";\r\n\r\n\tprivate static final String CAT_SERVICE_PROVISION_CODE = \"ICAT_EKKO_MATERIEL\";\r\n\tprivate static final String CAT_PAY_CODE = \"PAY_FF\";\r\n\r\n\tprivate static final String COSTL_MPM = \"VCA-AU-MPM\";\r\n\tprivate static final String COSTL_MPI = \"VCA-AU-MPI\";\r\n\tprivate static final String COSTL_PWBONIF = \"VM-PWBONIF\";\r\n\tprivate static final String OCC_TEMP_CODE_REF_INV = \"REF_INV\";\r\n\tprivate static final String OCC_TEMP_CODE_INV_STD = \"INV_STD\";\r\n\tprivate static final String SKIP_CHAR = \"/\";\r\n\tprivate static final String NEW_LINE = \"\\n\";\r\n\tprivate static final String PAD_STR = \" \";\r\n\r\n\tprivate static final String SUB_CAT_DEE = \"ISCAT_EKKO_DEEE\";\r\n\tprivate static final String COSTL_VCA_DE = \"VCA-DE-EKO\";\r\n\tprivate static final String COSTL_VCA_MA = \"VCA-MA-EKO\";\r\n\tprivate static final String COSTL_VCA_IN = \"VCA-IN-EKO\";\r\n\tprivate static final String COSTL_VCA_SE = \"VCA-SE-EKO\";\r\n\tprivate static final String ACCOUNT_1 = \"706260\";\r\n\tprivate static final String ACCOUNT_2 = \"709300\";\r\n\tprivate static final String ACCOUNT_3 = \"706800\";\r\n\tprivate String generationDate;\r\n\r\n\tprivate enum EventEnum {\r\n\t\tFACTURATION(\"Facturation\"),\r\n\t\tANNULATION_FACTURATION(\"Annulation Facturation\"),\r\n\t\tINV_CRN(\"INV_CRN\"),\r\n\t\tPAY_DDT(\"Encaissement Prelevement\"),\r\n\t\tPAY_CRD(\"Encaissement CB\"),\r\n\t\tPAY_CHK(\"Encaissement Cheque\"),\r\n\t\tPAY_TRF(\"Encaissement Virement\"),\r\n\t\tPAY_FF(\"Bonifications d'interets - Autres Banques\"),\r\n\t\tPAY_TIP(\"Encaissement Espece\"),\r\n\t\t// REF_DDT(\"Décaissement Prelevement\"),\r\n\t\tREF_DDT(\"Décaissement Virement\"),\r\n\t\tREF_CHK(\"Décaissement Cheque\"),\r\n\t\tREF_CRD(\"Décaissement CB\"),\r\n\t\tREF_TRF(\"Décaissement Virement\"),\r\n\t\tREF_TIP(\"Décaissement Espece\"),\r\n\t\tREJ_DDT(\"Prelevement Rejeter\"),\r\n\t\tREF_INV(\"Avoir sur Facturation\"),\r\n\t\tDBT_TRS(\"DBT_TRS\");\r\n\r\n\t\tString label;\r\n\r\n\t\tEventEnum(String label) {\r\n\t\t\tthis.label = label;\r\n\t\t}\r\n\r\n\t\tpublic String getLabel() {\r\n\t\t\treturn label;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate enum ZUONREnum {\r\n\t\tINVOICE(\"FACTURE\"), PAY_DDT(\"SDD\"), REF_DDT(\"SDD\"), PAY_CHK(\"CHQ\"), REF_CHK(\"CHQ\"), PAY_TIP(\"TIP\"), REF_TIP(\"TIP\"), PAY_CRD(\"CB\"), PAY_TRF(\"TRF\"), PAY_FF(\"FF\"),\r\n\t\tREF_TRF(\"TRF\"), REF_CRD(\"CB\"), REF_INV(\"SDD\"), REJ_DDT(\"SDD\"), INV_CRN(\"INV_CRN\"), DBT_TRS(\"DBT_TRS\");\r\n\r\n\t\tString label;\r\n\r\n\t\tZUONREnum(String label) {\r\n\t\t\tthis.label = label;\r\n\t\t}\r\n\r\n\t\tpublic String getLabel() {\r\n\t\t\treturn label;\r\n\t\t}\r\n\t}\r\n\r\n\tprivate InvoiceService invoiceService = (InvoiceService) getServiceInterface(\"InvoiceService\");\r\n\tprivate JobInstanceService jobInstanceService = (JobInstanceService) getServiceInterface(\"JobInstanceService\");\r\n\r\n\tprivate AccountingWritingService accountingWritingService = (AccountingWritingService) getServiceInterface(\"AccountingWritingService\");\r\n\tprivate AccountingCodeService accountingCodeService = (AccountingCodeService) getServiceInterface(\"AccountingCodeService\");\r\n\r\n\tprivate OCCTemplateService occTemplateService = (OCCTemplateService) getServiceInterface(\"OCCTemplateService\");\r\n\r\n\tprivate InvoiceSubCategoryService invoiceSubCategoryService = (InvoiceSubCategoryService) getServiceInterface(\"InvoiceSubCategoryService\");\r\n\tprivate InvoiceCategoryService invoiceCategoryService = (InvoiceCategoryService) getServiceInterface(\"InvoiceCategoryService\");\r\n\tprivate RatedTransactionService ratedTransactionService = (RatedTransactionService) getServiceInterface(\"RatedTransactionService\");\r\n\tprivate TaxService taxService = (TaxService) getServiceInterface(\"TaxService\");\r\n\r\n\tprivate DecimalFormat decimalFormat = (DecimalFormat) DecimalFormat.getInstance(Locale.FRENCH);\r\n\r\n\tprivate long coutJobExecution = 0l;\r\n\r\n\tprivate StringBuilder contentBuilder = new StringBuilder();\r\n\r\n\tprivate static class Zone {\r\n\t\tint lg;\r\n\t\tString value;\r\n\t\tString padStr = PAD_STR;\r\n\t\tboolean leftPad = false;\r\n\r\n\t\tpublic Zone(int lg, String value) {\r\n\t\t\tthis.lg = lg;\r\n\t\t\tthis.value = value;\r\n\t\t}\r\n\r\n\t\tpublic Zone(int lg, String value, String padStr, boolean leftPad) {\r\n\t\t\tthis.lg = lg;\r\n\t\t\tthis.value = value;\r\n\t\t\tthis.padStr = padStr;\r\n\t\t\tthis.leftPad = leftPad;\r\n\t\t}\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void execute(Map<String, Object> context) throws BusinessException {\r\n\r\n\t\tDate lastExecutionDate = new Date(1);\r\n\r\n\t\t// Date lastExecutionDate =\r\n\t\t// DateUtils.setDateToStartOfDay(DateUtils.addDaysToDate(new Date(), -1));\r\n\r\n\t\tdecimalFormat.setDecimalSeparatorAlwaysShown(true);\r\n\t\tdecimalFormat.setGroupingUsed(false);\r\n\t\tdecimalFormat.setMinimumFractionDigits(2);\r\n\r\n\t\tlog.info(\"Execute ExportRapsodie - Context: {}\", context);\r\n\t\tProvider appProvider = ((ProviderService) getServiceInterface(\"ProviderService\")).getProvider();\r\n\t\tString fileNameParam = (String) context.get(\"fileName\");\r\n\t\tString outputDirParam = (String) context.get(\"outputDir\");\r\n\t\tString archivedDirParam = (String) context.get(\"archivedDir\");\r\n\r\n\t\tString chrootDir = ParamBean.getInstance().getChrootDir(appProvider.getCode());\r\n\t\tString absoluteOutputFileName = chrootDir;\r\n\t\tString absoluteArchivedFileName = chrootDir;\r\n\t\tif (!StringUtils.isBlank(outputDirParam)) {\r\n\t\t\tabsoluteOutputFileName += File.separator + outputDirParam.replaceAll(\"\\\\..\", \"\");\r\n\t\t}\r\n\t\tif (!StringUtils.isBlank(archivedDirParam)) {\r\n\t\t\tabsoluteArchivedFileName += File.separator + archivedDirParam.replaceAll(\"\\\\..\", \"\");\r\n\t\t}\r\n\r\n\t\t// make dir if doesnt exist\r\n\t\tFile outputDir = new File(absoluteOutputFileName);\r\n\t\tif (!outputDir.exists()) {\r\n\t\t\toutputDir.mkdirs();\r\n\t\t}\r\n\t\tFile archivedDir = new File(absoluteArchivedFileName);\r\n\t\tif (!archivedDir.exists()) {\r\n\t\t\tarchivedDir.mkdirs();\r\n\t\t}\r\n\r\n\t\tgenerationDate = DateUtils.formatDateWithPattern(new Date(), \"ddMMyyyy_HHmmss\");\r\n\t\t// file name\r\n\t\tif (!StringUtils.isBlank(fileNameParam)) {\r\n\t\t\tabsoluteOutputFileName += File.separator + fileNameParam;\r\n\t\t\tabsoluteArchivedFileName += File.separator + fileNameParam;\r\n\t\t} else {\r\n\t\t\tabsoluteOutputFileName += File.separator + OC_CODE + \"_\" + ORGA_CODE + \"_\" + generationDate;\r\n\t\t\tabsoluteArchivedFileName += File.separator + OC_CODE + \"_\" + ORGA_CODE + \"_\" + generationDate;\r\n\t\t}\r\n\r\n\t\tcreateMaterializedViews();\r\n\r\n\t\t// 0 : batch input (BGR00)\r\n\t\tbuildBGR00();\r\n\t\tcontentBuilder.append(NEW_LINE);\r\n\r\n\t\tint index = 1;\r\n\t\tint index2 = index;\r\n\r\n\t\tList<String> lines = new ArrayList<>();\r\n\r\n\t\tList<AccountingEntry> invoiceWritings = getInvoiceWritingsV2();\r\n\t\tlog.info(\"Getting invoiceWritings. size={}\", invoiceWritings.size());\r\n\t\tfor (AccountingEntry invoiceWriting : invoiceWritings) {\r\n\r\n\t\t\tList<AccountingEntry> invoiceSubcatWritings = null;\r\n\t\t\tList<AccountingEntry> taxWritings = null;\r\n\r\n\t\t\tString invoicesAffected = invoiceWriting.getAccountOperations().stream().map(AccountOperation::getReference).collect(Collectors.joining(\";\"));\r\n\r\n\t\t\tlog.info(\"=== Writing invoiceWriting(accCode={}) for date {} ===\", invoiceWriting.getAccountingCode().getCode(), invoiceWriting.getEventDate());\r\n\t\t\tlog.info(\"invoices list:{}\",  invoicesAffected);\r\n\r\n\t\t\tBigDecimal totalInvSubCatWritingAmount = BigDecimal.ZERO;\r\n\t\t\tBigDecimal totalTaxWritingAmount = BigDecimal.ZERO;\r\n\r\n\t\t\t//invoiceSubcatWritings = getInvoiceSubcatsWritings(invoiceWriting.getEventDate(), invoiceWriting.getAccountingCode().getCode(), null);\r\n\t\t\t//taxWritings = getTaxWritings(invoiceWriting.getEventDate(), invoiceWriting.getAccountingCode().getCode(), null);\r\n\r\n\t\t\tinvoiceSubcatWritings = getInvoiceSubcatsWritingsV2(invoiceWriting.getEventDate(), invoiceWriting.getAccountingCode().getCode());\r\n\t\t\ttaxWritings = getTaxWritingsV2(invoiceWriting.getEventDate(), invoiceWriting.getAccountingCode().getCode());\r\n\r\n\t\t\t// ne pas afficher la ligne header FB01 que s'il y a au moins une sous-ligne avec montant non null\r\n\t\t\tboolean isExitNonZeroSubCat = invoiceSubcatWritings.stream().anyMatch(aw -> aw.getAmount().compareTo(BigDecimal.ZERO) != 0);\r\n\t\t\tboolean isExitNonZeroTax = taxWritings.stream().anyMatch(aw -> aw.getAmount().compareTo(BigDecimal.ZERO) != 0);\r\n\t\t\tif (invoiceWriting.getAmount().compareTo(BigDecimal.ZERO) != 0 || isExitNonZeroSubCat || isExitNonZeroTax) {\r\n\t\t\t\tlines.add(buildBBKPF(invoiceWriting.getEventDate(), new Date(), index++));\r\n\t\t\t\tindex2 = index - 1;\r\n\t\t\t}\r\n\r\n\t\t\tString OCEDateNumLecture = PREFIX + DateUtils.formatDateWithPattern(new Date(), \"ddMMyyyy\") + index2;\r\n\t\t\tfor (AccountingEntry invoiceSubcatWriting : invoiceSubcatWritings) {\r\n\t\t\t\tinvoiceSubcatWriting.setExtraParam2(OCEDateNumLecture);\r\n\t\t\t\t// ne pas inclure les lignes avec montant à 0\r\n\t\t\t\tif (invoiceSubcatWriting.getAmount().compareTo(BigDecimal.ZERO) == 0) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tString invoiceCategoryCode = invoiceSubcatWriting.getInvoiceCategory().getCode();\r\n\t\t\t\tString taxCode = invoiceSubcatWriting.getTax().getCode();\r\n\t\t\t\tlog.info(\"Writing invoiceSubcat line: occCode={}, code={}, tax={}, AmountWithoutTax={}\", invoiceSubcatWriting.getAccountingCode().getCode(), invoiceCategoryCode, taxCode, invoiceSubcatWriting.getAmount());\r\n\r\n\t\t\t\tString costl = getCostl(invoiceCategoryCode);\r\n\t\t\t\tString operationType = getOperationType(invoiceSubcatWriting);\r\n\t\t\t\tString eventType = getEventType(invoiceWriting);\r\n\t\t\t\tString line = buildBBSEG(operationType, eventType, leftPad(round(invoiceSubcatWriting.getAmount().abs(), 2), 16, \"0\"), null, ZUONREnum.INVOICE.getLabel(),\r\n\t\t\t\t\t\ttaxCode, invoiceSubcatWriting.getAccountingCode().getCode(), costl);\r\n\t\t\t\tlines.add(line);\r\n\r\n\t\t\t\ttotalInvSubCatWritingAmount = totalInvSubCatWritingAmount.add(invoiceSubcatWriting.getAmount().setScale(2, RoundingMode.HALF_UP));\r\n\t\t\t}\r\n\r\n\t\t\tfor (AccountingEntry taxWriting : taxWritings) {\r\n\t\t\t\ttaxWriting.setExtraParam2(OCEDateNumLecture);\r\n\t\t\t\t// ne pas inclure les lignes avec montant à 0\r\n\t\t\t\tif (taxWriting.getAmount().compareTo(BigDecimal.ZERO) == 0) {\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tlog.info(\"Writing tax line: occCode={}, code={}, AmountTax={}\", taxWriting.getAccountingCode().getCode(), taxWriting.getTax().getCode(), taxWriting.getAmount());\r\n\t\t\t\tString operationType = getOperationType(taxWriting);\r\n\t\t\t\tString taxCode = taxWriting.getTax().getCode();\r\n\t\t\t\tString taxLine = buildBBTAX(operationType, leftPad(round(taxWriting.getAmount().abs(), 2), 16, \"0\"), taxCode);\r\n\t\t\t\tlines.add(taxLine);\r\n\t\t\t\ttotalTaxWritingAmount = totalTaxWritingAmount.add(taxWriting.getAmount().setScale(2, RoundingMode.HALF_UP));\r\n\t\t\t}\r\n\r\n\t\t\tString eventType = getEventType(invoiceWriting);\r\n\t\t\tString accountType = DEBIT;\r\n\t\t\tif (invoiceWriting.getAmount().compareTo(BigDecimal.ZERO) < 0) {\r\n\t\t\t\taccountType = CREDIT;\r\n\t\t\t}\r\n\t\t\tinvoiceWriting.setExtraParam2(OCEDateNumLecture);\r\n\t\t\t// ne pas inclure les lignes avec montant à 0\r\n\t\t\tif (invoiceWriting.getAmount().compareTo(BigDecimal.ZERO) != 0) {\r\n\t\t\t\tlines.add(buildBBSEG(accountType, eventType, leftPad(round(invoiceWriting.getAmount().abs(), 2), 16, \"0\"), null, ZUONREnum.INVOICE.getLabel(), \"\",\r\n\t\t\t\t\t\tinvoiceWriting.getAccountingCode().getCode(), null));\r\n\t\t\t}\r\n\r\n\t\t\t// check that accountingWrinting on date eventDate are well balanced\r\n\t\t\tif (invoiceWriting.getAmount().compareTo(totalInvSubCatWritingAmount.add(totalTaxWritingAmount)) != 0) {\r\n\t\t\t\tlog.error(\"AccountingWrintings on date {} are not balanced. invoiceWriting.amount={}, totalInvSubCatWritingAmount={}, \" +\r\n\t\t\t\t\t\t\t\t\"totalTaxWritingAmount={}. Checking invoices with pb ...\", DateUtils.formatAsDate(invoiceWriting.getEventDate()),\r\n\t\t\t\t\t\tinvoiceWriting.getAmount(), totalInvSubCatWritingAmount, totalTaxWritingAmount);\r\n\t\t\t\tString invoicesWithPb = checkInvoicesNotWellBalenced(invoiceWriting.getAccountOperations().stream()\r\n\t\t\t\t\t\t.map(ao -> ((RecordedInvoice)ao).getInvoice())\r\n\t\t\t\t\t\t.collect(Collectors.toList()));\r\n\t\t\t\tthrow new BusinessException(\"AccountingWrintings on date \"+ DateUtils.formatAsDate(invoiceWriting.getEventDate()) +\" are not well balanced (see logs for more details). Invoices with pbs: \" + invoicesWithPb);\r\n\t\t\t}\r\n\r\n\t\t\t// create writings\r\n\t\t\tinvoiceWriting.setIsWritten(true);\r\n\t\t\taccountingWritingService.create(invoiceWriting);\r\n\r\n\t\t\tfor (AccountingEntry invoiceSubcatWriting : invoiceSubcatWritings) {\r\n\t\t\t\taccountingWritingService.create(invoiceSubcatWriting);\r\n\t\t\t}\r\n\t\t\tfor (AccountingEntry taxWriting : taxWritings) {\r\n\t\t\t\taccountingWritingService.create(taxWriting);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tList<AccountingEntry> paymentWritings = getPaymentWritings(lastExecutionDate);\r\n\t\tlog.info(\"=== Writing paymentWritings. size={} ===\", paymentWritings.size());\r\n\t\tfor (AccountingEntry paymentWriting : paymentWritings) {\r\n\t\t\tString OCEDateNumLecture = PREFIX + DateUtils.formatDateWithPattern(new Date(), \"ddMMyyyy\") + index2;\r\n\t\t\tpaymentWriting.setExtraParam2(OCEDateNumLecture);\r\n\r\n\t\t\tString occCode = \"\";\r\n\t\t\tString costl = \"\";\r\n\r\n\t\t\tTax tax = findTaxByCode(\"V0\");\r\n\t\t\tString taxCode = \"\";\r\n\t\t\tfor (AccountOperation ao : paymentWriting.getAccountOperations()) {\r\n\t\t\t\toccCode = ao.getCode();\r\n\t\t\t\tcostl = getCostl(occCode);\r\n\t\t\t\tif (occCode.equals(\"PAY_FF\")) {\r\n\t\t\t\t\tpaymentWriting.setTax(tax);\r\n\t\t\t\t\ttaxCode = paymentWriting.getTax().getCode();\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tlog.info(\"--- paymentWriting line: {}\", paymentWriting);\r\n\t\t\t// ne pas inclure les lignes avec montant à 0\r\n\t\t\tif (paymentWriting.getAmount().compareTo(BigDecimal.ZERO) != 0) {\r\n\t\t\t\tlines.add(buildBBKPF(paymentWriting.getEventDate(), new Date(), index++));\r\n\t\t\t\tindex2 = index - 1;\r\n\t\t\t\tString line = buildBBSEG(DEBIT, paymentWriting.getEventType(), leftPad(round(paymentWriting.getAmount(), 2), 16, \"0\"), paymentWriting.getEventDate(),\r\n\t\t\t\t\t\tgetZUONR(occCode, paymentWriting.getAccountingCode().getCode()), taxCode, paymentWriting.getAccountingCode().getCode(), costl);\r\n\t\t\t\tlines.add(line);\r\n\r\n\t\t\t\tString lineInvoicing = buildBBSEG(CREDIT, paymentWriting.getEventType(), leftPad(round(paymentWriting.getAmount(), 2), 16, \"0\"), paymentWriting.getEventDate(),\r\n\t\t\t\t\t\tgetZUONR(occCode, paymentWriting.getExtraParam1()), \"\", paymentWriting.getExtraParam1(), null);\r\n\t\t\t\tlines.add(lineInvoicing);\r\n\t\t\t}\r\n\t\t}\r\n\t\tfor (AccountingEntry paymentWriting : paymentWritings) {\r\n\t\t\taccountingWritingService.create(paymentWriting);\r\n\t\t}\r\n\r\n\t\tList<AccountingEntry> refundWritings = getRefundWritings(lastExecutionDate);\r\n\t\tlog.info(\"=== Writing refundWritings. size={} ===\", refundWritings.size());\r\n\t\tfor (AccountingEntry refundWriting : refundWritings) {\r\n\t\t\tString OCEDateNumLecture = PREFIX + DateUtils.formatDateWithPattern(new Date(), \"ddMMyyyy\") + index2;\r\n\t\t\trefundWriting.setExtraParam2(OCEDateNumLecture);\r\n\t\t\tString occCode = \"\";\r\n\t\t\tfor (AccountOperation ao : refundWriting.getAccountOperations()) {\r\n\t\t\t\toccCode = ao.getCode();\r\n\t\t\t}\r\n\r\n\t\t\tlog.info(\"--- RefundWritings line: {}\", refundWriting);\r\n\t\t\t// ne pas inclure les lignes avec montant à 0\r\n\t\t\tif (refundWriting.getAmount().compareTo(BigDecimal.ZERO) != 0) {\r\n\t\t\t\tlines.add(buildBBKPF(refundWriting.getEventDate(), new Date(), index++));\r\n\t\t\t\tindex2 = index - 1;\r\n\t\t\t\tString line = buildBBSEG(DEBIT, refundWriting.getEventType(), leftPad(round(refundWriting.getAmount(), 2), 16, \"0\"), refundWriting.getEventDate(),\r\n\t\t\t\t\t\tgetZUONR(occCode, refundWriting.getAccountingCode().getCode()), \"\", refundWriting.getAccountingCode().getCode(), null);\r\n\t\t\t\tlines.add(line);\r\n\r\n\t\t\t\tString linePayment = buildBBSEG(CREDIT, refundWriting.getEventType(), leftPad(round(refundWriting.getAmount(), 2), 16, \"0\"), refundWriting.getEventDate(),\r\n\t\t\t\t\t\tgetZUONR(occCode, refundWriting.getExtraParam1()), \"\", refundWriting.getExtraParam1(), null);\r\n\t\t\t\tlines.add(linePayment);\r\n\t\t\t}\r\n\t\t}\r\n\t\tfor (AccountingEntry refundWriting : refundWritings) {\r\n\t\t\taccountingWritingService.create(refundWriting);\r\n\t\t}\r\n\r\n\t\t// pour les lignes des annulations des commandes\r\n\t\tList<String> invoiceNumberList = getCancelinvoices(lastExecutionDate);\r\n\t\tlog.info(\"Checking for cancelInvoices ==> {}\", invoiceNumberList);\r\n\t\tif (!invoiceNumberList.isEmpty()) {\r\n\t\t\tList<AccountingEntry> invoiceWritingsAvoir = getAvoirWritings(invoiceNumberList);\r\n\t\t\tlog.info(\"Writing invoiceWritingsAvoir ==> size={}\", invoiceWritingsAvoir.size());\r\n\t\t\tfor (AccountingEntry invoiceWriting : invoiceWritingsAvoir) {\r\n\t\t\t\tList<AccountingEntry> invoiceSubcatWritings = null;\r\n\t\t\t\tList<AccountingEntry> taxWritings = null;\r\n\r\n\t\t\t\tBigDecimal totalInvSubCatWritingAmount = BigDecimal.ZERO;\r\n\t\t\t\tBigDecimal totalTaxWritingAmount = BigDecimal.ZERO;\r\n\t\t\t\tif (!invoiceWriting.getIsWritten()) {\r\n\r\n\t\t\t\t\tinvoiceSubcatWritings = getInvoiceSubcatsWritings(invoiceWriting.getEventDate(), invoiceWriting.getAccountingCode().getCode(), invoiceNumberList);\r\n\t\t\t\t\ttaxWritings = getTaxWritings(invoiceWriting.getEventDate(), invoiceWriting.getAccountingCode().getCode(), invoiceNumberList);\r\n\r\n\t\t\t\t\tboolean isExitNonZeroSubCat = invoiceSubcatWritings.stream().anyMatch(aw -> aw.getAmount().compareTo(BigDecimal.ZERO) != 0);\r\n\t\t\t\t\tboolean isExitNonZeroTax = taxWritings.stream().anyMatch(aw -> aw.getAmount().compareTo(BigDecimal.ZERO) != 0);\r\n\t\t\t\t\tif (invoiceWriting.getAmount().compareTo(BigDecimal.ZERO) != 0 || isExitNonZeroSubCat || isExitNonZeroTax) {\r\n\t\t\t\t\t\tlines.add(buildBBKPF(invoiceWriting.getEventDate(), new Date(), index++));\r\n\t\t\t\t\t\tindex2 = index - 1;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tString OCEDateNumLecture = PREFIX + DateUtils.formatDateWithPattern(new Date(), \"ddMMyyyy\") + index2;\r\n\r\n\t\t\t\t\tfor (AccountingEntry invoiceSubcatWriting : invoiceSubcatWritings) {\r\n\t\t\t\t\t\tinvoiceSubcatWriting.setExtraParam2(OCEDateNumLecture);\r\n\r\n\t\t\t\t\t\t// ne pas inclure les lignes avec montant à 0\r\n\t\t\t\t\t\tif (invoiceSubcatWriting.getAmount().compareTo(BigDecimal.ZERO) == 0) {\r\n\t\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tString invoiceCategoryCode = invoiceSubcatWriting.getInvoiceCategory().getCode();\r\n\t\t\t\t\t\tString taxCode = invoiceSubcatWriting.getTax().getCode();\r\n\t\t\t\t\t\tlog.info(\"Writing invoiceAvoirSubcat line: occCode={}, code={}, tax={}, AmountWithoutTax={}\",\r\n\t\t\t\t\t\t\t\tinvoiceSubcatWriting.getAccountingCode().getCode(), invoiceCategoryCode, taxCode,\tinvoiceSubcatWriting.getAmount());\r\n\t\t\t\t\t\tString costl = getCostl(invoiceCategoryCode);\r\n\t\t\t\t\t\tString operationType = getOperationTypeAvoir(invoiceSubcatWriting);\r\n\t\t\t\t\t\tString eventType = EventEnum.ANNULATION_FACTURATION.getLabel();// getEventType(invoiceWriting);\r\n\t\t\t\t\t\tString line = buildBBSEG(operationType, eventType, leftPad(round(invoiceSubcatWriting.getAmount().abs(), 2), 16, \"0\"), null, ZUONREnum.INVOICE.getLabel(),\r\n\t\t\t\t\t\t\t\ttaxCode, invoiceSubcatWriting.getAccountingCode().getCode(), costl);\r\n\t\t\t\t\t\tlines.add(line);\r\n\r\n\t\t\t\t\t\ttotalInvSubCatWritingAmount = totalInvSubCatWritingAmount.add(invoiceSubcatWriting.getAmount().setScale(2, RoundingMode.HALF_UP));\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tfor (AccountingEntry taxWriting : taxWritings) {\r\n\t\t\t\t\t\ttaxWriting.setExtraParam2(OCEDateNumLecture);\r\n\t\t\t\t\t\t// ne pas inclure les lignes avec montant à 0\r\n\t\t\t\t\t\tif (taxWriting.getAmount().compareTo(BigDecimal.ZERO) == 0) {\r\n\t\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tlog.info(\"Writing taxAvoirWriting line: occCode={}, code={}, AmountTax={}\", taxWriting.getAccountingCode().getCode(),\r\n\t\t\t\t\t\t\t\ttaxWriting.getTax().getCode(), taxWriting.getAmount());\r\n\t\t\t\t\t\tString operationType = getOperationTypeAvoir(taxWriting);\r\n\t\t\t\t\t\tString taxCode = taxWriting.getTax().getCode();\r\n\t\t\t\t\t\tString taxLine = buildBBTAX(operationType, leftPad(round(taxWriting.getAmount().abs(), 2), 16, \"0\"), taxCode);\r\n\t\t\t\t\t\tlines.add(taxLine);\r\n\t\t\t\t\t\ttotalTaxWritingAmount = totalTaxWritingAmount.add(taxWriting.getAmount().setScale(2, RoundingMode.HALF_UP));\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tString eventType = EventEnum.ANNULATION_FACTURATION.getLabel();// getEventType(invoiceWriting);\r\n\t\t\t\t\tString accountType = CREDIT;\r\n\t\t\t\t\tif (invoiceWriting.getAmount().compareTo(BigDecimal.ZERO) < 0) {\r\n\t\t\t\t\t\taccountType = DEBIT;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tinvoiceWriting.setExtraParam2(OCEDateNumLecture);\r\n\t\t\t\t\t// ne pas inclure les lignes avec montant à 0\r\n\t\t\t\t\tif (invoiceWriting.getAmount().compareTo(BigDecimal.ZERO) != 0) {\r\n\t\t\t\t\t\tlines.add(buildBBSEG(accountType, eventType, leftPad(round(invoiceWriting.getAmount().abs(), 2), 16, \"0\"), null, ZUONREnum.INVOICE.getLabel(), \"\",\r\n\t\t\t\t\t\t\t\tinvoiceWriting.getAccountingCode().getCode(), null));\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// check that accountingWrinting on date eventDate are well balanced\r\n\t\t\t\t\tif (invoiceWriting.getAmount().compareTo(totalInvSubCatWritingAmount.add(totalTaxWritingAmount)) != 0) {\r\n\t\t\t\t\t\tString invoicesWithPb = checkInvoicesNotWellBalenced(invoiceWriting.getAccountOperations().stream()\r\n\t\t\t\t\t\t\t\t.map(ao -> ((RecordedInvoice)ao).getInvoice())\r\n\t\t\t\t\t\t\t\t.collect(Collectors.toList()));\r\n\t\t\t\t\t\tlog.error(\"AccountingWrintings for canceled invoices on date {} are not balanced. invoiceWriting.amount={}, totalInvSubCatWritingAmount={}, \" +\r\n\t\t\t\t\t\t\t\t\t\t\"totalTaxWritingAmount={}. Invoices concerned: {}\", DateUtils.formatAsDate(invoiceWriting.getEventDate()),\r\n\t\t\t\t\t\t\t\tinvoiceWriting.getAmount(), totalInvSubCatWritingAmount, totalTaxWritingAmount, invoicesWithPb);\r\n\t\t\t\t\t\tthrow new BusinessException(\"AccountingWrintings for canceled invoices on date on date \"+ DateUtils.formatAsDate(invoiceWriting.getEventDate()) +\" are not well balanced (see logs for more details). Invoices with pbs: \" + invoicesWithPb);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// create writings\r\n\t\t\t\tinvoiceWriting.setIsWritten(true);\r\n\t\t\t\taccountingWritingService.create(invoiceWriting);\r\n\r\n\t\t\t\tfor (AccountingEntry invoiceSubcatWriting : invoiceSubcatWritings) {\r\n\t\t\t\t\taccountingWritingService.create(invoiceSubcatWriting);\r\n\t\t\t\t}\r\n\t\t\t\tfor (AccountingEntry taxWriting : taxWritings) {\r\n\t\t\t\t\taccountingWritingService.create(taxWriting);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\tJobExecutionResultImpl jobExecutionResult = (JobExecutionResultImpl) context.get(JOB_EXECUTION_RESULT);\r\n\t\t\tif (lines.size() > 0) {\r\n\t\t\t\tfor (String line : lines) {\r\n\t\t\t\t\tappendLine(line);\r\n\t\t\t\t}\r\n\t\t\t\tcontentBuilder.deleteCharAt(contentBuilder.lastIndexOf(NEW_LINE));\r\n\t\t\t\tFiles.write(contentBuilder, new File(absoluteOutputFileName), Charsets.UTF_8);\r\n\t\t\t\tFiles.write(contentBuilder, new File(absoluteArchivedFileName), Charsets.UTF_8);\r\n\t\t\t\tlog.info(\"absoluteOutputFileName:\" + absoluteOutputFileName);\r\n\t\t\t\tlog.info(\"absoluteArchivedFileName:\" + absoluteArchivedFileName);\r\n\r\n\t\t\t\tjobExecutionResult.addReport(\"Accounting export successfully done. File generated at \" + absoluteOutputFileName);\r\n\t\t\t} else {\r\n\t\t\t\tjobExecutionResult.addReport(\"No new accounting lines found to export! so no file generated.\");\r\n\t\t\t}\r\n\r\n\r\n\t\t} catch (IOException e) {\r\n\t\t\tthrow new BusinessException(e);\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tprivate List<AccountingEntry> getTaxWritingsV2(Date eventDate, String invoiceAccCode) {\r\n\t\tList<AccountingEntry> taxWritings = new ArrayList<>();\r\n\r\n\t\tString sql = \"select tax_code, tax_acc_code, event_time,\\n\" +\r\n\t\t\t\t\"\\tstring_agg(cast(ao_id as text), ',') as ao_ids,\" +\r\n\t\t\t\t\" sum(amount_tax) as amount_tax\\n\" +\r\n\t\t\t\t\"from rapsodie_rt_\"+generationDate+\"\\n\" +\r\n\t\t\t\t\"where event_time='\"+DateUtils.formatDateWithPattern(eventDate, \"yyyy-MM-dd\")+\"' and inv_acc_code='\"+invoiceAccCode+\"'\\n\" +\r\n\t\t\t\t\"group by tax_code, tax_acc_code, event_time\";\r\n\r\n\t\tList<Tuple> rows = invoiceService.getEntityManager().createNativeQuery(sql, Tuple.class).getResultList();\r\n\t\tfor (Tuple row : rows) {\r\n\t\t\tAccountingEntry accountingWriting = new AccountingEntry();\r\n\r\n\t\t\taccountingWriting.setEventDate(eventDate);\r\n\t\t\taccountingWriting.setAccountingCode(accountingCodeService.findByCode((String) row.get(\"tax_acc_code\")));\r\n\t\t\taccountingWriting.setExportDate(new Date());\r\n\t\t\tList<AccountOperation> accountOperations = invoiceCategoryService.getEntityManager()\r\n\t\t\t\t\t.createQuery(\"Select ao from AccountOperation ao where ao.id in (\"+row.get(\"ao_ids\")+\")\",\r\n\t\t\t\t\t\t\tAccountOperation.class).getResultList();\r\n\t\t\taccountingWriting.setAccountOperations(accountOperations);\r\n\t\t\taccountingWriting.setTax(taxService.findByCode((String) row.get(\"tax_code\")));\r\n\t\t\taccountingWriting.setAmount(round((BigDecimal) row.get(\"amount_tax\")));\r\n\r\n\t\t\ttaxWritings.add(accountingWriting);\r\n\t\t}\r\n\t\treturn taxWritings;\r\n\t}\r\n\r\n\tprivate List<AccountingEntry> getInvoiceSubcatsWritingsV2(Date eventDate, String invoiceAccCode) {\r\n\t\tList<AccountingEntry> invoiceCatsWritings = new ArrayList<>();\r\n\r\n\t\tString sql = \"select cat_code, tax_code, subcat_acc_code, event_time, \" +\r\n\t\t\t\t\"string_agg(cast(ao_id as text), ',') as ao_ids,\" +\r\n\t\t\t\t\" sum(amount_without_tax) as amount_without_tax\\n\" +\r\n\t\t\t\t\"from rapsodie_rt_\"+generationDate+\"\\n\" +\r\n\t\t\t\t\"where event_time='\"+DateUtils.formatDateWithPattern(eventDate, \"yyyy-MM-dd\")+\"' and inv_acc_code='\"+invoiceAccCode+\"'\\n\" +\r\n\t\t\t\t\"group by cat_code, tax_code, subcat_acc_code, event_time\";\r\n\r\n\t\tList<Tuple> rows = invoiceService.getEntityManager().createNativeQuery(sql, Tuple.class).getResultList();\r\n\t\tfor (Tuple row : rows) {\r\n\t\t\tAccountingEntry accountingWriting = new AccountingEntry();\r\n\r\n\t\t\taccountingWriting.setEventType(EventEnum.FACTURATION.getLabel());\r\n\t\t\taccountingWriting.setEventDate(eventDate);\r\n\t\t\taccountingWriting.setInvoiceCategory(invoiceCategoryService.findByCode((String) row.get(\"cat_code\")));\r\n\t\t\taccountingWriting.setAccountingCode(accountingCodeService.findByCode((String) row.get(\"subcat_acc_code\")));\r\n\t\t\taccountingWriting.setExportDate(new Date());\r\n\t\t\tList<AccountOperation> accountOperations = invoiceCategoryService.getEntityManager()\r\n\t\t\t\t\t.createQuery(\"Select ao from AccountOperation ao where ao.id in (\"+row.get(\"ao_ids\")+\")\",\r\n\t\t\t\t\t\t\tAccountOperation.class).getResultList();\r\n\t\t\taccountingWriting.setAccountOperations(accountOperations);\r\n\t\t\taccountingWriting.setTax(taxService.findByCode((String) row.get(\"tax_code\")));\r\n\t\t\taccountingWriting.setAmount(round((BigDecimal) row.get(\"amount_without_tax\")));\r\n\r\n\t\t\tinvoiceCatsWritings.add(accountingWriting);\r\n\t\t}\r\n\t\treturn invoiceCatsWritings;\r\n\t}\r\n\r\n\tprivate void createMaterializedViews() {\r\n\t\tEntityManager em = ratedTransactionService.getEntityManager();\r\n\t\t//delete old views\r\n\t\tQuery query = em.createNativeQuery(\"SELECT schemaname, matviewname FROM pg_matviews WHERE matviewname LIKE 'rapsodie_rt_%'\");\r\n\t\tList<Object[]> oldViews = query.getResultList();\r\n\t\tfor (Object[] oldView : oldViews) {\r\n\t\t\tString schemaName = (String) oldView[0];\r\n\t\t\tString matviewName = (String) oldView[1];\r\n\t\t\tem.createNativeQuery(\"DROP MATERIALIZED VIEW \" + schemaName + \".\" + matviewName).executeUpdate();\r\n\t\t}\r\n\r\n\t\tString sql = \"CREATE MATERIALIZED VIEW rapsodie_rt_\"+generationDate+\" AS \\n\" +\r\n\t\t\t\t\"select inv.created as inv_created, inv.invoice_number, tax.id as tax_id, tax.code as tax_code, acccode3.code as tax_acc_code,\\n\" +\r\n\t\t\t\t\"\\tcat.id as cat_id, cat.code as cat_code, acccode1.code as subcat_acc_code, invt.code as invoice_type, acccode2.code as inv_acc_code,\\n\" +\r\n\t\t\t\t\"\\tao.transaction_category as op_sens, ao.id as ao_id, cast(ao.created as date) as event_time, rt.id as rt_id,\\n\" +\r\n\t\t\t\t\"\\tcase \\n\" +\r\n\t\t\t\t\"\\t\\twhen invt.code='ADJ' then -rt.amount_without_tax\\n\" +\r\n\t\t\t\t\"\\t\\telse rt.amount_without_tax\\n\" +\r\n\t\t\t\t\"\\tend as amount_without_tax,\\n\" +\r\n\t\t\t\t\"\\tcase \\n\" +\r\n\t\t\t\t\"\\t\\twhen invt.code='ADJ' then -rt.amount_tax\\n\" +\r\n\t\t\t\t\"\\t\\telse rt.amount_tax\\n\" +\r\n\t\t\t\t\"\\tend as amount_tax,\\n\" +\r\n\t\t\t\t\"\\tcase \\n\" +\r\n\t\t\t\t\"\\t\\twhen invt.code='ADJ' then -rt.amount_with_tax\\n\" +\r\n\t\t\t\t\"\\t\\telse rt.amount_with_tax\\n\" +\r\n\t\t\t\t\"\\tend as amount_with_tax \\n\" +\r\n\t\t\t\t\" \\n\" +\r\n\t\t\t\t\"from billing_rated_transaction rt\\n\" +\r\n\t\t\t\t\"\\tinner join billing_tax tax on rt.tax_id=tax.id\\n\" +\r\n\t\t\t\t\"\\tinner join billing_accounting_code acccode3 on tax.accounting_code_id=acccode3.id\\n\" +\r\n\t\t\t\t\" \\tinner join billing_invoice_agregate scagg on rt.aggregate_id_f=scagg.id\\n\" +\r\n\t\t\t\t\"\\tinner join billing_invoice_sub_cat scat on scagg.invoicesubcategory=scat.id\\n\" +\r\n\t\t\t\t\"\\tinner join billing_invoice_cat cat on scat.invoice_category_id=cat.id\\n\" +\r\n\t\t\t\t\"\\tinner join billing_accounting_code acccode1 on scagg.accounting_code_id=acccode1.id\\n\" +\r\n\t\t\t\t\"\\tinner join billing_invoice inv on rt.invoice_id=inv.id\\n\" +\r\n\t\t\t\t\"\\tinner join billing_invoice_type invt on inv.invoice_type_id=invt.id\\n\" +\r\n\t\t\t\t\"\\tinner join ar_occ_template occt on invt.occ_template_id=occt.id\\n\" +\r\n\t\t\t\t\"\\tinner join billing_accounting_code acccode2 on occt.accounting_code_id=acccode2.id\\n\" +\r\n\t\t\t\t\"\\t\\n\" +\r\n\t\t\t\t\"\\tinner join ar_account_operation ao on inv.recorded_invoice_id = ao.id\\n\" +\r\n\t\t\t\t\"\\tleft join ar_accounting_writing_acc_operations accwao ON ao.id = accwao.account_operation_id\\n\" +\r\n\t\t\t\t\"\\n\" +\r\n\t\t\t\t\"where accwao.account_operation_id is null\\n\" +\r\n\t\t\t\t\"order by inv.id, cat.code, tax.code, rt.id\";\r\n\r\n\t\tem.createNativeQuery(sql).executeUpdate();\r\n\t}\r\n\r\n\tprivate String checkInvoicesNotWellBalenced(List<Invoice> invoices) {\r\n\t\tList<String> invoicesWithPb = new ArrayList<>();\r\n\r\n\t\tfor (Invoice inv : invoices) {\r\n\t\t\tList<RatedTransaction> rts = ratedTransactionService.getRatedTransactionsByInvoice(inv, true);\r\n\t\t\tMap<String, BigDecimal> subCatAmounts = new HashMap<>();\r\n\t\t\tMap<String, BigDecimal> taxAmounts = new HashMap<>();\r\n\t\t\tfor (var rt : rts) {\r\n\t\t\t\tsubCatAmounts\r\n\t\t\t\t\t\t.put(rt.getInvoiceSubCategory().getCode(),\r\n\t\t\t\t\t\t\t\tsubCatAmounts.computeIfAbsent(rt.getInvoiceSubCategory().getCode(), k->BigDecimal.ZERO)\r\n\t\t\t\t\t\t\t\t\t\t.add(rt.getAmountWithoutTax()));\r\n\t\t\t\ttaxAmounts\r\n\t\t\t\t\t\t.put(rt.getTax().getCode(),\r\n\t\t\t\t\t\t\t\ttaxAmounts.computeIfAbsent(rt.getTax().getCode(), k->BigDecimal.ZERO)\r\n\t\t\t\t\t\t\t\t\t\t.add(rt.getAmountTax()));\r\n\t\t\t}\r\n\t\t\tBigDecimal subCatTotal = subCatAmounts.values().stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO);\r\n\t\t\tBigDecimal taxTotal = taxAmounts.values().stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO);\r\n\r\n\t\t\tif (subCatTotal.add(taxTotal).compareTo(inv.getAmountWithTax()) != 0) {\r\n\t\t\t\tlog.error(\"Invoice {} is not well balanced: subCatTotal={}, taxTotal={}, subCatTotal+taxTotal={}, invoiceTTC={}\", inv.getInvoiceNumber(),\r\n\t\t\t\t\t\tsubCatTotal, taxTotal, subCatTotal.add(taxTotal), inv.getAmountWithTax());\r\n\t\t\t\tlog.error(\"Invoice {} subcats amounts details: {}\", inv.getInvoiceNumber(), subCatAmounts);\r\n\t\t\t\tlog.error(\"Invoice {} tax amounts details: {}\", inv.getInvoiceNumber(), taxAmounts);\r\n\t\t\t\tinvoicesWithPb.add(inv.getInvoiceNumber());\r\n\t\t\t} else {\r\n\t\t\t\tlog.error(\"Invoice {} is OK: subCatTotal={}, taxTotal={}, subCatTotal+taxTotal={}, invoiceTTC={}\", inv.getInvoiceNumber(),\r\n\t\t\t\t\t\tsubCatTotal, taxTotal, subCatTotal.add(taxTotal), inv.getAmountWithTax());\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (!invoicesWithPb.isEmpty()) {\r\n\t\t\treturn String.join(\",\", invoicesWithPb);\r\n\t\t} else {\r\n\t\t\treturn \"\";\r\n\t\t}\r\n\t}\r\n\r\n\tprivate List<AccountingEntry> getAvoirWritings(List<String> invoiceNumberList) {\r\n\r\n\t\tMap<String, Object> params = new HashMap<>();\r\n\t\tparams.put(\"invoiceList\", invoiceNumberList);\r\n\t\tString query = \"Select cast(inv.recordedInvoice.auditable.created as date), inv \" +\r\n\t\t\t\t\"FROM Invoice inv \" +\r\n\t\t\t\t\"WHERE ( (inv.recordedInvoice is not null and cfValues like '%CF_DATE_FIN_INSTALLATION%' and invoiceType.code = 'INS') or (inv.recordedInvoice is not null and invoiceType.code = 'PVT' ) ) and inv.invoiceNumber in :invoiceList \";\r\n\r\n\t\tOCCTemplate occTemplateRefInv = occTemplateService.findByCode(OCC_TEMP_CODE_REF_INV);\r\n\t\tMap<String, AccountingEntry> accountingEntries = new HashMap<String, AccountingEntry>();\r\n\r\n\t\tList<Object[]> rows = (List<Object[]>) invoiceService.executeSelectQuery(query, params);\r\n\t\tfor (Object[] row : rows) {\r\n\t\t\tDate date = (Date) row[0];\r\n\t\t\tInvoice invoice = (Invoice) row[1];\r\n\t\t\tcheckInvoiceAmounts(invoice);\r\n\t\t\tString key = date + \"_\" + occTemplateRefInv.getAccountingCode().getCode();\r\n\r\n\t\t\tAccountingEntry accountingWriting = new AccountingEntry();\r\n\t\t\tList<AccountOperation> accountOperations = new ArrayList<AccountOperation>();\r\n\t\t\tif (accountingEntries.get(key) != null) {\r\n\t\t\t\taccountingWriting = accountingEntries.get(key);\r\n\t\t\t\taccountingWriting.setAmount(invoice.getAmountWithTax().add(accountingWriting.getAmount()));\r\n\t\t\t\taccountOperations.addAll(accountingWriting.getAccountOperations());\r\n\t\t\t} else {\r\n\t\t\t\taccountingWriting.setAmount(invoice.getAmountWithTax());\r\n\t\t\t}\r\n\t\t\taccountOperations.add(invoice.getRecordedInvoice());\r\n\r\n\t\t\taccountingWriting.setAccountingCode(occTemplateRefInv.getAccountingCode());\r\n\t\t\taccountingWriting.setAccountOperations(accountOperations);\r\n\t\t\taccountingWriting.setEventType(EventEnum.ANNULATION_FACTURATION.getLabel());\r\n\t\t\taccountingWriting.setEventDate(date);\r\n\t\t\taccountingWriting.setExportDate(new Date());\r\n\t\t\taccountingWriting.setIsWritten(false);\r\n\t\t\taccountingEntries.put(key, accountingWriting);\r\n\t\t}\r\n\r\n\t\treturn new ArrayList<>(accountingEntries.values());\r\n\t}\r\n\r\n\tprivate List<AccountingEntry> getInvoiceWritings() throws BusinessException {\r\n\t\tString query = \"Select cast(inv.recordedInvoice.auditable.created as date), inv \" +\r\n\t\t\t\t\"FROM Invoice inv JOIN inv.recordedInvoice ri LEFT JOIN ri.accountingEntries ae \" +\r\n\t\t\t\t\"WHERE ri IS NOT NULL AND ae IS NULL \" +\r\n\t\t\t\t\"ORDER BY inv.recordedInvoice.auditable.created\";\r\n\r\n\t\tMap<String, AccountingEntry> accountingEntries = new HashMap<>();\r\n\r\n\t\tList<Object[]> rows = (List<Object[]>) invoiceService.executeSelectQuery(query, null);\r\n\t\tfor (Object[] row : rows) {\r\n\t\t\tDate date = (Date) row[0];\r\n\t\t\tInvoice invoice = (Invoice) row[1];\r\n\r\n\t\t\tcheckInvoiceAmounts(invoice);\r\n\r\n\t\t\tString key = date + \"_\" + invoice.getInvoiceType().getOccTemplate().getAccountingCode().getCode();\r\n\t\t\tAccountingEntry accountingWriting = new AccountingEntry();\r\n\t\t\tList<AccountOperation> accountOperations = new ArrayList<AccountOperation>();\r\n\t\t\tif (accountingEntries.get(key) != null) {\r\n\t\t\t\taccountingWriting = accountingEntries.get(key);\r\n\t\t\t\tBigDecimal invAmount = !invoice.getInvoiceType().getCode().equals(\"ADJ\") ?\r\n\t\t\t\t\t\tinvoice.getAmountWithTax() : invoice.getAmountWithTax().negate();\r\n\t\t\t\taccountingWriting.setAmount(invAmount.add(accountingWriting.getAmount()));\r\n\t\t\t\taccountOperations.addAll(accountingWriting.getAccountOperations());\r\n\t\t\t} else {\r\n\t\t\t\taccountingWriting.setAmount(invoice.getAmountWithTax());\r\n\t\t\t}\r\n\t\t\taccountOperations.add(invoice.getRecordedInvoice());\r\n\r\n\t\t\taccountingWriting.setAccountingCode(invoice.getInvoiceType().getOccTemplate().getAccountingCode());\r\n\t\t\taccountingWriting.setAccountOperations(accountOperations);\r\n\t\t\taccountingWriting.setEventType(EventEnum.FACTURATION.getLabel());\r\n\t\t\taccountingWriting.setEventDate(date);\r\n\t\t\taccountingWriting.setExportDate(new Date());\r\n\t\t\taccountingEntries.put(key, accountingWriting);\r\n\t\t}\r\n\t\treturn new ArrayList<>(accountingEntries.values());\r\n\t}\r\n\r\n\tprivate List<AccountingEntry> getInvoiceWritingsV2() throws BusinessException {\r\n\t\tString query = \"SELECT cast(ao.created as date) as event_date, acccode.code as inv_acc_code,\\n\" +\r\n\t\t\t\t\"\\tsum(case when invt.code='ADJ' then -inv.amount_with_tax else inv.amount_with_tax end) as amount_ttc,\\n\" +\r\n\t\t\t\t\"\\tstring_agg(cast(ao.id as text), ',') as ao_ids\\n\" +\r\n\t\t\t\t\"from billing_invoice inv\\n\" +\r\n\t\t\t\t\"\\tinner join billing_invoice_type invt on inv.invoice_type_id=invt.id\\n\" +\r\n\t\t\t\t\"\\tinner join ar_occ_template occt on invt.occ_template_id=occt.id\\n\" +\r\n\t\t\t\t\"\\tinner join billing_accounting_code acccode on occt.accounting_code_id=acccode.id\\n\" +\r\n\t\t\t\t\"\\tinner join ar_account_operation ao on inv.recorded_invoice_id = ao.id\\n\" +\r\n\t\t\t\t\"\\tleft join ar_accounting_writing_acc_operations accwao ON ao.id = accwao.account_operation_id\\n\" +\r\n\t\t\t\t\"\\n\" +\r\n\t\t\t\t\"where accwao.account_operation_id is null\\n\" +\r\n\t\t\t\t\"group by cast(ao.created as date), acccode.code\\n\" +\r\n\t\t\t\t\"order by cast(ao.created as date)\";\r\n\r\n\t\tList<AccountingEntry> accountingEntries = new ArrayList<>();\r\n\r\n\t\tList<Tuple> rows = invoiceService.getEntityManager()\r\n\t\t\t\t.createNativeQuery(query, Tuple.class).getResultList();\r\n\t\tfor (Tuple row : rows) {\r\n\t\t\tDate date = (Date) row.get(\"event_date\");\r\n\t\t\tAccountingEntry accountingWriting = new AccountingEntry();\r\n\t\t\tList<AccountOperation> accountOperations = invoiceService.getEntityManager()\r\n\t\t\t\t\t.createQuery(\"Select ao from AccountOperation ao where ao.id in (\"+row.get(\"ao_ids\")+\")\",\r\n\t\t\t\t\t\t\tAccountOperation.class).getResultList();\r\n\r\n\t\t\taccountingWriting.setAmount(round((BigDecimal) row.get(\"amount_ttc\")));\r\n\t\t\taccountingWriting.setAccountingCode(accountingCodeService.findByCode((String) row.get(\"inv_acc_code\")));\r\n\t\t\taccountingWriting.setAccountOperations(accountOperations);\r\n\t\t\taccountingWriting.setEventType(EventEnum.FACTURATION.getLabel());\r\n\t\t\taccountingWriting.setEventDate(date);\r\n\t\t\taccountingWriting.setExportDate(new Date());\r\n\r\n\t\t\taccountingEntries.add(accountingWriting);\r\n\t\t}\r\n\t\treturn accountingEntries;\r\n\t}\r\n\r\n\tprivate void checkInvoiceAmounts(Invoice invoice) throws BusinessException {\r\n\r\n\t\tBigDecimal ht = invoice.getAmountWithoutTax();\r\n\t\tBigDecimal tva = invoice.getAmountTax();\r\n\t\tBigDecimal ttc = invoice.getAmountWithTax();\r\n\r\n\t\tif (Math.max(0, ht.stripTrailingZeros().scale()) > 2\r\n\t\t\t\t|| Math.max(0, tva.stripTrailingZeros().scale()) > 2\r\n\t\t\t\t|| Math.max(0, ttc.stripTrailingZeros().scale()) > 2) {\r\n\t\t\tthrow new BusinessException(\"Incoherent amounts for Invoice \" + invoice.getInvoiceNumber() + \": Amounts with more than 2 decimals!\" );\r\n\t\t}\r\n\r\n\t\tif ((ht.add(tva)).compareTo(ttc) != 0) {\r\n\t\t\tthrow new BusinessException(\"Incoherent amounts for Invoice \" + invoice.getInvoiceNumber() + \": HT+TVA != TTC\" );\r\n\t\t}\r\n\r\n\t\tif (ht.abs().compareTo(tva.abs()) < 0) {\r\n\t\t\tthrow new BusinessException(\"Incoherent amounts for Invoice \" + invoice.getInvoiceNumber() + \": HT < TVA\" );\r\n\t\t}\r\n\t}\r\n\r\n\tprivate List<AccountingEntry> getPaymentWritings(Date date) {\r\n\t\tMap<String, AccountingEntry> accountingEntries = new HashMap<>();\r\n\t\tString query = \"Select cast(ma2.accountOperation.auditable.created as date), ma2, mc2 \"\r\n\t\t\t\t+ \" FROM MatchingCode mc2 JOIN mc2.matchingAmounts ma2 \"\r\n\t\t\t\t+ \" WHERE ma2.accountOperation.transactionCategory = org.meveo.model.payments.OperationCategoryEnum.CREDIT\"\r\n\t\t\t\t+ \" AND ma2.auditable.created > :date\"\r\n\t\t\t\t+ \" AND ma2.accountOperation.code != 'REF_INV'\"\r\n\t\t\t\t+ \" AND ma2.accountOperation.accountingEntries is empty\";\r\n\r\n\t\tMap<String, Object> params = new HashMap<>();\r\n\t\tparams.put(\"date\", date);\r\n\r\n\t\tList<Object[]> rows = (List<Object[]>) invoiceService.executeSelectQuery(query, params);\r\n\t\tlog.info(\"resultPaymentMatched=>\" + rows.size());\r\n\r\n\t\tfor (Object[] row : rows) {\r\n\t\t\tDate eventDate = (Date) row[0];\r\n\t\t\tMatchingAmount matchingAmount = (MatchingAmount) row[1];\r\n\t\t\tMatchingCode matchingCode = (MatchingCode) row[2];\r\n\t\t\tList<MatchingAmount> matchingAmounts = matchingCode.getMatchingAmounts();\r\n\t\t\tMatchingAmount invoiceMatchingAmount = matchingAmounts.stream()\r\n\t\t\t\t\t.filter(ma -> OperationCategoryEnum.DEBIT.equals(ma.getAccountOperation().getTransactionCategory())).findAny().orElse(null);\r\n\r\n\t\t\tAccountOperation accountOperation = matchingAmount.getAccountOperation();\r\n\t\t\tlog.info(\"accountOperation in paymentWritings=>\" + accountOperation);\r\n\t\t\tBigDecimal amount = matchingAmount.getMatchingAmount();\r\n\t\t\tString paymentAccountCode = accountOperation.getAccountingCode().getCode();\r\n\t\t\tString occCode = accountOperation.getCode();\r\n\r\n\t\t\tString key = eventDate + \"_\" + paymentAccountCode + \"_\" + occCode;\r\n\r\n\t\t\tAccountingEntry accountingWriting = new AccountingEntry();\r\n\t\t\tList<AccountOperation> accountOperations = new ArrayList<>();\r\n\t\t\tif (accountingEntries.get(key) != null) {\r\n\t\t\t\taccountingWriting = accountingEntries.get(key);\r\n\t\t\t\taccountingWriting.setAmount(amount.add(accountingWriting.getAmount()));\r\n\t\t\t\taccountOperations.addAll(accountingWriting.getAccountOperations());\r\n\t\t\t} else {\r\n\t\t\t\taccountingWriting.setAmount(amount);\r\n\t\t\t}\r\n\r\n\t\t\tAccountOperation aoInList = accountOperations.stream().filter(ao -> accountOperation.getId().equals(ao.getId())).findAny().orElse(null);\r\n\t\t\tif (aoInList == null) {\r\n\t\t\t\taccountOperations.add(accountOperation);\r\n\t\t\t}\r\n\r\n\t\t\taccountingWriting.setAccountingCode(matchingAmount.getAccountOperation().getAccountingCode());\r\n\t\t\taccountingWriting.setAccountOperations(accountOperations);\r\n\t\t\taccountingWriting.setEventType(getEventLabel(occCode));\r\n\t\t\taccountingWriting.setEventDate(eventDate);\r\n\t\t\taccountingWriting.setExportDate(new Date());\r\n\t\t\taccountingWriting.setIsWritten(false);\r\n\t\t\taccountingWriting.setExtraParam1(invoiceMatchingAmount.getAccountOperation().getAccountingCode().getCode());\r\n\t\t\taccountingEntries.put(key, accountingWriting);\r\n\t\t}\r\n\r\n\t\taccountingEntries = getPaymentNotMatchedWritings(date);\r\n\t\treturn new ArrayList<>(accountingEntries.values());\r\n\t}\r\n\r\n\tprivate Map<String, AccountingEntry> getPaymentNotMatchedWritings(Date date) {\r\n\t\tMap<String, AccountingEntry> accountingEntries = new HashMap<String, AccountingEntry>();\r\n\t\t// log.info(\"accountingEntries as input =>\"+accountingEntries);\r\n\t\tString query = \"Select cast(ao.auditable.created as date), ao\" + \" FROM AccountOperation ao\"\r\n\t\t\t\t+ \" WHERE ao.transactionCategory = org.meveo.model.payments.OperationCategoryEnum.CREDIT\" + \" AND ao.auditable.created > :date\" + \" AND ao.code != 'REF_INV'\"\r\n\t\t\t\t+ \" AND ao.accountingEntries is empty  \";\r\n\r\n\t\tMap<String, Object> params = new HashMap<>();\r\n\t\tparams.put(\"date\", date);\r\n\t\tList<Object[]> rows = (List<Object[]>) invoiceService.executeSelectQuery(query, params);\r\n\t\tfor (Object[] row : rows) {\r\n\t\t\tDate eventDate = (Date) row[0];\r\n\t\t\tAccountOperation accountOperation = (AccountOperation) row[1];\r\n\t\t\tlog.info(\"accountOperation in getPaymentNotMatchedWritings=>\" + accountOperation);\r\n\t\t\tBigDecimal amount = accountOperation.getAmount();\r\n\t\t\tString paymentAccountCode = accountOperation.getAccountingCode().getCode();\r\n\t\t\tString occCode = accountOperation.getCode();\r\n\t\t\tlog.info(\"---- encaissement 2: \");\r\n\t\t\tlog.info(\"2Amount ==>\" + amount);\r\n\t\t\tlog.info(\"2accountCode ==>\" + paymentAccountCode);\r\n\t\t\tlog.info(\"2occCode ==>\" + occCode);\r\n\t\t\tlog.info(\"2eventDate ==>\" + eventDate);\r\n\t\t\tString key = eventDate + \"_\" + paymentAccountCode + \"_\" + occCode;\r\n\t\t\tlog.info(\"2key==>\" + key);\r\n\r\n\t\t\tAccountingEntry accountingWriting = new AccountingEntry();\r\n\t\t\tList<AccountOperation> accountOperations = new ArrayList<AccountOperation>();\r\n\t\t\tif (accountingEntries.get(key) != null) {\r\n\t\t\t\taccountingWriting = accountingEntries.get(key);\r\n\t\t\t\tlog.info(\"accountingWriting.getAmount()==>\" + accountingWriting.getAmount());\r\n\t\t\t\taccountingWriting.setAmount(amount.add(accountingWriting.getAmount()));\r\n\t\t\t\tlog.info(\"accountingWritingAdded.getAmount()==>\" + accountingWriting.getAmount());\r\n\t\t\t\taccountOperations.addAll(accountingWriting.getAccountOperations());\r\n\t\t\t\tlog.info(\"accountingWriting2.getAccountOperations()=>\" + accountOperations);\r\n\t\t\t\tlog.info(\"accountOperations2.addAll=>\" + accountingWriting.getAccountOperations());\r\n\t\t\t} else {\r\n\t\t\t\tlog.info(\"new amount==>\" + amount);\r\n\t\t\t\taccountingWriting.setAmount(amount);\r\n\t\t\t}\r\n\r\n\t\t\tAccountOperation aoInList = accountOperations.stream().filter(ao -> accountOperation.getId().equals(ao.getId())).findAny().orElse(null);\r\n\t\t\tif (aoInList == null) {\r\n\t\t\t\tlog.debug(\"# adding Payment AO to AW\");\r\n\t\t\t\taccountOperations.add(accountOperation);\r\n\t\t\t}\r\n\t\t\tlog.info(\"accountOperation.getAccountingCode()=>\" + accountOperation.getAccountingCode());\r\n\t\t\taccountingWriting.setAccountingCode(accountOperation.getAccountingCode());\r\n\t\t\taccountingWriting.setAccountOperations(accountOperations);\r\n\t\t\taccountingWriting.setEventType(getEventLabel(occCode));\r\n\t\t\taccountingWriting.setEventDate(eventDate);\r\n\t\t\taccountingWriting.setExportDate(new Date());\r\n\t\t\taccountingWriting.setIsWritten(false);\r\n\t\t\t// envoyer une AW d'un paiement meme si la commande de solde n'existe pas encore\r\n\t\t\taccountingWriting.setExtraParam1(\"411120\");\r\n\t\t\t// accountingWriting.setExtraParam1(invoiceMatchingAmount.getAccountOperation().getAccountingCode().getCode());\r\n\t\t\tlog.info(\" accountingWriting2.setExtraParam1=>\" + accountingWriting.getExtraParam1());\r\n\t\t\tlog.info(\"accountingWritingLog=>\" + accountingWriting.getAccountingCode());\r\n\t\t\taccountingEntries.put(key, accountingWriting);\r\n\t\t\tlog.info(\"accountingEntries PaymentW==>\" + accountingEntries);\r\n\r\n\t\t}\r\n\t\treturn accountingEntries;\r\n\r\n\t}\r\n\r\n\tprivate List<AccountingEntry> getRefundWritings(Date date) {\r\n\r\n\t\tMap<String, AccountingEntry> accountingEntries = new HashMap<String, AccountingEntry>();\r\n\r\n\t\tString query = \"Select cast(ma2.accountOperation.auditable.created as date), ma2, mc2  \"\r\n\t\t\t\t+ \" FROM MatchingCode mc2 JOIN mc2.matchingAmounts ma2 \" + \" WHERE mc2 IN \"\r\n\t\t\t\t+ \" (SELECT mc FROM MatchingCode mc JOIN mc.matchingAmounts ma \"\r\n\t\t\t\t+ \" WHERE ma.accountOperation.transactionCategory = org.meveo.model.payments.OperationCategoryEnum.CREDIT)\"\r\n\t\t\t\t+ \" AND ma2.accountOperation.transactionCategory = org.meveo.model.payments.OperationCategoryEnum.DEBIT \"\r\n\t\t\t\t+ \" AND ma2.accountOperation.code != 'INV_STD' \"\r\n\t\t\t\t+ \" AND ma2.auditable.created > :date  \"\r\n\t\t\t\t+ \" AND ma2.accountOperation.accountingEntries is empty  \";\r\n\r\n\t\tMap<String, Object> params = new HashMap<>();\r\n\t\tparams.put(\"date\", date);\r\n\r\n\t\tList<Object[]> rows = (List<Object[]>) invoiceService.executeSelectQuery(query, params);\r\n\t\tlog.info(\"rowssize=>\" + rows.size());\r\n\t\tfor (Object[] row : rows) {\r\n\t\t\tDate eventDate = (Date) row[0];\r\n\t\t\tMatchingAmount matchingAmount = (MatchingAmount) row[1];\r\n\t\t\tlog.info(\"matchingAmount in refundWritings=>\" + matchingAmount);\r\n\t\t\tMatchingCode matchingCode = (MatchingCode) row[2];\r\n\t\t\tlog.info(\"matchingCode in refundWritings=>\" + matchingCode);\r\n\t\t\tList<MatchingAmount> matchingAmounts = matchingCode.getMatchingAmounts();\r\n\r\n\t\t\tMatchingAmount paymentMatchingAmount = matchingAmounts.stream()\r\n\t\t\t\t\t.filter(ma -> OperationCategoryEnum.CREDIT.equals(ma.getAccountOperation().getTransactionCategory())).findAny().orElse(null);\r\n\r\n\t\t\tAccountOperation accountOperation = matchingAmount.getAccountOperation();\r\n\t\t\tBigDecimal amount = matchingAmount.getMatchingAmount();\r\n\t\t\tString refundAccountCode = accountOperation.getAccountingCode().getCode();\r\n\t\t\tString occCode = accountOperation.getCode();\r\n\r\n\t\t\tlog.debug(\"---- remboursement : \");\r\n\t\t\tlog.debug(\"matchingAmount = {}\", matchingAmount);\r\n\t\t\tlog.debug(\"accountCode = {}\", refundAccountCode);\r\n\t\t\tlog.debug(\"occCode = {}\", occCode);\r\n\r\n\t\t\tString key = date + \"_\" + refundAccountCode + \"_\" + occCode;\r\n\r\n\t\t\tAccountingEntry accountingWriting = new AccountingEntry();\r\n\t\t\tList<AccountOperation> refundAccountOperations = new ArrayList<AccountOperation>();\r\n\t\t\tif (accountingEntries.get(key) != null) {\r\n\t\t\t\taccountingWriting = accountingEntries.get(key);\r\n\t\t\t\taccountingWriting.setAmount(amount.add(accountingWriting.getAmount()));\r\n\t\t\t\trefundAccountOperations.addAll(accountingWriting.getAccountOperations());\r\n\t\t\t} else {\r\n\t\t\t\taccountingWriting.setAmount(amount);\r\n\t\t\t}\r\n\r\n\t\t\tAccountOperation aoInList = refundAccountOperations.stream().filter(ao -> accountOperation.getId().equals(ao.getId())).findAny().orElse(null);\r\n\t\t\tif (aoInList == null) {\r\n\t\t\t\tlog.debug(\"# adding Refund AO to AW\");\r\n\t\t\t\trefundAccountOperations.add(accountOperation);\r\n\t\t\t}\r\n\r\n\t\t\taccountingWriting.setAccountingCode(matchingAmount.getAccountOperation().getAccountingCode());\r\n\t\t\taccountingWriting.setAccountOperations(refundAccountOperations);\r\n\t\t\taccountingWriting.setEventType(getEventLabel(occCode));\r\n\t\t\taccountingWriting.setEventDate(eventDate);\r\n\t\t\taccountingWriting.setExportDate(new Date());\r\n\t\t\taccountingWriting.setIsWritten(false);\r\n\t\t\taccountingWriting.setExtraParam1(paymentMatchingAmount.getAccountOperation().getAccountingCode().getCode());\r\n\t\t\taccountingEntries.put(key, accountingWriting);\r\n\r\n\t\t}\r\n\t\treturn new ArrayList<>(accountingEntries.values());\r\n\t}\r\n\r\n\tprivate List<String> getCancelinvoices(Date date) {\r\n\t\tList<String> invoiceNumberList = new ArrayList<>();\r\n\t\tString query = \"Select cast(ma2.accountOperation.auditable.created as date), ma2, mc2  \"\r\n\t\t\t\t+ \" FROM MatchingCode mc2 JOIN mc2.matchingAmounts ma2 \"\r\n\t\t\t\t+ \" WHERE mc2 IN \"\r\n\t\t\t\t+ \" (SELECT mc FROM MatchingCode mc JOIN mc.matchingAmounts ma \"\r\n\t\t\t\t+ \" WHERE ma.accountOperation.transactionCategory = org.meveo.model.payments.OperationCategoryEnum.CREDIT AND ma.accountOperation.code = 'REF_INV' )\"\r\n\t\t\t\t+ \" AND ma2.accountOperation.transactionCategory = org.meveo.model.payments.OperationCategoryEnum.DEBIT  \" + \" AND ma2.auditable.created > :date \";\r\n\r\n\t\tMap<String, Object> params = new HashMap<>();\r\n\t\tparams.put(\"date\", date);\r\n\r\n\t\tList<Object[]> rows = (List<Object[]>) invoiceService.executeSelectQuery(query, params);\r\n\t\tfor (Object[] row : rows) {\r\n\t\t\tMatchingAmount matchingAmount = (MatchingAmount) row[1];\r\n\r\n\t\t\tAccountOperation accountOperation = matchingAmount.getAccountOperation();// invoice\r\n\t\t\tString invoiceNumber = accountOperation.getReference();\r\n\t\t\tinvoiceNumberList.add(invoiceNumber);\r\n\t\t}\r\n\t\treturn invoiceNumberList;\r\n\t}\r\n\r\n\tprivate List<AccountingEntry> getTaxWritings(Date date, String accountingCode, List<String> invoiceNumberList) {\r\n\t\tMap<String, AccountingEntry> accountingEntries = new HashMap<String, AccountingEntry>();\r\n\r\n\t\tString query = null;\r\n\t\tMap<String, Object> params = new HashMap<>();\r\n\t\tOCCTemplate occTemplateInv = occTemplateService.findByCode(OCC_TEMP_CODE_INV_STD);\r\n\r\n\t\tif (invoiceNumberList == null) {\r\n\t\t\tquery = \"Select taxInvAgregate FROM TaxInvoiceAgregate taxInvAgregate\"\r\n\t\t\t\t\t+ \" WHERE taxInvAgregate.invoice.recordedInvoice is not null  \"\r\n\t\t\t\t\t+ \" AND cast(taxInvAgregate.invoice.recordedInvoice.auditable.created as date)=:date\"\r\n\t\t\t\t\t+ \" AND taxInvAgregate.invoice.invoiceType.occTemplate.accountingCode.code=:accountingCode\"\r\n\t\t\t\t\t+ \" AND taxInvAgregate.invoice.recordedInvoice.accountingEntries is empty \";\r\n\t\t\tparams.put(\"date\", date);\r\n\t\t\tparams.put(\"accountingCode\", accountingCode);\r\n\t\t} else {\r\n\r\n\t\t\tquery = \"Select taxInvAgregate FROM TaxInvoiceAgregate taxInvAgregate\"\r\n\t\t\t\t\t+ \" WHERE taxInvAgregate.invoice.recordedInvoice is not null AND cast(taxInvAgregate.invoice.recordedInvoice.auditable.created as date)=:date\"\r\n\t\t\t\t\t+ \" AND taxInvAgregate.invoice.invoiceType.occTemplate.accountingCode.code=:accountingCode\"\r\n\t\t\t\t\t+ \" AND taxInvAgregate.invoice.invoiceNumber in :invoiceNumberList  \";\r\n\t\t\tparams.put(\"invoiceNumberList\", invoiceNumberList);\r\n\t\t\tparams.put(\"accountingCode\", occTemplateInv.getAccountingCode().getCode());\r\n\r\n\t\t}\r\n\t\tparams.put(\"date\", date);\r\n\r\n\t\tList<TaxInvoiceAgregate> taxInvoiceAgregates = (List<TaxInvoiceAgregate>) invoiceService.executeSelectQuery(query, params);\r\n\t\tfor (TaxInvoiceAgregate taxInvoiceAgregate : taxInvoiceAgregates) {\r\n\t\t\tString amountSign = \"PLUS\";\r\n\t\t\tAccountingEntry accountingWriting = new AccountingEntry();\r\n\t\t\tList<AccountOperation> accountOperations = new ArrayList<AccountOperation>();\r\n\r\n\t\t\tBigDecimal tvaAmounts = computeTaxAgregateAmount(taxInvoiceAgregate);\r\n\t\t\tif (tvaAmounts.compareTo(BigDecimal.ZERO) < 0) {\r\n\t\t\t\tamountSign = \"MINUS\";\r\n\t\t\t}\r\n\t\t\tString key = date + \"_\" + taxInvoiceAgregate.getAccountingCode().getCode() + \"_\" + taxInvoiceAgregate.getTax().getCode() + \"_\" + amountSign;\r\n\r\n\t\t\tif (accountingEntries.get(key) != null) {\r\n\t\t\t\taccountingWriting = accountingEntries.get(key);\r\n\t\t\t\taccountingWriting.setAmount(round(tvaAmounts).add(accountingWriting.getAmount()));\r\n\t\t\t\taccountOperations.addAll(accountingWriting.getAccountOperations());\r\n\t\t\t} else {\r\n\t\t\t\taccountingWriting.setAmount(round(tvaAmounts));\r\n\t\t\t}\r\n\t\t\tif (!accountOperations.contains(taxInvoiceAgregate.getInvoice().getRecordedInvoice())) {\r\n\t\t\t\taccountOperations.add(taxInvoiceAgregate.getInvoice().getRecordedInvoice());\r\n\t\t\t}\r\n\t\t\taccountingWriting.setAccountingCode(taxInvoiceAgregate.getAccountingCode());\r\n\t\t\taccountingWriting.setAccountOperations(accountOperations);\r\n\t\t\taccountingWriting.setTax(taxInvoiceAgregate.getTax());\r\n\t\t\taccountingWriting.setEventDate(date);\r\n\t\t\taccountingWriting.setExportDate(new Date());\r\n\t\t\taccountingEntries.put(key, accountingWriting);\r\n\t\t}\r\n\t\treturn new ArrayList<>(accountingEntries.values());\r\n\t}\r\n\r\n\tprivate  List<AccountingEntry> getInvoiceSubcatsWritings(Date date, String accountingCode, List<String> invoiceNumberList) {\r\n\r\n\t\tString query = null;\r\n\t\tMap<String, Object> params = new HashMap<>();\r\n\t\tOCCTemplate occTemplateInv = occTemplateService.findByCode(OCC_TEMP_CODE_INV_STD);\r\n\r\n\t\tif(invoiceNumberList == null) {\r\n\t\t\tquery = \"Select subCatInvAgregate \"\r\n\t\t\t\t\t+ \" FROM SubCategoryInvoiceAgregate subCatInvAgregate \"\r\n\t\t\t\t\t+ \" WHERE subCatInvAgregate.invoice.recordedInvoice is not null  \"\r\n\t\t\t\t\t+ \" AND cast(subCatInvAgregate.invoice.recordedInvoice.auditable.created as date)=:date\"\r\n\t\t\t\t\t+ \" AND subCatInvAgregate.invoice.invoiceType.occTemplate.accountingCode.code=:accountingCode\"\r\n\t\t\t\t\t+ \" AND subCatInvAgregate.invoice.recordedInvoice.accountingEntries is empty  \";\r\n\t\t\tparams.put(\"accountingCode\", accountingCode);\r\n\t\t} else {\r\n\r\n\t\t\tquery = \"Select subCatInvAgregate \"\r\n\t\t\t\t\t+ \" FROM SubCategoryInvoiceAgregate subCatInvAgregate \"\r\n\t\t\t\t\t+ \" WHERE subCatInvAgregate.invoice.recordedInvoice is not null AND cast(subCatInvAgregate.invoice.recordedInvoice.auditable.created as date)=:date\"\r\n\t\t\t\t\t+ \" AND subCatInvAgregate.invoice.invoiceType.occTemplate.accountingCode.code=:accountingCode\"\r\n\t\t\t\t\t+ \" AND subCatInvAgregate.invoice.invoiceNumber in :invoiceNumberList \";\r\n\t\t\tparams.put(\"invoiceNumberList\", invoiceNumberList);\r\n\t\t\tparams.put(\"accountingCode\", occTemplateInv.getAccountingCode().getCode());\r\n\t\t}\r\n\t\tparams.put(\"date\", date);\r\n\r\n\t\tMap<String, AccountingEntry> accountingEntries = new HashMap<>();\r\n\t\tList<SubCategoryInvoiceAgregate> subCatInvAgregates = (List<SubCategoryInvoiceAgregate>) invoiceService.executeSelectQuery(query, params);\r\n\r\n\t\tfor (SubCategoryInvoiceAgregate subCatInvAgregate : subCatInvAgregates) {\r\n\r\n\t\t\tfor (Tax tax : subCatInvAgregate.getAmountsByTax().keySet()) {\r\n\t\t\t\tString key = date + \"_\" + subCatInvAgregate.getInvoiceSubCategory().getInvoiceCategory().getCode()\r\n\t\t\t\t\t\t+ \"_\" + subCatInvAgregate.getAccountingCode().getCode() + \"_\" + tax.getCode();\r\n\t\t\t\tAccountingEntry accountingWriting = new AccountingEntry();\r\n\t\t\t\tList<AccountOperation> accountOperations = new ArrayList<AccountOperation>();\r\n\t\t\t\tBigDecimal subCatHTAmount = computeTaxAgregateAmount(subCatInvAgregate, tax);\r\n\r\n\t\t\t\tif(accountingEntries.get(key) != null) {\r\n\t\t\t\t\taccountingWriting = accountingEntries.get(key);\r\n\t\t\t\t\taccountingWriting.setAmount(round(subCatHTAmount).add(accountingWriting.getAmount()));\r\n\t\t\t\t\taccountOperations.addAll(accountingWriting.getAccountOperations());\r\n\t\t\t\t} else {\r\n\t\t\t\t\taccountingWriting.setAmount(round(subCatHTAmount));\r\n\t\t\t\t}\r\n\t\t\t\tif(!accountOperations.contains(subCatInvAgregate.getInvoice().getRecordedInvoice())) {\r\n\t\t\t\t\taccountOperations.add(subCatInvAgregate.getInvoice().getRecordedInvoice());\r\n\t\t\t\t}\r\n\r\n\t\t\t\taccountingWriting.setEventDate(date);\r\n\t\t\t\tif(invoiceNumberList == null) {\r\n\t\t\t\t\taccountingWriting.setEventType(EventEnum.FACTURATION.getLabel());\r\n\t\t\t\t} else {\r\n\t\t\t\t\taccountingWriting.setEventType(EventEnum.ANNULATION_FACTURATION.getLabel());\r\n\t\t\t\t}\r\n\t\t\t\taccountingWriting.setAccountingCode(subCatInvAgregate.getAccountingCode());\r\n\t\t\t\taccountingWriting.setInvoiceCategory(subCatInvAgregate.getInvoiceSubCategory().getInvoiceCategory());\r\n\t\t\t\taccountingWriting.setExportDate(new Date());\r\n\t\t\t\taccountingWriting.setAccountOperations(accountOperations);\r\n\t\t\t\taccountingWriting.setTax(tax);\r\n\r\n\t\t\t\taccountingEntries.put(key, accountingWriting);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn new ArrayList<>(accountingEntries.values());\r\n\t}\r\n\r\n\r\n\r\n\tprivate BigDecimal computeTaxAgregateAmount(TaxInvoiceAgregate taxInvoiceAgregate) {\r\n\r\n\t\tString sql = \"Select sum(amount_tax) from billing_rated_transaction rt \" +\r\n\t\t\t\t\"inner join billing_tax tax on (rt.tax_id = tax.id and tax.code='\"+taxInvoiceAgregate.getTax().getCode()+\"') \" +\r\n\t\t\t\t\"where rt.invoice_id=\" + taxInvoiceAgregate.getInvoice().getId();\r\n\t\treturn (BigDecimal) ratedTransactionService.getEntityManager().createNativeQuery(sql).getSingleResult();\r\n\t}\r\n\r\n\tprivate BigDecimal computeTaxAgregateAmount(SubCategoryInvoiceAgregate subCatInvAgregate, Tax tax) {\r\n\r\n\t\tString sql = \"Select sum(amount_without_tax) from billing_rated_transaction rt \" +\r\n\t\t\t\t\"inner join billing_invoice_sub_cat subcat on (rt.invoice_sub_category_id = subcat.id and subcat.code='\"+subCatInvAgregate.getInvoiceSubCategory().getCode()+\"') \" +\r\n\t\t\t\t\"inner join billing_tax tax on (rt.tax_id = tax.id and tax.code='\"+tax.getCode()+\"') \" +\r\n\t\t\t\t\"where rt.invoice_id=\" + subCatInvAgregate.getInvoice().getId();\r\n\r\n\t\treturn (BigDecimal) ratedTransactionService.getEntityManager()\r\n\t\t\t\t.createNativeQuery(sql).getSingleResult();\r\n\t}\r\n\r\n\tprivate BigDecimal round(BigDecimal amount) {\r\n\t\treturn round(amount, false);\r\n\t}\r\n\r\n\tprivate BigDecimal round(BigDecimal amount, boolean stripTrailingZeros) {\r\n\t\tif (amount == null) {\r\n\t\t\tamount = BigDecimal.ZERO;\r\n\t\t}\r\n\t\tint scale = 2;\r\n\r\n\t\tamount = amount.setScale(scale, RoundingMode.HALF_UP);\r\n\t\tif (stripTrailingZeros) {\r\n\t\t\tamount = amount.stripTrailingZeros();\r\n\t\t}\r\n\t\treturn amount;\r\n\t}\r\n\r\n\tpublic Date getJobLastExecutionDate(String jobCode) throws BusinessException {\r\n\t\tJobInstance jobInstance = jobInstanceService.findByCode(jobCode);\r\n\t\tif (jobInstance == null) {\r\n\t\t\tlog.error(\"No Job instance by code {} was found\", jobCode);\r\n\t\t\tthrow new BusinessException(\"No Job instance by code was found\");\r\n\t\t}\r\n\r\n\t\tString query = \"select hist.startDate FROM JobExecutionResultImpl hist WHERE hist.nbItemsCorrectlyProcessed=1 AND hist.jobInstance=:jobInstance ORDER BY hist.startDate desc\";\r\n\t\tQuery q = jobInstanceService.getEntityManager().createQuery(query);\r\n\t\tq.setParameter(\"jobInstance\", jobInstance);\r\n\r\n\t\ttry {\r\n\t\t\tList<Object> results = q.getResultList();\r\n\t\t\tif (results.size() == 0) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t\tDate lastExecutionDate = (Date) q.getResultList().get(0);\r\n\t\t\treturn lastExecutionDate;\r\n\t\t} catch (Exception e) {\r\n\t\t\tlog.error(\"error = {}\", e);\r\n\t\t\treturn null;\r\n\t\t}\r\n\t}\r\n\r\n\tpublic long countJobExecutionHistory(String jobCode, Date startDate, Date endDate) throws BusinessException {\r\n\t\tJobInstance jobInstance = jobInstanceService.findByCode(jobCode);\r\n\t\tif (jobInstance == null) {\r\n\t\t\tlog.error(\"No Job instance by code {} was found\", jobCode);\r\n\t\t\tthrow new BusinessException(\"No Job instance by code was found\");\r\n\t\t}\r\n\r\n\t\tMap<String, Object> params = Maps.newHashMap();\r\n\t\tString query = \"select count(*) FROM JobExecutionResultImpl hist WHERE hist.jobInstance=:jobInstance\";\r\n\t\tparams.put(\"jobInstance\", jobInstance);\r\n\t\tif (startDate != null) {\r\n\t\t\tparams.put(\"startDate\", startDate);\r\n\t\t\tquery += \" and hist.startDate >= :startDate\";\r\n\t\t}\r\n\t\tif (endDate != null) {\r\n\t\t\tparams.put(\"endDate\", endDate);\r\n\t\t\tquery += \" and hist.endDate < :endDate\";\r\n\t\t}\r\n\r\n\t\tQuery q = jobInstanceService.getEntityManager().createQuery(query);\r\n\t\tfor (Entry<String, Object> entry : params.entrySet()) {\r\n\t\t\tq.setParameter(entry.getKey(), entry.getValue());\r\n\t\t}\r\n\t\tlong result = (long) q.getSingleResult();\r\n\t\treturn result > 9 ? 0 : result;\r\n\t}\r\n\r\n\tprivate static String getEventLabel(String occCode) {\r\n\t\tif (EventEnum.valueOf(occCode) != null) {\r\n\t\t\treturn EventEnum.valueOf(occCode).getLabel();\r\n\t\t}\r\n\t\treturn \"\";\r\n\t}\r\n\r\n\tprivate String getZUONR(String occCode, String accountingCode) {\r\n\t\tStringBuilder sb = new StringBuilder();\r\n\t\tsb.append(accountingCode);\r\n\t\tsb.append(PAD_STR);\r\n\t\tlog.info(\"ZUONR_accountingCode=>\" + accountingCode);\r\n\t\tlog.info(\"ZUONREnum.valueOf(occCode)=>\" + ZUONREnum.valueOf(occCode));\r\n\t\tif (ZUONREnum.valueOf(occCode) != null) {\r\n\t\t\tsb.append(ZUONREnum.valueOf(occCode).getLabel());\r\n\t\t}\r\n\r\n\t\treturn sb.toString();\r\n\t}\r\n\r\n\tprivate String getCostl(String invoiceCategoryCode) {\r\n\t\tString costl = null;\r\n\t\tString accountingCode = null;\r\n\t\tInvoiceCategory invoiceCategory = invoiceCategoryService.findByCode(invoiceCategoryCode);\r\n\t\tList<InvoiceSubCategory> invoiceSubCategories = invoiceSubCategoryService.findByInvoiceCategory(invoiceCategory);\r\n\t\tfor (InvoiceSubCategory subCat : invoiceSubCategories) {\r\n\t\t\taccountingCode = subCat.getAccountingCode() == null ? null : subCat.getAccountingCode().getCode();\r\n\t\t\tif (accountingCode != null) {\r\n\t\t\t\tif (CAT_VENDING_CODE.equals(invoiceCategoryCode) && (ACCOUNT_1.equals(accountingCode) || ACCOUNT_2.equals(accountingCode))) {\r\n\t\t\t\t\tcostl = COSTL_VCA_IN;\r\n\t\t\t\t} else if (CAT_VENDING_CODE_2.equals(invoiceCategoryCode) && (ACCOUNT_2.equals(accountingCode) || ACCOUNT_3.equals(accountingCode))) {\r\n\t\t\t\t\tcostl = COSTL_VCA_SE;\r\n\t\t\t\t} else if (CAT_SERVICE_PROVISION_CODE.equals(invoiceCategoryCode)) {\r\n\t\t\t\t\tif (SUB_CAT_DEE.equals(subCat.getCode()) && (ACCOUNT_1.equals(accountingCode) || ACCOUNT_2.equals(accountingCode))) {\r\n\t\t\t\t\t\tcostl = COSTL_VCA_DE;\r\n\t\t\t\t\t} else if (ACCOUNT_1.equals(accountingCode) || ACCOUNT_2.equals(accountingCode)) {\r\n\t\t\t\t\t\tcostl = COSTL_VCA_MA;\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn costl;\r\n\t}\r\n\r\n\tprivate String getOperationType(AccountingEntry accountingWriting) {\r\n\t\tString operationType = CREDIT;\r\n\t\tif (accountingWriting.getAmount().compareTo(BigDecimal.ZERO) < 0) {\r\n\t\t\toperationType = DEBIT;\r\n\t\t}\r\n\t\treturn operationType;\r\n\t}\r\n\r\n\tprivate String getOperationTypeAvoir(AccountingEntry accountingWriting) {\r\n\t\tString operationType = DEBIT;\r\n\t\tif (accountingWriting.getAmount().compareTo(BigDecimal.ZERO) < 0) {\r\n\t\t\toperationType = CREDIT;\r\n\t\t}\r\n\t\treturn operationType;\r\n\t}\r\n\r\n\tprivate String getEventType(AccountingEntry accountingWriting) {\r\n\t\tString eventType = EventEnum.FACTURATION.getLabel();\r\n\t\tif (accountingWriting.getAmount().compareTo(BigDecimal.ZERO) < 0) {\r\n\t\t\teventType = EventEnum.ANNULATION_FACTURATION.getLabel();\r\n\t\t}\r\n\t\treturn eventType;\r\n\t}\r\n\r\n\tprivate void appendLine(String line) {\r\n\t\tif (!StringUtils.isBlank(line)) {\r\n\t\t\tcontentBuilder.append(line);\r\n\t\t\tcontentBuilder.append(NEW_LINE);\r\n\t\t}\r\n\t}\r\n\r\n\tprivate void buildBGR00() {\r\n\t\tcontentBuilder.append(\"0\"); // STYPE\r\n\t\tcontentBuilder.append(FOLDER_ID).append(ORGA_CODE).append(OC_CODE);\r\n\t\tcontentBuilder.append(String.format(\"%03d\", LocalDate.now().getDayOfYear()));\r\n\t\tcontentBuilder.append(coutJobExecution); // GROUP _QUEUE_NAME\r\n\t\tcontentBuilder.append(MANDANT);\r\n\t\tcontentBuilder.append(rightPad(\"RAPEXPL\", 12, PAD_STR)); // USNAM\r\n\t\tcontentBuilder.append(rightPad(\"\", 8, PAD_STR)); // START\r\n\t\tcontentBuilder.append(\"X\"); // XKEEP\r\n\t\tcontentBuilder.append(SKIP_CHAR);// NODATA\r\n\t}\r\n\r\n\tprivate String buildBBKPF(Date bldat, Date budat, int index) {\r\n\t\tStringBuilder stringBuilder = new StringBuilder();\r\n\t\tstringBuilder.append(\"1\");// STYPE\r\n\t\tstringBuilder.append(rightPad(\"FB01\", 20, PAD_STR));// TCODE\r\n\t\tstringBuilder.append(DateUtils.formatDateWithPattern(bldat, \"ddMMyyyy\"));// BLDAT\r\n\t\tstringBuilder.append(\"WY\");// BLART\r\n\t\tstringBuilder.append(ORGA_CODE);// BUKRS\r\n\t\tstringBuilder.append(DateUtils.formatDateWithPattern(budat, \"ddMMyyyy\"));// BUDAT\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 2, PAD_STR));// MONAT\r\n\t\tstringBuilder.append(rightPad(\"EUR\", 5, PAD_STR));// WAERS\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 10, PAD_STR));// KURSF\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 10, PAD_STR));// BELNR\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 8, PAD_STR));// WWERT\r\n\t\tstringBuilder.append(rightPad(PREFIX + DateUtils.formatDateWithPattern(new Date(), \"ddMMyyyy\") + index, 16, PAD_STR));// XBLNR\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 16, PAD_STR));// BVORG\r\n\t\tstringBuilder.append(rightPad(ORGA_CODE + \"_\" + OC_CODE + \" \", 25, PAD_STR));// BVORG\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 4, PAD_STR));// PARGB\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 8, PAD_STR));// AUGLV\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 6, PAD_STR));// VBUND\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 1, PAD_STR));// XMWST\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 10, PAD_STR));// DOCID\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 40, PAD_STR));// BARCD\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 8, PAD_STR));// STODT\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 4, PAD_STR));// BRNCH\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 3, PAD_STR));// NUMPG\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 2, PAD_STR));// STGRD\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 10, PAD_STR));// KURSF_M\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 50, PAD_STR));// AUGTX\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 1, PAD_STR));// XPRFG\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 1, PAD_STR));// XBWAE\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 4, PAD_STR));// LDGRP\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 13, PAD_STR));// PROPMANO\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 8, PAD_STR));// VATDATE\r\n\t\tstringBuilder.append(rightPad(SKIP_CHAR, 1, PAD_STR));// SENDE\r\n\t\treturn stringBuilder.toString();\r\n\t}\r\n\r\n\tprivate String buildBBSEG(String accountType, String eventLabel, String amount, Date valut, String zuonr, String codeTVA, String accountCode, String kostl) {\r\n\t\tTreeMap<Integer, Zone> zonesBBSEG = new TreeMap<>();\r\n\t\tList<Integer> zoneLenghtBGR00List = Arrays.asList(new Integer[] { 1, 30, 2, 10, 1, 4, 16, 16, 16, 16, 2, 1, 16, 16, 4, 10, 4, 12, 10, 5, 16, 18, 4, 17, 3, 10, 6, 4, 8, 3,\r\n\t\t\t\t8, 8, 2, 18, 3, 1, 50, 2, 16, 8, 2, 16, 16, 4, 3, 6, 3, 6, 3, 1, 10, 4, 3, 1, 8, 1, 2, 16, 16, 11, 2, 27, 8, 2, 12, 4, 8, 3, 7, 16, 10, 1, 1, 5, 4, 10, 4, 4, 3, 3,\r\n\t\t\t\t1, 8, 8, 8, 1, 18, 1, 35, 35, 35, 35, 35, 35, 10, 3, 3, 15, 3, 18, 2, 16, 11, 8, 1, 3, 3, 20, 1, 1, 10, 10, 1, 1, 17, 3, 17, 10, 10, 13, 1, 4, 16, 16, 14, 6, 3, 2,\r\n\t\t\t\t10, 12, 8, 8, 10, 12, 4, 1, 2, 10, 24, 2, 15, 16, 10, 16, 16, 4, 12, 12, 10, 3, 8, 1, 1, 30, 30, 30, 30, 60, 60, 8, 3, 16, 16, 1, 1, 2, 1, 18, 2, 4, 4, 6, 5, 4, 4,\r\n\t\t\t\t4, 10, 2, 6, 10, 4, 12, 3, 1, 9, 10, 24, 12, 2, 4, 3, 4, 2, 4, 2, 2, 10, 10, 10, 2, 3, 9, 2, 2, 4, 3, 8, 10, 6, 4, 8, 1, 3, 24, 1, 2, 3, 2, 2, 2, 1, 18, 18, 20, 30,\r\n\t\t\t\t2, 2, 2, 2, 2, 5, 16, 4, 4, 6, 10, 8, 8, 8, 8, 13, 4, 5, 13, 10, 4, 10, 10, 10, 30, 30, 5, 15, 13, 13, 20, 1, 2, 20, 16, 1, 34, 8, 10, 10, 5, 1, 16, 8, 1, 10, 1, 1,\r\n\t\t\t\t8, 10, 8 });\r\n\r\n\t\tzonesBBSEG.put(1, new Zone(1, \"2\"));// STYPE\r\n\t\tzonesBBSEG.put(2, new Zone(30, \"BBSEG\"));// TBNAM\r\n\t\tzonesBBSEG.put(32, new Zone(2, accountType));// NEWBS : 40 si compte débit / 50 si compte crédit\r\n\t\tzonesBBSEG.put(49, new Zone(16, amount));// WRBTR\r\n\t\tzonesBBSEG.put(113, new Zone(2, StringUtils.isBlank(codeTVA) ? SKIP_CHAR : codeTVA));// MWSKZ\r\n\t\tif (!StringUtils.isBlank(kostl)) {\r\n\t\t\tzonesBBSEG.put(152, new Zone(10, kostl, \"\", true));// KOSTL\r\n\t\t}\r\n\t\tzonesBBSEG.put(282, new Zone(8, \"\"));// VALUT , previous value = DateUtils.formatDateWithPattern(valut, \"ddMMyyyy\"))\r\n\t\tzonesBBSEG.put(300, new Zone(18, \"Opencell\")); // ZUONR , previous value = zuonr\r\n\t\tzonesBBSEG.put(322, new Zone(50, eventLabel)); // ZUONR\r\n\t\tzonesBBSEG.put(1059, new Zone(17, accountCode, \"0\", true)); // NEWKO\r\n\r\n\t\treturn generateRecordLine(zonesBBSEG, zoneLenghtBGR00List);\r\n\t}\r\n\r\n\tprivate String buildBBTAX(String accountType, String amount, String codeTVA) {\r\n\t\tTreeMap<Integer, Zone> zonesBBTAX = new TreeMap<>();\r\n\t\tList<Integer> zoneLenghtBBTAXList = Arrays.asList(new Integer[] { 1, 30, 16, 2, 2, 15, 16, 4, 16, 16, 16, 16, 16, 16, 10, 1 });\r\n\r\n\t\tzonesBBTAX.put(1, new Zone(1, \"2\"));// STYPE\r\n\t\tzonesBBTAX.put(2, new Zone(30, \"BBTAX\"));// TBNAM\r\n\t\tzonesBBTAX.put(32, new Zone(16, amount));// FWSTE\r\n\t\tzonesBBTAX.put(48, new Zone(2, StringUtils.isBlank(codeTVA) ? SKIP_CHAR : codeTVA));// MWSKZ\r\n\t\tzonesBBTAX.put(50, new Zone(2, accountType));// BSCHL : 40 si compte débit / 50 si compte crédit\r\n\r\n\t\treturn generateRecordLine(zonesBBTAX, zoneLenghtBBTAXList);\r\n\t}\r\n\r\n\tprivate String generateRecordLine(TreeMap<Integer, Zone> zones, List<Integer> zoneLenghtList) {\r\n\t\tint pos = 1;\r\n\t\tint lg;\r\n\t\tfor (int i = 0; i < zoneLenghtList.size(); i++) {\r\n\t\t\tlg = zoneLenghtList.get(i);\r\n\t\t\tif (zones.get(pos) == null) {\r\n\t\t\t\tzones.put(pos, new Zone(lg, SKIP_CHAR));\r\n\t\t\t}\r\n\t\t\tpos += lg;\r\n\t\t}\r\n\t\tStringBuilder sb = new StringBuilder();\r\n\t\tzones.forEach((p, zone) -> {\r\n\t\t\tif (zone.value.length() >= zone.lg) {\r\n\t\t\t\tsb.append(zone.value.substring(0, zone.lg));\r\n\t\t\t} else {\r\n\t\t\t\tif (zone.leftPad) {\r\n\t\t\t\t\tsb.append(leftPad(zone.value, zone.lg, zone.padStr));\r\n\t\t\t\t} else {\r\n\t\t\t\t\tsb.append(rightPad(zone.value, zone.lg, zone.padStr));\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t\treturn sb.toString();\r\n\t}\r\n\r\n\tprivate String round(BigDecimal amount, Integer scale) {\r\n\t\tif (amount == null) {\r\n\t\t\tamount = BigDecimal.ZERO;\r\n\t\t}\r\n\t\tif (scale == null) {\r\n\t\t\tscale = 2;\r\n\t\t}\r\n\t\tamount = amount.setScale(scale, RoundingMode.HALF_UP);\r\n\t\treturn decimalFormat.format(amount);\r\n\t}\r\n\r\n\tprivate String getSafeAccountingCode(AccountingCode ac) {\r\n\t\tif (ac != null) {\r\n\t\t\treturn ac.getCode();\r\n\t\t}\r\n\t\treturn \"\";\r\n\t}\r\n\r\n\tprivate Invoice findByInvoiceNumber(String invoiceNumber) {\r\n\t\ttry {\r\n\r\n\t\t\tQueryBuilder qb = new QueryBuilder(Invoice.class, \"i\");\r\n\t\t\tqb.addCriterion(\"invoiceNumber\", \"=\", invoiceNumber, false);\r\n\r\n\t\t\treturn (Invoice) qb.getQuery(invoiceService.getEntityManager()).getSingleResult();\r\n\t\t} catch (NoResultException ne) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tprivate Tax findTaxByCode(String code) {\r\n\t\ttry {\r\n\r\n\t\t\tQueryBuilder qb = new QueryBuilder(Tax.class, \"t\");\r\n\t\t\tqb.addCriterion(\"code\", \"=\", code, false);\r\n\r\n\t\t\treturn (Tax) qb.getQuery(invoiceService.getEntityManager()).getSingleResult();\r\n\t\t} catch (NoResultException ne) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t}\r\n\r\n}\r\n\r\n\r\n]]>\r\n            </script>\r\n</ScriptInstance>"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "FixInvoicesAmountsScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript",
										"packages": {}
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.compta.FixInvoicesAmountsScript\" description=\"FixInvoicesAmountsScript\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.compta;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.model.billing.*;\r\nimport org.meveo.service.billing.impl.InvoiceAgregateService;\r\nimport org.meveo.service.billing.impl.InvoiceService;\r\nimport org.meveo.service.billing.impl.RatedTransactionService;\r\nimport org.meveo.service.script.Script;\r\n\r\nimport javax.persistence.Tuple;\r\nimport java.math.BigDecimal;\r\nimport java.util.ArrayList;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.stream.Collectors;\r\n\r\npublic class FixInvoicesAmountsScript extends Script {\r\n\r\n\r\n    private InvoiceService invoiceService = (InvoiceService) getServiceInterface(\"InvoiceService\");\r\n    private RatedTransactionService ratedTransactionService = (RatedTransactionService) getServiceInterface(\"RatedTransactionService\");\r\n    private InvoiceAgregateService invoiceAgregateService = (InvoiceAgregateService) getServiceInterface(\"InvoiceAgregateService\");\r\n    //private RecordedInvoiceService recordedInvoiceService = (RecordedInvoiceService) getServiceInterface(\"RecordedInvoiceService\");\r\n\r\n    @Override\r\n    public void execute(Map<String, Object> context) throws BusinessException {\r\n        List<Invoice> invWithPbList = new ArrayList<>();\r\n\r\n\r\n        // lits of invoices with pb sum(RT.amounts) != inv.totals\r\n        List<Object[]> invRTSumPbList = invoiceService.getEntityManager()\r\n                .createQuery(\"SELECT inv.id, SUM(rt.amountWithoutTax), inv.amountWithoutTax \" +\r\n                                \"FROM RatedTransaction rt JOIN rt.invoice inv Where inv.invoiceNumber LIKE '4%' \" +\r\n                                \"GROUP BY inv.id \" +\r\n                                \"HAVING SUM(rt.amountWithoutTax) <> inv.amountWithoutTax \" +\r\n                                \"OR SUM(rt.amountTax) <> inv.amountTax \" +\r\n                                \"OR SUM(rt.amountWithTax) <> inv.amountWithTax\",\r\n                        Object[].class).getResultList();\r\n\r\n        log.info(\"Fixing invoices with pb sum(RT.amounts) != inv.totals. Nbr of inv to fix {}\", invRTSumPbList.size());\r\n        invWithPbList.addAll(invRTSumPbList.stream().map(row -> invoiceService.findById((Long) row[0])).collect(Collectors.toList()));\r\n\r\n        // fixing invoice total pb\r\n        var invTotalPbList = invoiceService.getEntityManager()\r\n                .createQuery(\"Select inv from Invoice inv \" +\r\n                                \"Where inv.amountWithoutTax + inv.amountTax != inv.amountWithTax and inv.invoiceNumber LIKE '4%'\",\r\n                        Invoice.class).getResultList();\r\n\r\n        invWithPbList.addAll(invTotalPbList.stream()\r\n                .filter(inv -> inv.getAmountWithoutTax().add(inv.getAmountTax()).compareTo(inv.getAmountWithTax()) != 0)\r\n                .collect(Collectors.toList()));\r\n\r\n        log.info(\"Start fixing invoices amounts: {} invoices to fix\", invWithPbList.size());\r\n        log.info(\"invoices numbers to fix: {}\", invWithPbList.stream().map(Invoice::getInvoiceNumber).collect(Collectors.joining(\",\")));\r\n\r\n        for (Invoice invoice : invWithPbList) {\r\n            log.info(\"start fixing invoice {}\", invoice.getInvoiceNumber());\r\n            fixInvoiceTotals(invoice);\r\n            fixInvoiceAgregats(invoice);\r\n            //fixRecordedInvoiceAmounts(invoice);\r\n            log.info(\"finish fixing invoice {}\", invoice.getInvoiceNumber());\r\n        }\r\n    }\r\n\r\n    private void fixInvoiceTotals(Invoice invoice) {\r\n        log.info(\"fixing Invoice {} totals, old amounts: ht={}, tva={}, ttc={}\", invoice.getInvoiceNumber(),\r\n                invoice.getAmountWithoutTax(), invoice.getAmountTax(), invoice.getAmountWithTax());\r\n\r\n        var jpaInvoiceTotals = \"Select SUM(rt.amountWithoutTax) as ht, SUM(rt.amountTax) as tva, SUM(rt.amountWithTax) as ttc \" +\r\n                \"From RatedTransaction rt where rt.invoice = :invoice and rt.status='BILLED'\";\r\n        var invoiceTotals = invoiceService.getEntityManager()\r\n                .createQuery(jpaInvoiceTotals, Tuple.class)\r\n                .setParameter(\"invoice\", invoice)\r\n                .getResultList().get(0);\r\n\r\n        invoice.setAmountWithoutTax(invoiceTotals.get(\"ht\", BigDecimal.class));\r\n        invoice.setAmountTax(invoiceTotals.get(\"tva\", BigDecimal.class));\r\n        invoice.setAmountWithTax(invoiceTotals.get(\"ttc\", BigDecimal.class));\r\n\r\n        invoiceService.updateNoCheck(invoice);\r\n\r\n        log.info(\"new Invoice {} totals: ht={}, tva={}, ttc={}\", invoice.getInvoiceNumber(),\r\n                invoice.getAmountWithoutTax(), invoice.getAmountTax(), invoice.getAmountWithTax());\r\n    }\r\n\r\n    private void fixInvoiceAgregats(Invoice invoice) {\r\n        Map<Long, CategoryInvoiceAgregate> catInvAgregateMap = new HashMap<>();\r\n        Map<String, SubCategoryInvoiceAgregate> subCatInvAgregateMap = new HashMap<>();\r\n        Map<String, TaxInvoiceAgregate> taxInvAgregateMap = new HashMap<>();\r\n\r\n        log.info(\"fixing Invoice {} agregates...\", invoice.getInvoiceNumber());\r\n\r\n        // reset invoice's agregates amounts\r\n        for (InvoiceAgregate invoiceAgregate: invoice.getInvoiceAgregates()) {\r\n            if (invoiceAgregate instanceof CategoryInvoiceAgregate) {\r\n                catInvAgregateMap.put(invoiceAgregate.getId(), (CategoryInvoiceAgregate) invoiceAgregate);\r\n            }\r\n            if (invoiceAgregate instanceof SubCategoryInvoiceAgregate) {\r\n                SubCategoryInvoiceAgregate subCatInvAgregate = (SubCategoryInvoiceAgregate) invoiceAgregate;\r\n                subCatInvAgregateMap.put(subCatInvAgregate.getInvoiceSubCategory().getCode(), subCatInvAgregate);\r\n                for (var amountsByTax: subCatInvAgregate.getAmountsByTax().values()) {\r\n                    amountsByTax.setAmountWithoutTax(BigDecimal.ZERO);\r\n                    amountsByTax.setAmountTax(BigDecimal.ZERO);\r\n                    amountsByTax.setAmountWithTax(BigDecimal.ZERO);\r\n                }\r\n            }\r\n            if (invoiceAgregate instanceof TaxInvoiceAgregate) {\r\n                TaxInvoiceAgregate taxInvAgregate = (TaxInvoiceAgregate) invoiceAgregate;\r\n                taxInvAgregateMap.put(taxInvAgregate.getTax().getCode(), (TaxInvoiceAgregate) invoiceAgregate);\r\n            }\r\n            invoiceAgregate.setAmount(BigDecimal.ZERO);\r\n            invoiceAgregate.setAmountWithoutTax(BigDecimal.ZERO);\r\n            invoiceAgregate.setAmountWithTax(BigDecimal.ZERO);\r\n            invoiceAgregate.setAmountTax(BigDecimal.ZERO);\r\n            invoiceAgregate.setItemNumber(0);\r\n        }\r\n\r\n        var invRTsList = ratedTransactionService.listRatedTransactionsByInvoice(invoice);\r\n\r\n        for (var rt: invRTsList) {\r\n            SubCategoryInvoiceAgregate subCatInvAgregate = subCatInvAgregateMap.get(rt.getInvoiceSubCategory().getCode());\r\n            if (subCatInvAgregate == null) {\r\n                throw new BusinessException(\"Illegal state of invoice + \" + invoice.getInvoiceNumber() + \": It contains RT(id=\"\r\n                        +rt.getId()+\", subCat=\"+rt.getInvoiceSubCategory().getCode()+\") that belongs to any of invoice's subCatAgregates\");\r\n            }\r\n\r\n            //update sub cat agregate\r\n            subCatInvAgregate.addItemNumber(1);\r\n            subCatInvAgregate.addAmountWithoutTax(rt.getAmountWithoutTax());\r\n            subCatInvAgregate.addAmountWithTax(rt.getAmountWithTax());\r\n            subCatInvAgregate.addAmountTax(rt.getAmountTax());\r\n            SubcategoryInvoiceAgregateAmount scAmountInfo = subCatInvAgregate.getAmountsByTax().get(rt.getTax());\r\n            if (scAmountInfo == null) {\r\n                throw new BusinessException(\"Illegal state of invoice + \" + invoice.getInvoiceNumber() + \": It contains RT(id=\"\r\n                        +rt.getId()+\", tax=\"+rt.getTax().getCode()+\") that belongs to any of scAmountInfo of the subCatAgregate \"+rt.getInvoiceSubCategory().getCode());\r\n            }\r\n            scAmountInfo.addAmounts(rt.getAmountWithoutTax(), rt.getAmountWithTax(), rt.getAmountTax());\r\n\r\n            //update cat agregate\r\n            CategoryInvoiceAgregate catInvAgregate = catInvAgregateMap.get(subCatInvAgregate.getCategoryInvoiceAgregate().getId());\r\n            catInvAgregate.addItemNumber(1);\r\n            catInvAgregate.addAmountWithoutTax(rt.getAmountWithoutTax());\r\n            catInvAgregate.addAmountWithTax(rt.getAmountWithTax());\r\n            catInvAgregate.addAmountTax(rt.getAmountTax());\r\n\r\n            //update cat agregate\r\n            TaxInvoiceAgregate invoiceAgregateTax = taxInvAgregateMap.get(rt.getTax().getCode());\r\n            /*if (invoiceAgregateTax == null && BigDecimal.ZERO.compareTo(rt.getAmountTax().setScale(2, RoundingMode.HALF_EVEN)) != 0) {\r\n                throw new BusinessException(\"Illegal state of invoice + \" + invoice.getInvoiceNumber() + \": It contains RT(id=\"\r\n                        +rt.getId()+\") that belongs to any of invoice's taxAgregates\");\r\n            }*/\r\n            if (invoiceAgregateTax == null) {\r\n                continue;\r\n            }\r\n            invoiceAgregateTax.addItemNumber(1);\r\n            invoiceAgregateTax.addAmountWithoutTax(rt.getAmountWithoutTax());\r\n            invoiceAgregateTax.addAmountWithTax(rt.getAmountWithTax());\r\n            invoiceAgregateTax.addAmountTax(rt.getAmountTax());\r\n        }\r\n\r\n        for (CategoryInvoiceAgregate catInvAgregate : catInvAgregateMap.values()) {\r\n            log.info(\"fixing Invoice {} catInvAgregate[code={}, ht={}, tva={}, ttc={}]\", invoice.getInvoiceNumber(), catInvAgregate.getInvoiceCategory().getCode(),\r\n                    catInvAgregate.getAmountWithoutTax(), catInvAgregate.getAmountTax(), catInvAgregate.getAmountWithTax());\r\n            invoiceAgregateService.update(catInvAgregate);\r\n        }\r\n        for (SubCategoryInvoiceAgregate subCatInvAgregate : subCatInvAgregateMap.values()) {\r\n            log.info(\"fixing Invoice {} subCatInvAgregate[code={}, ht={}, tva={}, ttc={}]\", invoice.getInvoiceNumber(), subCatInvAgregate.getInvoiceSubCategory().getCode(),\r\n                    subCatInvAgregate.getAmountWithoutTax(), subCatInvAgregate.getAmountTax(), subCatInvAgregate.getAmountWithTax());\r\n            invoiceAgregateService.update(subCatInvAgregate);\r\n        }\r\n        for (TaxInvoiceAgregate taxInvAgregate : taxInvAgregateMap.values()) {\r\n            log.info(\"fixing Invoice {} taxInvAgregate[code={}, ht={}, tva={}, ttc={}]\", invoice.getInvoiceNumber(), taxInvAgregate.getTax().getCode(),\r\n                    taxInvAgregate.getAmountWithoutTax(), taxInvAgregate.getAmountTax(), taxInvAgregate.getAmountWithTax());\r\n            invoiceAgregateService.update(taxInvAgregate);\r\n        }\r\n    }\r\n\r\n    /*private void fixRecordedInvoiceAmounts(Invoice invoice) {\r\n        if (invoice.getRecordedInvoice() == null) {\r\n            return;\r\n        }\r\n        RecordedInvoice ri = invoice.getRecordedInvoice();\r\n\r\n\r\n        // adjust RI amounts\r\n        ri.setAmount(invoice.getAmountWithTax().abs());\r\n        ri.setAmountWithoutTax(invoice.getAmountWithoutTax().abs());\r\n        ri.setTaxAmount(invoice.getAmountTax().abs());\r\n\r\n        // adjust unmatched amount\r\n        BigDecimal diffAmount = invoice.getAmountWithTax().abs().subtract(ri.getAmount().abs());\r\n        boolean unMatchingAmountAltered = diffAmount.compareTo(BigDecimal.ZERO) != 0;\r\n\r\n        if (diffAmount.compareTo(BigDecimal.ZERO) >= 0) {\r\n            ri.setUnMatchingAmount(ri.getUnMatchingAmount().add(diffAmount.abs()));\r\n        } else {\r\n            ri.setUnMatchingAmount(ri.getUnMatchingAmount().subtract(diffAmount.abs()).abs());\r\n        }\r\n        if (unMatchingAmountAltered && ri.getMatchingStatus() == MatchingStatusEnum.L) {\r\n            if (BigDecimal.ZERO.compareTo(ri.getMatchingAmount()) == 0) {\r\n                ri.setMatchingStatus(MatchingStatusEnum.O);\r\n            } else {\r\n                ri.setMatchingStatus(MatchingStatusEnum.P);\r\n            }\r\n        }\r\n\r\n        recordedInvoiceService.updateNoCheck(ri);\r\n    }*/\r\n\r\n\r\n}\r\n\r\n]]>\r\n            </script>\r\n</ScriptInstance>"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "FixRTsAmountsScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.compta.FixRTsAmountsScript\" description=\"FixRTsAmountsScript\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[ package com.opencellsoft.service.ekko.compta;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.model.billing.CategoryInvoiceAgregate;\r\nimport org.meveo.model.billing.Invoice;\r\nimport org.meveo.model.billing.InvoiceAgregate;\r\nimport org.meveo.model.billing.RatedTransaction;\r\nimport org.meveo.model.billing.SubCategoryInvoiceAgregate;\r\nimport org.meveo.model.billing.SubcategoryInvoiceAgregateAmount;\r\nimport org.meveo.model.billing.TaxInvoiceAgregate;\r\nimport org.meveo.service.billing.impl.InvoiceAgregateService;\r\nimport org.meveo.service.billing.impl.InvoiceService;\r\nimport org.meveo.service.billing.impl.RatedTransactionService;\r\nimport org.meveo.service.script.Script;\r\n\r\nimport javax.persistence.Tuple;\r\nimport java.math.BigDecimal;\r\nimport java.math.RoundingMode;\r\nimport java.util.ArrayList;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.stream.Collectors;\r\n\r\npublic class FixRTsAmountsScript extends Script {\r\n\r\n\r\n    private InvoiceService invoiceService = (InvoiceService) getServiceInterface(\"InvoiceService\");\r\n    private RatedTransactionService ratedTransactionService = (RatedTransactionService) getServiceInterface(\"RatedTransactionService\");\r\n    private InvoiceAgregateService invoiceAgregateService = (InvoiceAgregateService) getServiceInterface(\"InvoiceAgregateService\");\r\n\r\n    @Override\r\n    public void execute(Map<String, Object> context) throws BusinessException {\r\n        List<Invoice> invWithPbList = new ArrayList<>();\r\n\r\n        //Apply SQLs fix RTs\r\n        log.info(\"Apply SQLs fix RTs...\");\r\n        String[] sqlFixRTsArray = new String[] {\r\n                \"update billing_rated_transaction set amount_tax =1.66 where amount_tax =1.67\"\r\n                ,\"update billing_rated_transaction set amount_tax =-1.66 where amount_tax =-1.67\"\r\n                ,\"update billing_rated_transaction set amount_tax =1.66 where amount_tax =1.7\"\r\n                ,\"update billing_rated_transaction set amount_tax =-1.66 where amount_tax =-1.7\"\r\n                ,\"update billing_rated_transaction set amount_tax =1.66 where amount_tax =1.665\"\r\n                ,\"update billing_rated_transaction set amount_tax =-1.66 where amount_tax =-1.665\"\r\n                ,\"update billing_rated_transaction set amount_without_tax =8.33 where amount_without_tax =8.3250\"\r\n                ,\"update billing_rated_transaction set amount_without_tax =-8.33 where amount_without_tax =-8.3250\"\r\n                ,\"update billing_rated_transaction set amount_tax =-0.66 where amount_tax =-0.67\"\r\n                ,\"update billing_rated_transaction set amount_without_tax =8.33 where amount_without_tax =8.55\"\r\n                ,\"update billing_rated_transaction set amount_without_tax =-8.33 where amount_without_tax =-8.55\"\r\n                ,\"update billing_rated_transaction set amount_with_tax =9.99 where amount_with_tax =10.00\"\r\n                ,\"update billing_rated_transaction set amount_with_tax =-9.99 where amount_with_tax =-10.00\"\r\n                ,\"update billing_rated_transaction set amount_tax=0.00 where amount_tax!= 0.00 and amount_without_tax =0.00\"\r\n                ,\"update billing_invoice set amount_tax =1.16 where amount_tax =1.1650\"\r\n                ,\"update billing_invoice set amount_tax =-1.16 where amount_tax =-1.1650\"\r\n                ,\"update billing_invoice set amount_without_tax =5.83 where amount_without_tax =5.8250\"\r\n                ,\"update billing_invoice set amount_without_tax =-5.83 where amount_without_tax =-5.8250\"\r\n                ,\"update billing_invoice set amount_without_tax =6.66, amount_tax =1.33 where amount_without_tax =6.655 and amount_tax =1.335\"\r\n                ,\"update billing_invoice set amount_without_tax =-6.66, amount_tax =-1.33 where amount_without_tax =-6.655 and amount_tax =-1.335\"\r\n                ,\"update billing_rated_transaction set amount_without_tax =-12.50, amount_tax =-2.50 where amount_without_tax =-2.50 and amount_tax =-12.50\"\r\n                ,\"update billing_invoice set amount_without_tax =1, amount_tax =0, amount_with_tax=2 where amount_without_tax =-2.50 and amount_tax =-12.50\"\r\n                ,\"update billing_rated_transaction set amount_with_tax =133.99 where amount_with_tax =134.00\"\r\n                ,\"update billing_rated_transaction set amount_with_tax =-133.99 where amount_with_tax =-134.00\"\r\n                ,\"update billing_rated_transaction set amount_with_tax =0.25 where amount_without_tax =0.21 and amount_with_tax =0.26\"\r\n                ,\"update billing_rated_transaction set amount_with_tax =-0.25 where amount_without_tax =-0.21 and amount_with_tax =-0.26\"\r\n                ,\"update billing_rated_transaction set amount_with_tax =44.75 where amount_without_tax =42.42 and amount_with_tax =44.76\"\r\n                ,\"update billing_rated_transaction set amount_with_tax =-44.75 where amount_without_tax =-42.42 and amount_with_tax =-44.76\"\r\n        };\r\n        for (int i = 0; i < sqlFixRTsArray.length; i++) {\r\n            String sql = sqlFixRTsArray[i];\r\n            int updatedRows = ratedTransactionService.getEntityManager().createNativeQuery(sql).executeUpdate();\r\n            log.info(\"SQL {} => rows updated {}\", sql, updatedRows);\r\n        }\r\n\r\n\r\n        // Fixing RT mith more then 3 decimals in their amounts\r\n        var rtDeciamlPbList = ratedTransactionService.getEntityManager()\r\n                .createQuery(\"SELECT rt FROM RatedTransaction rt \" +\r\n                        \"WHERE rt.amountWithoutTax * 100 <> ROUND(rt.amountWithoutTax * 100)\",\r\n                        RatedTransaction.class).getResultList();\r\n\r\n        log.info(\"Fixing RTs with more then 3 decimals. Nbr of RTs to fix {}\", rtDeciamlPbList.size());\r\n        for (RatedTransaction rt : rtDeciamlPbList) {\r\n            fixRTAmountsDecimals(rt);\r\n            if (!invWithPbList.contains(rt.getInvoice())) {\r\n                invWithPbList.add(rt.getInvoice());\r\n            }\r\n        }\r\n\r\n        // Fix RTs with pb HT+TVA!=TTC\r\n        var rtsHTPbList = invoiceService.getEntityManager().createQuery(\"Select rt from RatedTransaction rt \" +\r\n                \"Where rt.amountWithoutTax + rt.amountTax != rt.amountWithTax\",\r\n                RatedTransaction.class).getResultList();\r\n\r\n        log.info(\"Fixing RTs with HT+TVA!=TTC. Nbr of RTs to fix {}\", rtsHTPbList.size());\r\n        for (RatedTransaction rt : rtsHTPbList) {\r\n            fixRTAmountsDecimals(rt);\r\n            if (!invWithPbList.contains(rt.getInvoice())) {\r\n                invWithPbList.add(rt.getInvoice());\r\n            }\r\n        }\r\n\r\n        log.info(\"Start fixing invoices amounts: {} invoices to fix\", invWithPbList.size());\r\n        log.info(\"invoices numbers to fix: {}\", invWithPbList.stream().map(Invoice::getInvoiceNumber).collect(Collectors.joining(\",\")));\r\n\r\n        for (Invoice invoice : invWithPbList) {\r\n            log.info(\"start fixing invoice {}\", invoice.getInvoiceNumber());\r\n            fixInvoiceTotals(invoice);\r\n            fixInvoiceAgregats(invoice);\r\n            //fixRecordedInvoiceAmounts(invoice);\r\n            log.info(\"finish fixing invoice {}\", invoice.getInvoiceNumber());\r\n        }\r\n    }\r\n\r\n    private void fixRTAmountsDecimals(RatedTransaction rt) {\r\n        log.info(\"Fixing RT of inv[{}], amounts: HT={}, TAX={}, TTC={}\", rt.getInvoice().getInvoiceNumber(),\r\n                rt.getAmountWithoutTax(), rt.getAmountTax(), rt.getAmountWithTax());\r\n\r\n        rt.setAmountWithoutTax(rt.getAmountWithoutTax().setScale(2, RoundingMode.HALF_UP));\r\n        rt.setAmountWithTax(rt.getAmountWithTax().setScale(2, RoundingMode.HALF_UP));\r\n        rt.setAmountTax(rt.getAmountWithTax().subtract(rt.getAmountWithoutTax()));\r\n\r\n        ratedTransactionService.updateNoCheck(rt);\r\n    }\r\n\r\n    private void fixInvoiceTotals(Invoice invoice) {\r\n        log.info(\"fixing Invoice {} totals, old amounts: ht={}, tva={}, ttc={}\", invoice.getInvoiceNumber(),\r\n                invoice.getAmountWithoutTax(), invoice.getAmountTax(), invoice.getAmountWithTax());\r\n\r\n        var jpaInvoiceTotals = \"Select SUM(rt.amountWithoutTax) as ht, SUM(rt.amountTax) as tva, SUM(rt.amountWithTax) as ttc \" +\r\n                \"From RatedTransaction rt where rt.invoice = :invoice and rt.status='BILLED'\";\r\n        var invoiceTotals = invoiceService.getEntityManager()\r\n                .createQuery(jpaInvoiceTotals, Tuple.class)\r\n                .setParameter(\"invoice\", invoice)\r\n                .getResultList().get(0);\r\n\r\n        invoice.setAmountWithoutTax(invoiceTotals.get(\"ht\", BigDecimal.class));\r\n        invoice.setAmountTax(invoiceTotals.get(\"tva\", BigDecimal.class));\r\n        invoice.setAmountWithTax(invoiceTotals.get(\"ttc\", BigDecimal.class));\r\n\r\n        invoiceService.updateNoCheck(invoice);\r\n\r\n        log.info(\"new Invoice {} totals: ht={}, tva={}, ttc={}\", invoice.getInvoiceNumber(),\r\n                invoice.getAmountWithoutTax(), invoice.getAmountTax(), invoice.getAmountWithTax());\r\n    }\r\n\r\n    private void fixInvoiceAgregats(Invoice invoice) {\r\n        Map<Long, CategoryInvoiceAgregate> catInvAgregateMap = new HashMap<>();\r\n        Map<String, SubCategoryInvoiceAgregate> subCatInvAgregateMap = new HashMap<>();\r\n        Map<String, TaxInvoiceAgregate> taxInvAgregateMap = new HashMap<>();\r\n\r\n        log.info(\"fixing Invoice {} agregates...\", invoice.getInvoiceNumber());\r\n\r\n        // reset invoice's agregates amounts\r\n        for (InvoiceAgregate invoiceAgregate: invoice.getInvoiceAgregates()) {\r\n            if (invoiceAgregate instanceof CategoryInvoiceAgregate) {\r\n                catInvAgregateMap.put(invoiceAgregate.getId(), (CategoryInvoiceAgregate) invoiceAgregate);\r\n            }\r\n            if (invoiceAgregate instanceof SubCategoryInvoiceAgregate) {\r\n                SubCategoryInvoiceAgregate subCatInvAgregate = (SubCategoryInvoiceAgregate) invoiceAgregate;\r\n                subCatInvAgregateMap.put(subCatInvAgregate.getInvoiceSubCategory().getCode(), subCatInvAgregate);\r\n                for (var amountsByTax: subCatInvAgregate.getAmountsByTax().values()) {\r\n                    amountsByTax.setAmountWithoutTax(BigDecimal.ZERO);\r\n                    amountsByTax.setAmountTax(BigDecimal.ZERO);\r\n                    amountsByTax.setAmountWithTax(BigDecimal.ZERO);\r\n                }\r\n            }\r\n            if (invoiceAgregate instanceof TaxInvoiceAgregate) {\r\n                TaxInvoiceAgregate taxInvAgregate = (TaxInvoiceAgregate) invoiceAgregate;\r\n                taxInvAgregateMap.put(taxInvAgregate.getTax().getCode(), (TaxInvoiceAgregate) invoiceAgregate);\r\n            }\r\n            invoiceAgregate.setAmount(BigDecimal.ZERO);\r\n            invoiceAgregate.setAmountWithoutTax(BigDecimal.ZERO);\r\n            invoiceAgregate.setAmountWithTax(BigDecimal.ZERO);\r\n            invoiceAgregate.setAmountTax(BigDecimal.ZERO);\r\n            invoiceAgregate.setItemNumber(0);\r\n        }\r\n\r\n        var invRTsList = ratedTransactionService.listRatedTransactionsByInvoice(invoice);\r\n\r\n        for (var rt: invRTsList) {\r\n            SubCategoryInvoiceAgregate subCatInvAgregate = subCatInvAgregateMap.get(rt.getInvoiceSubCategory().getCode());\r\n            if (subCatInvAgregate == null) {\r\n                throw new BusinessException(\"Illegal state of invoice + \" + invoice.getInvoiceNumber() + \": It contains RT(id=\"\r\n                        +rt.getId()+\", subCat=\"+rt.getInvoiceSubCategory().getCode()+\") that belongs to any of invoice's subCatAgregates\");\r\n            }\r\n\r\n            //update sub cat agregate\r\n            subCatInvAgregate.addItemNumber(1);\r\n            subCatInvAgregate.addAmountWithoutTax(rt.getAmountWithoutTax());\r\n            subCatInvAgregate.addAmountWithTax(rt.getAmountWithTax());\r\n            subCatInvAgregate.addAmountTax(rt.getAmountTax());\r\n            SubcategoryInvoiceAgregateAmount scAmountInfo = subCatInvAgregate.getAmountsByTax().get(rt.getTax());\r\n            if (scAmountInfo == null) {\r\n                throw new BusinessException(\"Illegal state of invoice + \" + invoice.getInvoiceNumber() + \": It contains RT(id=\"\r\n                        +rt.getId()+\", tax=\"+rt.getTax().getCode()+\") that belongs to any of scAmountInfo of the subCatAgregate \"+rt.getInvoiceSubCategory().getCode());\r\n            }\r\n            scAmountInfo.addAmounts(rt.getAmountWithoutTax(), rt.getAmountWithTax(), rt.getAmountTax());\r\n\r\n            //update cat agregate\r\n            CategoryInvoiceAgregate catInvAgregate = catInvAgregateMap.get(subCatInvAgregate.getCategoryInvoiceAgregate().getId());\r\n            catInvAgregate.addItemNumber(1);\r\n            catInvAgregate.addAmountWithoutTax(rt.getAmountWithoutTax());\r\n            catInvAgregate.addAmountWithTax(rt.getAmountWithTax());\r\n            catInvAgregate.addAmountTax(rt.getAmountTax());\r\n\r\n            //update cat agregate\r\n            TaxInvoiceAgregate invoiceAgregateTax = taxInvAgregateMap.get(rt.getTax().getCode());\r\n            /*if (invoiceAgregateTax == null && BigDecimal.ZERO.compareTo(rt.getAmountTax().setScale(2, RoundingMode.HALF_EVEN)) != 0) {\r\n                throw new BusinessException(\"Illegal state of invoice + \" + invoice.getInvoiceNumber() + \": It contains RT(id=\"\r\n                        +rt.getId()+\") that belongs to any of invoice's taxAgregates\");\r\n            }*/\r\n            if (invoiceAgregateTax == null) {\r\n                continue;\r\n            }\r\n            invoiceAgregateTax.addItemNumber(1);\r\n            invoiceAgregateTax.addAmountWithoutTax(rt.getAmountWithoutTax());\r\n            invoiceAgregateTax.addAmountWithTax(rt.getAmountWithTax());\r\n            invoiceAgregateTax.addAmountTax(rt.getAmountTax());\r\n        }\r\n\r\n        for (CategoryInvoiceAgregate catInvAgregate : catInvAgregateMap.values()) {\r\n            log.info(\"fixing Invoice {} catInvAgregate[code={}, ht={}, tva={}, ttc={}]\", invoice.getInvoiceNumber(), catInvAgregate.getInvoiceCategory().getCode(),\r\n                    catInvAgregate.getAmountWithoutTax(), catInvAgregate.getAmountTax(), catInvAgregate.getAmountWithTax());\r\n            invoiceAgregateService.update(catInvAgregate);\r\n        }\r\n        for (SubCategoryInvoiceAgregate subCatInvAgregate : subCatInvAgregateMap.values()) {\r\n            log.info(\"fixing Invoice {} subCatInvAgregate[code={}, ht={}, tva={}, ttc={}]\", invoice.getInvoiceNumber(), subCatInvAgregate.getInvoiceSubCategory().getCode(),\r\n                    subCatInvAgregate.getAmountWithoutTax(), subCatInvAgregate.getAmountTax(), subCatInvAgregate.getAmountWithTax());\r\n            invoiceAgregateService.update(subCatInvAgregate);\r\n        }\r\n        for (TaxInvoiceAgregate taxInvAgregate : taxInvAgregateMap.values()) {\r\n            log.info(\"fixing Invoice {} taxInvAgregate[code={}, ht={}, tva={}, ttc={}]\", invoice.getInvoiceNumber(), taxInvAgregate.getTax().getCode(),\r\n                    taxInvAgregate.getAmountWithoutTax(), taxInvAgregate.getAmountTax(), taxInvAgregate.getAmountWithTax());\r\n            invoiceAgregateService.update(taxInvAgregate);\r\n        }\r\n    }\r\n\r\n    /*private void fixRecordedInvoiceAmounts(Invoice invoice) {\r\n        if (invoice.getRecordedInvoice() == null) {\r\n            return;\r\n        }\r\n        RecordedInvoice ri = invoice.getRecordedInvoice();\r\n\r\n\r\n        // adjust RI amounts\r\n        ri.setAmount(invoice.getAmountWithTax().abs());\r\n        ri.setAmountWithoutTax(invoice.getAmountWithoutTax().abs());\r\n        ri.setTaxAmount(invoice.getAmountTax().abs());\r\n\r\n        // adjust unmatched amount\r\n        BigDecimal diffAmount = invoice.getAmountWithTax().abs().subtract(ri.getAmount().abs());\r\n        boolean unMatchingAmountAltered = diffAmount.compareTo(BigDecimal.ZERO) != 0;\r\n\r\n        if (diffAmount.compareTo(BigDecimal.ZERO) >= 0) {\r\n            ri.setUnMatchingAmount(ri.getUnMatchingAmount().add(diffAmount.abs()));\r\n        } else {\r\n            ri.setUnMatchingAmount(ri.getUnMatchingAmount().subtract(diffAmount.abs()).abs());\r\n        }\r\n        if (unMatchingAmountAltered && ri.getMatchingStatus() == MatchingStatusEnum.L) {\r\n            if (BigDecimal.ZERO.compareTo(ri.getMatchingAmount()) == 0) {\r\n                ri.setMatchingStatus(MatchingStatusEnum.O);\r\n            } else {\r\n                ri.setMatchingStatus(MatchingStatusEnum.P);\r\n            }\r\n        }\r\n\r\n        recordedInvoiceService.updateNoCheck(ri);\r\n    }*/\r\n\r\n\r\n}\r\n\r\n\r\n\r\n]]>\r\n            </script>\r\n</ScriptInstance>"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						}
					]
				},
				{
					"name": "payment",
					"item": [
						{
							"name": "MercanetIntegrationScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Authorization",
										"value": "Basic b3BlbmNlbGwuYWRtaW46b3BlbmNlbGwuYWRtaW4="
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.payment.MercanetIntegrationScript\" description=\"Ekko Mercanet Integration Script\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.payment;\r\n\r\nimport java.io.BufferedReader;\r\nimport java.io.File;\r\nimport java.io.FileInputStream;\r\nimport java.io.FileNotFoundException;\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.io.InputStreamReader;\r\nimport java.math.BigDecimal;\r\nimport java.nio.charset.StandardCharsets;\r\nimport java.nio.file.Files;\r\nimport java.nio.file.Path;\r\nimport java.nio.file.Paths;\r\nimport java.time.LocalDate;\r\nimport java.time.ZoneId;\r\nimport java.util.ArrayList;\r\nimport java.util.Arrays;\r\nimport java.util.Date;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.stream.Collectors;\r\nimport java.util.stream.Stream;\r\n\r\nimport javax.persistence.NoResultException;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.admin.exception.NoAllOperationUnmatchedException;\r\nimport org.meveo.admin.exception.UnbalanceAmountException;\r\nimport org.meveo.commons.utils.ParamBean;\r\nimport org.meveo.commons.utils.ParamBeanFactory;\r\nimport org.meveo.commons.utils.QueryBuilder;\r\nimport org.meveo.commons.utils.StringUtils;\r\nimport org.meveo.model.MatchingReturnObject;\r\nimport org.meveo.model.crm.Provider;\r\nimport org.meveo.model.payments.CustomerAccount;\r\nimport org.meveo.model.payments.MatchingStatusEnum;\r\nimport org.meveo.model.payments.MatchingTypeEnum;\r\nimport org.meveo.model.payments.OCCTemplate;\r\nimport org.meveo.model.payments.Payment;\r\nimport org.meveo.model.payments.PaymentMethodEnum;\r\nimport org.meveo.model.payments.RecordedInvoice;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.service.admin.impl.SellerService;\r\nimport org.meveo.service.crm.impl.ProviderService;\r\nimport org.meveo.service.payments.impl.AccountOperationService;\r\nimport org.meveo.service.payments.impl.CustomerAccountService;\r\nimport org.meveo.service.payments.impl.MatchingCodeService;\r\nimport org.meveo.service.payments.impl.OCCTemplateService;\r\nimport org.meveo.service.payments.impl.PaymentService;\r\nimport org.meveo.service.payments.impl.RecordedInvoiceService;\r\nimport org.meveo.service.script.Script;\r\n\r\nimport com.google.common.collect.Maps;\r\n\r\n/**\r\n * /**\r\n * \r\n * @author myPower team , from dump PP 19/05/2021\r\n * \r\n * @author anasseh update for OC 11 and EKKO\r\n * @author anasseh 05/06/2022 SUPS-1688\r\n * @author anasseh 08/05/2023 SUPS-2462\r\n * \r\n * \r\n *\r\n */\r\npublic class MercanetIntegrationScript extends Script {\r\n\r\n\tprivate static final String SELLER_CODE = \"EKKO\";\r\n\tprivate static final String DATETIME_FORMAT = \"dd_MM_yyyy-HHmm\";\r\n\tprivate static final String MERCANET_INPUT_DIR = \"MERCANET_INPUT_DIR\";\r\n\tprivate static final String MERCANET_FILE_EXT = \"MERCANET_FILE_EXT\";\r\n\tprivate static final String MERCANET_DELIMITER = \"MERCANET_DELIMITER\";\r\n\tprivate static final String MERCANET_ARCH_DIR = \"MERCANET_ARCH_DIR\";\r\n\tprivate static final String MERCANET_ERR_DIR = \"MERCANET_ERR_DIR\";\r\n\tprivate static final String MERCANET_WARN_DIR = \"MERCANET_WARN_DIR\";\r\n\tprivate static final String MERCANET_REPORT_DIR = \"MERCANET_REPORT_DIR\";\r\n\tprivate RecordedInvoiceService recordedInvoiceService = (RecordedInvoiceService) getServiceInterface(\"RecordedInvoiceService\");\r\n\tprivate PaymentService paymentService = (PaymentService) getServiceInterface(\"PaymentService\");\r\n\tprivate ParamBeanFactory paramBeanFactory = (ParamBeanFactory) getServiceInterface(\"ParamBeanFactory\");\r\n\tprivate OCCTemplateService oCCTemplateService = (OCCTemplateService) getServiceInterface(\"OCCTemplateService\");\r\n\tprivate MatchingCodeService matchingCodeService = (MatchingCodeService) getServiceInterface(\"MatchingCodeService\");\r\n\tprivate Provider appProvider = ((ProviderService) getServiceInterface(\"ProviderService\")).getProvider();\r\n\tprivate SellerService sellerService = (SellerService) getServiceInterface(\"SellerService\");\r\n\tprivate CustomerAccountService customerAccountService = (CustomerAccountService) getServiceInterface(\"CustomerAccountService\");\r\n\tprivate AccountOperationService accountOperationService = (AccountOperationService) getServiceInterface(\"AccountOperationService\");\r\n\t\r\n\r\n\tprivate String delimiter;\r\n\tprivate OCCTemplate occCardTemplate;\r\n\tprivate Map<String, Integer> processedItemsIndexes;\r\n\tprivate List<String> reportMessages = new ArrayList<>();\r\n\t\r\n\r\n\t/**\r\n\t * script main execute method \r\n\t * \r\n\t * @param methodContext method context params\r\n\t * @throws BusinessException business exception\r\n\t */\r\n\t@Override\r\n\tpublic void execute(Map<String, Object> methodContext) throws BusinessException {\r\n\t\tlog.info(\"Execute methodContext:{}\", methodContext);\r\n\t\tlong startTime = System.currentTimeMillis();\r\n\t\tString mercanetDir = (String) methodContext.get(MERCANET_INPUT_DIR);\r\n\t\tString archiveDir = (String) methodContext.get(MERCANET_ARCH_DIR);\r\n\t\tString errorDir = (String) methodContext.get(MERCANET_ERR_DIR);\r\n\t\tString warnDir = (String) methodContext.get(MERCANET_WARN_DIR);\r\n\t\tString reportDir = (String) methodContext.get(MERCANET_REPORT_DIR);\r\n\t\tString mercanetFileExt = (String) methodContext.get(MERCANET_FILE_EXT);\r\n\t\tString mercanetDelimiter = (String) methodContext.get(MERCANET_DELIMITER);\r\n\t\tlog.debug(\"MERCANET_INPUT_DIR={}\", mercanetDir);\r\n\t\tlog.debug(\"MERCANET_FILE_EXT={}\", mercanetFileExt);\r\n\t\tlog.debug(\"MERCANET_DELIMITER={}\", mercanetDelimiter);\r\n\t\tlog.debug(\"MERCANET_ARCH_DIR={}\", archiveDir);\r\n\t\tlog.debug(\"MERCANET_WARN_DIR={}\", warnDir);\r\n\t\tlog.debug(\"MERCANET_ERR_DIR={}\", errorDir);\r\n\t\tlog.debug(\"MERCANET_REPORT_DIR={}\", reportDir);\r\n\t\tif (StringUtils.isBlank(mercanetDir)) {\r\n\t\t\tthrow new BusinessException(\"The variable input \" + MERCANET_INPUT_DIR + \" is mandatory\");\r\n\t\t}\r\n\t\tString rootDir = ParamBean.getInstance().getChrootDir(appProvider.getCode());\r\n\t\tPath archiveDirPath = Paths.get(rootDir + File.separator + (!StringUtils.isBlank(archiveDir) ? archiveDir : \"mercanet_archive\"));\r\n\t\tPath errorDirPath = Paths.get(rootDir + File.separator + (!StringUtils.isBlank(errorDir) ? errorDir : \"mercanet_errors\"));\r\n\t\tPath warnDirPath = Paths.get(rootDir + File.separator + (!StringUtils.isBlank(warnDir) ? warnDir : \"mercanet_warns\"));\r\n\t\tPath reportDirPath = Paths.get(rootDir + File.separator + (!StringUtils.isBlank(reportDir) ? reportDir : \"mercanet_reports\"));\r\n\t\tmercanetFileExt = !StringUtils.isBlank(mercanetFileExt) ? \".\" + mercanetFileExt : \".csv\";\r\n\t\tthis.delimiter = !StringUtils.isBlank(mercanetDelimiter) ? mercanetDelimiter : \"\\t\";\r\n\t\tPath inputDir = Paths.get(rootDir + File.separator + mercanetDir);\r\n\t\tif (!createDirIfNotExist(inputDir)) {\r\n\t\t\tthrow new BusinessException(\"inputDir doesn't exist and could not be created\");\r\n\t\t}\r\n\t\tif (!createDirIfNotExist(warnDirPath)) {\r\n\t\t\tthrow new BusinessException(\"warnDirPath doesn't exist and could not be created\");\r\n\t\t}\r\n\t\tList<Path> mercanetFiles = getMercanetLogFiles(inputDir, mercanetFileExt);\r\n\t\tlog.info(\"mercanetFiles\" + mercanetFiles);\r\n\r\n\t\tif (!createDirIfNotExist(reportDirPath)) {\r\n\t\t\tthrow new BusinessException(\"reportDirPath doesn't exist and could not be created\");\r\n\t\t}\r\n\t\tif (mercanetFiles == null || mercanetFiles.isEmpty()) {\r\n\t\t\tlog.warn(\"No mercanet files are found in the input Dir. will exit!\");\r\n\t\t\tmethodContext.put(Script.JOB_RESULT_NB_OK, 0);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tlog.debug(\"{} mercanet files found. start import them...\", mercanetFiles.size());\r\n\t\tif (!createDirIfNotExist(archiveDirPath)) {\r\n\t\t\tthrow new BusinessException(\"Archive dir doesn't exist and could not be created\");\r\n\t\t}\r\n\t\tif (!createDirIfNotExist(errorDirPath)) {\r\n\t\t\tthrow new BusinessException(\"Error dir doesn't exist and could not be created\");\r\n\t\t}\r\n\t\tStringBuilder sbFiles = new StringBuilder(\"Processed \" + mercanetFiles.size() + \" mercanet files :\\n\");\r\n\t\tmercanetFiles.forEach(file -> {\r\n\t\t\tsbFiles.append(file.getFileName() + \"\\n\");\r\n\t\t});\r\n\t\t// OCC template for card and refund\r\n\t\tParamBean paramBean = paramBeanFactory.getInstance();\r\n\t\tString occCardTemplateCode = paramBean.getProperty(\"occ.payment.card\", \"PAY_CRD\");\r\n\t\tthis.occCardTemplate = getOCCTemplate(occCardTemplateCode);\r\n\t\t// counters for all import\r\n\t\tProcessingReport allReport = new ProcessingReport();\r\n\t\tprocessedItemsIndexes = new HashMap<>();\r\n\t\tfor (Path mercanetFile : mercanetFiles) {\r\n\t\t\tString fileName = mercanetFile.getFileName().toString();\r\n\t\t\t// addReportMessage(\"Start processing file \" +fileName+ \"...\", null);\r\n\t\t\tInputStream inputStream = null;\r\n\t\t\ttry {\r\n\t\t\t\tinputStream = new FileInputStream(mercanetFile.toFile());\r\n\t\t\t} catch (FileNotFoundException e) {\r\n\t\t\t\tlog.error(\"Error reading mercanet file \", mercanetFile.toString(), e);\r\n\t\t\t\taddReportMessage(\"Error reading file: \" + e.getMessage(), fileName);\r\n\t\t\t\tallReport.opKo++;\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\t\t\ttry (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {\r\n\t\t\t\t// skip the headers of the csv\r\n\t\t\t\tbufferedReader.readLine();\r\n\t\t\t\tbufferedReader.readLine();\r\n\t\t\t\t// counters per file\r\n\t\t\t\tProcessingReport fileReport = new ProcessingReport();\r\n\t\t\t\t// Read operations lines\r\n\t\t\t\tString line;\r\n\t\t\t\tint index = 2;\r\n\t\t\t\twhile ((line = bufferedReader.readLine()) != null && !line.equals(\"END\") && !StringUtils.isBlank(line)) {\r\n\t\t\t\t\tindex++;\r\n\t\t\t\t\tMercanetItem item = mapToItem(line, index);\r\n\t\t\t\t\titem.fileName = fileName;\r\n\t\t\t\t\t// #203 : Uniqueness of payment based on reference and MerchantId\r\n\t\t\t\t\tif (findPaymentByReferenceAndPaymentOrder(item.transactionReference) != null) {\r\n\t\t\t\t\t\tlog.error(\"Payment already created for mercanet operation at line n={}, fileName={}\", item.numLine, item.fileName);\r\n\t\t\t\t\t\taddReportMessage(\"Payment already created for line n=\" + item.numLine, item.fileName);\r\n\t\t\t\t\t\tfileReport.opKo++;\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (processedItemsIndexes.get(item.getIdentifier()) != null) {\r\n\t\t\t\t\t\tInteger duplicateIndex = processedItemsIndexes.get(item.getIdentifier());\r\n\t\t\t\t\t\tlog.debug(\"Warning! Line \" + index + \" is a duplicate of line number \" + processedItemsIndexes.get(item.getIdentifier()) + \". Filename=\" + fileName);\r\n\t\t\t\t\t\taddReportMessage(\"Warning! Line=\" + index + \", message=Line is escaped because it's a duplicate of line number \" + duplicateIndex, fileName);\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (item.operationType.equals(\"CREDIT\") || item.operationType.equals(\"DEBIT\") || item.operationType.equals(\"DEBIT_CAPTURE\")) {\r\n\t\t\t\t\t\ttry {\r\n\t\t\t\t\t\t\tPayment payment =  null;\r\n\t\t\t\t\t\t\tRecordedInvoice mainRecordedInvoice  = getRecordedInvoice(item.invoiceNumber);\r\n\t\t\t\t\t\t\tCustomerAccount customerAccount = null;\r\n\t\t\t\t\t\t\tif(mainRecordedInvoice != null) {\r\n\t\t\t\t\t\t\t\tcustomerAccount = mainRecordedInvoice.getCustomerAccount();\r\n\t\t\t\t\t\t\t\tpayment = createPayment(item, fileReport,customerAccount);\r\n\t\t\t\t\t\t\t\tif (payment != null) {\r\n\t\t\t\t\t\t\t\t\t// matching the created payment\r\n\t\t\t\t\t\t\t\t\tmatchOperation(item.transactionReference, payment, mainRecordedInvoice, fileName, index, fileReport);\r\n\t\t\t\t\t\t\t\t\tpayment = (Payment) accountOperationService.findById(payment.getId());\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}else {\r\n\t\t\t\t\t\t\t\tcustomerAccount = customerAccountService.findByCode(item.customerCode);\r\n\t\t\t\t\t\t\t\tif(customerAccount == null) {\r\n\t\t\t\t\t\t\t\t\tlog.error(\"Can't found invoice and customer at line n={}, fileName={}\", item.numLine, item.fileName);\r\n\t\t\t\t\t\t\t\t\taddReportMessage(\"Can't found invoice and customer for line n=\" + item.numLine, item.fileName);\r\n\t\t\t\t\t\t\t\t\tfileReport.opKo++;\r\n\t\t\t\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\tpayment = createPayment(item, fileReport,customerAccount);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\tList<RecordedInvoice> listOpenedInvoioces = getListOpenedInvoioces(customerAccount);\r\n\t\t\t\t\t\t\tfor (RecordedInvoice aoINV : listOpenedInvoioces) {\r\n\t\t\t\t                if (BigDecimal.ZERO.compareTo(payment.getUnMatchingAmount()) == 0) {\r\n\t\t\t\t                    break;\r\n\t\t\t\t                }\r\n\t\t\t\t                log.info(\"matching .... AO invoice id:{} unmatchingAount:{}\", aoINV.getId(), aoINV.getUnMatchingAmount());\r\n\t\t\t\t                matchOperation(item.transactionReference, payment, aoINV, fileName, index, fileReport);\r\n\t\t\t\t                payment = (Payment) accountOperationService.findById(payment.getId());\r\n\t\t\t\t            }\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\t\t\tlog.error(\"Error processing line {}, file {}\", index, fileName, e);\r\n\t\t\t\t\t\t\taddReportMessage(\"Error processing line=\" + index + \", message=\" + e.getMessage() + \"\", fileName);\r\n\t\t\t\t\t\t\tfileReport.opKo++;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}else {\r\n\t\t\t\t\t\tlog.debug(\"Error on line=\" + index + \", operationType \\\"\" + item.operationType + \"\\\" not recognized. Filename=\" + fileName);\r\n\t\t\t\t\t\taddReportMessage(\"Error processing line=\" + index + \", message= Operation type \\\"\" + item.operationType + \"\\\" not recognized.\", fileName);\r\n\t\t\t\t\t\tfileReport.opKo++;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tprocessedItemsIndexes.put(item.getIdentifier(), index);\r\n\t\t\t\t}\r\n\t\t\t\t// close mercanet file\r\n\t\t\t\tbufferedReader.close();\r\n\t\t\t\tinputStream.close();\r\n\t\t\t\t// report for one file\r\n\t\t\t\tfileReport.opAll = index - 2;\r\n\t\t\t\tif (fileReport.opKo > 0) {\r\n\t\t\t\t\tmoveToErrorDirectory(errorDirPath, mercanetFile);\r\n\t\t\t\t} else if (fileReport.matchKo > 0) {\r\n\t\t\t\t\tmoveToWarnDirectory(warnDirPath, mercanetFile);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tarchivateMercanetFile(archiveDirPath, mercanetFile);\r\n\t\t\t\t}\r\n\t\t\t\tallReport.opAll += fileReport.opAll;\r\n\t\t\t\tallReport.opOk += fileReport.opOk;\r\n\t\t\t\tallReport.opKo += fileReport.opKo;\r\n\t\t\t\tallReport.matchOk += fileReport.matchOk;\r\n\t\t\t\tallReport.matchKo += fileReport.matchKo;\r\n\t\t\t} catch (Exception e) {\r\n\t\t\t\tlog.error(\"Error processing mercanet file {}\", fileName, e);\r\n\t\t\t\taddReportMessage(\"Error processing mercanet file [ message=\" + e.getMessage() + \" ]\", fileName);\r\n\t\t\t\tallReport.opKo = 1;\r\n\t\t\t\tmoveToErrorDirectory(errorDirPath, mercanetFile);\r\n\t\t\t}\r\n\t\t}\r\n\t\tmethodContext.put(Script.JOB_RESULT_NB_OK, allReport.opOk);\r\n\t\tmethodContext.put(Script.JOB_RESULT_NB_WARN, allReport.matchKo);\r\n\t\tmethodContext.put(Script.JOB_RESULT_NB_KO, allReport.opKo);\r\n\t\tmethodContext.put(Script.JOB_RESULT_REPORT, reportMessages);\r\n\t\taddReportMessage(sbFiles.toString(), null);\r\n\t\tlong processDuration = (System.currentTimeMillis() - startTime) / 1000;\r\n\t\taddReportMessage(\"Files are processed in \" + processDuration + \" seconds.\", null);\r\n\t\taddReportMessage(\"Import report : Total=\" + allReport.opAll + \". \" + \"AO creation: Ok=\" + allReport.opOk + \", KO=\" + allReport.opKo + \". \" + \"AO matching: OK=\"\r\n\t\t\t\t+ allReport.matchOk + \", KO=\" + allReport.matchKo, null);\r\n\t\t// create import report file in input dir\r\n\t\tPath reportFile = Paths.get(reportDirPath.toString() + File.separator + \"report_\" + DateUtils.formatDateWithPattern(new Date(), DATETIME_FORMAT));\r\n\t\ttry {\r\n\t\t\tFiles.createFile(reportFile);\r\n\t\t\tlog.debug(\"creating mercanet import report file at {}\", reportFile);\r\n\t\t\tFiles.write(reportFile, reportMessages, StandardCharsets.UTF_8);\r\n\t\t} catch (IOException e) {\r\n\t\t\tlog.error(\"Could not create or write to mercanet import report file at {}\", reportFile, e);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Create a payment from mercanet log item\r\n\t * \r\n\t * @param item   mercanet item\r\n\t * @param report processing report\r\n\t * @return OC payment entity\r\n\t */\r\n\tprivate Payment createPayment(MercanetItem item, ProcessingReport report,CustomerAccount  customerAccount) throws BusinessException {\r\n\t\tPayment payment = new Payment();\r\n\t\tsetAOProperties(payment, item,customerAccount);\r\n\t\tif (payment.getCustomerAccount() != null) {\r\n\t\t\ttry {\r\n\t\t\t\tpayment.setPaymentOrder(item.merchantId);\r\n\t\t\t\tpaymentService.create(payment);\r\n\t\t\t\treport.opOk++;\r\n\t\t\t\treturn payment;\r\n\t\t\t} catch (BusinessException e) {\r\n\t\t\t\tlog.error(\"Couldn't create Payement entity for mercanet operation at line n={}, error={}\", item.numLine, e);\r\n\t\t\t\taddReportMessage(\"Couldn't create payment for line n=\" + item.numLine + \". error=\" + e.getMessage(), item.fileName);\r\n\t\t\t\treport.opKo++;\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tlog.error(\"Couldn't create Payement entity for mercanet operation at line n={} : transactionReference={} not found\", item.numLine, item.transactionReference);\r\n\t\t\taddReportMessage(\"Couldn't create payment for line n=\" + item.numLine + \". transactionReference=\" + item.transactionReference + \" not found\", item.fileName);\r\n\t\t\treport.opKo++;\r\n\t\t\treturn null;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * move mercanet file containing errors to error directory\r\n\t * \r\n\t * @param errorDirPath error dir pth\r\n\t * @param mercanetFile mercanet file\r\n\t */\r\n\tprivate void moveToErrorDirectory(Path errorDirPath, Path mercanetFile) {\r\n\t\tlog.debug(\"moving mercanet file {} to error dir.\", mercanetFile);\r\n\t\ttry {\r\n\t\t\tFiles.move(mercanetFile, Paths.get(errorDirPath + File.separator + mercanetFile.getFileName() + \".\" + DateUtils.formatDateWithPattern(new Date(), DATETIME_FORMAT)));\r\n\t\t} catch (IOException e) {\r\n\t\t\tlog.error(\"Couldn't move mercanet file {} to errors dir {}\", mercanetFile.toString(), errorDirPath, e);\r\n\t\t\taddReportMessage(\"Couldn't move mercanet file to errors dir: \" + e.getMessage(), null);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * move mercanet file containing errors to error directory\r\n\t * \r\n\t * @param mercanetFile mercanet file\r\n\t */\r\n\tprivate void moveToWarnDirectory(Path warnDirPath, Path mercanetFile) {\r\n\t\tlog.debug(\"moving mercanet file {} to warn dir.\", mercanetFile);\r\n\t\ttry {\r\n\t\t\tFiles.move(mercanetFile, Paths.get(warnDirPath + File.separator + mercanetFile.getFileName() + \".\" + DateUtils.formatDateWithPattern(new Date(), DATETIME_FORMAT)));\r\n\t\t} catch (IOException e) {\r\n\t\t\tlog.error(\"Couldn't move mercanet file {} to warns dir {}\", mercanetFile.toString(), warnDirPath, e);\r\n\t\t\taddReportMessage(\"Couldn't move mercanet file to warns dir: \" + e.getMessage(), null);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * archivate imported mercanet file\r\n\t * \r\n\t * @param archiveDirPath archive directory path\r\n\t * @param mercanetFile   mercanet file to archive\r\n\t */\r\n\tprivate void archivateMercanetFile(Path archiveDirPath, Path mercanetFile) {\r\n\t\tString strArchiFilePath = archiveDirPath + File.separator + mercanetFile.getFileName() + \".\" + DateUtils.formatDateWithPattern(new Date(), DATETIME_FORMAT);\r\n\t\tPath archFile = Paths.get(strArchiFilePath);\r\n\t\ttry {\r\n\t\t\tFiles.move(mercanetFile, archFile);\r\n\t\t} catch (IOException e) {\r\n\t\t\tlog.error(\"Couldn't arcivate mercanet file {} to {}\", mercanetFile.toString(), archFile.toString(), e);\r\n\t\t\taddReportMessage(\"Couldn't move mercanet file to errors dir: \" + e.getMessage(), null);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t *\r\n\t * @param reportMessage report message\r\n\t * @param fileName      current processing mercanet file name\r\n\t */\r\n\tprivate void addReportMessage(String reportMessage, String fileName) {\r\n\t\tif (fileName != null) {\r\n\t\t\treportMessages.add(fileName + \" >> \" + reportMessage);\r\n\t\t} else {\r\n\t\t\treportMessages.add(reportMessage);\r\n\t\t}\r\n\t}\r\n\t\r\n\tprivate List<RecordedInvoice> getListOpenedInvoioces(CustomerAccount ca) {\r\n        try {\r\n            String query = \"select inv from RecordedInvoice inv where inv.code='INV_STD' and inv.matchingStatus in ('O','P') and inv.customerAccount.id =:caIdIN  and inv.unMatchingAmount > 0 order by inv.invoiceDate \";\r\n            Map<String, Object> queryParams = new HashMap<>();\r\n            queryParams.put(\"caIdIN\", ca.getId());\r\n            List<RecordedInvoice> listOpenedInvoioces = (List<RecordedInvoice>) recordedInvoiceService.executeSelectQuery(query, queryParams);\r\n            return listOpenedInvoioces;\r\n        } catch (Exception e) {\r\n            log.error(\"rror on getListOpenedInvoioces: [{}] \", e.getMessage(), e);\r\n            throw new BusinessException(\"Error on getListOpenedInvoioces\");\r\n        }\r\n    }\r\n\r\n\t/**\r\n\t * create directory if not exists\r\n\t * \r\n\t * @param dirPath directory path\r\n\t * @return true if created else false\r\n\t */\r\n\tprivate boolean createDirIfNotExist(Path dirPath) {\r\n\t\tif (!dirPath.toFile().exists()) {\r\n\t\t\ttry {\r\n\t\t\t\tFiles.createDirectories(dirPath);\r\n\t\t\t\tlog.debug(\"dir {} didn't exist and is created successfully.\", dirPath);\r\n\t\t\t} catch (IOException e) {\r\n\t\t\t\tlog.error(\"Error creating directory {}\", dirPath, e);\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\t/**\r\n\t *\r\n\t * @param inputDir mercanet input dierctory\r\n\t * @param ext      mercanet file extention\r\n\t * @return list of mercanet files found into input directory\r\n\t * @throws BusinessException business exception\r\n\t */\r\n\tprivate List<Path> getMercanetLogFiles(Path inputDir, String ext) throws BusinessException {\r\n\t\tif (!inputDir.toFile().exists() || !inputDir.toFile().isDirectory()) {\r\n\t\t\tlog.error(\"Mercanet input path {} is not a valid directory!\", inputDir);\r\n\t\t\tthrow new BusinessException(\"Param inputDir is not a valid directory\");\r\n\t\t}\r\n\t\ttry (Stream<Path> filesStream = Files.list(inputDir)) {\r\n\t\t\tif (filesStream != null) {\r\n\t\t\t\treturn filesStream.map(Path::toAbsolutePath).collect(Collectors.toList());\r\n\t\t\t} else {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t} catch (IOException e) {\r\n\t\t\tlog.error(\"Error on getting list Mercanet log files!\", e);\r\n\t\t\tthrow new BusinessException(e);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * set AO properties from mercanet item and OCC template\r\n\t * \r\n\t * @param payment account operation\r\n\t * @param item    mercanet log item\r\n\t */\r\n\tprivate void setAOProperties(Payment payment, MercanetItem item,CustomerAccount customerAccount) throws BusinessException {\r\n\r\n\t\tpayment.setCustomerAccount(customerAccount);\r\n\r\n\t\tpayment.setPaymentMethod(PaymentMethodEnum.CARD);\r\n\r\n\t\tpayment.setAmount(item.amount);\r\n\t\tpayment.setMatchingAmount(BigDecimal.ZERO);\r\n\t\tpayment.setUnMatchingAmount(item.amount);\r\n\t\tpayment.setAccountingCode(occCardTemplate.getAccountingCode());\r\n\t\tpayment.setCode(occCardTemplate.getCode());\r\n\t\tpayment.setDescription(occCardTemplate.getDescription());\r\n\t\tpayment.setTransactionCategory(occCardTemplate.getOccCategory());\r\n\t\tpayment.setAccountCodeClientSide(occCardTemplate.getAccountCodeClientSide());\r\n\t\tpayment.setReference(item.transactionReference);\r\n\t\t// tansaction date + 1 jour\r\n\t\tif (item.transactionDateTime != null) {\r\n\t\t\tLocalDate trDatePlus1Day = item.transactionDateTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate().plusDays(1);\r\n\t\t\tpayment.setTransactionDate(Date.from(trDatePlus1Day.atStartOfDay(ZoneId.systemDefault()).toInstant()));\r\n\t\t}\r\n\t\tpayment.setDueDate(new Date());\r\n\t\tpayment.setMatchingStatus(MatchingStatusEnum.O);\r\n\t\tpayment.setSeller(sellerService.findByCode(SELLER_CODE));\r\n\t}\r\n\r\n\t/**\r\n\t * get OCC template by code\r\n\t * \r\n\t * @param occTemplateCode occ template code\r\n\t * @return OCC Template\r\n\t * @throws BusinessException Business Exception\r\n\t */\r\n\tprivate OCCTemplate getOCCTemplate(String occTemplateCode) throws BusinessException {\r\n\t\tOCCTemplate occTemplate = oCCTemplateService.findByCode(occTemplateCode);\r\n\t\tif (occTemplate == null) {\r\n\t\t\tthrow new BusinessException(\"Cannot find OCC Template with code=\" + occTemplateCode);\r\n\t\t}\r\n\t\treturn occTemplate;\r\n\t}\r\n\r\n\t/**\r\n\t * get recorded invoice by order number\r\n\t * \r\n\t * @param orderNumber order number\r\n\t * @return recorded invoice\r\n\t */\r\n\tprivate RecordedInvoice getRecordedInvoice(String invoiceNumber) throws BusinessException {\r\n\r\n\t\tMap<String, Object> params = Maps.newHashMap();\r\n\t\tString query = \"From RecordedInvoice ri where ri.reference=:invoiceNumberIN and (ri.matchingStatus ='O' or ri.matchingStatus ='P')\";\r\n\t\tparams.put(\"invoiceNumberIN\", invoiceNumber);\r\n\t\tList<RecordedInvoice> recordedInvoices = (List<RecordedInvoice>) recordedInvoiceService.executeSelectQuery(query, params);\r\n\t\tif (recordedInvoices.isEmpty()) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t\treturn recordedInvoices.iterator().next();\r\n\t}\r\n\r\n\t/**\r\n\t * Match the open\r\n\t * \r\n\t * @param payment  operationToMatch\r\n\t * @param fileName mercanet file name currently processed\r\n\t * @param numLine  line index\r\n\t * @param report   processing report\r\n\t */\r\n\tprivate void matchOperation(String orderNumber, Payment payment, RecordedInvoice recordedInvoice, String fileName, Integer numLine, ProcessingReport report) {\r\n\r\n\t\tList<Long> operationIds = new ArrayList<Long>();\r\n\t\toperationIds.add(payment.getId());\r\n\t\toperationIds.add(recordedInvoice.getId());\r\n\r\n\t\tMatchingReturnObject matchingReturn = null;\r\n\t\ttry {\r\n\t\t\tmatchingReturn = matchingCodeService.matchOperations(payment.getCustomerAccount().getId(), null, operationIds, null, MatchingTypeEnum.A);\r\n\t\t} catch (BusinessException | NoAllOperationUnmatchedException | UnbalanceAmountException e) {\r\n\t\t\tlog.warn(\"Problem on matching operation id={}, line n={}!\", payment.getId(), numLine, e);\r\n\t\t\taddReportMessage(\"[WARN] Problem on matching operation on line=\" + numLine + \", opid=\" + payment.getId() + \", message=\" + e.getMessage(), fileName);\r\n\t\t\treport.matchKo++;\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (matchingReturn.isOk()) {\r\n\t\t\tlog.debug(\"Matching is OK for the operation id={}, line n={}!\", payment.getId(), numLine);\r\n\t\t\treport.matchOk++;\r\n\t\t} else {\r\n\t\t\tlog.warn(\"Matching is NOK for the operation id={}, line n°{}!\", payment.getId(), numLine);\r\n\t\t\taddReportMessage(\"[WARN] Matching NOK for operation on line=\" + numLine + \", opid=\" + payment.getId(), fileName);\r\n\t\t\treport.matchKo++;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * map mercanet file line with MercanetItem item\r\n\t * \r\n\t * @param line  mercanet operation line\r\n\t * @param index line index\r\n\t * @return MercanetItem item\r\n\t */\r\n\tprivate MercanetItem mapToItem(String line, int index) throws BusinessException {\r\n\t\ttry {\r\n\t\t\tString[] lineFields = line.split(this.delimiter);\r\n\t\t\tlog.info(\"lineFields:\" + Arrays.toString(lineFields));\r\n\t\t\tint lineLength = lineFields.length;\r\n\t\t\tMercanetItem item = new MercanetItem();\r\n\t\t\titem.numLine = index;\r\n\t\t\titem.merchantId = lineLength > 1 ? lineFields[1] : null;\r\n\t\t\titem.transactionReference = lineLength > 2 ? lineFields[2] : null;\r\n\t\t\titem.transactionDateTime = lineLength > 7 ? toDate(lineFields[7]) : null;\r\n\t\t\titem.operationType = lineLength > 4 ? lineFields[4] : null;\r\n\t\t\titem.amount = lineLength > 5 ? toBigDecimal(lineFields[5]) : null;\r\n\t\t\tif (StringUtils.isBlank(item.transactionReference) || item.transactionReference.length() < 12) {\r\n\t\t\t\tthrow new BusinessException(\"transactionReference length should be 12 char at less\");\r\n\t\t\t}\r\n\t\t\titem.invoiceNumber = item.transactionReference.substring(0, 12);\r\n\t\t\titem.customerCode = lineLength > 17 ? lineFields[17] : null;\r\n\t\t\treturn item;\r\n\t\t} catch (Exception e) {\r\n\t\t\tthrow new BusinessException(e.getMessage());\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * String to bigdecimal\r\n\t * \r\n\t * @param input string\r\n\t * @return bigdecimal\r\n\t */\r\n\tprivate BigDecimal toBigDecimal(String input) throws BusinessException {\r\n\t\ttry{\r\n\t\t\treturn new BigDecimal(input).divide(new BigDecimal(100));\r\n\t\t\t\r\n\t\t}catch (Exception e) {\r\n\t\t\tthrow new BusinessException(\"Amount is null or invalid:\"+input);\r\n\t\t}\t\r\n\t}\r\n\r\n\t/**\r\n\t * String to date\r\n\t * \r\n\t * @param input string\r\n\t * @return date\r\n\t */\r\n\tprivate Date toDate(String input) {\r\n\t\treturn DateUtils.guessDate(input, \"yyyyMMdd hhmmss\", \"yyyy-MM-dd hh:mm:ss\");\r\n\t}\r\n\r\n\t/**\r\n\t * Classe to map mercanet line\r\n\t */\r\n\tprivate class MercanetItem {\r\n\t\tString fileName;\r\n\t\tint numLine;\r\n\t\tString merchantId;\r\n\t\tString transactionReference;\r\n\t\tDate transactionDateTime;\r\n\t\tString operationType;\r\n\t\tBigDecimal amount;\r\n\t\tString invoiceNumber;\r\n\t\tString customerCode;\r\n\r\n\t\tString getIdentifier() {\r\n\t\t\treturn fileName + \"_\" + transactionReference;\r\n\t\t}\r\n\r\n\t\t@Override\r\n\t\tpublic String toString() {\r\n\t\t\treturn \"MercanetItem [fileName=\" + fileName + \", numLine=\" + numLine + \", merchantId=\" + merchantId + \", transactionReference=\" + transactionReference\r\n\t\t\t\t\t+ \", transactionDateTime=\" + transactionDateTime + \", operationType=\" + operationType + \", amount=\" + amount + \", invoiceNumber=\" + invoiceNumber + \", customerCode=\"+customerCode+\"]\";\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tprivate class ProcessingReport {\r\n\t\tint opAll = 0;\r\n\t\tint opOk = 0;\r\n\t\tint opKo = 0;\r\n\t\tint matchOk = 0;\r\n\t\tint matchKo = 0;\r\n\t}\r\n\r\n\t/**\r\n\t * Find payment by reference and payment order.\r\n\t *\r\n\t * @param reference    the reference\r\n\t * @param paymentOrder the payment order\r\n\t * @return the payment\r\n\t */\r\n\tpublic Payment findPaymentByReferenceAndPaymentOrder(String reference) {\r\n\t\ttry {\r\n\r\n\t\t\tQueryBuilder qb = new QueryBuilder(Payment.class, \"p\");\r\n\t\t\tqb.addCriterion(\"reference\", \"=\", reference, false);\r\n\r\n\t\t\treturn (Payment) qb.getQuery(paymentService.getEntityManager()).getSingleResult();\r\n\t\t} catch (NoResultException ne) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\t}\r\n}\r\n\r\n]]>\r\n            </script>\r\n</ScriptInstance>"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								}
							},
							"response": []
						},
						{
							"name": "Create SepaDDRequestBuilderScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Successful request\", () => {",
											"  pm.expect(pm.response.code).to.be.oneOf([201,200,202]);",
											"});",
											"",
											""
										],
										"type": "text/javascript",
										"packages": {}
									}
								}
							],
							"request": {
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Proxy-Authorization",
										"value": "{{proxy.auth}}"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.payment.SepaDDRequestBuilderScript\" description=\"Ekko Sepa Pain08 et camt54 Script\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.payment;\r\n\r\nimport java.io.File;\r\nimport java.math.BigDecimal;\r\nimport java.math.RoundingMode;\r\nimport java.util.ArrayList;\r\nimport java.util.Arrays;\r\nimport java.util.Date;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.regex.Pattern;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.admin.sepa.DDRejectFileInfos;\r\nimport org.meveo.admin.sepa.jaxb.camt054.AccountNotification2;\r\nimport org.meveo.admin.sepa.jaxb.camt054.BankToCustomerDebitCreditNotificationV02;\r\nimport org.meveo.admin.sepa.jaxb.pain001.AmountType3Choice;\r\nimport org.meveo.admin.sepa.jaxb.pain001.CreditTransferTransactionInformation10;\r\nimport org.meveo.admin.sepa.jaxb.pain001.CustomerCreditTransferInitiationV03;\r\nimport org.meveo.admin.sepa.jaxb.pain001.GroupHeader32;\r\nimport org.meveo.admin.sepa.jaxb.pain001.PaymentInstructionInformation3;\r\nimport org.meveo.admin.sepa.jaxb.pain001.PaymentMethod3Code;\r\nimport org.meveo.admin.sepa.jaxb.pain001.PaymentTypeInformation19;\r\nimport org.meveo.admin.sepa.jaxb.pain001.RemittanceInformation5;\r\nimport org.meveo.admin.sepa.jaxb.pain008.AccountIdentification4Choice;\r\nimport org.meveo.admin.sepa.jaxb.pain008.ActiveOrHistoricCurrencyAndAmount;\r\nimport org.meveo.admin.sepa.jaxb.pain008.BranchAndFinancialInstitutionIdentification4;\r\nimport org.meveo.admin.sepa.jaxb.pain008.CashAccount16;\r\nimport org.meveo.admin.sepa.jaxb.pain008.CustomerDirectDebitInitiationV02;\r\nimport org.meveo.admin.sepa.jaxb.pain008.DirectDebitTransaction6;\r\nimport org.meveo.admin.sepa.jaxb.pain008.DirectDebitTransactionInformation9;\r\nimport org.meveo.admin.sepa.jaxb.pain008.Document;\r\nimport org.meveo.admin.sepa.jaxb.pain008.FinancialInstitutionIdentification7;\r\nimport org.meveo.admin.sepa.jaxb.pain008.GenericFinancialIdentification1;\r\nimport org.meveo.admin.sepa.jaxb.pain008.GenericPersonIdentification1;\r\nimport org.meveo.admin.sepa.jaxb.pain008.GroupHeader39;\r\nimport org.meveo.admin.sepa.jaxb.pain008.LocalInstrument2Choice;\r\nimport org.meveo.admin.sepa.jaxb.pain008.MandateRelatedInformation6;\r\nimport org.meveo.admin.sepa.jaxb.pain008.Party6Choice;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PartyIdentification32;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PaymentIdentification1;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PaymentInstructionInformation4;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PaymentMethod2Code;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PaymentTypeInformation20;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PersonIdentification5;\r\nimport org.meveo.admin.sepa.jaxb.pain008.PersonIdentificationSchemeName1Choice;\r\nimport org.meveo.admin.sepa.jaxb.pain008.SequenceType1Code;\r\nimport org.meveo.admin.sepa.jaxb.pain008.ServiceLevel8Choice;\r\nimport org.meveo.admin.util.ArConfig;\r\nimport org.meveo.commons.utils.EjbUtils;\r\nimport org.meveo.commons.utils.JAXBUtils;\r\nimport org.meveo.commons.utils.ParamBean;\r\nimport org.meveo.commons.utils.StringUtils;\r\nimport org.meveo.model.admin.Seller;\r\nimport org.meveo.model.billing.BankCoordinates;\r\nimport org.meveo.model.billing.Subscription;\r\nimport org.meveo.model.crm.Provider;\r\nimport org.meveo.model.payments.AccountOperation;\r\nimport org.meveo.model.payments.CustomerAccount;\r\nimport org.meveo.model.payments.DDPaymentMethod;\r\nimport org.meveo.model.payments.DDRequestItem;\r\nimport org.meveo.model.payments.DDRequestLOT;\r\nimport org.meveo.model.payments.OperationCategoryEnum;\r\nimport org.meveo.model.payments.PaymentGateway;\r\nimport org.meveo.model.payments.PaymentMethod;\r\nimport org.meveo.model.payments.PaymentMethodEnum;\r\nimport org.meveo.model.payments.RecordedInvoice;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.model.shared.Name;\r\nimport org.meveo.model.shared.Title;\r\nimport org.meveo.service.admin.impl.SellerService;\r\nimport org.meveo.service.billing.impl.SubscriptionService;\r\nimport org.meveo.service.catalog.impl.CalendarBankingService;\r\nimport org.meveo.service.catalog.impl.TitleService;\r\nimport org.meveo.service.payments.impl.AccountOperationService;\r\nimport org.meveo.service.payments.impl.CustomerAccountService;\r\nimport org.meveo.service.payments.impl.DDRequestItemService;\r\nimport org.meveo.service.payments.impl.DDRequestLOTService;\r\nimport org.meveo.service.payments.impl.PaymentGatewayService;\r\nimport org.meveo.service.payments.impl.PaymentMethodService;\r\nimport org.meveo.service.payments.impl.RecordedInvoiceService;\r\nimport org.meveo.service.script.payment.DDRequestBuilderScript;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n/**\r\n * The Class SepaDDRequestBuilderScript.\r\n *\r\n * @author anasseh\r\n * \r\n * 02/03/2022 supprimer le dossier 'EKKO'\r\n * 02/03/2022 fileName : from SDD.PRL.MYP1_EKKO_20210401XXXXXXXXX.xml to SDD.PRL.MPE.20210401XXXXXXXXX.xml\r\n * 03/10/22 add sepa refund\r\n * 31/05/2023 SUPS-2597\r\n * 16/06/2023 SUPS-2597(bis)\r\n * 21/06/2023 SUPS-2692\r\n * 15/042024  ENG382-146\r\n * 30/042024  ENG382-146 \r\n */\r\n\r\npublic class SepaDDRequestBuilderScript extends DDRequestBuilderScript {\r\n\t/** The log. */\r\n\tprivate static Logger log = LoggerFactory.getLogger(SepaDDRequestBuilderScript.class);\r\n\r\n\t/** The location of SDD schema. */\r\n\tprivate static final String SDD_SCHEMA_LOCATION = \"https://github.com/w2c/sepa-sdd-xml-generator/blob/master/validation_schemes/pain.008.001.02.xsd\";\r\n\r\n\t   /** The location of SCT schema. */\r\n    private static final String SCT_SCHEMA_LOCATION = \"https://github.com/digitick/php-sepa-xml/blob/master/tests/pain.001.001.03.xsd\";\r\n    \r\n\t/** The Constant SIMPLE_DATE_PATTERN. */\r\n\tprivate static final String SIMPLE_DATE_PATTERN = \"yyyyMMdd\";\r\n\r\n\t/** The Constant EMPTY_STRING. */\r\n\tprivate static final String EMPTY_STRING = \"\";\r\n\r\n\t/** The Constant DASH_STRING. */\r\n\tprivate static final String DASH_STRING = \"-\";\r\n\r\n\t/** The Constant DOUBLE_POINT. */\r\n\tprivate static final String DOUBLE_POINT = \"\\\\..\";\r\n\r\n\t/** The underscore separator used at sepa file name. */\r\n\tprivate static final String UNDERSCORE_SEPARATOR = \"_\";\r\n\r\n\t/** The Constant EURO_CCY. */\r\n\tprivate static final String EURO_CCY = \"EUR\";\r\n\r\n\t/** The Constant SEPA_SERVICE_LEVEL_CD. */\r\n\tprivate static final String SEPA_SERVICE_LEVEL_CD = \"SEPA\";\r\n\r\n\t/** The Constant SEPA_LOCAL_INSTRUMENT_CODE. */\r\n\tprivate static final String SEPA_LOCAL_INSTRUMENT_CODE = \"CORE\";\r\n\t\r\n\t   /** The Constant COMMA_STRING. */\r\n    private static final String COMMA_STRING = \",\";\r\n    \r\n    /** The PATTERN that the IBAN should match. */\r\n    private static final String IBAN_PATTERN = \"[A-Z]{2,2}[0-9]{2,2}[a-zA-Z0-9]{1,30}\";\r\n    \r\n    /** The Constant NOTPROVIDED_BIC. */\r\n    private static final String NOTPROVIDED_BIC = \"NOTPROVIDED\";\r\n\r\n    /** The Constant CATEGORY_PURPOSE_CODE. */\r\n    private static final String CATEGORY_PURPOSE_CODE = \"SUPP\";\r\n    /** The Constant FR_COUNTRY. */\r\n    private static final String FR_COUNTRY = \"FR\";\r\n    private Pattern pattern = Pattern.compile(IBAN_PATTERN);\r\n\r\n\t/** The dd request item service. */\r\n\tprivate DDRequestItemService ddRequestItemService = (DDRequestItemService) EjbUtils.getServiceInterface(\"DDRequestItemService\");\r\n\r\n\t/** The dd request LOT service. */\r\n\tprivate DDRequestLOTService ddRequestLOTService = (DDRequestLOTService) EjbUtils.getServiceInterface(\"DDRequestLOTService\");\r\n\r\n\t/** The customer account service. */\r\n\tprivate CustomerAccountService customerAccountService = (CustomerAccountService) EjbUtils.getServiceInterface(\"CustomerAccountService\");\r\n\tprivate SubscriptionService subscriptionService = (SubscriptionService) EjbUtils.getServiceInterface(\"SubscriptionService\");\r\n\r\n\t/** The recorded invoice service. */\r\n\tprivate RecordedInvoiceService recordedInvoiceService = (RecordedInvoiceService) EjbUtils.getServiceInterface(\"RecordedInvoiceService\");\r\n\tprivate SellerService sellerService = (SellerService) EjbUtils.getServiceInterface(\"SellerService\");\r\n\tprivate TitleService titleService = (TitleService) EjbUtils.getServiceInterface(\"TitleService\");\r\n\tprivate CalendarBankingService calendarBankingService = (CalendarBankingService) getServiceInterface(\"CalendarBankingService\");\r\n\tprivate PaymentMethodService paymentMethodService = (PaymentMethodService) getServiceInterface(\"PaymentMethodService\");\r\n\tprivate AccountOperationService accountOperationService = (AccountOperationService) EjbUtils.getServiceInterface(\"AccountOperationService\");\r\n\t\r\n\t\r\n\t@Override\r\n\tpublic String getDDFileName(Map<String, Object> methodContext) throws BusinessException {\r\n\t\tDDRequestLOT ddRequestLOT = (DDRequestLOT) methodContext.get(DDRequestBuilderScript.DD_REQUEST_LOT);\r\n\t\tProvider appProvider = (Provider) methodContext.get(DDRequestBuilderScript.PROVIDER);\r\n\t\tif (ddRequestLOT.getPaymentOrRefundEnum().getOperationCategoryToProcess() == OperationCategoryEnum.DEBIT) {\r\n\t\t\treturn getFileName(ddRequestLOT, appProvider, \r\n\t\t\t    ParamBean.getInstance().getProperty(\"bayad.ddrequest.fileName.prefix\", \"SDD.PRL.MPE.\"), \r\n\t\t\t    ParamBean.getInstance().getProperty(\"bayad.ddrequest.fileName.extension\", \"xml\"),  \r\n\t\t\t    ParamBean.getInstance().getProperty(\"bayad.ddrequest.outputDir\", \"prelevement\"));\r\n\t\t} else {\r\n\t\t    return getFileName(ddRequestLOT, appProvider, \r\n\t\t        ParamBean.getInstance().getProperty(\"bayad.sctrequest.fileName.prefix\", \"SCT.VIR.MPE.\"), \r\n                ParamBean.getInstance().getProperty(\"bayad.sctrequest.fileName.extension\", \"xml\"),  \r\n                ParamBean.getInstance().getProperty(\"bayad.sctrequest.outputDir\", \"virement\"));\r\n\t\t}\r\n\t}\r\n\r\n\t@Override\r\n\tpublic void generateDDRequestLotFile(Map<String, Object> methodContext) throws BusinessException {\r\n\r\n\t\tlog.info(\" >>> Starting generateDDRequestLotFile ... \");\r\n\t\tProvider appProvider = (Provider) methodContext.get(DDRequestBuilderScript.PROVIDER);\r\n\t\tDDRequestLOT ddRequestLOT = (DDRequestLOT) methodContext.get(DDRequestBuilderScript.DD_REQUEST_LOT);\r\n\t\tDDRequestLOTService ddRequestLotService = (DDRequestLOTService) getServiceInterface(\"DDRequestLOTService\");\r\n\t\tddRequestLOT = ddRequestLotService.findById(ddRequestLOT.getId(), Arrays.asList(\"ddrequestItems\", \"ddRequestBuilder\"));\r\n\t\tif (ddRequestLOT.getPaymentOrRefundEnum().getOperationCategoryToProcess() == OperationCategoryEnum.DEBIT) {\r\n\t\t\tgenerateDDRequestLotFileForSSD(ddRequestLOT, appProvider);\r\n\t\t} else {\r\n\t\t\t generateDDRequestLotFileForSCT(ddRequestLOT, appProvider);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the file name.\r\n\t *\r\n\t * @param ddRequestLot        the dd request lot\r\n\t * @param appProvider         the app provider\r\n\t * @param fileNamePrefix      the file name prefix\r\n\t * @param fileNameExtension   the file name extension\r\n\t * @param additionalOutputDir the additional output dir\r\n\t * @return the file name\r\n\t * @throws BusinessException the business exception\r\n\t */\r\n\tprivate String getFileName(DDRequestLOT ddRequestLot, Provider appProvider, String fileNamePrefix, String fileNameExtension, String additionalOutputDir)\r\n\t\t\tthrows BusinessException {\r\n\t\ttry {\r\n\t\t\t//SDD.PRL.MYP1_EKKO_20210401XXXXXXXXX.xml ==> debut projet\r\n\t\t\t//SDD.PRL.MPE.20210401XXXXXXXXX.xml ==> 02/03/2022 live test MEP\r\n\t\t\tParamBean paramBean = ParamBean.getInstanceByProvider(appProvider.getCode());\r\n\t\t\tString fileName = fileNamePrefix+DateUtils.formatDateWithPattern(new Date(), \"yyyyMMddhhmmssSSS\")+\".\"+fileNameExtension;\r\n\t\t\t\r\n\t\t\tString outputDir = paramBean.getChrootDir(appProvider.getCode());\r\n\r\n\t\t\toutputDir = outputDir + File.separator + additionalOutputDir;\r\n\t\t\toutputDir = outputDir.replaceAll(DOUBLE_POINT, EMPTY_STRING);\r\n\r\n\t\t\tlog.info(\"DDRequest output directory=\" + outputDir);\r\n\t\t\tFile dir = new File(outputDir);\r\n\t\t\tif (!dir.exists()) {\r\n\t\t\t\tdir.mkdirs();\r\n\t\t\t}\r\n\t\t\treturn outputDir + File.separator + fileName;\r\n\t\t} catch (Exception e) {\r\n\t\t\tlog.error(e.getMessage(), e);\r\n\t\t\tthrow new BusinessException(e.getMessage());\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Generate DD request lot file for SSD.\r\n\t *\r\n\t * @param ddRequestLot the dd request lot\r\n\t * @param appProvider  the app provider\r\n\t * @throws BusinessException the business exception\r\n\t */\r\n\tprivate void generateDDRequestLotFileForSSD(DDRequestLOT ddRequestLot, Provider appProvider) throws BusinessException {\r\n\t\ttry {\r\n\t\t\tParamBean paramBean = ParamBean.getInstanceByProvider(appProvider.getCode());\r\n\t\t\tDocument document = new Document();\r\n\t\t\tCustomerDirectDebitInitiationV02 message = new CustomerDirectDebitInitiationV02();\r\n\t\t\tdocument.setCstmrDrctDbtInitn(message);\r\n\t\t\taddHeader(message, ddRequestLot, appProvider);\r\n\r\n\t\t\tboolean isEmptyLot = addPaymentInformation(message, ddRequestLot, appProvider);\r\n\r\n\t\t\tif (isEmptyLot) {\r\n\t\t\t\tlog.warn(\"There no valid dd item, file will not created\");\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tString schemaLocation = paramBean.getProperty(\"sepa.schemaLocation.pain008\", SDD_SCHEMA_LOCATION);\r\n\t\t\tJAXBUtils.marshaller(document, new File(ddRequestLot.getFileName()), schemaLocation);\r\n\t\t} catch (Exception e) {\r\n\t\t\tlog.error(\"Error on generateDDRequestLotFileForSSD\", e);\r\n\t\t\tthrow new BusinessException(e.getMessage());\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Adds the header of SDD file.\r\n\t *\r\n\t * @param message      the SDD message\r\n\t * @param ddRequestLOT the dd request LOT\r\n\t * @param appProvider  the provider\r\n\t * @throws Exception the exception\r\n\t */\r\n\tprivate void addHeader(CustomerDirectDebitInitiationV02 message, DDRequestLOT ddRequestLOT, Provider appProvider) throws Exception {\r\n\r\n\t\tGroupHeader39 groupHeader = new GroupHeader39();\r\n\t\tmessage.setGrpHdr(groupHeader);\r\n\t\tgroupHeader.setMsgId(ArConfig.getDDRequestHeaderReference() + DASH_STRING + ddRequestLOT.getId());\r\n\t\tgroupHeader.setCreDtTm(DateUtils.dateToXMLGregorianCalendar(new Date()));\r\n\t\tgroupHeader.setNbOfTxs(String.valueOf(ddRequestLOT.getNbItemsOk()));\r\n\t\tBigDecimal total = BigDecimal.ZERO;\r\n\t\tfor (DDRequestItem item : ddRequestLOT.getDdrequestItems()) {\r\n\t\t\tif (!item.hasError()) {\r\n\t\t\t\ttotal = total.add(item.getAmount().setScale(2, RoundingMode.HALF_UP));\r\n\t\t\t}\r\n\t\t}\r\n\t\tddRequestLOT.setTotalAmount(total);\r\n\t\tddRequestLOTService.updateNoCheck(ddRequestLOT);\r\n\t\tgroupHeader.setCtrlSum(total.setScale(2, RoundingMode.HALF_UP));\r\n\t\tPartyIdentification32 initgPty = new PartyIdentification32();\r\n\t\tif (ddRequestLOT.getSeller() != null) {\t\t\t\r\n\t\t\tinitgPty.setNm(format(sellerService.refreshOrRetrieve(ddRequestLOT.getSeller()).getDescription()));\r\n\t\t} else {\r\n\t\t\tinitgPty.setNm(format(appProvider.getDescription()));\r\n\t\t}\r\n\r\n\t\tgroupHeader.setInitgPty(initgPty);\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Adds the payment information of SDD file.\r\n\t *\r\n\t * @param Message       the SDD message\r\n\t * @param dDRequestItem the dd request item\r\n\t * @param appProvider   the provider\r\n\t * @throws Exception the exception\r\n\t */\r\n\tprivate boolean addPaymentInformation(CustomerDirectDebitInitiationV02 Message, DDRequestLOT ddRequestLot, Provider appProvider) throws Exception {\r\n\t\tboolean isEmptyLot = true;\r\n\t\tlog.info(\"addPaymentInformation dDRequestLot id=\" + ddRequestLot.getId());\r\n\t\tParamBean paramBean = ParamBean.getInstanceByProvider(appProvider.getCode());\r\n\t\tPaymentInstructionInformation4 paymentInformation = new PaymentInstructionInformation4();\r\n\t\tMessage.getPmtInf().add(paymentInformation);\r\n\t\tpaymentInformation.setPmtInfId(ArConfig.getDDRequestHeaderReference() + DASH_STRING + ddRequestLot.getId());\r\n\t\tpaymentInformation.setPmtMtd(PaymentMethod2Code.DD);\r\n\t\tpaymentInformation.setNbOfTxs(\"\" + ddRequestLot.getNbItemsOk());\r\n\t\tpaymentInformation.setCtrlSum(ddRequestLot.getTotalAmount().setScale(2, RoundingMode.HALF_UP));\r\n\t\tPaymentTypeInformation20 paymentTypeInformation = new PaymentTypeInformation20();\r\n\t\tpaymentInformation.setPmtTpInf(paymentTypeInformation);\r\n\t\tServiceLevel8Choice serviceLevel = new ServiceLevel8Choice();\r\n\t\tpaymentTypeInformation.setSvcLvl(serviceLevel);\r\n\t\tserviceLevel.setCd(SEPA_SERVICE_LEVEL_CD);\r\n\t\tLocalInstrument2Choice localInstrument = new LocalInstrument2Choice();\r\n\t\tpaymentTypeInformation.setLclInstrm(localInstrument);\r\n\t\tlocalInstrument.setCd(paramBean.getProperty(\"sepa.LclInstrm\", SEPA_LOCAL_INSTRUMENT_CODE));\r\n\t\tpaymentTypeInformation.setSeqTp(SequenceType1Code.RCUR);\r\n\t\t\r\n\t\t\r\n\t\tSeller seller = sellerService.findByCode(\"EKKO\");\r\n\t\t\r\n\t\tLong nbDaysPay = (Long) seller.getCfValue(\"CF_SEL_PAY_NB_BUSI_DAYS\");\r\n\t\tLong nbDaysToAdd = nbDaysPay;\r\n\t\t\r\n\t\tDate customerRequestedDate = addBusinessDays(new Date(), nbDaysToAdd);\r\n\t\tlog.info(\"customerRequestedDate business day:\" + customerRequestedDate);\r\n\r\n\t\tpaymentInformation.setReqdColltnDt(DateUtils.dateToXMLGregorianCalendarFieldUndefined(customerRequestedDate));\r\n\r\n\t\tBankCoordinates bankCoordinates = getBankCoordinates(ddRequestLot, appProvider);\r\n\r\n\t\tif (bankCoordinates == null) {\r\n\t\t\tthrow new BusinessException(\"Missing bank information on provider or seller\");\r\n\t\t}\r\n\t\tPartyIdentification32 creditor = new PartyIdentification32();\r\n\t\tif (ddRequestLot.getSeller() != null) {\r\n\t\t\tcreditor.setNm(format(sellerService.refreshOrRetrieve(ddRequestLot.getSeller()).getDescription()));\r\n\t\t} else {\r\n\t\t\tcreditor.setNm(format(appProvider.getDescription()));\r\n\t\t}\r\n\r\n\t\tpaymentInformation.setCdtr(creditor);\r\n\r\n\t\tCashAccount16 creditorAccount = new CashAccount16();\r\n\t\tpaymentInformation.setCdtrAcct(creditorAccount);\r\n\t\tAccountIdentification4Choice identification = new AccountIdentification4Choice();\r\n\t\tcreditorAccount.setId(identification);\r\n\t\tidentification.setIBAN(format(bankCoordinates.getIban()));\r\n\r\n\t\tBranchAndFinancialInstitutionIdentification4 creditorAgent = new BranchAndFinancialInstitutionIdentification4();\r\n\t\tpaymentInformation.setCdtrAgt(creditorAgent);\r\n\t\tFinancialInstitutionIdentification7 financialInstitutionIdentification = new FinancialInstitutionIdentification7();\r\n\t\tcreditorAgent.setFinInstnId(financialInstitutionIdentification);\r\n\t\tfinancialInstitutionIdentification.setBIC(bankCoordinates.getBic());\r\n\t\tPartyIdentification32 creditorSchemeIdentification = new PartyIdentification32();\r\n\t\tpaymentInformation.setCdtrSchmeId(creditorSchemeIdentification);\r\n\t\tParty6Choice cdtrSchmeId = new Party6Choice();\r\n\t\tcreditorSchemeIdentification.setId(cdtrSchmeId);\r\n\t\tPersonIdentification5 privateidentifier = new PersonIdentification5();\r\n\t\tcdtrSchmeId.setPrvtId(privateidentifier);\r\n\t\tGenericPersonIdentification1 other = new GenericPersonIdentification1();\r\n\t\tprivateidentifier.getOthr().add(other);\r\n\t\tother.setId(bankCoordinates.getIcs());\r\n\t\tPersonIdentificationSchemeName1Choice schemeName = new PersonIdentificationSchemeName1Choice();\r\n\t\tother.setSchmeNm(schemeName);\r\n\t\tschemeName.setPrtry(SEPA_SERVICE_LEVEL_CD);\r\n\r\n\t\tfor (DDRequestItem ddrequestItem : ddRequestLot.getDdrequestItems()) {\r\n\t\t\tddrequestItem = ddRequestItemService.findById(ddrequestItem.getId(), Arrays.asList(\"accountOperations\"));\r\n\t\t\tif (!ddrequestItem.hasError()) {\r\n\t\t\t\taddTransaction(ddrequestItem, paymentInformation);\r\n\t\t\t\tisEmptyLot = false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn isEmptyLot;\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Adds the transaction of SDD file.\r\n\t *\r\n\t * @param dDRequestItem      the dd request item\r\n\t * @param paymentInformation the payment information of SDD file\r\n\t * @throws Exception the exception\r\n\t */\r\n\tprivate void addTransaction(DDRequestItem dDRequestItem, PaymentInstructionInformation4 paymentInformation) throws Exception {\r\n\t\tCustomerAccount ca = customerAccountService.findById(dDRequestItem.getAccountOperations().get(0).getCustomerAccount().getId(), Arrays.asList(\"paymentMethods\"));\r\n        AccountOperation ao = accountOperationService.findById(dDRequestItem.getAccountOperations().get(0).getId(), Arrays.asList(\"subscription\"));\r\n\t\tSubscription sub = subscriptionService.findById(ao.getSubscription().getId(), Arrays.asList(\"paymentMethod\"));\r\n        PaymentMethod preferedPaymentMethod = sub.getPaymentMethod();\r\n        if(preferedPaymentMethod == null) {\r\n        \tpreferedPaymentMethod = ca.getPreferredPaymentMethod();\r\n        }\r\n\t\tif (preferedPaymentMethod == null || !(preferedPaymentMethod instanceof DDPaymentMethod)) {\r\n\t\t\tthrow new BusinessException(\"Payment method not valid!\");\r\n\t\t}\r\n\t\tBankCoordinates bankCoordinates = ((DDPaymentMethod) preferedPaymentMethod).getBankCoordinates();\r\n\r\n\t\tif (bankCoordinates == null) {\r\n\t\t\tthrow new BusinessException(\"Bank Coordinate is absent for Payment method \" + ((DDPaymentMethod) preferedPaymentMethod).getAlias());\r\n\t\t}\r\n\r\n\t\tDirectDebitTransactionInformation9 directDebitTransactionInformation = new DirectDebitTransactionInformation9();\r\n\t\tpaymentInformation.getDrctDbtTxInf().add(directDebitTransactionInformation);\r\n\t\tPaymentIdentification1 PaymentIdentification = new PaymentIdentification1();\r\n\t\tdirectDebitTransactionInformation.setPmtId(PaymentIdentification);\r\n\t\tPaymentIdentification.setInstrId(getCorrelationId(ca, dDRequestItem.getAccountOperations().get(0), dDRequestItem.getId()));\r\n\t\tPaymentIdentification.setEndToEndId(getCorrelationId(ca, dDRequestItem.getAccountOperations().get(0), dDRequestItem.getId()));\r\n\t\tActiveOrHistoricCurrencyAndAmount instructedAmount = new ActiveOrHistoricCurrencyAndAmount();\r\n\t\tdirectDebitTransactionInformation.setInstdAmt(instructedAmount);\r\n\t\tinstructedAmount.setValue(dDRequestItem.getAmount().setScale(2, RoundingMode.HALF_UP));\r\n\t\tinstructedAmount.setCcy(EURO_CCY);\r\n\t\tDirectDebitTransaction6 directDebitTransaction = new DirectDebitTransaction6();\r\n\t\tdirectDebitTransactionInformation.setDrctDbtTx(directDebitTransaction);\r\n\t\tMandateRelatedInformation6 mandateRelatedInformation = new MandateRelatedInformation6();\r\n\t\tdirectDebitTransaction.setMndtRltdInf(mandateRelatedInformation);\r\n\r\n\t\tmandateRelatedInformation.setMndtId(((DDPaymentMethod) preferedPaymentMethod).getMandateIdentification());\r\n\t\tmandateRelatedInformation.setDtOfSgntr(DateUtils.dateToXMLGregorianCalendarFieldUndefined(((DDPaymentMethod) preferedPaymentMethod).getMandateDate()));\r\n\t\tBranchAndFinancialInstitutionIdentification4 debtorAgent = new BranchAndFinancialInstitutionIdentification4();\r\n\t\tdirectDebitTransactionInformation.setDbtrAgt(debtorAgent);\r\n\t\tFinancialInstitutionIdentification7 financialInstitutionIdentification = new FinancialInstitutionIdentification7();\r\n\t\tGenericFinancialIdentification1 bicInfo = new GenericFinancialIdentification1();\r\n\t\tbicInfo.setId(\"NOTPROVIDED\");\r\n\t\tfinancialInstitutionIdentification.setOthr(bicInfo);\r\n\t\tdebtorAgent.setFinInstnId(financialInstitutionIdentification);\r\n\r\n\t\tPartyIdentification32 debtor = new PartyIdentification32();\r\n\t\tdirectDebitTransactionInformation.setDbtr(debtor);\r\n\t\tdebtor.setNm(format(getDebtorFullName(ca)));\r\n\r\n\t\tCashAccount16 debtorAccount = new CashAccount16();\r\n\t\tdirectDebitTransactionInformation.setDbtrAcct(debtorAccount);\r\n\t\tAccountIdentification4Choice identification = new AccountIdentification4Choice();\r\n\t\tidentification.setIBAN(bankCoordinates.getIban());\r\n\t\tdebtorAccount.setId(identification);\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the correlation id.\r\n\t *\r\n\t * @param ca               the ca\r\n\t * @param accountOperation the account operation\r\n\t * @param ddReqItemId      the dd req item id\r\n\t * @return the correlation id\r\n\t */\r\n\tprivate String getCorrelationId(CustomerAccount ca, AccountOperation accountOperation, Long ddReqItemId) {\r\n\r\n\t\treturn accountOperation.getId() + \"_\" + ca.getCode() + \"_\" + ddReqItemId;\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the debtor full name.\r\n\t *\r\n\t * @param ca the ca\r\n\t * @return the debtor full name\r\n\t */\r\n\tprivate String getDebtorFullName(CustomerAccount ca) {\r\n\t\tString fullName = \"\";\r\n\t\tName name = ca.getName();\r\n\t\tif (name != null) {\t\t\r\n\t\t\tfullName = geFullName(name);\r\n\t\t} else {\r\n\t\t\tfullName = geFullName(ca.getCustomer().getName());\r\n\t\t}\r\n\t\treturn fullName;\r\n\t}\r\n\t\r\n\tprivate String geFullName(Name name) {\r\n\t\tTitle title = titleService.refreshOrRetrieve(name.getTitle());\r\n\t\treturn   title.getCode()+\" \"+name.getFirstName()+\" \"+name.getLastName();\r\n\t\t\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the bank coordinates.\r\n\t *\r\n\t * @param ddRequestLOT the dd request LOT\r\n\t * @param appProvider  the app provider\r\n\t * @return the bank coordinates\r\n\t * @throws BusinessException the business exception\r\n\t */\r\n\tprivate BankCoordinates getBankCoordinates(DDRequestLOT ddRequestLOT, Provider appProvider) throws BusinessException {\r\n\t\tif (ddRequestLOT.getSeller() != null) {\r\n\t\t\tPaymentGatewayService paymentGatewayService = (PaymentGatewayService) getServiceInterface(\"PaymentGatewayService\");\r\n\t\t\tPaymentGateway paymentGateway = paymentGatewayService.getPaymentGateway(ddRequestLOT.getSeller(), PaymentMethodEnum.DIRECTDEBIT);\r\n\t\t\tif (paymentGateway == null) {\r\n\t\t\t\tthrow new BusinessException(\"Cant find payment gateway for seller : \" + ddRequestLOT.getSeller());\r\n\t\t\t}\r\n\t\t\treturn paymentGateway.getBankCoordinates();\r\n\t\t} else {\r\n\t\t\treturn appProvider.getBankCoordinates();\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the end to end id.\r\n\t *\r\n\t * @param accountNotification2 the account notification 2\r\n\t * @return the end to end id\r\n\t */\r\n\tprivate String getEndToEndId(AccountNotification2 accountNotification2) {\r\n\t\tString endToEndId = null;\r\n\t\ttry {\r\n\t\t\tendToEndId = accountNotification2.getNtry().get(0).getNtryDtls().get(0).getTxDtls().get(0).getRefs().getEndToEndId();\r\n\t\t\treturn endToEndId;\r\n\t\t} catch (Exception e) {\r\n\t\t\tthrow new BusinessException(\"Can't found END_TO_END \");\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the dd item id from end to end.\r\n\t *\r\n\t * @param endToEnd the end to end\r\n\t * @return the dd item id from end to end\r\n\t */\r\n\tprivate Long getDdItemIdFromEndToEnd(String endToEnd) {\r\n\t\tif (StringUtils.isBlank(endToEnd) || endToEnd.indexOf(\"_\") == -1) {\r\n\t\t\tthrow new BusinessException(\"Invalid format END_TO_END :\" + endToEnd);\r\n\t\t}\r\n\t\ttry {\r\n\r\n\t\t\treturn Long.valueOf(endToEnd.substring(endToEnd.lastIndexOf(\"_\") + 1, endToEnd.length()));\r\n\t\t} catch (Exception e) {\r\n\t\t\tthrow new BusinessException(\"Invalid type END_TO_END :\" + endToEnd);\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the a id from end to end.\r\n\t *\r\n\t * @param endToEnd the end to end\r\n\t * @return the a id from end to end\r\n\t */\r\n\tprivate Long getAIdFromEndToEnd(String endToEnd) {\r\n\t\tif (StringUtils.isBlank(endToEnd) || endToEnd.indexOf(\"_\") == -1) {\r\n\t\t\tthrow new BusinessException(\"Invalid format END_TO_END :\" + endToEnd);\r\n\t\t}\r\n\t\ttry {\r\n\r\n\t\t\treturn Long.valueOf(endToEnd.substring(0, endToEnd.indexOf(\"_\")));\r\n\t\t} catch (Exception e) {\r\n\t\t\tthrow new BusinessException(\"Invalid type END_TO_END :\" + endToEnd);\r\n\t\t}\r\n\r\n\t}\r\n\r\n\tpublic DDRejectFileInfos processSDDRejectedFile(Map<String, Object> methodContext) throws BusinessException {\r\n\t\tFile sepaRejectedFile = (File) methodContext.get(DDRequestBuilderScript.DD_REJECT_FILE);\r\n\t\tif (sepaRejectedFile == null) {\r\n\t\t\tthrow new BusinessException(\"sepaRejectedFile is null\");\r\n\t\t}\r\n\t\tlog.info(\"processSDDRejectedFile:\" + sepaRejectedFile.getName());\r\n\t\tDDRejectFileInfos ddRejectFileInfos = new DDRejectFileInfos();\r\n\t\ttry {\r\n\t\t\tddRejectFileInfos.setFileName(sepaRejectedFile.getName());\r\n\t\t\torg.meveo.admin.sepa.jaxb.camt054.Document camt54 = (org.meveo.admin.sepa.jaxb.camt054.Document) JAXBUtils\r\n\t\t\t\t\t.unmarshaller(org.meveo.admin.sepa.jaxb.camt054.Document.class, sepaRejectedFile);\r\n\r\n\t\t\tBankToCustomerDebitCreditNotificationV02 bkToCstmrDbtCdtNtfctn = camt54.getBkToCstmrDbtCdtNtfctn();\r\n\r\n\t\t\tList<AccountNotification2> listNtfctn = bkToCstmrDbtCdtNtfctn.getNtfctn();\r\n\t\t\tfor (AccountNotification2 accountNotification2 : listNtfctn) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tString endToEnd = getEndToEndId(accountNotification2);\r\n\t\t\t\t\tString rejectReason = getRejectReason(accountNotification2);\r\n\t\t\t\t\tddRejectFileInfos.getListInvoiceRefsRejected().put(getDdItemIdFromEndToEnd(endToEnd), rejectReason);\r\n\t\t\t\t\tddRequestLOTService.rejectPayment(ddRequestItemService.findById(getDdItemIdFromEndToEnd(endToEnd)), rejectReason, sepaRejectedFile.getName());\r\n\t\t\t\t\tddRejectFileInfos.addItemOk();\r\n\r\n\t\t\t\t\tRecordedInvoice ri = recordedInvoiceService.findById(getAIdFromEndToEnd(endToEnd));\r\n\t\t\t\t\tri.setPaymentInfo6(\"NotAllowed\");\r\n\t\t\t\t\trecordedInvoiceService.updateNoCheck(ri);\r\n\r\n\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\tddRejectFileInfos.addItemKo();\r\n\t\t\t\t\tlog.error(\"Error on processSDDRejectedFile :\", e);\r\n\t\t\t\t\tddRejectFileInfos.getListErrors().add(e.getMessage());\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t} catch (Exception e) {\r\n\t\t\tthrow new BusinessException(e.getMessage());\r\n\t\t}\r\n\t\treturn ddRejectFileInfos;\r\n\t}\r\n\r\n\t/**\r\n\t * Format.\r\n\t *\r\n\t * @param valueStr the value str\r\n\t * @return the string\r\n\t */\r\n\tprivate String format(String valueStr) {\r\n\t\tif (valueStr == null) {\r\n\t\t\treturn \"\";\r\n\t\t}\r\n\t\treturn StringUtils.enleverAccent(valueStr);\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the reject reason.\r\n\t *\r\n\t * @param accountNotification2 the account notification 2\r\n\t * @return the reject reason\r\n\t */\r\n\tprivate String getRejectReason(AccountNotification2 accountNotification2) {\r\n\t\tString rejectReason = null;\r\n\t\ttry {\r\n\t\t\trejectReason = accountNotification2.getNtry().get(0).getNtryDtls().get(0).getTxDtls().get(0).getRtrInf().getRsn().getCd();\r\n\t\t\tif (\"AC01\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"IBAN incorrect ou inconnu\";\r\n\t\t\tif (\"AC04\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Le titulaire a ferm\\u00E9 son compte\";\r\n\t\t\tif (\"AC06\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Compte bloqu\\u00E9 pour pr\\u00E9l\\u00e8vement automatique\";\r\n\t\t\tif (\"AG02\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Information incorrecte\";\r\n\t\t\tif (\"AM04\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Fonds insuffisants\";\r\n\t\t\tif (\"MD01\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Mandat non valide\";\r\n\t\t\tif (\"MD06\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"R\\u00E9tro-facturation du paiement\";\r\n\t\t\tif (\"MD07\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Le client est d\\u00E9c\\u00E9d\\u00E9\";\r\n\t\t\tif (\"MS02\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Transaction refus\\u00E9e\";\r\n\t\t\tif (\"MS03\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Autre raison\";\r\n\t\t\tif (\"SL01\".equals(rejectReason))\r\n\t\t\t\treturn rejectReason + \":\" + \"Refus\\u00E9 par la banque d\\u00E9bitrice\";\r\n\t\t\treturn rejectReason;\r\n\t\t} catch (Exception e) {\r\n\t\t\tthrow new BusinessException(\"Can't found rejectReason \");\r\n\t\t}\r\n\t}\r\n\t\r\n\tprivate Date addBusinessDays(Date dateStart, Long nbDays) {\t\r\n\t\tif(nbDays == null || nbDays.intValue() < 0) {\r\n\t\t\tnbDays = 0L;\r\n\t\t}\r\n\t\tint daysAdded = 0;\r\n\t\tDate endDate = dateStart;\r\n\t\twhile (daysAdded < nbDays.intValue()) {\r\n\t\t\tendDate = DateUtils.addDaysToDate(endDate, 1);\r\n\t\t\tif (calendarBankingService.isBankWorkingDate(endDate)) {\r\n\t\t\t\tdaysAdded++;\r\n\t\t\t}\r\n\t\t\tlog.info(\"daysAdded:\"+daysAdded);\r\n\t\t}\r\n\t\treturn DateUtils.setDateToEndOfDay(endDate);\r\n\t}\r\n\t\r\n\t/**\r\n     * Generate DD request lot file for SCT.\r\n     *\r\n     * @param ddRequestLot the dd request lot\r\n     * @param appProvider  the app provider\r\n     * @throws BusinessException the business exception\r\n     */\r\n    private void generateDDRequestLotFileForSCT(DDRequestLOT ddRequestLot, Provider appProvider) throws BusinessException {\r\n        ParamBean paramBean = ParamBean.getInstanceByProvider(appProvider.getCode());\r\n   \t\r\n        org.meveo.admin.sepa.jaxb.pain001.Document document;\r\n        CustomerCreditTransferInitiationV03 message;\r\n        List<DDRequestItem> ddrequestItems = ddRequestLot.getDdrequestItems();\r\n        DDRequestItem ddrequestItem;\r\n        Long operationsByFile = ddRequestLot.getDdRequestBuilder().getNbOperationPerFile();\r\n        long ddRequestItemSize = ddrequestItems.size();\r\n        if (operationsByFile == null || operationsByFile <= 0) {\r\n            operationsByFile = ddRequestItemSize;\r\n        }\r\n        int filesToGenerate = ddrequestItems.isEmpty() ? 0 : (int) Math.ceil(ddRequestItemSize / (double) operationsByFile);\r\n        int opToGenerateByFile;\r\n        int generatedOps = 0;\r\n        int opWithErrorsByFile;\r\n        BigDecimal totalAmount;\r\n        List<String> generatedFilesNames = new ArrayList<String>();\r\n        String fileName;\r\n        for (int fileNumber = 1; fileNumber <= filesToGenerate; fileNumber++) {\r\n            try {\r\n                fileName = ddRequestLot.getFileName();//getDDFileName(ddRequestLot, appProvider);\r\n                document = new org.meveo.admin.sepa.jaxb.pain001.Document();\r\n                message = new CustomerCreditTransferInitiationV03();\r\n                document.setCstmrCdtTrfInitn(message);\r\n                addSctHeader(message, ddRequestLot, appProvider, fileNumber);\r\n                totalAmount = BigDecimal.ZERO;\r\n                opToGenerateByFile = 0;\r\n                opWithErrorsByFile = 0;\r\n                while (generatedOps < ddRequestItemSize && opToGenerateByFile < operationsByFile) {\r\n                    ddrequestItem = ddrequestItems.get(generatedOps);\r\n                    totalAmount = totalAmount.add(ddrequestItem.getAmount());\r\n                    if (!ddrequestItem.hasError()) {\r\n                        addSctPaymentInformation(message, ddrequestItem, appProvider);\r\n                    } else {\r\n                        log.error(\"ddrequestItem with id ={} has Errors :{} . The file {} will not contain all payment informations.\", ddrequestItem.getId(), ddrequestItem.getErrorMsg(), fileName);\r\n                        opWithErrorsByFile++;\r\n                    }\r\n                    opToGenerateByFile++;\r\n                    generatedOps++;\r\n                }\r\n                if (opToGenerateByFile > opWithErrorsByFile) { // The file is generated only if it contains at least one operation without\r\n                                                                // errors\r\n                    message.getGrpHdr().setCtrlSum(totalAmount.setScale(2, RoundingMode.HALF_UP));\r\n                    message.getGrpHdr().setNbOfTxs(String.valueOf(opToGenerateByFile));\r\n                    // the Pain001 jaxb classes are generated from the xsd located at:\r\n                    // https://www.iso20022.org/documents/messages/1_0_version/pain/schemas/pain.001.001.03.zip\r\n                    JAXBUtils.marshaller(document, new File(fileName),\r\n                            paramBean.getProperty(\"sepa.schemaLocation.pain001\", SCT_SCHEMA_LOCATION));\r\n                    generatedFilesNames.add(fileName);\r\n                }\r\n            } catch (Exception e) {\r\n                log.error(e.getMessage(), e);\r\n                throw new BusinessException(e.getMessage());\r\n            }\r\n\r\n        }\r\n        ddRequestLot.setFileName(String.join(COMMA_STRING, generatedFilesNames));\r\n    }\r\n    \r\n    /**\r\n     * Adds the header for SCT file.\r\n     *\r\n     * @param message      the SCT message\r\n     * @param ddRequestLot the dd request lot\r\n     * @param appProvider  the provider\r\n     * @param fileNumber   the file number: used when generatin severals files for\r\n     *                     one ddRequest lot\r\n     * @throws Exception the exception\r\n     */\r\n    private void addSctHeader(CustomerCreditTransferInitiationV03 message, DDRequestLOT ddRequestLot, Provider appProvider, int fileNumber) {\r\n        GroupHeader32 groupHeader = new GroupHeader32();\r\n        message.setGrpHdr(groupHeader);\r\n        groupHeader.setMsgId(ArConfig.getSCTRequestHeaderRefrence() + DASH_STRING + ddRequestLot.getId() + DASH_STRING + fileNumber);\r\n        try{\r\n            groupHeader.setCreDtTm(DateUtils.dateToXMLGregorianCalendar(new Date()));\r\n        }\r\n        catch(Exception e){\r\n            throw new BusinessException(e);\r\n        }\r\n        org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32 initgPty = new org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32();\r\n        initgPty.setNm(appProvider.getDescription());\r\n        groupHeader.setInitgPty(initgPty);\r\n\r\n    }\r\n    /**\r\n     * Adds the payment information for SCT file.\r\n     *\r\n     * @param message       the SCT message\r\n     * @param ddrequestItem the ddrequest item\r\n     * @param appProvider   the provider\r\n     * @throws Exception the exception\r\n     */\r\n    private void addSctPaymentInformation(CustomerCreditTransferInitiationV03 message, DDRequestItem ddrequestItem, Provider appProvider) {\r\n\r\n        log.info(\"addSctPaymentInformation dDRequestItem id={} \", ddrequestItem.getId());\r\n        ddrequestItem = ddRequestItemService.findById(ddrequestItem.getId(), Arrays.asList(\"accountOperations\"));\r\n        PaymentInstructionInformation3 paymentInformation = new PaymentInstructionInformation3();\r\n        message.getPmtInf().add(paymentInformation);\r\n        paymentInformation.setPmtInfId(ArConfig.getDDRequestHeaderReference() + DASH_STRING + ddrequestItem.getId());\r\n        paymentInformation.setPmtMtd(PaymentMethod3Code.TRF);\r\n        paymentInformation.setBtchBookg(true);\r\n        paymentInformation.setNbOfTxs(String.valueOf(ddrequestItem.getAccountOperations().size()));\r\n        paymentInformation.setCtrlSum(ddrequestItem.getAmount().setScale(2, RoundingMode.HALF_UP));\r\n        PaymentTypeInformation19 paymentTypeInformation = new PaymentTypeInformation19();\r\n        paymentInformation.setPmtTpInf(paymentTypeInformation);\r\n        org.meveo.admin.sepa.jaxb.pain001.ServiceLevel8Choice serviceLevel = new org.meveo.admin.sepa.jaxb.pain001.ServiceLevel8Choice();\r\n        paymentTypeInformation.setSvcLvl(serviceLevel);\r\n        serviceLevel.setCd(SEPA_SERVICE_LEVEL_CD);\r\n        org.meveo.admin.sepa.jaxb.pain001.CategoryPurpose1Choice ctgyPurp = new org.meveo.admin.sepa.jaxb.pain001.CategoryPurpose1Choice();\r\n        paymentTypeInformation.setCtgyPurp(ctgyPurp);\r\n        ctgyPurp.setCd(CATEGORY_PURPOSE_CODE);\r\n        \r\n    \tSeller seller = sellerService.findByCode(\"EKKO\");\r\n\t\tLong nbDaysSepa = (Long) seller.getCfValue(\"CF_SEL_SEPA_NB_BUSI_DAYS\");\r\n\t\t\r\n\t\t\r\n\t\tDate customerRequestedDate = addBusinessDays(new Date(), nbDaysSepa);\r\n\t\tlog.info(\"customerRequestedDate business day:\" + customerRequestedDate);\r\n        \r\n        try{\r\n            paymentInformation.setReqdExctnDt(DateUtils.dateToXMLGregorianCalendarFieldUndefined(customerRequestedDate));\r\n        }\r\n        catch (Exception e) {\r\n            throw new BusinessException(e);\r\n        }\r\n\r\n        org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32 dbtr = new org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32();\r\n        if (ddrequestItem.getDdRequestLOT().getSeller() != null) {\r\n            dbtr.setNm(ddrequestItem.getDdRequestLOT().getSeller().getDescription());\r\n        } else {\r\n            dbtr.setNm(appProvider.getDescription());\r\n        }\r\n\r\n        paymentInformation.setDbtr(dbtr);\r\n\r\n        org.meveo.admin.sepa.jaxb.pain001.CashAccount16 dbtrAccount = new org.meveo.admin.sepa.jaxb.pain001.CashAccount16();\r\n        paymentInformation.setDbtrAcct(dbtrAccount);\r\n        org.meveo.admin.sepa.jaxb.pain001.AccountIdentification4Choice identification = new org.meveo.admin.sepa.jaxb.pain001.AccountIdentification4Choice();\r\n        dbtrAccount.setId(identification);\r\n\r\n        BankCoordinates bankCoordinates = getBankCoordinates(ddrequestItem.getDdRequestLOT(), appProvider);\r\n\r\n        if (bankCoordinates == null) {\r\n            throw new BusinessException(\"Missing bank information on provider\");\r\n        }\r\n       \r\n        identification.setIBAN(bankCoordinates.getIban());\r\n\r\n        dbtrAccount.setCcy(EURO_CCY);\r\n        org.meveo.admin.sepa.jaxb.pain001.BranchAndFinancialInstitutionIdentification4 dbtrAgent = new org.meveo.admin.sepa.jaxb.pain001.BranchAndFinancialInstitutionIdentification4();\r\n        paymentInformation.setDbtrAgt(dbtrAgent);\r\n        org.meveo.admin.sepa.jaxb.pain001.FinancialInstitutionIdentification7 financialInstitutionIdentification = new org.meveo.admin.sepa.jaxb.pain001.FinancialInstitutionIdentification7();\r\n        dbtrAgent.setFinInstnId(financialInstitutionIdentification);\r\n        if (StringUtils.isBlank(bankCoordinates.getBic())) {\r\n            org.meveo.admin.sepa.jaxb.pain001.GenericFinancialIdentification1 othr = new org.meveo.admin.sepa.jaxb.pain001.GenericFinancialIdentification1();\r\n            othr.setId(NOTPROVIDED_BIC);\r\n            financialInstitutionIdentification.setOthr(othr);\r\n        }\r\n\r\n        financialInstitutionIdentification.setBIC(bankCoordinates.getBic());\r\n        paymentInformation.setChrgBr(org.meveo.admin.sepa.jaxb.pain001.ChargeBearerType1Code.SLEV);\r\n        addSctTransaction(ddrequestItem, paymentInformation);\r\n    }\r\n   \r\n    /**\r\n     * Adds the transaction for SCT file.\r\n     *\r\n     * @param paymentInformation the payment information of SCT file\r\n     */\r\n    private void addSctTransaction(DDRequestItem dDRequestItem, PaymentInstructionInformation3 paymentInformation) {\r\n    \tCustomerAccount ca = customerAccountService.findById(dDRequestItem.getAccountOperations().get(0).getCustomerAccount().getId(), Arrays.asList(\"paymentMethods\"));\r\n        AccountOperation ao = accountOperationService.findById(dDRequestItem.getAccountOperations().get(0).getId(), Arrays.asList(\"subscription\"));\r\n\t\tSubscription sub = subscriptionService.findById(ao.getSubscription().getId(), Arrays.asList(\"paymentMethod\"));\r\n        PaymentMethod preferedPaymentMethod = sub.getPaymentMethod();\r\n\t\tif (preferedPaymentMethod == null || !(preferedPaymentMethod instanceof DDPaymentMethod)) {\r\n\t\t\tthrow new BusinessException(\"Payment method not valid!\");\r\n\t\t}\r\n\t\tBankCoordinates bankCoordinates = ((DDPaymentMethod) preferedPaymentMethod).getBankCoordinates();\r\n\r\n\t\tif (bankCoordinates == null) {\r\n\t\t\tthrow new BusinessException(\"Bank Coordinate is absent for Payment method \" + ((DDPaymentMethod) preferedPaymentMethod).getAlias());\r\n\t\t}\r\n\r\n        CreditTransferTransactionInformation10 cdtTrfTxInf = new CreditTransferTransactionInformation10();\r\n        paymentInformation.getCdtTrfTxInf().add(cdtTrfTxInf);\r\n        org.meveo.admin.sepa.jaxb.pain001.PaymentIdentification1 paymentIdentification = new org.meveo.admin.sepa.jaxb.pain001.PaymentIdentification1();\r\n        cdtTrfTxInf.setPmtId(paymentIdentification);\r\n        paymentIdentification.setInstrId(String.valueOf(dDRequestItem.getDdRequestLOT().getId()));\r\n        paymentIdentification.setEndToEndId(String.valueOf(dDRequestItem.getId()));\r\n\r\n        AmountType3Choice amt = new AmountType3Choice();\r\n        cdtTrfTxInf.setAmt(amt);\r\n        org.meveo.admin.sepa.jaxb.pain001.ActiveOrHistoricCurrencyAndAmount instdAmt = new org.meveo.admin.sepa.jaxb.pain001.ActiveOrHistoricCurrencyAndAmount();\r\n\r\n        instdAmt.setValue(dDRequestItem.getAmount().setScale(2, RoundingMode.HALF_UP));\r\n        instdAmt.setCcy(EURO_CCY);\r\n        amt.setInstdAmt(instdAmt);\r\n\r\n        org.meveo.admin.sepa.jaxb.pain001.BranchAndFinancialInstitutionIdentification4 cdtrAgent = new org.meveo.admin.sepa.jaxb.pain001.BranchAndFinancialInstitutionIdentification4();\r\n        cdtTrfTxInf.setCdtrAgt(cdtrAgent);\r\n        org.meveo.admin.sepa.jaxb.pain001.FinancialInstitutionIdentification7 finInstnId = new org.meveo.admin.sepa.jaxb.pain001.FinancialInstitutionIdentification7();\r\n        finInstnId.setBIC(bankCoordinates.getBic());\r\n        cdtrAgent.setFinInstnId(finInstnId);\r\n        org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32 cdtr = new org.meveo.admin.sepa.jaxb.pain001.PartyIdentification32();\r\n        cdtTrfTxInf.setCdtr(cdtr);\r\n        cdtr.setNm(ca.getDescription());\r\n        cdtr.setCtryOfRes(FR_COUNTRY);\r\n        org.meveo.admin.sepa.jaxb.pain001.CashAccount16 cdtrAccount = new org.meveo.admin.sepa.jaxb.pain001.CashAccount16();\r\n        cdtTrfTxInf.setCdtrAcct(cdtrAccount);\r\n        org.meveo.admin.sepa.jaxb.pain001.AccountIdentification4Choice identification = new org.meveo.admin.sepa.jaxb.pain001.AccountIdentification4Choice();\r\n       \r\n        identification.setIBAN(bankCoordinates.getIban());\r\n        cdtrAccount.setId(identification);\r\n\r\n        RemittanceInformation5 rmtInf = new RemittanceInformation5();\r\n        cdtTrfTxInf.setRmtInf(rmtInf);\r\n        rmtInf.getUstrd().add(\"Remboursement \" + getReference(dDRequestItem));\r\n    }\r\n    \r\n    \r\n    private String getReference(DDRequestItem dDRequestItem) {\r\n        String references = \"\";\r\n       List<AccountOperation> aos =  dDRequestItem.getAccountOperations();\r\n        if(aos != null && !aos.isEmpty()) {\r\n            for(AccountOperation ao : aos) {\r\n                if(!ao.getReference().startsWith(\"ddItem\")) {\r\n                    references += \" \"+ao.getReference(); \r\n                }\r\n            }\r\n        }\r\n        return references;\r\n    }\r\n}\r\n\r\n\r\n ]]>\r\n            </script>\r\n</ScriptInstance>"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								},
								"description": "A Custom script to compute CUrrent Month Date range."
							},
							"response": []
						},
						{
							"name": "Create PaymentEkkoDateRangeScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Status code is 200\", function () {",
											"    pm.response.to.have.status(200);",
											"});"
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"auth": {
									"type": "basic",
									"basic": [
										{
											"key": "username",
											"value": "{{opencell.username}}",
											"type": "string"
										},
										{
											"key": "password",
											"value": "{{opencell.password}}",
											"type": "string"
										}
									]
								},
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Proxy-Authorization",
										"value": "{{proxy.auth}}"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.payment.PaymentEkkoDateRangeScript\" description=\"Range date payment EKKO\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.payment;\r\n\r\nimport java.util.Date;\r\nimport java.util.Map;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.admin.job.DateRange;\r\nimport org.meveo.model.admin.Seller;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.service.admin.impl.SellerService;\r\nimport org.meveo.service.catalog.impl.CalendarBankingService;\r\nimport org.meveo.service.script.payment.DateRangeScript;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\n/**\r\n * \r\n * @author anasseh\r\n *  03/04/2022 fix ENG382-102\r\n *  21/06/2023 SUPS-2692\r\n */\r\n\r\npublic class PaymentEkkoDateRangeScript extends DateRangeScript {\r\n\tprivate Logger log = LoggerFactory.getLogger(PaymentEkkoDateRangeScript.class);\r\n\r\n\tprivate CalendarBankingService calendarBankingService = (CalendarBankingService) getServiceInterface(\"CalendarBankingService\");\r\n\tprivate SellerService sellerService = (SellerService) getServiceInterface(\"SellerService\");\r\n\r\n\t\r\n\tprivate static final String CF_SEL_SEPA_NB_BUSI_DAYS = \"CF_SEL_SEPA_NB_BUSI_DAYS\";\r\n\t\r\n\t@Override\r\n\tpublic DateRange computeDateRange(Map<String, Object> methodContext) throws BusinessException {\r\n\t\t\r\n\t\tlog.info(\"Execute context : {} \",methodContext);\r\n\t\t\r\n\t\tSeller seller = sellerService.findByCode(\"EKKO\");\r\n\t\tLong nbDaysSepa = (Long) seller.getCfValue(CF_SEL_SEPA_NB_BUSI_DAYS);\r\n\r\n\t\tDateRange dateRange = new DateRange(DateUtils.setDateToStartOfDay(new Date(1)), DateUtils.addDaysToDate(addBusinessDays(new Date(),nbDaysSepa),1));\r\n\r\n\t\tlog.info(\"sysdate:{} startDate:{} endDate:{}\", new Date(), dateRange.getFrom(), dateRange.getTo());\r\n\t\treturn dateRange;\r\n\t}\r\n\r\n\tprivate Date addBusinessDays(Date dateStart, Long nbDays) {\r\n\t\tif(nbDays == null || nbDays.intValue() < 0) {\r\n\t\t\tnbDays = 0L;\r\n\t\t}\r\n\t\tint daysAdded = 0;\r\n\t\tDate endDate = dateStart;\r\n\t\twhile (daysAdded < nbDays.intValue()) {\r\n\t\t\tendDate = DateUtils.addDaysToDate(endDate, 1);\r\n\t\t\tif (calendarBankingService.isBankWorkingDate(endDate)) {\r\n\t\t\t\tdaysAdded++;\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn DateUtils.setDateToEndOfDay(endDate);\r\n\t}\r\n} ]]>\r\n            </script>\r\n</ScriptInstance>\r\n\r\n"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								},
								"description": "A Custom script to compute CUrrent Month Date range."
							},
							"response": []
						},
						{
							"name": "Create BlankGatewayScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Status code is 200\", function () {",
											"    pm.response.to.have.status(200);",
											"});"
										],
										"type": "text/javascript"
									}
								}
							],
							"request": {
								"auth": {
									"type": "basic",
									"basic": [
										{
											"key": "username",
											"value": "{{opencell.username}}",
											"type": "string"
										},
										{
											"key": "password",
											"value": "{{opencell.password}}",
											"type": "string"
										}
									]
								},
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Proxy-Authorization",
										"value": "{{proxy.auth}}"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.payment.BlankGatewayScript\" description=\"BlankGatewayScript\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.payment;\r\n\r\nimport java.util.Map;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.service.script.payment.PaymentScript;\r\n\r\npublic class BlankGatewayScript extends PaymentScript{\r\n\r\n\tprivate static final long serialVersionUID = 1L;\r\n\t\r\n\tpublic void createCardToken(Map<String, Object> methodContext) throws BusinessException {           \r\n        methodContext.put(PaymentScript.RESULT_TOKEN, \"7ced0000-3ab2-000d-6a50-08d4b8a6\"+(int )(Math.random() * 1000 + 1));\r\n    }\r\n    public void doPaymentToken(Map<String, Object> methodContext) throws BusinessException {\r\n       throw new BusinessException(\"There no gateway to process payment\");\r\n    }\r\n      public void doPaymentCard(Map<String, Object> methodContext) throws BusinessException {\r\n    \t  throw new BusinessException(\"There no gateway to process payment\");\r\n    }\r\n  \r\n    public void doRefundToken(Map<String, Object> methodContext) throws BusinessException {\r\n    \t throw new BusinessException(\"There no gateway to process refund\");\r\n    }\r\n   public void doRefundCard(Map<String, Object> methodContext) throws BusinessException {\r\n\t   throw new BusinessException(\"There no gateway to process refund\");\r\n    }\r\n     \r\n}\r\n             ]]>\r\n            </script>\r\n</ScriptInstance>\r\n\r\n"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								},
								"description": "A Custom script to compute CUrrent Month Date range."
							},
							"response": []
						},
						{
							"name": "AOFilterScript",
							"event": [
								{
									"listen": "test",
									"script": {
										"exec": [
											"pm.test(\"Status code is 200\", function () {",
											"    pm.response.to.have.status(200);",
											"});"
										],
										"type": "text/javascript",
										"packages": {}
									}
								}
							],
							"request": {
								"auth": {
									"type": "basic",
									"basic": [
										{
											"key": "username",
											"value": "{{opencell.username}}",
											"type": "string"
										},
										{
											"key": "password",
											"value": "{{opencell.password}}",
											"type": "string"
										}
									]
								},
								"method": "POST",
								"header": [
									{
										"key": "Content-Type",
										"value": "application/xml"
									},
									{
										"key": "Proxy-Authorization",
										"value": "{{proxy.auth}}"
									}
								],
								"body": {
									"mode": "raw",
									"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.payment.AOFilterScript\" description=\"AOFilterScript\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.payment;\r\n\r\nimport java.math.BigDecimal;\r\nimport java.util.ArrayList;\r\nimport java.util.Arrays;\r\nimport java.util.Date;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\n\r\nimport org.meveo.commons.utils.EjbUtils;\r\nimport org.meveo.model.admin.Seller;\r\nimport org.meveo.model.billing.Subscription;\r\nimport org.meveo.model.payments.AccountOperation;\r\nimport org.meveo.model.payments.CustomerAccount;\r\nimport org.meveo.model.payments.OperationCategoryEnum;\r\nimport org.meveo.model.payments.PaymentMethodEnum;\r\nimport org.meveo.service.admin.impl.SellerService;\r\nimport org.meveo.service.billing.impl.SubscriptionService;\r\nimport org.meveo.service.payments.impl.AccountOperationService;\r\nimport org.meveo.service.payments.impl.CustomerAccountService;\r\nimport org.meveo.service.script.payment.AccountOperationFilterScript;\r\n\r\n/**\r\n * \r\n * @author anasseh\r\n *  \r\n *  16/06/2023  SUPS-2597(bis)\r\n *  15/04/2024  ENG382-146\r\n *  30/04/2024  ENG382-146 \r\n *  13/05/2024  ENG382-185 \r\n *  19/05/2024  ENG382-192\r\n */\r\npublic class AOFilterScript extends AccountOperationFilterScript {\r\n\r\n\r\n\tprivate final AccountOperationService accountOperationService = (AccountOperationService) getServiceInterface(\"AccountOperationService\");\r\n\tprivate SellerService sellerService = (SellerService) EjbUtils.getServiceInterface(\"SellerService\");\r\n\tprivate SubscriptionService subscriptionService = (SubscriptionService) EjbUtils.getServiceInterface(\"SubscriptionService\");\r\n\tprivate CustomerAccountService customerAccountService = (CustomerAccountService) EjbUtils.getServiceInterface(\"CustomerAccountService\");\r\n\t\r\n\t\r\n\t\r\n\t@SuppressWarnings(\"unchecked\")\r\n\t@Override\r\n\tpublic List<AccountOperation> filterAoToPay(Map<String, Object> methodContext) {\r\n\t\tlog.debug(\" filterAoToPay : [{}]\", methodContext);\r\n\t\tDate fromDueDate = (Date) methodContext.get(AccountOperationFilterScript.FROM_DUE_DATE);\r\n\t\tDate toDateFrom = (Date) methodContext.get(AccountOperationFilterScript.TO_DUE_DATE);\r\n\t\tPaymentMethodEnum paymentMethod = (PaymentMethodEnum) methodContext\r\n\t\t\t\t.get(AccountOperationFilterScript.PAYMENT_METHOD);\r\n\t\tOperationCategoryEnum catToProcess = (OperationCategoryEnum) methodContext\r\n\t\t\t\t.get(AccountOperationFilterScript.CAT_TO_PROCESS);\r\n\r\n\t\tString typeIN = \" ('I','OCC') \";\r\n\t\tif(catToProcess == OperationCategoryEnum.CREDIT) {\t\t\r\n\t\t\ttypeIN =  \" ('I','OCC','P','AP') \";\r\n\t\t}\r\n\t\t\r\n\t\tString queryStr = \"Select distinct(ao)  from AccountOperation as ao,PaymentMethod as pm  where  ao.dueDate >=:fromDueDateIN and ao.dueDate <:toDueDateIN and ao.transactionCategory =:catToProcessIN and ao.type  in \"+typeIN+\"  and \"\r\n\t\t\t\t+ \" ao.matchingStatus ='O' and  ao.customerAccount.id = pm.customerAccount.id and pm.paymentType =:paymentMethodIN   \";\r\n\r\n\r\n\t\t\r\n\t\tMap<String, Object> params = new HashMap<String, Object>();\r\n\t\tparams.put(\"fromDueDateIN\", fromDueDate);\r\n\t\tparams.put(\"toDueDateIN\", toDateFrom);\r\n\t\tparams.put(\"paymentMethodIN\", paymentMethod);\r\n\t\tparams.put(\"catToProcessIN\", catToProcess);\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\tlog.debug(\"fromDueDateIN={} , toDueDateIN={} ,paymentMethodIN={} , catToProcessIN={} \", fromDueDate, toDateFrom, paymentMethod, catToProcess);\r\n\t\tList<AccountOperation> aosSelect = (List<AccountOperation>) accountOperationService.executeSelectQuery(queryStr, params);\r\n\t\tList<AccountOperation> aos = new ArrayList<AccountOperation>();\r\n\t\tfor (AccountOperation ao : aosSelect) {\r\n\t\t\tif (ao.getSubscription() != null) {\r\n\t\t\t\ttry {\r\n\t\t\t\t\tSubscription sub = subscriptionService.findById(ao.getSubscription().getId(),\r\n\t\t\t\t\t\t\tArrays.asList(\"paymentMethod\"));\r\n\r\n\t\t\t\t\tif (sub != null && sub.getPaymentMethod() != null\r\n\t\t\t\t\t\t\t&& sub.getPaymentMethod().getPaymentType() == PaymentMethodEnum.DIRECTDEBIT) {\r\n\t\t\t\t\t\taos.add(ao);\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif (sub != null && sub.getPaymentMethod() != null\r\n\t\t\t\t\t\t\t&& sub.getPaymentMethod().getPaymentType() != PaymentMethodEnum.DIRECTDEBIT) {\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tCustomerAccount ca = customerAccountService.findById(ao.getCustomerAccount().getId(),\r\n\t\t\t\t\t\t\tArrays.asList(\"paymentMethods\"));\r\n\t\t\t\t\tPaymentMethodEnum paymentMethodEnum = ca.getPreferredPaymentMethodType();\r\n\t\t\t\t\tlog.debug(\"ca.getPreferredPaymentMethodType():\" + paymentMethodEnum);\r\n\t\t\t\t\tif (paymentMethodEnum != null && paymentMethodEnum == PaymentMethodEnum.DIRECTDEBIT) {\r\n\t\t\t\t\t\taos.add(ao);\r\n\t\t\t\t\t}\r\n\t\t\t\t} catch (Exception e) {\r\n\t\t\t\t\te.printStackTrace();\r\n\t\t\t\t}\r\n\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\t\r\n\t\tlog.info(\"findListAoToPay  aos:{}\",aos);\t\t\r\n\t\tSeller seller = sellerService.findByCode(\"EKKO\");\r\n\t\tDouble paymentThreshold = (Double) seller.getCfValue(\"CF_SEL_PAY_AMOUNT_THRESHOLD\");\r\n\t\tif(paymentThreshold == null) {\r\n\t\t\tpaymentThreshold = 1d;\r\n\t\t}\r\n\r\n\t\tMap<Subscription, List<AccountOperation>> aosBySUB = new HashMap<Subscription, List<AccountOperation>>();\r\n\t\tfor (AccountOperation ao : aos) {\r\n\t\t\tao = accountOperationService.refreshOrRetrieve(ao);\r\n\t\t\tSubscription sub = subscriptionService.refreshOrRetrieve(ao.getSubscription());\r\n\t\t\tList<AccountOperation> aosForSUB = new ArrayList<AccountOperation>();\r\n\t\t\tif (aosBySUB.containsKey(sub)) {\r\n\t\t\t\taosForSUB = aosBySUB.get(sub);\r\n\t\t\t}\r\n\t\t\taosForSUB.add(ao);\r\n\t\t\taosBySUB.put(sub, aosForSUB);\r\n\t\t}\r\n\t\taos = new ArrayList<AccountOperation>();\r\n\t\tfor (Map.Entry<Subscription, List<AccountOperation>> entry : aosBySUB.entrySet()) {\r\n\t\t\tBigDecimal amountToPayByItem = BigDecimal.ZERO;\r\n\t\t\t\r\n\t\t\tSubscription sub = entry.getKey();\r\n\t\t\t\r\n\t\t\tfor (AccountOperation ao : entry.getValue()) {\r\n\t\t\t\t\r\n\t\t\t\t\tamountToPayByItem = amountToPayByItem.add(ao.getUnMatchingAmount());\r\n\t\t\t\t\r\n\t\t\t}\r\n\t\t\tif(amountToPayByItem.compareTo(BigDecimal.valueOf(paymentThreshold))>=0) {\r\n\t\t\t\taos.addAll(entry.getValue());\r\n\t\t\t}\r\n\r\n\t\t\t\r\n\t\t}\r\n\t\tlog.info(\"findListAoToPay return aos:{}\",aos);\r\n\t\treturn aos;\t\t\r\n\t}\r\n}\r\n\r\n\r\n             ]]>\r\n            </script>\r\n</ScriptInstance>\r\n\r\n"
								},
								"url": {
									"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
									"host": [
										"{{opencell.url}}"
									],
									"path": [
										"scriptInstance",
										"createOrUpdate"
									]
								},
								"description": "A Custom script to compute CUrrent Month Date range."
							},
							"response": []
						}
					]
				},
				{
					"name": "SObjectSyncingScript",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Status code is 200\", function () {",
									"    pm.response.to.have.status(200);",
									"});"
								],
								"type": "text/javascript",
								"packages": {}
							}
						}
					],
					"request": {
						"auth": {
							"type": "basic",
							"basic": [
								{
									"key": "username",
									"value": "{{opencell.username}}",
									"type": "string"
								},
								{
									"key": "password",
									"value": "{{opencell.password}}",
									"type": "string"
								}
							]
						},
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/xml"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "<ScriptInstance code=\"org.opencell.eeko.service.script.syncing.SObjectSyncingScript\" description=\"Salesforce object syncing script\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package org.opencell.eeko.service.script.syncing;\r\n\r\nimport java.math.BigDecimal;\r\nimport java.math.RoundingMode;\r\nimport java.text.MessageFormat;\r\nimport java.util.ArrayList;\r\nimport java.util.Date;\r\nimport java.util.HashMap;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.Base64;\r\nimport javax.persistence.Query;\r\nimport javax.persistence.EntityManager;\r\nimport javax.ws.rs.HttpMethod;\r\nimport javax.ws.rs.ProcessingException;\r\nimport javax.ws.rs.client.Entity;\r\nimport javax.ws.rs.client.Invocation;\r\nimport javax.ws.rs.core.Form;\r\nimport javax.ws.rs.core.HttpHeaders;\r\nimport javax.ws.rs.core.MultivaluedMap;\r\nimport javax.ws.rs.core.Response;\r\n\r\nimport org.apache.commons.lang3.builder.ToStringBuilder;\r\nimport org.apache.commons.lang3.builder.ToStringStyle;\r\nimport org.hibernate.proxy.HibernateProxy;\r\nimport org.jboss.resteasy.client.jaxrs.ResteasyClient;\r\nimport org.meveo.commons.utils.ResteasyClientProxyBuilder;\r\nimport org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;\r\nimport org.json.simple.JSONArray;\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.api.exception.MeveoApiException;\r\nimport org.meveo.commons.utils.JsonUtils;\r\nimport org.meveo.commons.utils.ParamBean;\r\nimport org.meveo.commons.utils.ParamBeanFactory;\r\nimport org.meveo.commons.utils.ReflectionUtils;\r\nimport org.meveo.commons.utils.StringUtils;\r\nimport org.meveo.model.BaseEntity;\r\nimport org.meveo.model.BusinessEntity;\r\nimport org.meveo.model.ICustomFieldEntity;\r\nimport org.meveo.model.IEntity;\r\nimport org.meveo.model.billing.Invoice;\r\nimport org.meveo.model.crm.Customer;\r\nimport org.meveo.model.billing.Subscription;\r\nimport org.meveo.model.payments.AccountOperation;\r\nimport org.meveo.model.payments.MatchingAmount;\r\nimport org.meveo.model.payments.MatchingCode;\r\nimport org.meveo.model.payments.OperationCategoryEnum;\r\nimport org.meveo.model.payments.OtherCreditAndCharge;\r\nimport org.meveo.model.payments.Payment;\r\nimport org.meveo.model.payments.RecordedInvoice;\r\nimport org.meveo.model.payments.RejectedPayment;\r\nimport org.meveo.model.shared.DateUtils;\r\nimport org.meveo.service.base.BaseEntityService;\r\nimport org.meveo.service.billing.impl.InvoiceService;\r\nimport org.meveo.service.payments.impl.AccountOperationService;\r\nimport org.meveo.service.script.Script;\r\nimport org.slf4j.Logger;\r\nimport org.slf4j.LoggerFactory;\r\n\r\nimport com.google.gson.JsonObject;\r\nimport com.google.gson.annotations.SerializedName;\r\n\r\n/**\r\n * \r\n * This script allows to send the object available in the context param to its equivalent on the SFDC side The process is using the oauth2 with refresh based on the global system\r\n * properties provided by the SFDC env\r\n * \r\n * @author Youssef IZEM\r\n * @author anasseh ENG382-122 01/02/2024\r\n */\r\npublic class SObjectSyncingScript extends Script {\r\n\r\n\tprivate static final long serialVersionUID = 1L;\r\n\r\n\t/**\r\n\t * Salesforce resources path\r\n\t */\r\n\tprivate static final String END_POINT_API_VERSION = \"v50.0\";\r\n\tprivate static final String END_POINT_TOKEN_REQUEST = \"/services/oauth2/token\";\r\n\tprivate static final String END_POINT_SOBJECT_INVOICE = \"/services/data/{{version}}/sobjects/opencell__invoice__c\";\r\n\tprivate static final String END_POINT_SOBJECT_ATTACHMENT = \"/services/data/{{version}}/sobjects/Attachment\";\r\n\tprivate static final String END_POINT_RESOURCE_COMPOSITE = \"/services/data/{{version}}/composite/\";\r\n\tprivate static final String END_POINT_SOBJECT_SUBSCRIPTION = \"/services/data/{{version}}/sobjects/opencell__Subscription__c\";\r\n\tprivate static final String END_POINT_SOBJECT_ACCOUNT_OPERATION = \"/services/data/{{version}}/sobjects/opencell__AccountOperation__c\";\r\n\r\n\t/**\r\n\t * Global properties credentials for Salesforce authent\r\n\t */\r\n\tprivate static final String PROPERTY_KEY_SALESFORCE_URL = \"salesforce.url\";\r\n\tprivate static final String PROPERTY_KEY_SALESFORCE_USERNAME = \"salesforce.username\";\r\n\tprivate static final String PROPERTY_KEY_SALESFORCE_PASSWORD = \"salesforce.password\";\r\n\tprivate static final String PROPERTY_KEY_SALESFORCE_CLIENT_ID = \"salesforce.clientId\";\r\n\tprivate static final String PROPERTY_KEY_SALESFORCE_CLIENT_SECRET = \"salesforce.clientSecret\";\r\n\r\n\t/**\r\n\t * Salesforce oAuth2 request params\r\n\t */\r\n\tprivate static final String TOKEN_REQUEST_PARAM_USERNAME = \"username\";\r\n\tprivate static final String TOKEN_REQUEST_PARAM_PASSWORD = \"password\";\r\n\tprivate static final String TOKEN_REQUEST_PARAM_CLIENT_ID = \"client_id\";\r\n\tprivate static final String TOKEN_REQUEST_PARAM_GRANT_TYPE = \"grant_type\";\r\n\tprivate static final String TOKEN_REQUEST_PARAM_CLIENT_SECRET = \"client_secret\";\r\n\tprivate static final String TOKEN_REQUEST_PARAM_REFRESH_TOKEN = \"refresh_token\";\r\n\tprivate static final String TOKEN_REQUEST_PARAM_GRANT_TYPE_REFRESH = \"refresh_token\";\r\n\tprivate static final String TOKEN_REQUEST_RESPONSE_INVALID_SESSION = \"INVALID_SESSION_ID\";\r\n\tprivate static final String TOKEN_REQUEST_PARAM_GRANT_TYPE_PASSWORD = \"password\";\r\n\tprivate static final String TOKEN_REQUEST_RESPONSE_AUTHENTICATION_ERROR = \"Authentication error\";\r\n\r\n\t/**\r\n\t * Salesforce oAuth2 timeout\r\n\t */\r\n\tpublic static final Integer OAUTH_TOKEN_RETRY_TIMES = 1;\r\n\tpublic static final Integer OAUTH_TOKEN_REFRESH_IN_MINUTES = 15;\r\n\tpublic static final Integer OAUTH_READ_TIMEOUT_IN_SECONDS = 10;\r\n\tpublic static final Integer OAUTH_SOCKET_TIMEOUT_IN_SECONDS = 5;\r\n\tpublic static final Integer OAUTH_CONNECT_TIMEOUT_IN_SECONDS = 5;\r\n\r\n\t/**\r\n\t * Constants\r\n\t */\r\n\tprivate static final String SFDC_REFERENCE_ID = \"referenceId\";\r\n\tprivate static final String CF_IS_SYNCED_NAME = \"CF_ENTITY_IS_SYNCED\";\r\n\tprivate static final String CF_SFDC_INVOICE_ID = \"CF_SFDC_INVOICE_ID\";\r\n\tprivate static final String CF_SFDC_ATTACHMENT_ID = \"CF_SFDC_ATTACHMENT_ID\";\r\n\r\n\t/**\r\n\t * Syncing erros custom table SQL requests\r\n\t */\r\n\tprivate static final String DELETE_ERRORS_QUERY = \"DELETE FROM SYNCING_ERRORS WHERE entity_type='%s' AND entity_id = '%s'\";\r\n\tprivate static final String INSERT_ERRORS_QUERY = \"INSERT INTO SYNCING_ERRORS (entity_id, entity_code, entity_type, syncing_date, request_path_info, request_body, response_status, response_message, response_body) \"\r\n\t\t\t+ \"VALUES ('%s','%s', '%s', '%s','%s', '%s','%s','%s', '%s');\";\r\n\r\n\t/**\r\n\t * Salesforce oAuth2 token\r\n\t */\r\n\tprivate static Token token;\r\n\r\n\t/**\r\n\t * All core services used in the syncing process\r\n\t */\r\n\tprivate transient ParamBean paramBean = ((ParamBeanFactory) getServiceInterface(\"ParamBeanFactory\")).getInstance();\r\n\tprivate transient InvoiceService invoiceService = (InvoiceService) getServiceInterface(\"InvoiceService\");\r\n\tprivate transient AccountOperationService accountOperationService = (AccountOperationService) getServiceInterface(\"AccountOperationService\");\t\r\n\tprivate transient BaseEntityService baseEntityService = (BaseEntityService) getServiceInterface(\"BaseEntityService\");\r\n\tprivate transient EntityManager em = invoiceService.getEntityManager();\r\n\tprivate static final ResteasyClient client = new ResteasyClientProxyBuilder().build();\r\n\r\n\t/**\r\n\t * The main method called by the object updating/creating notifications\r\n\t */\r\n\t@Override\r\n\tpublic void execute(Map<String, Object> context) {\r\n\t\tObject object = context.get(Script.CONTEXT_ENTITY);\r\n\t\tif (!(object instanceof IEntity)) {\r\n\t\t\tlog.warn(\"<======== This object isn't configured to be synced : {}\", object);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tIEntity entity = (IEntity) object;\r\n\t\tClass clazz = ReflectionUtils.getClassBySimpleNameAndParentClass(entity.getClass().getSimpleName(), BaseEntity.class);\r\n\t\tbaseEntityService.setEntityClass(clazz);\r\n\t\t\r\n\t\tentity = baseEntityService.retrieveIfNotManaged(entity);\r\n\t\tlog.info(\"========> Start syncing the entity : {}[id={}]  ...............\", entity.getClass().getSimpleName(), ((IEntity) entity).getId());\r\n\r\n\t\ttry {\r\n\t\t\tif (entity instanceof Invoice) {\r\n\t\t\t\tsendInvoice((Invoice) entity);\r\n\t\t\t\tsendPDF((Invoice) entity);\r\n\t\t\t} else if (entity instanceof Subscription) {\r\n\t\t\t\tsendSubscription((Subscription) entity);\r\n\t\t\t} else if (entity instanceof MatchingCode) {\r\n\t\t\t\tsendMatchingCode((MatchingCode) entity);\r\n\t\t\t} else if (entity instanceof AccountOperation) {\r\n\t\t\t\tsendAccountOperation((AccountOperation) entity);\r\n\t\t\t} else {\r\n\t\t\t\tlog.warn(\"<======== This entity isn't configured to be synced : {}\", entity);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tlog.info(\"<======== This entity has successfully been synced : {}\", entity);\r\n\r\n\t\t} catch (SObjectSyncingException ex) {\r\n\t\t\tlog.error(\"<======== \" + ex.getMessage());\r\n\t\t} catch (Exception ex) {\r\n\t\t\tregisterResult(entity, null, null, null, ex.getMessage(), false);\r\n\t\t\tlog.error(\"<======== Generic error thrown during entity sending : {} => {} \", entity, ex.getMessage());\r\n\t\t} finally {\r\n\t\t\tentity = this.baseEntityService.updateNoCheck(entity);\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Sends Subscription object to SFDC\r\n\t * \r\n\t * @param subscription\r\n\t */\r\n\tprivate void sendSubscription(Subscription subscription) {\r\n\r\n\t\tCompositeSubRequestDto subscriptionReq = new CompositeSubRequestDto();\r\n\t\tsubscriptionReq.setMethod(HttpMethod.PATCH);\r\n\t\tsubscriptionReq.setReferenceId(SFDC_REFERENCE_ID);\r\n\t\tsubscriptionReq.setBody(toSubscriptionJson(subscription));\r\n\t\tsubscriptionReq.setUrl(getEndPoint(END_POINT_SOBJECT_SUBSCRIPTION, \"OCCode\", subscription.getCode()));\r\n\r\n\t\tCompositeRequestDto request = new CompositeRequestDto();\r\n\t\trequest.setAllOrNone(true);\r\n\t\trequest.addSubRequest(subscriptionReq);\r\n\t\trequest.setCollateSubrequests(true);\r\n\r\n\t\tsendRequest(request, subscription, null);\r\n\t}\r\n\r\n\t/**\r\n\t * Sends invoice object to SFDC\r\n\t * \r\n\t * @param invoice\r\n\t */\r\n\tprivate void sendInvoice(Invoice invoice) {\r\n\r\n\t\tCompositeSubRequestDto invoiceReq = new CompositeSubRequestDto();\r\n\t\tinvoiceReq.setMethod(HttpMethod.PATCH);\r\n\t\tinvoiceReq.setReferenceId(SFDC_REFERENCE_ID);\r\n\t\tinvoiceReq.setBody(toInvoiceJson(invoice));\r\n\t\tinvoiceReq.setUrl(getEndPoint(END_POINT_SOBJECT_INVOICE, \"Id\", invoice.getId()));\r\n\r\n\t\tCompositeRequestDto request = new CompositeRequestDto();\r\n\t\trequest.setAllOrNone(true);\r\n\t\trequest.addSubRequest(invoiceReq);\r\n\t\trequest.setCollateSubrequests(false);\r\n\r\n\t\tsendRequest(request, invoice, CF_SFDC_INVOICE_ID);\r\n\t}\r\n\r\n\t/**\r\n\t * Sends invoice pdf to SFDC, we start by deleting old pdf because the patch based on the external id is not working with the attachment object\r\n\t * \r\n\t * @param invoice\r\n\t */\r\n\tprivate void sendPDF(Invoice invoice) {\r\n\r\n\t\tif (invoiceService.isInvoicePdfExist(invoice)) {\r\n\t\t\tCompositeRequestDto request = new CompositeRequestDto();\r\n\t\t\tObject invoiceId = invoice.getCfValue(CF_SFDC_INVOICE_ID);\r\n\t\t\tif (invoiceId instanceof String) {\r\n\t\t\t\tObject attachmentId = invoice.getCfValue(CF_SFDC_ATTACHMENT_ID);\r\n//\t\t\t\tif (attachmentId instanceof String) {\r\n//\t\t\t\t\tCompositeSubRequestDto delAttachmentReq = new CompositeSubRequestDto();\r\n//\t\t\t\t\tdelAttachmentReq.setMethod(HttpMethod.DELETE);\r\n//\t\t\t\t\tdelAttachmentReq.setReferenceId(\"refDelAttachment\");\r\n//\t\t\t\t\tdelAttachmentReq.setUrl(getEndPoint(END_POINT_SOBJECT_ATTACHMENT) + \"/\" + attachmentId);\r\n//\t\t\t\t\trequest.addSubRequest(delAttachmentReq);\r\n//\t\t\t\t}\r\n\t\t\t\tif (!(attachmentId instanceof String)) {\r\n\t\t\t\t\tCompositeSubRequestDto attachmentReq = new CompositeSubRequestDto();\r\n\t\t\t\t\tattachmentReq.setMethod(HttpMethod.POST);\r\n\t\t\t\t\tattachmentReq.setReferenceId(SFDC_REFERENCE_ID);\r\n\t\t\t\t\tattachmentReq.setUrl(getEndPoint(END_POINT_SOBJECT_ATTACHMENT));\r\n\t\t\t\t\tattachmentReq.setBody(toAttachmentJson(invoice, (String) invoiceId));\r\n\t\t\t\t\trequest.addSubRequest(attachmentReq);\r\n\r\n\t\t\t\t\trequest.setAllOrNone(false);\r\n\t\t\t\t\trequest.setCollateSubrequests(false);\r\n\t\t\t\t\tsendRequest(request, invoice, CF_SFDC_ATTACHMENT_ID);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Sends an accountOperation object to SFDC\r\n\t * \r\n\t * @param accountOperation\r\n\t */\r\n\tprivate void sendAccountOperation(AccountOperation accountOperation) {\r\n\r\n\t\tCompositeSubRequestDto paymentReq = new CompositeSubRequestDto();\r\n\t\tpaymentReq.setUrl(getEndPoint(END_POINT_SOBJECT_ACCOUNT_OPERATION, \"Id\", accountOperation.getId()));\r\n\t\tpaymentReq.setMethod(HttpMethod.PATCH);\r\n\t\tpaymentReq.setReferenceId(SFDC_REFERENCE_ID);\r\n\t\tpaymentReq.setBody(toAccountOperationJson(accountOperation));\r\n\r\n\t\tCompositeRequestDto request = new CompositeRequestDto();\r\n\t\trequest.setAllOrNone(true);\r\n\t\trequest.addSubRequest(paymentReq);\r\n\t\trequest.setCollateSubrequests(true);\r\n\r\n\t\tsendRequest(request, accountOperation, null);\r\n\t}\r\n\r\n\t/**\r\n\t * Updates the AO already sent to SFDC after been matched on OC\r\n\t * \r\n\t * @param matchingCode\r\n\t */\r\n\tprivate void sendMatchingCode(MatchingCode matchingCode) {\r\n\t\tif (matchingCode.getMatchingAmounts() != null && !matchingCode.getMatchingAmounts().isEmpty()) {\r\n\t\t\tfor (MatchingAmount matchingAmount : matchingCode.getMatchingAmounts()) {\r\n\t\t\t\tif (matchingAmount != null && matchingAmount.getAccountOperation() != null) {\r\n\t\t\t\t\tAccountOperation accountOperation = matchingAmount.getAccountOperation();\r\n\t\t\t\t\taccountOperation = (AccountOperation) baseEntityService.retrieveIfNotManaged(accountOperation);\r\n\t\t\t\t\tlog.info(\" --- [MatchingCode] : syncing the AO : {}  ...............\", accountOperation);\r\n\t\t\t\t\tsendAccountOperation(accountOperation);\r\n\t\t\t\t\tif (accountOperation instanceof RecordedInvoice && ((RecordedInvoice) accountOperation).getInvoice() != null) {\r\n\t\t\t\t\t\tInvoice invoice = ((RecordedInvoice) accountOperation).getInvoice();\r\n\t\t\t\t\t\tinvoice = (Invoice) baseEntityService.retrieveIfNotManaged(invoice);\r\n\t\t\t\t\t\tlog.info(\" --- [Matched invoice] : syncing the matched invoice : {}  ...............\", invoice);\r\n\t\t\t\t\t\tsendInvoice(invoice);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Send composite request to salesforce\r\n\t * \r\n\t * @param request\r\n\t * @param entity\r\n\t * @param cfName\r\n\t */\r\n\tprivate void sendRequest(CompositeRequestDto request, IEntity entity, String cfName) {\r\n\r\n\t\tint cp = 1;\r\n\t\tString targetUri = \"\";\r\n\t\tString instanceUrl = \"\";\r\n\t\tString authorization = \"\";\r\n\t\tResponse response = null;\r\n\t\tboolean isAuthenticated = false;\r\n\t\tString exceptionMessage = \"\";\r\n\r\n\t\tdo {\r\n\t\t\ttry {\r\n\t\t\t\tif (token == null) {\r\n\t\t\t\t\tisAuthenticated = this.authenticate();\r\n\t\t\t\t}\r\n\t\t\t\tif (token != null) {\r\n\t\t\t\t\tinstanceUrl = token.getInstanceUrl();\r\n\t\t\t\t\tauthorization = token.getAuth();\r\n\t\t\t\t}\r\n\t\t\t\ttargetUri = instanceUrl + getEndPoint(END_POINT_RESOURCE_COMPOSITE);\r\n\t\t\t\tlogRequest(targetUri, request);\r\n\t\t\t\tResteasyWebTarget target = client.target(targetUri);\r\n\t\t\t\tInvocation.Builder requestBuilder = target.request();\r\n\t\t\t\trequestBuilder = requestBuilder.header(HttpHeaders.AUTHORIZATION, authorization);\r\n\t\t\t\tlog.debug(\"request to send :\"+Entity.json(JsonUtils.toJson(request, false)));\r\n\t\t\t\tresponse = requestBuilder.post((Entity.json(JsonUtils.toJson(request, false))));\r\n\t\t\t\tprocessResponse(entity, cfName, request, response);\r\n\t\t\t\tisAuthenticated = true;\r\n\t\t\t} catch (ProcessingException ex) {\r\n\t\t\t\tex.printStackTrace();\r\n\t\t\t\texceptionMessage = ex.getMessage();\r\n\t\t\t\tlog.error(\"Error invoking target {} with request {} =>  {}\", targetUri, request, exceptionMessage);\r\n\t\t\t\tisAuthenticated = this.authenticate();\r\n\t\t\t} catch (SObjectSyncingException ex) {\r\n\t\t\t\tex.printStackTrace();\r\n\t\t\t\tif (ex.getMessage() != null && ex.getMessage().contains(TOKEN_REQUEST_RESPONSE_AUTHENTICATION_ERROR)) {\r\n\t\t\t\t\ttoken = null;\r\n\t\t\t\t\tcontinue;\r\n\t\t\t\t}\r\n\t\t\t\tthrow ex;\r\n\t\t\t} catch (Exception ex) {\r\n\t\t\t\tex.printStackTrace();\r\n\t\t\t\tlog.error(\"Error invoking target {} with request {} =>  {}\", targetUri, request, ex.getMessage());\r\n\t\t\t\tregisterResult(entity, request, null, response, ex.getMessage(), false);\r\n\t\t\t\tthrow new SObjectSyncingException(ErrorMessage.ENTITY_SYNCING_ERROR, entity, ex.getMessage());\r\n\t\t\t}\r\n\r\n\t\t} while (!isAuthenticated && cp++ < OAUTH_TOKEN_RETRY_TIMES);\r\n\r\n\t\tif (!isAuthenticated) {\r\n\t\t\tlog.error(\"Failed to invoke target {} with request {} After {} attempts  =>  {}\", targetUri, request, OAUTH_TOKEN_RETRY_TIMES, exceptionMessage);\r\n\t\t\tregisterResult(entity, request, null, response, exceptionMessage, false);\r\n\t\t\tthrow new SObjectSyncingException(ErrorMessage.ENTITY_SYNCING_ERROR, entity, exceptionMessage);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Process the Salesforce syncing response\r\n\t * \r\n\t * @param entity\r\n\t * @param cfName to store the SF id on Opencell\r\n\t * @param request\r\n\t * @param response\r\n\t */\r\n\tprivate void processResponse(IEntity entity, String cfName, CompositeRequestDto request, Response response) {\r\n\r\n\t\tString jsonResponse = response.readEntity(String.class);\r\n\t\tif (log.isDebugEnabled()) {\r\n\t\t\tlog.debug(\"Json Response : [{}:{}] => {}\", response.getStatus(), response.getStatusInfo().getReasonPhrase(), jsonResponse);\r\n\t\t}\r\n\r\n\t\tif (isSuccessResponse(response)) {\r\n\t\t\tResponseDto result = JsonUtils.toObject(jsonResponse, ResponseDto.class);\r\n\t\t\tboolean isSuccess = result.isRequestSuccess(SFDC_REFERENCE_ID);\r\n\t\t\tregisterResult(entity, request, null, response, jsonResponse, isSuccess);\r\n\t\t\tif (!isSuccess) {\r\n\t\t\t\tif (jsonResponse.contains(TOKEN_REQUEST_RESPONSE_INVALID_SESSION)) {\r\n\t\t\t\t\tthrow new SObjectSyncingException(ErrorMessage.AUTHENTICATION_ERROR, response.getStatus(), response.getStatusInfo().getReasonPhrase(), jsonResponse);\r\n\t\t\t\t} else {\r\n\t\t\t\t\t  throw new SObjectSyncingException(ErrorMessage.ENTITY_SYNCING_ERROR, entity, result);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (cfName != null && entity instanceof ICustomFieldEntity) {\r\n\t\t\t\t((ICustomFieldEntity) entity).setCfValue(cfName, result.getSObjectId(SFDC_REFERENCE_ID));\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tJSONArray errorResponse = JsonUtils.toObject(jsonResponse, JSONArray.class);\r\n\t\t\tregisterResult(entity, request, null, response, jsonResponse, false);\r\n\t\t\tif (jsonResponse.contains(TOKEN_REQUEST_RESPONSE_INVALID_SESSION)) {\r\n\t\t\t\tthrow new SObjectSyncingException(ErrorMessage.AUTHENTICATION_ERROR, response.getStatus(), response.getStatusInfo().getReasonPhrase(), jsonResponse);\r\n\t\t\t} else {\r\n\t\t\t  throw new SObjectSyncingException(ErrorMessage.ENTITY_SYNCING_ERROR, entity, errorResponse);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Allows to register the syncing process result on the system espacially the syncing status to avoid to resync the objects already synced next iteration.\r\n\t * \r\n\t * @param service\r\n\t * @param entity\r\n\t * @param isSynced\r\n\t */\r\n\tprivate void registerResult(IEntity entity, CompositeRequestDto request, String jsonRequest, Response response, String jsonResponse, boolean isSynced) {\r\n\r\n\t\tif (entity instanceof ICustomFieldEntity) {\r\n\t\t\t((ICustomFieldEntity) entity).setCfValue(CF_IS_SYNCED_NAME, isSynced);\r\n\t\t}\r\n\r\n\t\tString entityId = \"-\";\r\n\t\tString entityType = \"-\";\r\n\t\tString queryToExecute = null;\r\n\t\tString endPoint = (token != null ? token.getInstanceUrl() : \"\") + getEndPoint(END_POINT_RESOURCE_COMPOSITE);\r\n\r\n\t\tif (entity == null) { // Token case\r\n\t\t\tentityType = \"Token\";\r\n\t\t} else {\r\n\t\t\tentityType = entity.getClass().getName();\r\n\t\t\tentityId = entity.getId() + \"\";\r\n\t\t}\r\n\r\n\t\tif (isSynced) {\r\n\t\t\tqueryToExecute = String.format(DELETE_ERRORS_QUERY, entityType, entityId);\r\n\t\t} else {\r\n\r\n\t\t\tString entityCode = \"-\";\r\n\t\t\tString requestBody = \"-\";\r\n\t\t\tString responseBody = \"-\";\r\n\t\t\tString responseStatus = \"-\";\r\n\t\t\tString responseMessage = \"-\";\r\n\t\t\tString requestEndPoint = endPoint;\r\n\t\t\tString lastSyncingDate = this.formatAsTime(new Date());\r\n\r\n\t\t\tif (entity instanceof BusinessEntity) {\r\n\t\t\t\tentityCode = ((BusinessEntity) entity).getCode();\r\n\t\t\t}\r\n\t\t\tif (entity instanceof Invoice) {\r\n\t\t\t\tentityCode = ((Invoice) entity).getInvoiceNumber();\r\n\t\t\t}\r\n\t\t\tif (request != null) {\r\n\t\t\t\trequestBody = JsonUtils.toJson(request, false);\r\n\t\t\t}\r\n\t\t\tif (jsonRequest != null) {\r\n\t\t\t\trequestBody = jsonRequest;\r\n\t\t\t}\r\n\t\t\tif (response != null) {\r\n\t\t\t\tresponseStatus = response.getStatus() + \"\";\r\n\t\t\t\tresponseMessage = response.getStatusInfo() == null ? responseMessage : response.getStatusInfo().getReasonPhrase();\r\n\t\t\t}\r\n\t\t\tif (jsonResponse != null) {\r\n\t\t\t\tresponseBody = jsonResponse;\r\n\t\t\t}\r\n\r\n\t\t\tqueryToExecute = String.format(INSERT_ERRORS_QUERY, entityId, entityCode, entityType, lastSyncingDate, requestEndPoint, requestBody, responseStatus, responseMessage,\r\n\t\t\t\tresponseBody);\r\n\t\t}\r\n\r\n\t\tif (queryToExecute != null) {\r\n\t\t\t/*Query query = em.createNativeQuery(queryToExecute);\r\n\t\t\tif (query != null) {\r\n\t\t\t\tquery.executeUpdate();\r\n\t\t\t}*/\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Logs the request sent to SFDC\r\n\t * \r\n\t * @param endPoint\r\n\t * @param request\r\n\t */\r\n\tprivate void logRequest(String endPoint, CompositeRequestDto request) {\r\n\t\tif (log.isDebugEnabled()) {\r\n\t\t\tString jsonBody = JsonUtils.toJson(request, false);\r\n\t\t\tlog.debug(\"Calling target=[{}] with request=[{}]\", endPoint, jsonBody);\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Checks if is success response.\r\n\t *\r\n\t * @param response the response\r\n\t * @return true, if is success response\r\n\t */\r\n\tprivate boolean isSuccessResponse(Response response) {\r\n\t\treturn Response.Status.Family.SUCCESSFUL == response.getStatusInfo().getFamily();\r\n\t}\r\n\r\n\t/**\r\n\t * Put the right version & the external ID in the endPoint param\r\n\t * \r\n\t * @param endPoint\r\n\t * @return\r\n\t */\r\n\tprivate String getEndPoint(String endPoint, String fieldName, Object fieldValue) {\r\n\t\treturn this.getEndPoint(endPoint) + \"/opencell__\" + fieldName + \"__c/\" + fieldValue;\r\n\t}\r\n\r\n\tprivate String getEndPoint(String endPoint) {\r\n\t\treturn endPoint.replace(\"{{version}}\", END_POINT_API_VERSION);\r\n\t}\r\n\r\n\t/**\r\n\t * All the oAuth2 process is done in this method\r\n\t */\r\n\tprivate boolean authenticate() {\r\n\t\ttry {\r\n\t\t\tfinal String tokenRequetsUrl = this.getMandatoryParam(PROPERTY_KEY_SALESFORCE_URL) + END_POINT_TOKEN_REQUEST;\r\n\t\t\tResteasyWebTarget resourceTarget = client.target(tokenRequetsUrl);\r\n\r\n\t\t\tForm form = buildTokenRequest();\r\n\t\t\tif (log.isDebugEnabled()) {\r\n\t\t\t\tlog.debug(\"A token request will be sent... {}\", securedLog(form));\r\n\t\t\t}\r\n\r\n\t\t\tResponse response = resourceTarget.request().post(Entity.form(form), Response.class);\r\n\t\t\tString jsonResponse = response.readEntity(String.class);\r\n\r\n\t\t\tboolean isSuccess = isSuccessResponse(response);\r\n\t\t\tregisterResult(null, null, securedLog(form), response, jsonResponse, isSuccess);\r\n\t\t\tif (isSuccess) {\r\n\t\t\t\ttoken = JsonUtils.toObject(jsonResponse, Token.class);\r\n\t\t\t\tif (log.isDebugEnabled()) {\r\n\t\t\t\t\tlog.debug(\"A new token has successfully been obtained : {}\", token);\r\n\t\t\t\t}\r\n\t\t\t\treturn true;\r\n\t\t\t} else {\r\n\t\t\t\tthrow new SObjectSyncingException(ErrorMessage.AUTHENTICATION_ERROR, response.getStatus(), response.getStatusInfo().getReasonPhrase(), jsonResponse);\r\n\t\t\t}\r\n\r\n\t\t} catch (SObjectSyncingException e) {\r\n\t\t\tthrow e;\r\n\t\t} catch (Exception e) {\r\n\t\t\tregisterResult(null, null, null, null, e.getMessage(), false);\r\n\t\t\tthrow new SObjectSyncingException(ErrorMessage.AUTHENTICATION_ERROR_UNKNOWN, e.getMessage());\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Secures Request form params to log them\r\n\t * \r\n\t * @param form\r\n\t * @return\r\n\t */\r\n\tprivate String securedLog(Form form) {\r\n\t\tif (form == null || form.asMap() == null) {\r\n\t\t\treturn \"\";\r\n\t\t}\r\n\r\n\t\tMap<String, String> result = new HashMap<>();\r\n\t\tMultivaluedMap<String, String> map = form.asMap();\r\n\t\tfor (Map.Entry<String, List<String>> entry : map.entrySet()) {\r\n\t\t\tif (entry.getValue() != null && !entry.getValue().isEmpty()) {\r\n\t\t\t\tresult.put(entry.getKey(), maskString(entry.getValue().get(0)));\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn result.toString();\r\n\t}\r\n\r\n\t/**\r\n\t * Masks a part of the string param\r\n\t * \r\n\t * @param stringToMask\r\n\t * @return\r\n\t */\r\n\tprivate static String maskString(String stringToMask) {\r\n\t\tif (stringToMask != null && stringToMask.length() >= 8) {\r\n\t\t\treturn new StringBuilder(stringToMask.substring(0, 4)).append(org.apache.commons.lang3.StringUtils.repeat('*', stringToMask.length() - 8))\r\n\t\t\t\t.append(stringToMask.substring(stringToMask.length() - 4)).toString();\r\n\t\t}\r\n\t\treturn \"\";\r\n\t}\r\n\r\n\t/**\r\n\t * Reads the configuration from the system properties and builds the token request based on.\r\n\t * \r\n\t * @return\r\n\t */\r\n\tprivate Form buildTokenRequest() {\r\n\t\tfinal String username = this.getMandatoryParam(PROPERTY_KEY_SALESFORCE_USERNAME);\r\n\t\tfinal String password = this.getMandatoryParam(PROPERTY_KEY_SALESFORCE_PASSWORD);\r\n\t\tfinal String clientId = this.getMandatoryParam(PROPERTY_KEY_SALESFORCE_CLIENT_ID);\r\n\t\tfinal String clientSecret = this.getMandatoryParam(PROPERTY_KEY_SALESFORCE_CLIENT_SECRET);\r\n\r\n\t\tForm request = new Form();\r\n\t\trequest.param(TOKEN_REQUEST_PARAM_USERNAME, username);\r\n\t\trequest.param(TOKEN_REQUEST_PARAM_PASSWORD, password);\r\n\t\trequest.param(TOKEN_REQUEST_PARAM_CLIENT_ID, clientId);\r\n\t\trequest.param(TOKEN_REQUEST_PARAM_CLIENT_SECRET, clientSecret);\r\n\t\trequest.param(TOKEN_REQUEST_PARAM_GRANT_TYPE, TOKEN_REQUEST_PARAM_GRANT_TYPE_PASSWORD);\r\n\r\n\t\treturn request;\r\n\t}\r\n\r\n\t/**\r\n\t * Reads the configuration from the system properties and builds the refresh token request based on. NOT SUPPORTED YET BY SFDC\r\n\t * \r\n\t * @return\r\n\t */\r\n\tprivate Form buildTokenRefresh() {\r\n\t\tfinal String clientId = this.getMandatoryParam(PROPERTY_KEY_SALESFORCE_CLIENT_ID);\r\n\t\tfinal String clientSecret = this.getMandatoryParam(PROPERTY_KEY_SALESFORCE_CLIENT_SECRET);\r\n\r\n\t\tForm request = new Form();\r\n\t\trequest.param(TOKEN_REQUEST_PARAM_CLIENT_ID, clientId);\r\n\t\trequest.param(TOKEN_REQUEST_PARAM_CLIENT_SECRET, clientSecret);\r\n\t\trequest.param(TOKEN_REQUEST_PARAM_REFRESH_TOKEN, token.getAccessToken());\r\n\t\trequest.param(TOKEN_REQUEST_PARAM_GRANT_TYPE, TOKEN_REQUEST_PARAM_GRANT_TYPE_REFRESH);\r\n\r\n\t\treturn request;\r\n\t}\r\n\r\n\t/**\r\n\t * Build the subscription json to send to SFDC\r\n\t * \r\n\t * @param subscription\r\n\t * @return\r\n\t */\r\n\tprivate JsonObject toSubscriptionJson(Subscription subscription) {\r\n\r\n\t\tJsonObject subscriptionJson = new JsonObject();\r\n\t\tsubscriptionJson.addProperty(\"opencell__Id__c\", subscription.getId());\r\n\t\tsubscriptionJson.addProperty(\"opencell__Code__c\", subscription.getCode());\r\n\t\tsubscriptionJson.addProperty(\"opencell__Description__c\", subscription.getDescription());\r\n\r\n\t\tif (subscription.getOffer() != null) {\r\n\t\t\tsubscriptionJson.addProperty(\"opencell__OfferCode__c\", subscription.getOffer().getCode());\r\n\t\t\tsubscriptionJson.addProperty(\"opencell__OfferDescription__c\", subscription.getOffer().getDescription());\r\n\t\t}\r\n\t\tif (subscription.getStatus() != null) {\r\n\t\t\tsubscriptionJson.addProperty(\"opencell__Status__c\", subscription.getStatus().name());\r\n\t\t}\r\n\t\tif (subscription.getUserAccount() != null) {\r\n\t\t\tCustomer customer = subscription.getUserAccount().getBillingAccount().getCustomerAccount().getCustomer();\r\n\t\t\tif (customer != null && StringUtils.isNotBlank(customer.getExternalRef1())) {\r\n\t\t\t\tsubscriptionJson.addProperty(\"opencell__AccountID__c\", customer.getExternalRef1());\r\n\t\t\t} else {\r\n\t\t\t\tsubscriptionJson.addProperty(\"opencell__AccountID__c\", subscription.getUserAccount().getCode());\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (subscription.getStatusDate() != null) {\r\n\t\t\tsubscriptionJson.addProperty(\"opencell__StatusDate__c\", this.formatAsDate(subscription.getStatusDate()));\r\n\t\t}\r\n\t\tif (subscription.getSubscriptionDate() != null) {\r\n\t\t\tsubscriptionJson.addProperty(\"opencell__subscriptionDate__c\", this.formatAsDate(subscription.getSubscriptionDate()));\r\n\t\t}\r\n\t\tif (subscription.getTerminationDate() != null) {\r\n\t\t\tsubscriptionJson.addProperty(\"opencell__TerminationDate__c\", this.formatAsDate(subscription.getTerminationDate()));\r\n\t\t}\r\n\t\tif (subscription.getEndAgreementDate() != null) {\r\n\t\t\tsubscriptionJson.addProperty(\"opencell__EndAgreementDate__c\", this.formatAsDate(subscription.getEndAgreementDate()));\r\n\t\t}\r\n\t\tif (subscription.getSubscribedTillDate() != null) {\r\n\t\t\tsubscriptionJson.addProperty(\"opencell__SubscribedTillDate__c\", this.formatAsDate(subscription.getSubscribedTillDate()));\r\n\t\t}\r\n\t\tif (subscription.getSubscriptionTerminationReason() != null) {\r\n\t\t\tsubscriptionJson.addProperty(\"opencell__SubscriptionTerminationReason__c\", subscription.getSubscriptionTerminationReason().getCode());\r\n\t\t}\r\n\r\n\t\treturn subscriptionJson;\r\n\t}\r\n\r\n\t/**\r\n\t * Build the invoice json to send to SFDC\r\n\t * \r\n\t * @param invoice\r\n\t * @return\r\n\t */\r\n\tprivate JsonObject toInvoiceJson(Invoice invoice) {\r\n\t\tboolean isAdjInvoice = invoice.getInvoiceType().getCode().equals(\"ADJ\");\r\n\t\tBigDecimal netToPay = invoice.getNetToPay();\r\n\r\n\t\tJsonObject invoiceJson = new JsonObject();\r\n\t\tinvoiceJson.addProperty(\"opencell__DueBalance__c\", invoice.getDueBalance());\r\n\t\tinvoiceJson.addProperty(\"opencell__AmountTax__c\", invoice.getAmountTax());\r\n\t\tinvoiceJson.addProperty(\"opencell__Amount_With_Tax__c\", invoice.getAmountWithTax());\r\n\t\tinvoiceJson.addProperty(\"opencell__Amount_Without_Tax__c\", invoice.getAmountWithoutTax());\r\n\t\tinvoiceJson.addProperty(\"opencell__InvoiceNumber__c\", invoice.getInvoiceNumber());\r\n\t\tinvoiceJson.addProperty(\"opencell__NetToPay__c\", netToPay);\r\n\t\t// Deprecated\r\n\t\tinvoiceJson.addProperty(\"opencell__Invoice_Number_del__c\", invoice.getInvoiceNumber());\r\n\t\tif (invoice.getStatus() != null) {\r\n\t\t\tinvoiceJson.addProperty(\"opencell__Status__c\", invoice.getStatus().name());\r\n\t\t}\r\n\t\tif (invoice.getSubscription() != null) {\r\n\t\t\tinvoiceJson.addProperty(\"opencell__SubscriptionId__c\", invoice.getSubscription().getId());\r\n\t\t\tinvoiceJson.addProperty(\"opencell__ExternalRef__c\", invoice.getSubscription().getCode());\r\n\t\t}\r\n\t\tif (invoice.getPaymentMethodType() != null) {\r\n\t\t\tinvoiceJson.addProperty(\"opencell__PaymentMethod__c\", invoice.getPaymentMethodType().name());\r\n\t\t}\r\n\t\tif (invoice.getBillingAccount() != null) {\r\n\t\t\tCustomer customer = invoice.getBillingAccount().getCustomerAccount().getCustomer();\r\n\t\t\tif (customer != null && StringUtils.isNotBlank(customer.getExternalRef1())) {\r\n\t\t\t\tinvoiceJson.addProperty(\"opencell__Account_Name__c\", customer.getExternalRef1());\r\n\t\t\t} else {\r\n\t\t\t\tinvoiceJson.addProperty(\"opencell__Account_Name__c\", invoice.getBillingAccount().getCode());\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (invoice.getDueDate() != null) {\r\n\t\t\tinvoiceJson.addProperty(\"opencell__DueDate__c\", this.formatAsDate(invoice.getDueDate()));\r\n\t\t}\r\n\t\tif (invoice.getInvoiceDate() != null) {\r\n\t\t\tinvoiceJson.addProperty(\"opencell__Invoice_Date__c\", this.formatAsDate(invoice.getInvoiceDate()));\r\n\t\t}\r\n\t\tif (invoice.getInvoiceType() != null) {\r\n\t\t\tinvoiceJson.addProperty(\"opencell__InvoiceType__c\", invoice.getInvoiceType().getCode());\r\n\t\t}\r\n\t\tif (invoice.getCfValue(\"CF_COMMENT\") instanceof String) {\r\n\t\t\tinvoiceJson.addProperty(\"opencell__Comment__c\", (String) invoice.getCfValue(\"CF_COMMENT\"));\r\n\t\t}\r\n\r\n\t\treturn invoiceJson;\r\n\t}\r\n\r\n\t/**\r\n\t * Build the accountOperation json to send to SFDC\r\n\t * \r\n\t * @param accountOperation\r\n\t * @return\r\n\t */\r\n\tprivate JsonObject toAccountOperationJson(AccountOperation accountOperation) {\r\n\r\n\t\tJsonObject accountOperationJson = new JsonObject();\r\n\t\taccountOperationJson.addProperty(\"opencell__Code__c\", accountOperation.getCode());\r\n\t\taccountOperationJson.addProperty(\"opencell__Type__c\", accountOperation.getType());\r\n\t\taccountOperationJson.addProperty(\"opencell__Amount__c\", accountOperation.getAmount());\r\n\t\taccountOperationJson.addProperty(\"opencell__BankLot__c\", accountOperation.getBankLot());\r\n\t\taccountOperationJson.addProperty(\"opencell__Reference__c\", accountOperation.getReference());\r\n\t\taccountOperationJson.addProperty(\"opencell__TaxAmount__c\", accountOperation.getTaxAmount());\r\n\t\taccountOperationJson.addProperty(\"opencell__Description__c\", accountOperation.getDescription());\r\n\t\taccountOperationJson.addProperty(\"opencell__BankReference__c\", accountOperation.getBankReference());\r\n\t\taccountOperationJson.addProperty(\"opencell__MatchedAmount__c\", accountOperation.getMatchingAmount());\r\n\t\taccountOperationJson.addProperty(\"opencell__UnmatchedAmount__c\", accountOperation.getUnMatchingAmount());\r\n\t\taccountOperationJson.addProperty(\"opencell__AmountWithoutTax__c\", accountOperation.getAmountWithoutTax());\r\n\t\tif (accountOperation.getDueDate() != null) {\r\n\t\t\taccountOperationJson.addProperty(\"opencell__DueDate__c\", this.formatAsDate(accountOperation.getDueDate()));\r\n\t\t}\r\n\t\tif (accountOperation.getDepositDate() != null) {\r\n\t\t\taccountOperationJson.addProperty(\"opencell__DepositDate__c\", this.formatAsDate(accountOperation.getDepositDate()));\r\n\t\t}\r\n\t\tif (accountOperation.getTransactionDate() != null) {\r\n\t\t\taccountOperationJson.addProperty(\"opencell__TransactionDate__c\", this.formatAsDate(accountOperation.getTransactionDate()));\r\n\t\t}\r\n\t\tif (accountOperation.getBankCollectionDate() != null) {\r\n\t\t\taccountOperationJson.addProperty(\"opencell__BankCollectionDate__c\", this.formatAsDate(accountOperation.getBankCollectionDate()));\r\n\t\t}\r\n\t\tif (accountOperation.getPaymentMethod() != null) {\r\n\t\t\taccountOperationJson.addProperty(\"opencell__PaymentMethod__c\", accountOperation.getPaymentMethod().name());\r\n\t\t}\r\n\t\tif (accountOperation.getAccountingCode() != null) {\r\n\t\t\taccountOperationJson.addProperty(\"opencell__AccountingCode__c\", accountOperation.getAccountingCode().getCode());\r\n\t\t}\r\n\t\tif (accountOperation.getMatchingStatus() != null) {\r\n\t\t\taccountOperationJson.addProperty(\"opencell__MatchingStatus__c\", accountOperation.getMatchingStatus().name());\r\n\t\t}\r\n\t\tif (accountOperation.getCustomerAccount() != null) {\r\n\t\t\tCustomer customer = accountOperation.getCustomerAccount().getCustomer();\r\n\t\t\tif (customer != null && StringUtils.isNotBlank(customer.getExternalRef1())) {\r\n\t\t\t\taccountOperationJson.addProperty(\"opencell__AccountId__c\", customer.getExternalRef1());\r\n\t\t\t} else {\r\n\t\t\t\taccountOperationJson.addProperty(\"opencell__AccountId__c\", accountOperation.getCustomerAccount().getCode());\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (accountOperation.getTransactionCategory() != null) {\r\n\t\t\taccountOperationJson.addProperty(\"opencell__Category__c\", accountOperation.getTransactionCategory().name());\r\n\t\t}\r\n\r\n\t\tif (accountOperation instanceof Payment) {\r\n\t\t\taccountOperationJson.addProperty(\"opencell__Fees__c\", ((Payment) accountOperation).getFees());\r\n\t\t\taccountOperationJson.addProperty(\"opencell__Comment__c\", ((Payment) accountOperation).getComment());\r\n\t\t}\r\n\t\tif (accountOperation instanceof RejectedPayment) {\r\n\t\t\tRejectedPayment rejectedPayment = (RejectedPayment) accountOperation;\r\n\t\t\taccountOperationJson.addProperty(\"opencell__RejectedCode__c\", rejectedPayment.getRejectedCode());\r\n\t\t\taccountOperationJson.addProperty(\"opencell__RejectedDescription__c\", rejectedPayment.getRejectedDescription());\r\n\t\t\tif (rejectedPayment.getRejectedType() != null) {\r\n\t\t\t\taccountOperationJson.addProperty(\"opencell__RejectedType__c\", rejectedPayment.getRejectedType().name());\r\n\t\t\t}\r\n\t\t\tif (rejectedPayment.getRejectedDate() != null) {\r\n\t\t\t\taccountOperationJson.addProperty(\"opencell__RejectedDate__c\", this.formatAsDate(rejectedPayment.getRejectedDate()));\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (accountOperation instanceof RecordedInvoice) {\r\n\t\t\tRecordedInvoice recordedInvoice = (RecordedInvoice) accountOperation;\r\n\t\t\taccountOperationJson.addProperty(\"opencell__NetToPay__c\", recordedInvoice.getNetToPay());\r\n\t\t\tif (recordedInvoice.getInvoiceDate() != null) {\r\n\t\t\t\taccountOperationJson.addProperty(\"opencell__InvoiceDate__c\", this.formatAsDate(recordedInvoice.getInvoiceDate()));\r\n\t\t\t}\r\n\t\t\tif (recordedInvoice.getProductionDate() != null) {\r\n\t\t\t\taccountOperationJson.addProperty(\"opencell__ProductionDate__c\", this.formatAsDate(recordedInvoice.getProductionDate()));\r\n\t\t\t}\r\n\t\t\tif (recordedInvoice.getInvoice() != null) {\r\n\t\t\t\taccountOperationJson.addProperty(\"opencell__InvoiceId__c\", recordedInvoice.getInvoice().getId());\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (accountOperation instanceof OtherCreditAndCharge) {\r\n\t\t\tOtherCreditAndCharge occ = (OtherCreditAndCharge) accountOperation;\r\n\t\t\tif (occ.getOperationDate() != null) {\r\n\t\t\t\taccountOperationJson.addProperty(\"opencell__OperationDate__c\", this.formatAsDate(occ.getOperationDate()));\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn accountOperationJson;\r\n\t}\r\n\r\n\t/**\r\n\t * Build the invoice pdf json to send to SFDC\r\n\t * \r\n\t * @param invoice\r\n\t * @param invoiceId\r\n\t * @return\r\n\t */\r\n\tprivate JsonObject toAttachmentJson(Invoice invoice, String invoiceId) {\r\n\t\tJsonObject invoiceJson = new JsonObject();\r\n\t\tinvoiceJson.addProperty(\"Name\", invoice.getInvoiceNumber() + \"_PDF\");\r\n\t\tinvoiceJson.addProperty(\"ParentId\", invoiceId);\r\n\t\tinvoiceJson.addProperty(\"Description\", \"INVOICE\");\r\n\t\tinvoiceJson.addProperty(\"ContentType\", \"application/pdf\");\r\n\t\tinvoiceJson.addProperty(\"Body\", Base64.getEncoder().encodeToString(invoiceService.getInvoicePdf(invoice)));\r\n\t\t//invoiceJson.addProperty(\"Body\", Base64.encodeBase64String(invoiceService.getInvoicePdf(invoice)));\r\n\t\treturn invoiceJson;\r\n\t}\r\n\r\n\t/**\r\n\t * Format date to yyyy-MM-dd pattern\r\n\t * \r\n\t * @param date Date to format\r\n\t * @return Date as yyyy-MM-dd string\r\n\t */\r\n\tprivate String formatAsDate(Date date) {\r\n\t\treturn DateUtils.formatDateWithPattern(date, DateUtils.DATE_PATTERN);\r\n\t}\r\n\r\n\t/**\r\n\t * Format date to yyyy-MM-dd'T'hh:mm:ssXXX pattern\r\n\t * \r\n\t * @param date Date to format\r\n\t * @return Date as yyyy-MM-dd'T'hh:mm:ssXXX string\r\n\t */\r\n\tprivate String formatAsTime(Date date) {\r\n\t\treturn DateUtils.formatDateWithPattern(date, DateUtils.DATE_TIME_PATTERN);\r\n\t}\r\n\r\n\t/**\r\n\t * Gets the mondatory param.\r\n\t *\r\n\t * @param paramKey the param key\r\n\t * @return the mondatory yousign param\r\n\t * @throws MeveoApiException the meveo api exception\r\n\t */\r\n\tprivate String getMandatoryParam(String paramKey) throws MeveoApiException {\r\n\t\treturn this.getParam(paramKey, true);\r\n\t}\r\n\r\n\tprivate String getParam(String paramKey, boolean isMandatory) throws MeveoApiException {\r\n\t\treturn this.getParam(paramKey, isMandatory, \"\");\r\n\t}\r\n\r\n\tprivate String getParam(String paramKey, boolean isMandatory, String defaultValue) throws MeveoApiException {\r\n\t\tString paramValue = paramBean.getProperty(paramKey, defaultValue);\r\n\t\tif (isMandatory && StringUtils.isBlank(paramValue)) {\r\n\t\t\tthrow new MeveoApiException(\" Mandatory param not configured : \" + paramKey);\r\n\t\t}\r\n\t\treturn paramValue;\r\n\t}\r\n\r\n\tpublic IEntity updateNoCheck(IEntity entity) throws BusinessException {\r\n\t\tlog.info(\"start of update {} entity (id={}) ..\", entity.getClass().getSimpleName(), entity.getId());\r\n\t\treturn em.merge(entity);\r\n\t}\r\n\r\n\tprivate IEntity retrieveIfNotManaged(IEntity entity) {\r\n\r\n\t\tif (entity.getId() == null) {\r\n\t\t\treturn entity;\r\n\t\t}\r\n\t\t// Entity is managed already\r\n\t\tif (!em.contains(entity)) {\r\n\t\t\tClass<? extends IEntity> entityClass = entity.getClass();\r\n\t\t\tlog.trace(\"Find {}/{} by id\", entityClass.getSimpleName(), entity.getId());\r\n\t\t\tentity = em.find(entityClass, entity.getId());\r\n\t\t}\r\n\t\tif (entity instanceof HibernateProxy) {\r\n\t\t\tentity = (IEntity) ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();\r\n\t\t}\r\n\r\n\t\treturn entity;\r\n\t}\r\n\r\n\t/**********************************************************************************\r\n\t * \r\n\t * \r\n\t * All The composite request/response classes to interact with salesforce\r\n\t * \r\n\t * @author Youssef IZEM\r\n\t * @lastModifiedVersion 1.0\r\n\t **********************************************************************************/\r\n\r\n\tclass CompositeRequestDto {\r\n\r\n\t\tprivate boolean allOrNone = true;\r\n\t\tprivate boolean collateSubrequests = true;\r\n\t\tprivate List<CompositeSubRequestDto> compositeRequest = new ArrayList<>();\r\n\r\n\t\tpublic boolean isAllOrNone() {\r\n\t\t\treturn allOrNone;\r\n\t\t}\r\n\r\n\t\tpublic void setAllOrNone(boolean allOrNone) {\r\n\t\t\tthis.allOrNone = allOrNone;\r\n\t\t}\r\n\r\n\t\tpublic boolean isCollateSubrequests() {\r\n\t\t\treturn collateSubrequests;\r\n\t\t}\r\n\r\n\t\tpublic void setCollateSubrequests(boolean collateSubrequests) {\r\n\t\t\tthis.collateSubrequests = collateSubrequests;\r\n\t\t}\r\n\r\n\t\tpublic List<CompositeSubRequestDto> getCompositeRequest() {\r\n\t\t\treturn compositeRequest;\r\n\t\t}\r\n\r\n\t\tpublic void addSubRequest(CompositeSubRequestDto subRequest) {\r\n\t\t\tthis.compositeRequest.add(subRequest);\r\n\t\t}\r\n\r\n\t\tpublic CompositeSubRequestDto getSubRequest(String reference) {\r\n\t\t\tif (compositeRequest == null || reference == null) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t\tfor (CompositeSubRequestDto request : compositeRequest) {\r\n\t\t\t\tif (reference.equals(request.getReferenceId())) {\r\n\t\t\t\t\treturn request;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t@Override\r\n\t\tpublic String toString() {\r\n\t\t\treturn ToStringBuilder.reflectionToString(this, ToStringStyle.NO_CLASS_NAME_STYLE);\r\n\t\t}\r\n\t}\r\n\r\n\tclass CompositeSubRequestDto {\r\n\r\n\t\tprivate String url;\r\n\t\tprivate JsonObject body;\r\n\t\tprivate String method;\r\n\t\tprivate String referenceId;\r\n\r\n\t\tpublic String getUrl() {\r\n\t\t\treturn url;\r\n\t\t}\r\n\r\n\t\tpublic void setUrl(String url) {\r\n\t\t\tthis.url = url;\r\n\t\t}\r\n\r\n\t\tpublic JsonObject getBody() {\r\n\t\t\treturn body;\r\n\t\t}\r\n\r\n\t\tpublic void setBody(JsonObject body) {\r\n\t\t\tthis.body = body;\r\n\t\t}\r\n\r\n\t\tpublic String getMethod() {\r\n\t\t\treturn method;\r\n\t\t}\r\n\r\n\t\tpublic void setMethod(String method) {\r\n\t\t\tthis.method = method;\r\n\t\t}\r\n\r\n\t\tpublic String getReferenceId() {\r\n\t\t\treturn referenceId;\r\n\t\t}\r\n\r\n\t\tpublic void setReferenceId(String referenceId) {\r\n\t\t\tthis.referenceId = referenceId;\r\n\t\t}\r\n\r\n\t\t@Override\r\n\t\tpublic String toString() {\r\n\t\t\treturn ToStringBuilder.reflectionToString(this, ToStringStyle.NO_CLASS_NAME_STYLE);\r\n\t\t}\r\n\t}\r\n\r\n\tclass ResponseDto {\r\n\r\n\t\tprivate List<CompositeSubRequestResponse> compositeResponse = new ArrayList<>();\r\n\r\n\t\tpublic List<CompositeSubRequestResponse> getSubCompositeResponse() {\r\n\t\t\treturn compositeResponse;\r\n\t\t}\r\n\r\n\t\tpublic void setCompositeResponse(List<CompositeSubRequestResponse> compositeResponse) {\r\n\t\t\tthis.compositeResponse = compositeResponse;\r\n\t\t}\r\n\r\n\t\t/**\r\n\t\t * Get the id for the created SOBJECT\r\n\t\t * \r\n\t\t * @param reference\r\n\t\t * @return\r\n\t\t */\r\n\t\tpublic Object getSObjectId(String reference) {\r\n\t\t\tif (compositeResponse == null || reference == null) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t\tfor (CompositeSubRequestResponse response : compositeResponse) {\r\n\t\t\t\tif (reference.equals(response.getReferenceId()) && response.getBody() instanceof Map) {\r\n\t\t\t\t\treturn ((Map) response.getBody()).get(\"id\");\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t/**\r\n\t\t * Get the subResponse for the created SOBJECT\r\n\t\t * \r\n\t\t * @param reference\r\n\t\t * @return\r\n\t\t */\r\n\t\tpublic CompositeSubRequestResponse getSubResponse(String reference) {\r\n\t\t\tif (compositeResponse == null || reference == null) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t\tfor (CompositeSubRequestResponse response : compositeResponse) {\r\n\t\t\t\tif (reference.equals(response.getReferenceId())) {\r\n\t\t\t\t\treturn response;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t/**\r\n\t\t * Get the Error code for specific request\r\n\t\t * \r\n\t\t * @param reference\r\n\t\t * @return\r\n\t\t */\r\n\t\tpublic Object getErrorCode(String reference) {\r\n\t\t\tif (compositeResponse == null || reference == null) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t\tfor (CompositeSubRequestResponse response : compositeResponse) {\r\n\t\t\t\treturn response.getBody().getClass().getSimpleName();\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\t/**\r\n\t\t * Checks if all requests have successfully executed\r\n\t\t * \r\n\t\t * @return\r\n\t\t */\r\n\t\tprivate boolean areAllRequestsSuccess() {\r\n\t\t\tif (compositeResponse == null) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\tfor (CompositeSubRequestResponse response : compositeResponse) {\r\n\t\t\t\tif (!response.isSuccess()) {\r\n\t\t\t\t\treturn false;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn true;\r\n\t\t}\r\n\r\n\t\tprivate boolean isRequestSuccess(String referenceId) {\r\n\t\t\tif (compositeResponse == null || referenceId == null) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\tfor (CompositeSubRequestResponse response : compositeResponse) {\r\n\t\t\t\tif (referenceId.equals(response.getReferenceId()) && response.isSuccess()) {\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\t@Override\r\n\t\tpublic String toString() {\r\n\t\t\treturn ToStringBuilder.reflectionToString(this, ToStringStyle.NO_CLASS_NAME_STYLE);\r\n\t\t}\r\n\t}\r\n\r\n\tclass CompositeSubRequestResponse {\r\n\r\n\t\tprivate String referenceId;\r\n\t\tprivate String httpStatusCode;\r\n\t\tprivate Object body = new ArrayList<>();\r\n\t\tprivate Map<String, String> httpHeaders = new HashMap<>();\r\n\r\n\t\tpublic String getReferenceId() {\r\n\t\t\treturn referenceId;\r\n\t\t}\r\n\r\n\t\tpublic void setReferenceId(String referenceId) {\r\n\t\t\tthis.referenceId = referenceId;\r\n\t\t}\r\n\r\n\t\tpublic String getHttpStatusCode() {\r\n\t\t\treturn httpStatusCode;\r\n\t\t}\r\n\r\n\t\tpublic void setHttpStatusCode(String httpStatusCode) {\r\n\t\t\tthis.httpStatusCode = httpStatusCode;\r\n\t\t}\r\n\r\n\t\tpublic boolean isSuccess() {\r\n\t\t\treturn Response.Status.Family.SUCCESSFUL == Response.Status.Family.familyOf(Integer.parseInt(httpStatusCode));\r\n\t\t}\r\n\r\n\t\tpublic Object getBody() {\r\n\t\t\treturn body;\r\n\t\t}\r\n\r\n\t\tpublic void setBody(List<Body> body) {\r\n\t\t\tthis.body = body;\r\n\t\t}\r\n\r\n\t\tpublic void setBody(Body body) {\r\n\t\t\tthis.body = body;\r\n\t\t}\r\n\r\n\t\tpublic Map<String, String> getHttpHeaders() {\r\n\t\t\treturn httpHeaders;\r\n\t\t}\r\n\r\n\t\tpublic void setHttpHeaders(Map<String, String> httpHeaders) {\r\n\t\t\tthis.httpHeaders = httpHeaders;\r\n\t\t}\r\n\r\n\t\t@Override\r\n\t\tpublic String toString() {\r\n\t\t\treturn ToStringBuilder.reflectionToString(this, ToStringStyle.NO_CLASS_NAME_STYLE);\r\n\t\t}\r\n\t}\r\n\r\n\tclass Body {\r\n\t\tprivate String id;\r\n\t\tprivate String message;\r\n\t\tprivate String errorCode;\r\n\t\tprivate boolean success;\r\n\t\tprivate List<String> erros;\r\n\t\tprivate List<String> fields;\r\n\r\n\t\tpublic String getId() {\r\n\t\t\treturn id;\r\n\t\t}\r\n\r\n\t\tpublic void setId(String id) {\r\n\t\t\tthis.id = id;\r\n\t\t}\r\n\r\n\t\tpublic String getMessage() {\r\n\t\t\treturn message;\r\n\t\t}\r\n\r\n\t\tpublic void setMessage(String message) {\r\n\t\t\tthis.message = message;\r\n\t\t}\r\n\r\n\t\tpublic String getErrorCode() {\r\n\t\t\treturn errorCode;\r\n\t\t}\r\n\r\n\t\tpublic void setErrorCode(String errorCode) {\r\n\t\t\tthis.errorCode = errorCode;\r\n\t\t}\r\n\r\n\t\tpublic boolean isSuccess() {\r\n\t\t\treturn success;\r\n\t\t}\r\n\r\n\t\tpublic void setSuccess(boolean success) {\r\n\t\t\tthis.success = success;\r\n\t\t}\r\n\r\n\t\tpublic List<String> getErros() {\r\n\t\t\treturn erros;\r\n\t\t}\r\n\r\n\t\tpublic void setErros(List<String> erros) {\r\n\t\t\tthis.erros = erros;\r\n\t\t}\r\n\r\n\t\tpublic List<String> getFields() {\r\n\t\t\treturn fields;\r\n\t\t}\r\n\r\n\t\tpublic void setFields(List<String> fields) {\r\n\t\t\tthis.fields = fields;\r\n\t\t}\r\n\r\n\t\t@Override\r\n\t\tpublic String toString() {\r\n\t\t\treturn ToStringBuilder.reflectionToString(this, ToStringStyle.NO_CLASS_NAME_STYLE);\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * \r\n\t * Token class containing the access token infos got from SFDC\r\n\t * \r\n\t * @author Youssef IZEM\r\n\t * @lastModifiedVersion 1.0\r\n\t */\r\n\tstatic class Token {\r\n\t\tprotected Logger log = LoggerFactory.getLogger(this.getClass());\r\n\r\n\t\t@SerializedName(value = \"issuedAt\", alternate = \"issued_at\")\r\n\t\tprivate Date issuedAt;\r\n\t\t@SerializedName(value = \"tokenType\", alternate = \"token_type\")\r\n\t\tprivate String tokenType;\r\n\t\t@SerializedName(value = \"accessToken\", alternate = \"access_token\")\r\n\t\tprivate String accessToken;\r\n\t\t@SerializedName(value = \"instanceUrl\", alternate = \"instance_url\")\r\n\t\tprivate String instanceUrl;\r\n\r\n\t\tpublic void reset() {\r\n\t\t\tthis.issuedAt = new Date();\r\n\t\t\tthis.tokenType = StringUtils.EMPTY;\r\n\t\t\tthis.accessToken = StringUtils.EMPTY;\r\n\t\t\tthis.instanceUrl = StringUtils.EMPTY;\r\n\t\t}\r\n\r\n\t\tpublic Date getIssuedAt() {\r\n\t\t\treturn issuedAt;\r\n\t\t}\r\n\r\n\t\tpublic String getAuth() {\r\n\t\t\tif (StringUtils.isBlank(this.tokenType) || StringUtils.isBlank(this.accessToken)) {\r\n\t\t\t\treturn StringUtils.EMPTY;\r\n\t\t\t}\r\n\t\t\treturn this.tokenType + \" \" + this.accessToken;\r\n\t\t}\r\n\r\n\t\tpublic void setIssuedAt(String issuedAt) {\r\n\t\t\tthis.issuedAt = new Date(Long.parseLong(issuedAt));\r\n\t\t}\r\n\r\n\t\tpublic String getTokenType() {\r\n\t\t\treturn tokenType;\r\n\t\t}\r\n\r\n\t\tpublic void setTokenType(String tokenType) {\r\n\t\t\tthis.tokenType = tokenType;\r\n\t\t}\r\n\r\n\t\tpublic String getAccessToken() {\r\n\t\t\treturn accessToken;\r\n\t\t}\r\n\r\n\t\tpublic String getMaskedAccessToken() {\r\n\t\t\treturn SObjectSyncingScript.maskString(accessToken);\r\n\t\t}\r\n\r\n\t\tpublic void setAccessToken(String accessToken) {\r\n\t\t\tthis.accessToken = accessToken;\r\n\t\t}\r\n\r\n\t\tpublic String getInstanceUrl() {\r\n\t\t\treturn instanceUrl;\r\n\t\t}\r\n\r\n\t\tpublic void setInstanceUrl(String instanceUrl) {\r\n\t\t\tthis.instanceUrl = instanceUrl;\r\n\t\t}\r\n\r\n\t\t@Override\r\n\t\tpublic String toString() {\r\n\t\t\treturn String.format(\"%s[instanceUrl=%s, tokenType=%s, issuedAt=%s, accessToken=%s]\", this.getClass().getSimpleName(), this.instanceUrl, this.tokenType, this.issuedAt,\r\n\t\t\t\tthis.getMaskedAccessToken());\r\n\t\t}\r\n\t}\r\n\r\n\t/**********************************************************************************\r\n\t * \r\n\t * \r\n\t * All business error messages and exception for an object syncing\r\n\t * \r\n\t * @author Youssef IZEM\r\n\t * @lastModifiedVersion 1.0\r\n\t **********************************************************************************/\r\n\r\n\t/**\r\n\t * \r\n\t * Keobiz business exception\r\n\t * \r\n\t * @author Youssef IZEM\r\n\t * @lastModifiedVersion 1.0\r\n\t */\r\n\tclass SObjectSyncingException extends BusinessException {\r\n\r\n\t\tprivate static final long serialVersionUID = 1L;\r\n\r\n\t\tprivate IEntity entity;\r\n\t\tprivate CompositeRequestDto request;\r\n\t\tprivate Response response;\r\n\t\tprivate String jsonResponse;\r\n\t\tprivate boolean isSynced;\r\n\r\n\t\tpublic SObjectSyncingException() {\r\n\t\t\tthis.entity = null;\r\n\t\t\tthis.request = null;\r\n\t\t\tthis.isSynced = false;\r\n\t\t\tthis.response = null;\r\n\t\t\tthis.jsonResponse = null;\r\n\t\t}\r\n\r\n\t\tpublic SObjectSyncingException(ErrorMessage errorMessage, Object... args) {\r\n\t\t\tsuper(MessageFormat.format(errorMessage.getMessage(), args));\r\n\t\t}\r\n\r\n\t\tpublic SObjectSyncingException(IEntity entity, CompositeRequestDto request, Response response, String jsonResponse, boolean isSynced, ErrorMessage errorMessage,\r\n\t\t\t\tObject... args) {\r\n\t\t\tsuper(MessageFormat.format(errorMessage.getMessage(), args));\r\n\t\t\tthis.entity = entity;\r\n\t\t\tthis.entity = entity;\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t/**\r\n\t * Business Error message list\r\n\t * \r\n\t * @author Youssef IZEM\r\n\t * @lastModifiedVersion 1.0\r\n\t */\r\n\tenum ErrorMessage {\r\n\r\n\t\tENTITY_SYNCING_ERROR(\"Error occured during the syncing process of the {0} => {1}\"),\r\n\r\n\t\tAUTHENTICATION_ERROR(\"Authentication error occured while requesting new token : [{0}:{1}] ==> Response got : {2}\"),\r\n\r\n\t\tAUTHENTICATION_ERROR_UNKNOWN(\"Unknown Authentication error occured while requesting new token : {0}\"),\r\n\r\n\t\tPAGE_NOT_FOUND(\"Target resource not found : {0}\"),\r\n\r\n\t\tMETHOD_NOT_ALLOWED(\"Method not supported by this API\");\r\n\r\n\t\tprivate final String message;\r\n\r\n\t\tErrorMessage(String message) {\r\n\t\t\tthis.message = message;\r\n\t\t}\r\n\r\n\t\tpublic String getMessage(Object... args) {\r\n\t\t\treturn MessageFormat.format(message, args);\r\n\t\t}\r\n\r\n\t}\r\n\t\r\n\tprivate BigDecimal getRappelSolde(Invoice invoice) {\r\n\r\n\t\tList<AccountOperation> aos = (List<AccountOperation>) accountOperationService\r\n\t\t\t\t.executeSelectQuery(\"select ao from AccountOperation ao where (ao.reference is null or ao.reference != '\" + invoice.getInvoiceNumber()\r\n\t\t\t\t\t\t+ \"' )and ao.matchingStatus in ('O','P' ) and ao.customerAccount.id = \"\r\n\t\t\t\t\t\t+ invoice.getBillingAccount().getCustomerAccount().getId() + \" order by ao.id\", null);\r\n\r\n\t\tBigDecimal totalUnpaidInvoices = BigDecimal.ZERO;\r\n\t\tfor (AccountOperation ao : aos) {\t\t\t\r\n\t\t\tOperationCategoryEnum invOpCat = ao.getTransactionCategory();\r\n\r\n\t\t\ttotalUnpaidInvoices = totalUnpaidInvoices\r\n\t\t\t\t\t.add(invOpCat == OperationCategoryEnum.DEBIT ? ao.getUnMatchingAmount()\r\n\t\t\t\t\t\t\t: ao.getUnMatchingAmount().negate());\r\n\r\n\t\t}\r\n\t\treturn totalUnpaidInvoices;\r\n\t}\r\n\t\r\n\tprivate BigDecimal round(BigDecimal amount) {\r\n\t\treturn round(amount, false);\r\n\t}\r\n\r\n\tprivate BigDecimal round(BigDecimal amount, boolean stripTrailingZeros) {\r\n\t\tif (amount == null) {\r\n\t\t\tamount = BigDecimal.ZERO;\r\n\t\t}\r\n\t\tint scale = 2;\r\n\r\n\t\tamount = amount.setScale(scale, RoundingMode.HALF_UP);\r\n\t\tif (stripTrailingZeros) {\r\n\t\t\tamount = amount.stripTrailingZeros();\r\n\t\t}\r\n\t\treturn amount;\r\n\t}\r\n\r\n}\r\n\r\n\r\n\r\n\r\n \r\n            \r\n\r\n ]]>\r\n            </script>\r\n</ScriptInstance>\r\n\r\n"
						},
						"url": {
							"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"scriptInstance",
								"createOrUpdate"
							]
						},
						"description": "A Custom script to compute CUrrent Month Date range."
					},
					"response": []
				},
				{
					"name": "AnonymizeScript",
					"event": [
						{
							"listen": "test",
							"script": {
								"exec": [
									"pm.test(\"Status code is 200\", function () {",
									"    pm.response.to.have.status(200);",
									"});"
								],
								"type": "text/javascript"
							}
						}
					],
					"request": {
						"auth": {
							"type": "basic",
							"basic": [
								{
									"key": "username",
									"value": "{{opencell.username}}",
									"type": "string"
								},
								{
									"key": "password",
									"value": "{{opencell.password}}",
									"type": "string"
								}
							]
						},
						"method": "POST",
						"header": [
							{
								"key": "Content-Type",
								"value": "application/xml"
							},
							{
								"key": "Proxy-Authorization",
								"value": "{{proxy.auth}}"
							}
						],
						"body": {
							"mode": "raw",
							"raw": "<ScriptInstance code=\"com.opencellsoft.service.ekko.util.AnonymizeScript\" description=\"AnonymizeScript\">\r\n            <type>JAVA</type>\r\n            <script>\r\n            <![CDATA[package com.opencellsoft.service.ekko.util;\r\n\r\nimport org.meveo.admin.exception.BusinessException;\r\nimport org.meveo.model.AccountEntity;\r\nimport org.meveo.model.billing.BillingAccount;\r\nimport org.meveo.model.billing.UserAccount;\r\nimport org.meveo.model.crm.Customer;\r\nimport org.meveo.model.payments.CustomerAccount;\r\nimport org.meveo.service.crm.impl.CustomerService;\r\nimport org.meveo.service.script.Script;\r\n\r\nimport javax.persistence.EntityManager;\r\nimport java.util.List;\r\nimport java.util.Map;\r\nimport java.util.UUID;\r\n\r\npublic class AnonymizeScript extends Script {\r\n\r\n    private int anonymizationSeq = 0;\r\n    private CustomerService customerService = (CustomerService) getServiceInterface(\"CustomerService\");\r\n    @Override\r\n    public void execute(Map<String, Object> context) throws BusinessException {\r\n\r\n        EntityManager em = customerService.getEntityManager();\r\n        // Get list ids of all customers\r\n        List<Long> ids = em.createQuery(\"select c.id from Customer c\", Long.class)\r\n                .getResultList();\r\n        String randomCode;\r\n        for (int i = 0; i < ids.size(); i++) {\r\n            Long id = ids.get(i);\r\n            randomCode = UUID.randomUUID().toString();\r\n            //log.info(\"dd\");\r\n            Customer customer = customerService.findById(id);\r\n            customer.anonymize(randomCode);\r\n\r\n            anonymizeDescription(customer);\r\n            for (CustomerAccount ca : customer.getCustomerAccounts()) {\r\n                anonymizeDescription(ca);\r\n                for (BillingAccount ba : ca.getBillingAccounts()) {\r\n                    anonymizeDescription(ba);\r\n                    for (UserAccount userAccount : ba.getUsersAccounts()) {\r\n                        anonymizeDescription(userAccount);\r\n                    }\r\n                }\r\n            }\r\n            anonymizationSeq++;\r\n\r\n            if (i > 0 && i % 500 == 0) {\r\n                // flush a batch of updates and release memory\r\n                em.flush();\r\n                em.clear();\r\n            }\r\n        }\r\n    }\r\n\r\n    private void anonymizeDescription(AccountEntity ae) {\r\n        ae.setDescription(\"Anonym_\" + anonymizationSeq);\r\n    }\r\n}\r\n\r\n\r\n\r\n\r\n ]]>\r\n            </script>\r\n</ScriptInstance>\r\n\r\n"
						},
						"url": {
							"raw": "{{opencell.url}}/scriptInstance/createOrUpdate",
							"host": [
								"{{opencell.url}}"
							],
							"path": [
								"scriptInstance",
								"createOrUpdate"
							]
						},
						"description": "A Custom script to compute CUrrent Month Date range."
					},
					"response": []
				}
			]
		}
	],
	"auth": {
		"type": "basic",
		"basic": [
			{
				"key": "password",
				"value": "{{opencell.password}}",
				"type": "string"
			},
			{
				"key": "username",
				"value": "{{opencell.username}}",
				"type": "string"
			},
			{
				"key": "saveHelperData",
				"type": "any"
			},
			{
				"key": "showPassword",
				"value": false,
				"type": "boolean"
			}
		]
	},
	"event": [
		{
			"listen": "prerequest",
			"script": {
				"type": "text/javascript",
				"exec": [
					"var now=new Date();",
					"pm.globals.set(\"timestamp.iso\", now.toISOString());",
					"pm.globals.set(\"request.label\", pm.info.requestName);",
					"var parts = pm.info.requestName.split(\"|\");",
					"for(let i=0; i<parts.length; i++) {",
					"    pm.globals.set(\"wait\", 0);",
					"    pm.globals.set(\"request.label.\"+i, parts[i]);",
					"    if(parts[i].indexOf(\"=\") != -1 ){",
					"        propName = parts[i].split(\"=\")[0].trim();",
					"        propValue = parts[i].split(\"=\")[1];",
					"        pm.globals.set(propName, propValue);",
					"    }",
					"}"
				]
			}
		},
		{
			"listen": "test",
			"script": {
				"type": "text/javascript",
				"exec": [
					"let skipTest = pm.environment.get('skipTest');",
					"",
					"(skipTest ? pm.test.skip : pm.test('Status code is ' + pm.response.code, function() {",
					"    pm.expect(pm.response.code).to.be.oneOf([200, 201]);",
					"}));",
					"",
					"(skipTest ? pm.test.skip : pm.test(\"Successful request\", function () {",
					"    var jsonData = pm.response.json();",
					"    if (responseBody.has(\"actionStatus\")) {",
					"        pm.expect(jsonData.actionStatus.status).to.eql(\"SUCCESS\");",
					"    } else {",
					"        pm.expect(jsonData.status).to.eql(\"SUCCESS\");",
					"    }",
					"}));"
				]
			}
		}
	]
}