dcos-core-monalisav2-latam 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/README.md +130 -0
  2. package/index.js +350 -0
  3. package/package.json +52 -0
  4. package/src/auth/handler.js +3 -0
  5. package/src/common/MondelezCastOrder.js +449 -0
  6. package/src/common/utils/AuthSecurity.js +46 -0
  7. package/src/common/utils/account-error-handler.js +279 -0
  8. package/src/common/utils/account-error-helper.js +231 -0
  9. package/src/common/utils/account-properties-handler.js +355 -0
  10. package/src/common/utils/api-response.js +62 -0
  11. package/src/common/utils/aws-services.js +186 -0
  12. package/src/common/utils/constants/account-error-codes.json +801 -0
  13. package/src/common/utils/constants.js +37 -0
  14. package/src/common/utils/convert/MondelezClientsItemsCast.js +52 -0
  15. package/src/common/utils/convert/MondelezInventoryItemsCast.js +15 -0
  16. package/src/common/utils/convert/MondelezOrderStatusCast.js +34 -0
  17. package/src/common/utils/convert/MondelezPricesItemsCast.js +37 -0
  18. package/src/common/utils/cron-ftp-get.js +143 -0
  19. package/src/common/utils/data-tables-helper.js +213 -0
  20. package/src/common/utils/date-range-calculator.js +113 -0
  21. package/src/common/utils/delay.js +17 -0
  22. package/src/common/utils/ftp-sftp.js +320 -0
  23. package/src/common/utils/logger.js +126 -0
  24. package/src/common/utils/nodemailerLib.js +61 -0
  25. package/src/common/utils/product-unit-converter.js +168 -0
  26. package/src/common/utils/schemas-utils.js +101 -0
  27. package/src/common/utils/seller-email-sharing-service.js +441 -0
  28. package/src/common/utils/sftp-utils.js +202 -0
  29. package/src/common/utils/status.js +15 -0
  30. package/src/common/utils/util.js +236 -0
  31. package/src/common/utils/validate-state-order.js +35 -0
  32. package/src/common/utils/validateProviders.js +67 -0
  33. package/src/common/utils/validation-data.js +45 -0
  34. package/src/common/utils/vtex/save-hooks.js +65 -0
  35. package/src/common/utils/vtex/save-schemas.js +65 -0
  36. package/src/common/utils/vtex-hook-handler.js +71 -0
  37. package/src/common/validation/AccountCoordinatesValidation.js +350 -0
  38. package/src/common/validation/GeneralErrorValidation.js +11 -0
  39. package/src/common/validation/MainErrorValidation.js +8 -0
  40. package/src/entities/account.js +639 -0
  41. package/src/entities/clients.js +104 -0
  42. package/src/entities/controlprice.js +196 -0
  43. package/src/entities/controlstock.js +206 -0
  44. package/src/entities/cron.js +77 -0
  45. package/src/entities/cronjob.js +71 -0
  46. package/src/entities/orders.js +195 -0
  47. package/src/entities/sftp-inbound.js +88 -0
  48. package/src/entities/sku.js +220 -0
  49. package/src/entities/taxpromotion.js +249 -0
  50. package/src/functions/account/account-get.js +262 -0
  51. package/src/functions/account/account-handler.js +299 -0
  52. package/src/functions/account/clients.js +10 -0
  53. package/src/functions/account/index.js +208 -0
  54. package/src/functions/actions/save-promotions-order-history.js +324 -0
  55. package/src/functions/affiliates/affiliates-hook-consumer.js +87 -0
  56. package/src/functions/affiliates/affiliates-hook-producer.js +45 -0
  57. package/src/functions/clients/clients-audience.js +62 -0
  58. package/src/functions/clients/clients-consumer.js +648 -0
  59. package/src/functions/clients/clients-producer.js +362 -0
  60. package/src/functions/clients/clients-suggested-product-consumer.js +166 -0
  61. package/src/functions/clients/helpers/suggested-product-mdlz.js +233 -0
  62. package/src/functions/clients_peru/email.html +129 -0
  63. package/src/functions/clients_peru/splitfile.js +357 -0
  64. package/src/functions/clients_peru/updateClients.js +1334 -0
  65. package/src/functions/clients_peru/utils.js +243 -0
  66. package/src/functions/cronjobs/cron-jobs-manager.js +40 -0
  67. package/src/functions/cronjobs/cron-jobs.js +171 -0
  68. package/src/functions/crons/cron.js +39 -0
  69. package/src/functions/distributors/distributor-handler.js +81 -0
  70. package/src/functions/distributors/distributor.js +535 -0
  71. package/src/functions/distributors/index.js +60 -0
  72. package/src/functions/financialpolicy/assign-financialpolicy.js +111 -0
  73. package/src/functions/financialpolicy/get-financialpolicy.js +91 -0
  74. package/src/functions/financialpolicy/index.js +28 -0
  75. package/src/functions/inventory/catalog-sync-consumer.js +17 -0
  76. package/src/functions/inventory/catalog-sync-handler.js +311 -0
  77. package/src/functions/inventory/inventory-consumer.js +119 -0
  78. package/src/functions/inventory/inventory-producer.js +197 -0
  79. package/src/functions/multiPresentation/multipre-queue.js +155 -0
  80. package/src/functions/multiPresentation/multipres.js +459 -0
  81. package/src/functions/nodeflow/index.js +83 -0
  82. package/src/functions/nodeflow/nodeflow-cron.js +200 -0
  83. package/src/functions/nodeflow/nodeflow-pub.js +203 -0
  84. package/src/functions/nodeflow/nodeflow-pvt.js +266 -0
  85. package/src/functions/notifications/download-leads-handler.js +67 -0
  86. package/src/functions/notifications/new-leads-notification-consumer.js +17 -0
  87. package/src/functions/notifications/new-leads-notification-handler.js +359 -0
  88. package/src/functions/notifications/order-status-notification-handler.js +482 -0
  89. package/src/functions/notifications/promotion-notification-handler.js +193 -0
  90. package/src/functions/orders/index.js +32 -0
  91. package/src/functions/orders/orders-cancel-handler.js +74 -0
  92. package/src/functions/orders/orders-handler.js +280 -0
  93. package/src/functions/orders/orders-hook-consumer.js +137 -0
  94. package/src/functions/orders/orders-hook-producer.js +170 -0
  95. package/src/functions/orders/orders-notifications-handler.js +137 -0
  96. package/src/functions/orders/orders-status-consumer.js +461 -0
  97. package/src/functions/orders/orders-status-producer.js +443 -0
  98. package/src/functions/prices/index.js +75 -0
  99. package/src/functions/prices/prices-consumer.js +236 -0
  100. package/src/functions/prices/prices-producer.js +323 -0
  101. package/src/functions/prices/promotion-and-tax.js +1284 -0
  102. package/src/functions/routesflow/assign-routeflow-queue.js +77 -0
  103. package/src/functions/schemas/vtex/handle-schemas.js +102 -0
  104. package/src/functions/security/process_gas.js +221 -0
  105. package/src/functions/security/security-handler.js +950 -0
  106. package/src/functions/sftp/sftp-consumer.js +453 -0
  107. package/src/functions/sftpIntegrations/processes/redirectServices.js +184 -0
  108. package/src/functions/sftpIntegrations/processes/validateFileSchema.js +226 -0
  109. package/src/functions/sftpIntegrations/schemas/credential-schema.js +123 -0
  110. package/src/functions/sftpIntegrations/schemas/record-schema.js +131 -0
  111. package/src/functions/sftpIntegrations/schemas/sftp_required_fields.json +3 -0
  112. package/src/functions/sftpIntegrations/sftp-config-producer.js +112 -0
  113. package/src/functions/sftpIntegrations/sftp-consumer.js +700 -0
  114. package/src/functions/sftpIntegrations/test/validateFile.test.js +122 -0
  115. package/src/functions/sftpIntegrations/utils/connect-dynamo.js +29 -0
  116. package/src/functions/sftpIntegrations/utils/split-data.js +25 -0
  117. package/src/functions/utils/index.js +130 -0
  118. package/src/functions/vtex/vtex-helpers.js +694 -0
  119. package/src/integrations/accountErrors/AccountErrorManager.js +437 -0
  120. package/src/integrations/audience/Audience.js +70 -0
  121. package/src/integrations/financialPolicy/FinancialPolicyApi.js +377 -0
  122. package/src/integrations/index.js +0 -0
  123. package/src/integrations/mobilvendor/MobilvendorApi.js +405 -0
  124. package/src/integrations/productmultipresentation/ProductMultiPresentation.js +200 -0
  125. package/src/mdlz/auth/SecretManagerApi.js +77 -0
  126. package/src/mdlz/client/MdlzApi.js +70 -0
  127. package/src/vtex/clients/ProvidersApi.js +51 -0
  128. package/src/vtex/clients/VtexApi.js +511 -0
  129. package/src/vtex/models/VtexOrder.js +87 -0
