@unchainedshop/platform 1.1.3

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 (196) hide show
  1. package/README.md +3 -0
  2. package/lib/bulk-importer/createBulkImporter.d.ts +4 -0
  3. package/lib/bulk-importer/createBulkImporter.js +102 -0
  4. package/lib/bulk-importer/createBulkImporter.js.map +1 -0
  5. package/lib/bulk-importer/handlers/assortment/create.d.ts +11 -0
  6. package/lib/bulk-importer/handlers/assortment/create.js +59 -0
  7. package/lib/bulk-importer/handlers/assortment/create.js.map +1 -0
  8. package/lib/bulk-importer/handlers/assortment/index.d.ts +3 -0
  9. package/lib/bulk-importer/handlers/assortment/index.js +4 -0
  10. package/lib/bulk-importer/handlers/assortment/index.js.map +1 -0
  11. package/lib/bulk-importer/handlers/assortment/remove.d.ts +9 -0
  12. package/lib/bulk-importer/handlers/assortment/remove.js +13 -0
  13. package/lib/bulk-importer/handlers/assortment/remove.js.map +1 -0
  14. package/lib/bulk-importer/handlers/assortment/update.d.ts +10 -0
  15. package/lib/bulk-importer/handlers/assortment/update.js +61 -0
  16. package/lib/bulk-importer/handlers/assortment/update.js.map +1 -0
  17. package/lib/bulk-importer/handlers/assortment/upsertAssortmentChildren.d.ts +7 -0
  18. package/lib/bulk-importer/handlers/assortment/upsertAssortmentChildren.js +30 -0
  19. package/lib/bulk-importer/handlers/assortment/upsertAssortmentChildren.js.map +1 -0
  20. package/lib/bulk-importer/handlers/assortment/upsertAssortmentContent.d.ts +7 -0
  21. package/lib/bulk-importer/handlers/assortment/upsertAssortmentContent.js +9 -0
  22. package/lib/bulk-importer/handlers/assortment/upsertAssortmentContent.js.map +1 -0
  23. package/lib/bulk-importer/handlers/assortment/upsertAssortmentFilters.d.ts +7 -0
  24. package/lib/bulk-importer/handlers/assortment/upsertAssortmentFilters.js +29 -0
  25. package/lib/bulk-importer/handlers/assortment/upsertAssortmentFilters.js.map +1 -0
  26. package/lib/bulk-importer/handlers/assortment/upsertAssortmentProducts.d.ts +7 -0
  27. package/lib/bulk-importer/handlers/assortment/upsertAssortmentProducts.js +32 -0
  28. package/lib/bulk-importer/handlers/assortment/upsertAssortmentProducts.js.map +1 -0
  29. package/lib/bulk-importer/handlers/assortment/upsertMedia.d.ts +7 -0
  30. package/lib/bulk-importer/handlers/assortment/upsertMedia.js +67 -0
  31. package/lib/bulk-importer/handlers/assortment/upsertMedia.js.map +1 -0
  32. package/lib/bulk-importer/handlers/filter/create.d.ts +11 -0
  33. package/lib/bulk-importer/handlers/filter/create.js +42 -0
  34. package/lib/bulk-importer/handlers/filter/create.js.map +1 -0
  35. package/lib/bulk-importer/handlers/filter/index.d.ts +3 -0
  36. package/lib/bulk-importer/handlers/filter/index.js +4 -0
  37. package/lib/bulk-importer/handlers/filter/index.js.map +1 -0
  38. package/lib/bulk-importer/handlers/filter/remove.d.ts +9 -0
  39. package/lib/bulk-importer/handlers/filter/remove.js +14 -0
  40. package/lib/bulk-importer/handlers/filter/remove.js.map +1 -0
  41. package/lib/bulk-importer/handlers/filter/update.d.ts +10 -0
  42. package/lib/bulk-importer/handlers/filter/update.js +34 -0
  43. package/lib/bulk-importer/handlers/filter/update.js.map +1 -0
  44. package/lib/bulk-importer/handlers/filter/upsertFilterContent.d.ts +13 -0
  45. package/lib/bulk-importer/handlers/filter/upsertFilterContent.js +6 -0
  46. package/lib/bulk-importer/handlers/filter/upsertFilterContent.js.map +1 -0
  47. package/lib/bulk-importer/handlers/filter/upsertFilterOptionContent.d.ts +5 -0
  48. package/lib/bulk-importer/handlers/filter/upsertFilterOptionContent.js +8 -0
  49. package/lib/bulk-importer/handlers/filter/upsertFilterOptionContent.js.map +1 -0
  50. package/lib/bulk-importer/handlers/product/create.d.ts +11 -0
  51. package/lib/bulk-importer/handlers/product/create.js +51 -0
  52. package/lib/bulk-importer/handlers/product/create.js.map +1 -0
  53. package/lib/bulk-importer/handlers/product/index.d.ts +3 -0
  54. package/lib/bulk-importer/handlers/product/index.js +4 -0
  55. package/lib/bulk-importer/handlers/product/index.js.map +1 -0
  56. package/lib/bulk-importer/handlers/product/remove.d.ts +9 -0
  57. package/lib/bulk-importer/handlers/product/remove.js +14 -0
  58. package/lib/bulk-importer/handlers/product/remove.js.map +1 -0
  59. package/lib/bulk-importer/handlers/product/transformSpecificationToProductStructure.d.ts +2 -0
  60. package/lib/bulk-importer/handlers/product/transformSpecificationToProductStructure.js +13 -0
  61. package/lib/bulk-importer/handlers/product/transformSpecificationToProductStructure.js.map +1 -0
  62. package/lib/bulk-importer/handlers/product/update.d.ts +10 -0
  63. package/lib/bulk-importer/handlers/product/update.js +48 -0
  64. package/lib/bulk-importer/handlers/product/update.js.map +1 -0
  65. package/lib/bulk-importer/handlers/product/upsertMedia.d.ts +6 -0
  66. package/lib/bulk-importer/handlers/product/upsertMedia.js +69 -0
  67. package/lib/bulk-importer/handlers/product/upsertMedia.js.map +1 -0
  68. package/lib/bulk-importer/handlers/product/upsertProductContent.d.ts +6 -0
  69. package/lib/bulk-importer/handlers/product/upsertProductContent.js +9 -0
  70. package/lib/bulk-importer/handlers/product/upsertProductContent.js.map +1 -0
  71. package/lib/bulk-importer/handlers/product/upsertVariations.d.ts +6 -0
  72. package/lib/bulk-importer/handlers/product/upsertVariations.js +39 -0
  73. package/lib/bulk-importer/handlers/product/upsertVariations.js.map +1 -0
  74. package/lib/context/index.d.ts +2 -0
  75. package/lib/context/index.js +3 -0
  76. package/lib/context/index.js.map +1 -0
  77. package/lib/context/setAccessToken.d.ts +3 -0
  78. package/lib/context/setAccessToken.js +10 -0
  79. package/lib/context/setAccessToken.js.map +1 -0
  80. package/lib/context/withAccessToken.d.ts +2 -0
  81. package/lib/context/withAccessToken.js +33 -0
  82. package/lib/context/withAccessToken.js.map +1 -0
  83. package/lib/migrations/createMigrationRunner.d.ts +14 -0
  84. package/lib/migrations/createMigrationRunner.js +49 -0
  85. package/lib/migrations/createMigrationRunner.js.map +1 -0
  86. package/lib/migrations/migrationRepository.d.ts +3 -0
  87. package/lib/migrations/migrationRepository.js +16 -0
  88. package/lib/migrations/migrationRepository.js.map +1 -0
  89. package/lib/migrations/runMigrations.d.ts +7 -0
  90. package/lib/migrations/runMigrations.js +47 -0
  91. package/lib/migrations/runMigrations.js.map +1 -0
  92. package/lib/platform-index.d.ts +2 -0
  93. package/lib/platform-index.js +3 -0
  94. package/lib/platform-index.js.map +1 -0
  95. package/lib/setup/generateEventTypeDefs.d.ts +1 -0
  96. package/lib/setup/generateEventTypeDefs.js +9 -0
  97. package/lib/setup/generateEventTypeDefs.js.map +1 -0
  98. package/lib/setup/generateRoleActionTypeDefs.d.ts +1 -0
  99. package/lib/setup/generateRoleActionTypeDefs.js +9 -0
  100. package/lib/setup/generateRoleActionTypeDefs.js.map +1 -0
  101. package/lib/setup/generateWorkTypeDefs.d.ts +1 -0
  102. package/lib/setup/generateWorkTypeDefs.js +11 -0
  103. package/lib/setup/generateWorkTypeDefs.js.map +1 -0
  104. package/lib/setup/setupAccounts.d.ts +2 -0
  105. package/lib/setup/setupAccounts.js +91 -0
  106. package/lib/setup/setupAccounts.js.map +1 -0
  107. package/lib/setup/setupAutoScheduling.d.ts +1 -0
  108. package/lib/setup/setupAutoScheduling.js +5 -0
  109. package/lib/setup/setupAutoScheduling.js.map +1 -0
  110. package/lib/setup/setupCarts.d.ts +3 -0
  111. package/lib/setup/setupCarts.js +14 -0
  112. package/lib/setup/setupCarts.js.map +1 -0
  113. package/lib/setup/setupTemplates.d.ts +1 -0
  114. package/lib/setup/setupTemplates.js +17 -0
  115. package/lib/setup/setupTemplates.js.map +1 -0
  116. package/lib/setup/setupWorkqueue.d.ts +6 -0
  117. package/lib/setup/setupWorkqueue.js +11 -0
  118. package/lib/setup/setupWorkqueue.js.map +1 -0
  119. package/lib/startPlatform.d.ts +8 -0
  120. package/lib/startPlatform.js +105 -0
  121. package/lib/startPlatform.js.map +1 -0
  122. package/lib/templates/resolveAccountActionTemplate.d.ts +2 -0
  123. package/lib/templates/resolveAccountActionTemplate.js +131 -0
  124. package/lib/templates/resolveAccountActionTemplate.js.map +1 -0
  125. package/lib/templates/resolveEnrollmentStatusTemplate.d.ts +2 -0
  126. package/lib/templates/resolveEnrollmentStatusTemplate.js +34 -0
  127. package/lib/templates/resolveEnrollmentStatusTemplate.js.map +1 -0
  128. package/lib/templates/resolveForwardDeliveryTemplate.d.ts +2 -0
  129. package/lib/templates/resolveForwardDeliveryTemplate.js +114 -0
  130. package/lib/templates/resolveForwardDeliveryTemplate.js.map +1 -0
  131. package/lib/templates/resolveOrderConfirmationTemplate.d.ts +2 -0
  132. package/lib/templates/resolveOrderConfirmationTemplate.js +111 -0
  133. package/lib/templates/resolveOrderConfirmationTemplate.js.map +1 -0
  134. package/lib/templates/resolveOrderRejectionTemplate.d.ts +2 -0
  135. package/lib/templates/resolveOrderRejectionTemplate.js +77 -0
  136. package/lib/templates/resolveOrderRejectionTemplate.js.map +1 -0
  137. package/lib/templates/resolveQuotationStatusTemplate.d.ts +2 -0
  138. package/lib/templates/resolveQuotationStatusTemplate.js +40 -0
  139. package/lib/templates/resolveQuotationStatusTemplate.js.map +1 -0
  140. package/lib/templates/utils/getOrderAttachmentsData.d.ts +8 -0
  141. package/lib/templates/utils/getOrderAttachmentsData.js +28 -0
  142. package/lib/templates/utils/getOrderAttachmentsData.js.map +1 -0
  143. package/lib/templates/utils/getOrderPositionsData.d.ts +6 -0
  144. package/lib/templates/utils/getOrderPositionsData.js +32 -0
  145. package/lib/templates/utils/getOrderPositionsData.js.map +1 -0
  146. package/package.json +58 -0
  147. package/src/bulk-importer/createBulkImporter.ts +120 -0
  148. package/src/bulk-importer/handlers/assortment/create.ts +86 -0
  149. package/src/bulk-importer/handlers/assortment/index.js +3 -0
  150. package/src/bulk-importer/handlers/assortment/remove.ts +15 -0
  151. package/src/bulk-importer/handlers/assortment/update.ts +85 -0
  152. package/src/bulk-importer/handlers/assortment/upsertAssortmentChildren.ts +51 -0
  153. package/src/bulk-importer/handlers/assortment/upsertAssortmentContent.ts +20 -0
  154. package/src/bulk-importer/handlers/assortment/upsertAssortmentFilters.ts +39 -0
  155. package/src/bulk-importer/handlers/assortment/upsertAssortmentProducts.ts +55 -0
  156. package/src/bulk-importer/handlers/assortment/upsertMedia.ts +99 -0
  157. package/src/bulk-importer/handlers/filter/create.ts +62 -0
  158. package/src/bulk-importer/handlers/filter/index.js +3 -0
  159. package/src/bulk-importer/handlers/filter/remove.ts +16 -0
  160. package/src/bulk-importer/handlers/filter/update.ts +49 -0
  161. package/src/bulk-importer/handlers/filter/upsertFilterContent.ts +17 -0
  162. package/src/bulk-importer/handlers/filter/upsertFilterOptionContent.ts +21 -0
  163. package/src/bulk-importer/handlers/product/create.ts +73 -0
  164. package/src/bulk-importer/handlers/product/index.js +3 -0
  165. package/src/bulk-importer/handlers/product/remove.ts +17 -0
  166. package/src/bulk-importer/handlers/product/transformSpecificationToProductStructure.js +19 -0
  167. package/src/bulk-importer/handlers/product/update.ts +65 -0
  168. package/src/bulk-importer/handlers/product/upsertMedia.ts +97 -0
  169. package/src/bulk-importer/handlers/product/upsertProductContent.ts +23 -0
  170. package/src/bulk-importer/handlers/product/upsertVariations.ts +77 -0
  171. package/src/context/index.ts +2 -0
  172. package/src/context/setAccessToken.ts +15 -0
  173. package/src/context/withAccessToken.ts +34 -0
  174. package/src/migrations/createMigrationRunner.js +61 -0
  175. package/src/migrations/migrationRepository.ts +18 -0
  176. package/src/migrations/runMigrations.ts +64 -0
  177. package/src/platform-index.ts +2 -0
  178. package/src/setup/generateEventTypeDefs.js +9 -0
  179. package/src/setup/generateRoleActionTypeDefs.js +9 -0
  180. package/src/setup/generateWorkTypeDefs.js +11 -0
  181. package/src/setup/setupAccounts.ts +129 -0
  182. package/src/setup/setupAutoScheduling.ts +5 -0
  183. package/src/setup/setupCarts.ts +27 -0
  184. package/src/setup/setupTemplates.ts +17 -0
  185. package/src/setup/setupWorkqueue.ts +17 -0
  186. package/src/startPlatform.ts +145 -0
  187. package/src/templates/resolveAccountActionTemplate.ts +144 -0
  188. package/src/templates/resolveEnrollmentStatusTemplate.ts +43 -0
  189. package/src/templates/resolveForwardDeliveryTemplate.ts +128 -0
  190. package/src/templates/resolveOrderConfirmationTemplate.ts +133 -0
  191. package/src/templates/resolveOrderRejectionTemplate.ts +85 -0
  192. package/src/templates/resolveQuotationStatusTemplate.ts +54 -0
  193. package/src/templates/utils/getOrderAttachmentsData.ts +47 -0
  194. package/src/templates/utils/getOrderPositionsData.ts +49 -0
  195. package/tsconfig.build.json +26 -0
  196. package/tsconfig.json +8 -0