@@ -0,0 +1,233 @@
1
+ const AWSServices = require("../../../common/utils/aws-services");
2
+ const ApiResponse = require("../../../common/utils/api-response");
3
+ const Logger = require("../../../common/utils/logger");
4
+ const AccountData = require("../../../entities/account");
5
+ const VtexApi = require("../../../vtex/clients/VtexApi");
6
+
7
+ const SQS_CLIENT_PRODUCT_QUEUE_URL = process.env.SQS_CLIENT_PRODUCT_QUEUE_URL;
8
+ const DEFAULT_MIN_PRODUCTS_COUNT = process.env.MIN_PRODUCTS_COUNT || 5;
9
+
10
+ const validateBody = (event, minProductsCount = DEFAULT_MIN_PRODUCTS_COUNT) => {
11
+ if (!event.body) {
12
+ return { valid: false, error: ApiResponse.response(400, "Body is required") };
13
+ }
14
+
15
+ const body = JSON.parse(event.body);
16
+ const { an, clients } = body;
17
+
18
+ if (!an || typeof an !== 'string') {
19
+ return { valid: false, error: ApiResponse.response(400, "Field 'an' is required and must be a string") };
20
+ }
21
+
22
+ if (!clients || !Array.isArray(clients) || clients.length === 0) {
23
+ return { valid: false, error: ApiResponse.response(400, "Field 'clients' is required and must be a non-empty array") };
24
+ }
25
+
26
+ for (const client of clients) {
27
+ if (!Array.isArray(client.productsRegular)) {
28
+ return { valid: false, error: ApiResponse.response(400, "Field 'productsRegular' must be an array") };
29
+ }
30
+ if (!Array.isArray(client.productsIncremental)) {
31
+ return { valid: false, error: ApiResponse.response(400, "Field 'productsIncremental' must be an array") };
32
+ }
33
+ if (client.productsRegular.length < minProductsCount) {
34
+ return { valid: false, error: ApiResponse.response(400, `Field 'productsRegular' must have at least ${minProductsCount} elements`) };
35
+ }
36
+ if (client.productsIncremental.length < minProductsCount) {
37
+ return { valid: false, error: ApiResponse.response(400, `Field 'productsIncremental' must have at least ${minProductsCount} elements`) };
38
+ }
39
+ }
40
+
41
+ return { valid: true, data: body };
42
+ };
43
+
44
+ const validateSkusInVtex = async (skus, vtexApi) => {
45
+ if (!skus || skus.length === 0) {
46
+ Logger.info("No SKUs to validate");
47
+ return { validSkus: [], invalidSkus: [] };
48
+ }
49
+
50
+ try {
51
+ const skuIds = skus.map(s => s.sku);
52
+ Logger.info(`Requesting VTEX validation for SKUs: [${skuIds.join(', ')}]`);
53
+
54
+ const vtexSkus = await vtexApi.getDetailSkuById(skuIds);
55
+ Logger.info(`VTEX API returned ${Array.isArray(vtexSkus) ? vtexSkus.length : 'invalid'} results`);
56
+
57
+ const validSkus = [];
58
+ const invalidSkus = [];
59
+
60
+ if (!vtexSkus || !Array.isArray(vtexSkus)) {
61
+ Logger.warn("VTEX API returned invalid response");
62
+ return { validSkus: [], invalidSkus: skus };
63
+ }
64
+
65
+ skus.forEach(sku => {
66
+ const found = vtexSkus.find(v => String(sku?.sku) === String(v?.Id));
67
+ if (found && found.IsActive !== false) {
68
+ validSkus.push(sku);
69
+ } else {
70
+ invalidSkus.push(sku);
71
+ }
72
+ });
73
+
74
+ Logger.info(`Validation completed: ${validSkus.length} valid, ${invalidSkus.length} invalid`);
75
+ return { validSkus, invalidSkus };
76
+ } catch (error) {
77
+ return { validSkus: [], invalidSkus: skus };
78
+ }
79
+ };
80
+
81
+ const processClient = async (client, vtexApi, accountName, account) => {
82
+ try {
83
+ const { pdv, productsRegular = [], productsIncremental = [] } = client;
84
+
85
+ const suggestedConfig = account?.ProductSuggestedConfig
86
+ const entityName = suggestedConfig?.entityName || 'suggestedProducts';
87
+ const minProductsCount = suggestedConfig?.minProductsCount || DEFAULT_MIN_PRODUCTS_COUNT;
88
+
89
+ const regularValidation = await validateSkusInVtex(productsRegular, vtexApi);
90
+ const incrementalValidation = await validateSkusInVtex(productsIncremental, vtexApi);
91
+
92
+ const hasMinimumValid = regularValidation.validSkus.length >= minProductsCount &&
93
+ incrementalValidation.validSkus.length >= minProductsCount;
94
+
95
+ if (!hasMinimumValid) {
96
+ return {
97
+ pdv,
98
+ success: false,
99
+ error: `Minimum ${minProductsCount} valid SKUs required`,
100
+ regularValid: regularValidation.validSkus.length,
101
+ incrementalValid: incrementalValidation.validSkus.length,
102
+ originalData: client
103
+ };
104
+ }
105
+
106
+ const dataSend = {
107
+ an: accountName,
108
+ parentAccount: account?.ParentAccountName,
109
+ key: account?.Credentials?.key,
110
+ token: account?.Credentials?.token,
111
+ pdv,
112
+ productsRegular: regularValidation.validSkus,
113
+ productsIncremental: incrementalValidation.validSkus,
114
+ invalidSkusRegular: regularValidation.invalidSkus,
115
+ invalidSkusIncremental: incrementalValidation.invalidSkus,
116
+ originalData: client,
117
+ nameEntityProductSuggested: entityName
118
+ };
119
+
120
+ if (SQS_CLIENT_PRODUCT_QUEUE_URL) {
121
+ try {
122
+ await AWSServices.sendSQSMessage(SQS_CLIENT_PRODUCT_QUEUE_URL, dataSend);
123
+ Logger.info(`Message sent to SQS for client ${pdv}`);
124
+ } catch (sqsError) {
125
+ Logger.error(`Failed to send SQS message for client ${pdv}`, {
126
+ error: sqsError.message
127
+ });
128
+ }
129
+ } else {
130
+ Logger.warn(`SQS URL not configured`);
131
+ }
132
+
133
+ return {
134
+ pdv,
135
+ success: true,
136
+ validRegular: regularValidation.validSkus.length,
137
+ validIncremental: incrementalValidation.validSkus.length,
138
+ invalidRegular: regularValidation.invalidSkus.length,
139
+ invalidIncremental: incrementalValidation.invalidSkus.length,
140
+ warnings: regularValidation.invalidSkus.length > 0 || incrementalValidation.invalidSkus.length > 0
141
+ ? "Some SKUs were excluded as they don't exist in VTEX" : null
142
+ };
143
+
144
+ } catch (error) {
145
+ Logger.error(`Critical error in processClient for PDV: ${client?.pdv}`, {
146
+ error: error.message,
147
+ stack: error.stack,
148
+ pdv: client?.pdv
149
+ });
150
+ throw error;
151
+ }
152
+ };
153
+
154
+ const suggestedProductMdlz = async (event) => {
155
+ try {
156
+ const { an, clients } = JSON.parse(event.body);
157
+
158
+ const account = await AccountData.getAccountDataByAccountName(an);
159
+ if (!account) {
160
+ return ApiResponse.response(404, "Account not found");
161
+ }
162
+
163
+ if (!account?.Credentials?.key || !account?.Credentials?.token) {
164
+ return ApiResponse.response(400, "VTEX credentials not configured for account");
165
+ }
166
+
167
+ const suggestedConfig = account?.ProductSuggestedConfig;
168
+ const minProductsCount = suggestedConfig?.minProductsCount || DEFAULT_MIN_PRODUCTS_COUNT;
169
+
170
+ const validation = validateBody(event, minProductsCount);
171
+ if (!validation.valid) {
172
+ return validation.error;
173
+ }
174
+
175
+ const vtexApi = new VtexApi(
176
+ account.AccountName,
177
+ account.Credentials.key,
178
+ account.Credentials.token
179
+ );
180
+
181
+ const results = [];
182
+ const failedClients = [];
183
+
184
+ for (const client of clients) {
185
+ try {
186
+ const result = await processClient(client, vtexApi, an, account);
187
+ if (result.success) {
188
+ results.push(result);
189
+ } else {
190
+ failedClients.push(result);
191
+ }
192
+ } catch (error) {
193
+ Logger.error("Error processing client", {
194
+ pdv: client.pdv,
195
+ error: error.message,
196
+ stack: error.stack
197
+ });
198
+ failedClients.push({
199
+ pdv: client.pdv,
200
+ success: false,
201
+ error: "Internal processing error",
202
+ originalData: client
203
+ });
204
+ }
205
+ }
206
+
207
+ const response = failedClients.length > 0
208
+ ? {
209
+ message: "Not all clients were processed successfully",
210
+ processedClients: results.length,
211
+ failedClients
212
+ }
213
+ : {
214
+ message: "All clients processed successfully",
215
+ processedClients: results.length,
216
+ results
217
+ };
218
+
219
+ const statusCode = failedClients.length > 0 ? 207 : 200;
220
+ Logger.info(`Process completed with status ${statusCode}, processed: ${results.length}, failed: ${failedClients.length}`);
221
+
222
+ return ApiResponse.response(statusCode, response);
223
+
224
+ } catch (error) {
225
+ Logger.error("Critical error in suggestedProductMdlz", {
226
+ error: error.message,
227
+ stack: error.stack
228
+ });
229
+ return ApiResponse.response(500, "Internal server error");
230
+ }
231
+ };
232
+
233
+ module.exports = suggestedProductMdlz;
@@ -0,0 +1,129 @@
1
+ <!DOCTYPE html
2
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml"
4
+ style="-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;box-sizing:border-box;width:100%;height:100%;margin:0;padding:0;background:#f1f1f1!important">
5
+
6
+ <body>
7
+ <div class="responsive"
8
+ style="box-sizing:border-box;width:100%;height:100%;margin:0;padding:0;background:#f1f1f1!important;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif">
9
+ <table width="100%" border="0" cellpadding="0" cellspacing="0"
10
+ style="box-sizing:border-box;margin:0;padding:0;background:#f1f1f1;border-collapse:collapse;border-spacing:0;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;width:100%;height:100%;line-height:100%!important">
11
+ <tbody>
12
+ <tr style="box-sizing:border-box!important">
13
+ <td valign="top"
14
+ style="font-size:14px;line-height:20px;box-sizing:border-box;border-collapse:collapse;text-align:left!important;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif">
15
+ <table width="100%" align="center" border="0" cellpadding="0" cellspacing="0"
16
+ style="box-sizing:border-box;max-width:600px;width:100%;background-color:#fff;border-collapse:collapse;border-spacing:0;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif"
17
+ bgcolor="#fff">
18
+ <tbody>
19
+ <tr style="box-sizing:border-box!important">
20
+ <td style="font-size:14px;line-height:20px;box-sizing:border-box;border-collapse:collapse;width:100%;padding-bottom:1rem;text-align:center!important;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;background:#4f2170;border-radius:0 0 30px 30px;height:81px"
21
+ align="center">
22
+ <div
23
+ style="box-sizing:border-box;width:8rem;margin-bottom:1rem;margin-top:2rem;margin-right:auto;margin-left:auto!important">
24
+ <a href="https://www.mitiendamondelez.com/"
25
+ style="box-sizing:border-box!important" rel="noreferrer noreferrer"
26
+ target="_blank"
27
+ data-saferedirecturl="https://www.google.com/url?q=https://www.mitiendamondelez.com/&amp;source=gmail&amp;ust=1651759820344000&amp;usg=AOvVaw1Ba9t2y3zarxtQFChNTCsq"><img
28
+ alt="" border="0" width="auto"
29
+ src="https://mdlzcol.vteximg.com.br/arquivos/mailings-logo-mondelez-bl.png?v=638337711282500000"
30
+ style="vertical-align:top;outline:0;text-decoration:none;max-width:100%;border:none;max-height:80px!important"
31
+ class="CToWUd"></a>
32
+ </div>
33
+ </td>
34
+ </tr>
35
+ <tr>
36
+ <td>
37
+ <div
38
+ style="box-sizing:border-box;width:100%;height:100%;margin:0;padding:0;background:#f1f1f1!important;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif">
39
+ <table width="100%" border="0" cellpadding="0" cellspacing="0"
40
+ style="box-sizing:border-box;margin:0;padding:0;background:#f1f1f1;border-collapse:collapse;border-spacing:0;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;width:100%;height:100%;line-height:100%!important">
41
+ <tbody>
42
+ <tr style="box-sizing:border-box!important">
43
+ <td valign="top"
44
+ style="font-size:14px;line-height:20px;box-sizing:border-box;border-collapse:collapse;text-align:left!important;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif">
45
+ <table width="100%" align="center" border="0"
46
+ cellpadding="0" cellspacing="0"
47
+ style="position:relative;box-sizing:border-box;width:100%;background-color:#fff;border-collapse:collapse;border-spacing:0;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif"
48
+ bgcolor="#fff">
49
+ <tbody>
50
+ <tr style="box-sizing:border-box!important">
51
+ <td
52
+ style="padding:0 62px;font-size:14px;line-height:20px;box-sizing:border-box;border-collapse:collapse;width:100%;padding-bottom:11px;text-align:center!important;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif">
53
+ <h1
54
+ style="font-family:Calibri;margin-top:42px;margin-bottom:0;font-size:24px;line-height:24px;box-sizing:border-box!important;color:#4f2170;text-transform:uppercase;text-align:left;padding:0 10px">
55
+ Hola EQUIPO Mdlz</h1>
56
+ </td>
57
+ </tr>
58
+ <tr style="box-sizing:border-box!important">
59
+ <td
60
+ style="padding:0 62px;font-size:14px;line-height:20px;box-sizing:border-box;border-collapse:collapse;text-align:left;width:100%">
61
+ <div
62
+ style="box-sizing:border-box;padding:10px 13px 0;letter-spacing:.4px;font-size:14px;color:#000;line-height:24px;font-family:Calibri;margin-bottom:7px;margin-top:0">
63
+ <span
64
+ style="box-sizing:border-box;padding:0;letter-spacing:.4px;font-size:14px;color:#4f2170!important;font-weight:700;line-height:24px;margin-right:2px">Distribuidora:</span>{seller}
65
+ </div>
66
+ </td>
67
+ </tr>
68
+ <tr style="box-sizing:border-box!important">
69
+ <td
70
+ style="padding:0 62px;font-size:14px;line-height:20px;box-sizing:border-box;border-collapse:collapse;text-align:left;width:100%">
71
+ <p
72
+ style="box-sizing:border-box;padding:10px;letter-spacing:.4px;font-size:14px;color:#000;line-height:24px;font-family:Calibri;margin:0">
73
+ A continuación se presenta el reporte de ejecución del proceso de creación y/o actualización de clientes
74
+ </p>
75
+ </td>
76
+ </tr>
77
+ <tr style="box-sizing:border-box!important">
78
+ <td
79
+ style="padding:0 62px;font-size:14px;line-height:20px;box-sizing:border-box;border-collapse:collapse;text-align:left;width:100%">
80
+ <div
81
+ style="box-sizing:border-box;padding:10px 13px 0;letter-spacing:.4px;font-size:14px;color:#000;line-height:24px;font-family:Calibri;margin-bottom:7px;margin-top:0">
82
+ <h2
83
+ style="color:#4f2170!important;margin:0">
84
+ Archivos procesados:</h2>
85
+ {processedFilesData}
86
+ </div>
87
+ </td>
88
+ </tr>
89
+ <tr style="box-sizing:border-box!important">
90
+ <td
91
+ style="padding:0 62px;font-size:14px;line-height:20px;box-sizing:border-box;border-collapse:collapse;text-align:left;width:100%">
92
+ <div
93
+ style="box-sizing:border-box;padding:10px 13px 0;letter-spacing:.4px;font-size:14px;color:#000;line-height:24px;font-family:Calibri;margin-bottom:7px;margin-top:0">
94
+ <h2
95
+ style="color:#4f2170!important;margin:0">
96
+ Procesos de Web Services:</h2>
97
+ {webServiceData}
98
+ </div>
99
+ </td>
100
+ </tr>
101
+ <tr style="box-sizing:border-box!important">
102
+ <td
103
+ style="padding:0 62px;font-size:14px;line-height:20px;box-sizing:border-box;border-collapse:collapse;text-align:left;width:100%">
104
+ <p
105
+ style="box-sizing:border-box;padding:10px 10px 0;letter-spacing:.4px;font-size:14px;color:#000;line-height:24px;font-family:Calibri;margin-bottom:2px;margin-top:20px">
106
+ Para mayor información por favor
107
+ consultar al Administrador del sitio.
108
+ </p>
109
+ </td>
110
+ </tr>
111
+ </tbody>
112
+ </table>
113
+ </td>
114
+ </tr>
115
+ </tbody>
116
+ </table>
117
+ </div>
118
+ </td>
119
+ </tr>
120
+ </tbody>
121
+ </table>
122
+ </td>
123
+ </tr>
124
+ </tbody>
125
+ </table>
126
+ </div>
127
+ </body>
128
+
129
+ </html>