@@ -0,0 +1,128 @@
1
+ import { TemplateResolver } from '@unchainedshop/types/messaging';
2
+ import moment from 'moment';
3
+ import { systemLocale } from '@unchainedshop/utils';
4
+ import { getOrderAttachmentsData } from './utils/getOrderAttachmentsData';
5
+ import { getOrderPositionsData } from './utils/getOrderPositionsData';
6
+
7
+ const { EMAIL_FROM, EMAIL_WEBSITE_NAME, ROOT_URL } = process.env;
8
+
9
+ const mjmlTemplate = `
10
+ <mjml>
11
+ <mj-body background-color="#FAFAFA">
12
+ <mj-section padding-bottom="32px" background-color="#fcfcfc">
13
+ <mj-column width="100%">
14
+ <mj-text align="center" font-size="20px" color="#232323" font-family="Helvetica Neue" font-weight="200">
15
+ <h2 >{{subject}}</h2>
16
+ </mj-text>
17
+ <mj-text align="left" font-size="20px" color="#232323" font-family="Helvetica Neue" font-weight="200">
18
+ <span>Order number: {{orderNumber}}</span><br/>
19
+ <span>Order date: {{orderDate}}</span>
20
+ <a href="{{controlpanelLink}}">{{controlpanelLink}}</a>
21
+ </mj-text>
22
+ <mj-text align="left" font-size="20px" color="#232323">Delivery address</mj-text>
23
+ <mj-text align="left">
24
+ {{address.firstName}} {{address.lastName}}<br/>
25
+ {{address.company}}<br/>
26
+ {{address.addressLine}}<br/>
27
+ {{address.addressLine2}}<br/>
28
+ {{address.postalCode}} {{address.city}} {{address.regionCode}}<br/>
29
+ {{address.countryCode}}<br/>
30
+ </mj-text>
31
+ <mj-divider border-width="1px" border-style="dashed" border-color="lightgrey" />
32
+ <mj-text align="left" font-size="20px" color="#232323">Articles</mj-text>
33
+ <mj-table>
34
+ <tr style="border-bottom:1px solid #ecedee;text-align:left;padding:15px 0;">
35
+ <th style="padding: 0 15px 0 0;">Article</th>
36
+ <th style="padding: 0 15px;">Quantity</th>
37
+ </tr>
38
+ {{#items}}
39
+ <tr>
40
+ <td style="padding: 0 15px 0 0;">{{sku}} - {{name}}</td>
41
+ <td style="padding: 0 15px;">{{quantity}}</td>
42
+ </tr>
43
+ {{/items}}
44
+ </mj-table>
45
+ </mj-column>
46
+ </mj-section>
47
+ </mj-body>
48
+ </mjml>
49
+ `;
50
+
51
+ const textTemplate = `
52
+ {{subject}}\n
53
+ \n
54
+ Order number: {{orderNumber}}\n
55
+ Order date: {{orderDate}}\n
56
+ Link: {{controlpanelLink}}\n
57
+ \n
58
+ Delivery address:\n
59
+ -----------------\n
60
+ {{address.firstName}} {{address.lastName}}\n
61
+ {{address.company}}\n
62
+ {{address.addressLine}}\n
63
+ {{address.addressLine2}}\n
64
+ {{address.postalCode}} {{address.city}}\n
65
+ {{address.regionCode}}\n
66
+ {{address.countryCode}}\n
67
+ \n
68
+ Articles:\n
69
+ -----------------\n
70
+ {{#items}}
71
+ * {{sku}} - {{name}} CHF {{price}} {{quantity}}\n
72
+ {{/items}}
73
+ `;
74
+
75
+ export const resolveForwardDeliveryTemplate: TemplateResolver = async (
76
+ { config, orderId, transactionContext },
77
+ context,
78
+ ) => {
79
+ const { modules } = context;
80
+ const order = await modules.orders.findOrder({ orderId });
81
+ const orderPricing = modules.orders.pricingSheet(order);
82
+
83
+ const momentDate = moment(order.ordered);
84
+ momentDate.locale(systemLocale.normalized);
85
+ const orderDate = momentDate.format('lll');
86
+
87
+ const attachments = await getOrderAttachmentsData(order, { fileType: 'DELIVERY_NOTE' }, context);
88
+
89
+ const address = transactionContext?.address || order.billingAddress;
90
+ const configObject = config.reduce((acc, { key, value }) => {
91
+ return {
92
+ ...acc,
93
+ [key]: value,
94
+ };
95
+ }, {});
96
+
97
+ const subject = `${EMAIL_WEBSITE_NAME}: New Order / ${order.orderNumber}`;
98
+
99
+ const controlpanelLink = `${ROOT_URL}/orders/view/?_id=${order._id}`;
100
+
101
+ const data = {
102
+ contact: order.contact || {},
103
+ controlpanelLink,
104
+ items: getOrderPositionsData(order, { locale: systemLocale }, context),
105
+ orderDate,
106
+ orderNumber: order.orderNumber,
107
+ shopName: EMAIL_WEBSITE_NAME,
108
+ subject,
109
+ total: orderPricing.total({ useNetPrice: false }).amount / 100,
110
+ ...configObject,
111
+ address,
112
+ };
113
+
114
+ return [
115
+ {
116
+ type: 'EMAIL',
117
+ input: {
118
+ from: configObject.from || EMAIL_FROM || 'noreply@unchained.local',
119
+ to: configObject.to || 'orders@unchained.local',
120
+ cc: configObject.cc,
121
+ subject,
122
+ text: modules.messaging.renderToText(textTemplate, data),
123
+ html: modules.messaging.renderMjmlToHtml(mjmlTemplate, data),
124
+ attachments,
125
+ },
126
+ },
127
+ ];
128
+ };
@@ -0,0 +1,133 @@
1
+ import { TemplateResolver } from '@unchainedshop/types/messaging';
2
+ import { OrderPricingRowCategory } from '@unchainedshop/types/orders.pricing';
3
+ import { getOrderAttachmentsData } from './utils/getOrderAttachmentsData';
4
+ import { getOrderPositionsData } from './utils/getOrderPositionsData';
5
+
6
+ const { EMAIL_FROM, EMAIL_WEBSITE_NAME, EMAIL_WEBSITE_URL } = process.env;
7
+
8
+ const mjmlTemplate = `
9
+ <mjml>
10
+ <mj-body background-color="#FAFAFA">
11
+ <mj-section padding-bottom="32px" background-color="#FFFFFF">
12
+ <mj-column width="100%">
13
+ <mj-text font-size="20px" color="#232323" font-family="Helvetica Neue" font-weight="400">
14
+ <h2>{{subject}}</h2>
15
+ </mj-text>
16
+ <mj-text font-size="20px" color="#232323" font-family="Helvetica Neue">
17
+ <p>{{thankyou}} <a style="color:#2CAADF" href="{{shopUrl}}">{{shopName}}</a></p>
18
+ </mj-text>
19
+ </mj-column>
20
+ </mj-section>
21
+
22
+ <mj-section padding-bottom="20px" background-color="#F3F3F3">
23
+ <mj-column>
24
+ <mj-button href="{{url}}" font-family="Helvetica" background-color="#31302E" color="#FFFFFF">
25
+ {{buttonText}}
26
+ </mj-button>
27
+ </mj-column>
28
+ </mj-section>
29
+ </mj-body>
30
+ </mjml>
31
+ `;
32
+
33
+ const textTemplate = `
34
+ {{subject}}\n
35
+ \n
36
+ {{thankyou}}\n
37
+ \n
38
+ -----------------\n
39
+ {{buttonText}}: {{url}}\n
40
+ -----------------\n
41
+ `;
42
+
43
+ const texts = {
44
+ en: {
45
+ buttonText: 'Follow purchase order status',
46
+ thankyou: 'Thank you for your order on',
47
+ subject: `${EMAIL_WEBSITE_NAME}: Order confirmation`,
48
+ },
49
+ de: {
50
+ buttonText: 'Bestellstatus verfolgen',
51
+ thankyou: 'Vielen Dank für deine Bestellung bei',
52
+ subject: `${EMAIL_WEBSITE_NAME}: Bestellbestätigung`,
53
+ },
54
+ fr: {
55
+ buttonText: 'Follow purchase order status',
56
+ thankyou: 'Thank you for your order on',
57
+ subject: `${EMAIL_WEBSITE_NAME}: Order confirmation`,
58
+ },
59
+ };
60
+
61
+ export const resolveOrderConfirmationTemplate: TemplateResolver = async (
62
+ { orderId, locale },
63
+ context,
64
+ ) => {
65
+ const { modules } = context;
66
+ const order = await modules.orders.findOrder({ orderId });
67
+
68
+ if (order.status === 'PENDING') {
69
+ return [];
70
+ }
71
+
72
+ const formatPrice = (price: number) => {
73
+ const fixedPrice = price / 100;
74
+ return `${order.currency} ${fixedPrice}`;
75
+ };
76
+
77
+ // TODO: If order.status is PENDING, we should only send the user
78
+ // a notice that we have received the order but not confirming it
79
+ const attachments = await getOrderAttachmentsData(order, { fileType: 'ORDER_CONFIRMATION' }, context);
80
+
81
+ const orderPricing = modules.orders.pricingSheet(order);
82
+
83
+ const { subject } = texts[locale.language];
84
+
85
+ const data = {
86
+ ...texts[locale.language],
87
+ shopName: EMAIL_WEBSITE_NAME,
88
+ shopUrl: EMAIL_WEBSITE_URL,
89
+ subject,
90
+ url: `${EMAIL_WEBSITE_URL}/order?_id=${order._id}`,
91
+ summary: {
92
+ items: formatPrice(
93
+ orderPricing.total({
94
+ category: OrderPricingRowCategory.Items,
95
+ useNetPrice: false,
96
+ }).amount,
97
+ ),
98
+ taxes: formatPrice(
99
+ orderPricing.total({
100
+ category: OrderPricingRowCategory.Taxes,
101
+ useNetPrice: false,
102
+ }).amount,
103
+ ),
104
+ delivery: formatPrice(
105
+ orderPricing.total({
106
+ category: OrderPricingRowCategory.Delivery,
107
+ useNetPrice: false,
108
+ }).amount,
109
+ ),
110
+ payment: formatPrice(
111
+ orderPricing.total({
112
+ category: OrderPricingRowCategory.Payment,
113
+ useNetPrice: false,
114
+ }).amount,
115
+ ),
116
+ gross: formatPrice(orderPricing.total({ useNetPrice: false }).amount),
117
+ },
118
+ positions: getOrderPositionsData(order, { locale }, context),
119
+ };
120
+ return [
121
+ {
122
+ type: 'EMAIL',
123
+ input: {
124
+ from: EMAIL_FROM || 'orders@unchained.local',
125
+ to: order.contact.emailAddress,
126
+ subject,
127
+ text: modules.messaging.renderToText(textTemplate, data),
128
+ html: modules.messaging.renderMjmlToHtml(mjmlTemplate, data),
129
+ attachments,
130
+ },
131
+ },
132
+ ];
133
+ };
@@ -0,0 +1,85 @@
1
+ import { TemplateResolver } from '@unchainedshop/types/messaging';
2
+
3
+ const { EMAIL_FROM, EMAIL_WEBSITE_NAME, EMAIL_WEBSITE_URL } = process.env;
4
+
5
+ const mjmlTemplate = `
6
+ <mjml>
7
+ <mj-body background-color="#FAFAFA">
8
+ <mj-section padding-bottom="32px" background-color="#FFFFFF">
9
+ <mj-column width="100%">
10
+ <mj-text font-size="20px" color="#232323" font-family="Helvetica Neue" font-weight="400">
11
+ <h2>{{subject}}</h2>
12
+ </mj-text>
13
+ <mj-text font-size="20px" color="#232323" font-family="Helvetica Neue">
14
+ <p>{{rejection}}</p>
15
+ </mj-text>
16
+ </mj-column>
17
+ </mj-section>
18
+
19
+ <mj-section padding-bottom="20px" background-color="#F3F3F3">
20
+ <mj-column>
21
+ <mj-button href="{{url}}" font-family="Helvetica" background-color="#31302E" color="#FFFFFF">
22
+ {{buttonText}}
23
+ </mj-button>
24
+ </mj-column>
25
+ </mj-section>
26
+ </mj-body>
27
+ </mjml>
28
+ `;
29
+
30
+ const textTemplate = `
31
+ {{subject}}\n
32
+ \n
33
+ {{rejection}}\n
34
+ \n
35
+ -----------------\n
36
+ {{buttonText}}: {{url}}\n
37
+ -----------------\n
38
+ `;
39
+
40
+ const texts = {
41
+ en: {
42
+ buttonText: 'Details are available at',
43
+ rejection: 'Your order was cancelled.',
44
+ subject: `${EMAIL_WEBSITE_NAME}: Order cancelled`,
45
+ },
46
+ de: {
47
+ buttonText: 'Details abrufen',
48
+ rejection: 'Deine Bestellung wurde storniert',
49
+ subject: `${EMAIL_WEBSITE_NAME}: Bestellung storniert`,
50
+ },
51
+ fr: {
52
+ buttonText: 'Details are available at',
53
+ rejection: 'Your order was cancelled.',
54
+ subject: `${EMAIL_WEBSITE_NAME}: Order cancelled`,
55
+ },
56
+ };
57
+
58
+ export const resolveOrderRejectionTemplate: TemplateResolver = async ({ orderId, locale }, context) => {
59
+ const { modules } = context;
60
+ const order = await modules.orders.findOrder({ orderId });
61
+
62
+ if (order.status !== 'REJECTED') {
63
+ return [];
64
+ }
65
+
66
+ const { subject } = texts[locale.language];
67
+
68
+ const data = {
69
+ ...texts[locale.language],
70
+ subject,
71
+ url: `${EMAIL_WEBSITE_URL}/order?_id=${order._id}`,
72
+ };
73
+ return [
74
+ {
75
+ type: 'EMAIL',
76
+ input: {
77
+ from: EMAIL_FROM || 'orders@unchained.local',
78
+ to: order.contact.emailAddress,
79
+ subject,
80
+ text: modules.messaging.renderToText(textTemplate, data),
81
+ html: modules.messaging.renderMjmlToHtml(mjmlTemplate, data),
82
+ },
83
+ },
84
+ ];
85
+ };
@@ -0,0 +1,54 @@
1
+ import { TemplateResolver } from '@unchainedshop/types/messaging';
2
+
3
+ const { EMAIL_FROM, EMAIL_WEBSITE_NAME, EMAIL_WEBSITE_URL } = process.env;
4
+
5
+ const textTemplate = `
6
+ {{subject}}\n
7
+ \n
8
+ Status: {{quotation.status}}
9
+ \n
10
+ -----------------\n
11
+ Show: {{url}}\n
12
+ -----------------\n
13
+ `;
14
+
15
+ export const resolveQuotationStatusTemplate: TemplateResolver = async (
16
+ { quotationId, locale },
17
+ { modules },
18
+ ) => {
19
+ const quotation = await modules.quotations.findQuotation({ quotationId });
20
+ const user = await modules.users.findUserById(quotation.userId);
21
+ const attachments = (
22
+ await modules.files.findFilesByMetaData(
23
+ { meta: { quotationId: quotation._id, type: 'PROPOSAL ' } },
24
+ { sort: { 'meta.date': -1 } },
25
+ )
26
+ )
27
+ .filter(Boolean)
28
+ .map((file) => ({
29
+ filename: `${quotation.quotationNumber}_${file.name}`,
30
+ path: file.url,
31
+ }));
32
+
33
+ const subject = `${EMAIL_WEBSITE_NAME}: Updated Quotation / ${quotation.quotationNumber}`;
34
+
35
+ const data = {
36
+ locale,
37
+ quotation,
38
+ subject,
39
+ url: `${EMAIL_WEBSITE_URL}/quotation?_id=${quotation._id}`,
40
+ };
41
+
42
+ return [
43
+ {
44
+ type: 'EMAIL',
45
+ input: {
46
+ from: EMAIL_FROM,
47
+ to: modules.users.primaryEmail(user)?.address,
48
+ subject,
49
+ text: modules.messaging.renderToText(textTemplate, data),
50
+ attachments,
51
+ },
52
+ },
53
+ ];
54
+ };
@@ -0,0 +1,47 @@
1
+ import { Context } from '@unchainedshop/types/api';
2
+ import { Order } from '@unchainedshop/types/orders';
3
+
4
+ export const getOrderAttachmentsData = async (
5
+ order: Order,
6
+ params: { fileType: string },
7
+ { modules }: Context,
8
+ ) => {
9
+ const orderId = order._id;
10
+ const attachments = [];
11
+
12
+ const orderFiles = await modules.files.findFilesByMetaData(
13
+ {
14
+ meta: { orderId: order._id, type: params.fileType },
15
+ },
16
+ { limit: 1 },
17
+ );
18
+ attachments.concat(orderFiles);
19
+ const payment = await modules.orders.payments.findOrderPayment(
20
+ {
21
+ orderPaymentId: order.paymentId,
22
+ },
23
+ { limit: 1 },
24
+ );
25
+ if (modules.orders.payments.isBlockingOrderFullfillment(payment)) {
26
+ const invoices = await modules.files.findFilesByMetaData(
27
+ {
28
+ meta: { orderId, type: 'INVOICE' },
29
+ },
30
+ { limit: 1 },
31
+ );
32
+ attachments.concat(invoices);
33
+ } else {
34
+ const receipts = await modules.files.findFilesByMetaData(
35
+ {
36
+ meta: { orderId, type: 'RECEIPT' },
37
+ },
38
+ { limit: 1 },
39
+ );
40
+ attachments.concat(receipts);
41
+ }
42
+
43
+ return attachments.map((file) => ({
44
+ filename: `${order.orderNumber}_${file.name}`,
45
+ path: file.path,
46
+ }));
47
+ };
@@ -0,0 +1,49 @@
1
+ import { Context } from '@unchainedshop/types/api';
2
+ import { Locale } from '@unchainedshop/types/common';
3
+ import { Order } from '@unchainedshop/types/orders';
4
+
5
+ export const getOrderPositionsData = async (
6
+ order: Order,
7
+ params: { locale?: Locale },
8
+ context: Context,
9
+ ) => {
10
+ const { modules } = context;
11
+ const orderPositions = await modules.orders.positions.findOrderPositions({
12
+ orderId: order._id,
13
+ });
14
+
15
+ const formatPrice = (price: number) => {
16
+ const fixedPrice = price / 100;
17
+ return `${order.currency} ${fixedPrice}`;
18
+ };
19
+
20
+ await Promise.all(
21
+ orderPositions.map(async (orderPosition) => {
22
+ const productTexts = await modules.products.texts.findLocalizedText({
23
+ productId: orderPosition.productId,
24
+ locale: params.locale?.normalized,
25
+ });
26
+ const originalProductTexts = await modules.products.texts.findLocalizedText({
27
+ productId: orderPosition.originalProductId,
28
+ locale: params.locale?.normalized,
29
+ });
30
+
31
+ const productTitle = productTexts?.title; // deprecated
32
+
33
+ const positionPricing = modules.orders.positions.pricingSheet(
34
+ orderPosition,
35
+ order.currency,
36
+ context,
37
+ );
38
+ const total = formatPrice(positionPricing.sum());
39
+ const { quantity } = positionPricing;
40
+ return {
41
+ originalProductTexts,
42
+ product: productTitle,
43
+ productTexts,
44
+ quantity,
45
+ total,
46
+ };
47
+ }),
48
+ );
49
+ };
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "allowJs": true,
4
+ "allowSyntheticDefaultImports": true,
5
+ "declaration": true,
6
+ "esModuleInterop": true,
7
+ "experimentalDecorators": true,
8
+ "forceConsistentCasingInFileNames": true,
9
+ "lib": ["esnext"],
10
+ "module": "esnext",
11
+ "moduleResolution": "node",
12
+ "noImplicitReturns": true,
13
+ "noUnusedLocals": false,
14
+ "outDir": "lib",
15
+ "preserveWatchOutput": true,
16
+ "skipLibCheck": true,
17
+ "sourceMap": true,
18
+ "target": "esnext",
19
+ "types": ["node"],
20
+ "baseUrl": ".", // This must be specified if "paths" is.
21
+ "paths": {
22
+ "meteor/unchained:*": ["node_modules/@unchainedshop/types/index.d.ts"]
23
+ }
24
+ },
25
+ "include": ["src"]
26
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "./tsconfig.build.json",
3
+ "compilerOptions": {
4
+ "noEmit": true,
5
+ "types": ["node", "mocha"]
6
+ },
7
+ "include": ["src", "tests"]
8
+ }