@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.
- package/README.md +3 -0
- package/lib/bulk-importer/createBulkImporter.d.ts +4 -0
- package/lib/bulk-importer/createBulkImporter.js +102 -0
- package/lib/bulk-importer/createBulkImporter.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/create.d.ts +11 -0
- package/lib/bulk-importer/handlers/assortment/create.js +59 -0
- package/lib/bulk-importer/handlers/assortment/create.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/index.d.ts +3 -0
- package/lib/bulk-importer/handlers/assortment/index.js +4 -0
- package/lib/bulk-importer/handlers/assortment/index.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/remove.d.ts +9 -0
- package/lib/bulk-importer/handlers/assortment/remove.js +13 -0
- package/lib/bulk-importer/handlers/assortment/remove.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/update.d.ts +10 -0
- package/lib/bulk-importer/handlers/assortment/update.js +61 -0
- package/lib/bulk-importer/handlers/assortment/update.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentChildren.d.ts +7 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentChildren.js +30 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentChildren.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentContent.d.ts +7 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentContent.js +9 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentContent.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentFilters.d.ts +7 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentFilters.js +29 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentFilters.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentProducts.d.ts +7 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentProducts.js +32 -0
- package/lib/bulk-importer/handlers/assortment/upsertAssortmentProducts.js.map +1 -0
- package/lib/bulk-importer/handlers/assortment/upsertMedia.d.ts +7 -0
- package/lib/bulk-importer/handlers/assortment/upsertMedia.js +67 -0
- package/lib/bulk-importer/handlers/assortment/upsertMedia.js.map +1 -0
- package/lib/bulk-importer/handlers/filter/create.d.ts +11 -0
- package/lib/bulk-importer/handlers/filter/create.js +42 -0
- package/lib/bulk-importer/handlers/filter/create.js.map +1 -0
- package/lib/bulk-importer/handlers/filter/index.d.ts +3 -0
- package/lib/bulk-importer/handlers/filter/index.js +4 -0
- package/lib/bulk-importer/handlers/filter/index.js.map +1 -0
- package/lib/bulk-importer/handlers/filter/remove.d.ts +9 -0
- package/lib/bulk-importer/handlers/filter/remove.js +14 -0
- package/lib/bulk-importer/handlers/filter/remove.js.map +1 -0
- package/lib/bulk-importer/handlers/filter/update.d.ts +10 -0
- package/lib/bulk-importer/handlers/filter/update.js +34 -0
- package/lib/bulk-importer/handlers/filter/update.js.map +1 -0
- package/lib/bulk-importer/handlers/filter/upsertFilterContent.d.ts +13 -0
- package/lib/bulk-importer/handlers/filter/upsertFilterContent.js +6 -0
- package/lib/bulk-importer/handlers/filter/upsertFilterContent.js.map +1 -0
- package/lib/bulk-importer/handlers/filter/upsertFilterOptionContent.d.ts +5 -0
- package/lib/bulk-importer/handlers/filter/upsertFilterOptionContent.js +8 -0
- package/lib/bulk-importer/handlers/filter/upsertFilterOptionContent.js.map +1 -0
- package/lib/bulk-importer/handlers/product/create.d.ts +11 -0
- package/lib/bulk-importer/handlers/product/create.js +51 -0
- package/lib/bulk-importer/handlers/product/create.js.map +1 -0
- package/lib/bulk-importer/handlers/product/index.d.ts +3 -0
- package/lib/bulk-importer/handlers/product/index.js +4 -0
- package/lib/bulk-importer/handlers/product/index.js.map +1 -0
- package/lib/bulk-importer/handlers/product/remove.d.ts +9 -0
- package/lib/bulk-importer/handlers/product/remove.js +14 -0
- package/lib/bulk-importer/handlers/product/remove.js.map +1 -0
- package/lib/bulk-importer/handlers/product/transformSpecificationToProductStructure.d.ts +2 -0
- package/lib/bulk-importer/handlers/product/transformSpecificationToProductStructure.js +13 -0
- package/lib/bulk-importer/handlers/product/transformSpecificationToProductStructure.js.map +1 -0
- package/lib/bulk-importer/handlers/product/update.d.ts +10 -0
- package/lib/bulk-importer/handlers/product/update.js +48 -0
- package/lib/bulk-importer/handlers/product/update.js.map +1 -0
- package/lib/bulk-importer/handlers/product/upsertMedia.d.ts +6 -0
- package/lib/bulk-importer/handlers/product/upsertMedia.js +69 -0
- package/lib/bulk-importer/handlers/product/upsertMedia.js.map +1 -0
- package/lib/bulk-importer/handlers/product/upsertProductContent.d.ts +6 -0
- package/lib/bulk-importer/handlers/product/upsertProductContent.js +9 -0
- package/lib/bulk-importer/handlers/product/upsertProductContent.js.map +1 -0
- package/lib/bulk-importer/handlers/product/upsertVariations.d.ts +6 -0
- package/lib/bulk-importer/handlers/product/upsertVariations.js +39 -0
- package/lib/bulk-importer/handlers/product/upsertVariations.js.map +1 -0
- package/lib/context/index.d.ts +2 -0
- package/lib/context/index.js +3 -0
- package/lib/context/index.js.map +1 -0
- package/lib/context/setAccessToken.d.ts +3 -0
- package/lib/context/setAccessToken.js +10 -0
- package/lib/context/setAccessToken.js.map +1 -0
- package/lib/context/withAccessToken.d.ts +2 -0
- package/lib/context/withAccessToken.js +33 -0
- package/lib/context/withAccessToken.js.map +1 -0
- package/lib/migrations/createMigrationRunner.d.ts +14 -0
- package/lib/migrations/createMigrationRunner.js +49 -0
- package/lib/migrations/createMigrationRunner.js.map +1 -0
- package/lib/migrations/migrationRepository.d.ts +3 -0
- package/lib/migrations/migrationRepository.js +16 -0
- package/lib/migrations/migrationRepository.js.map +1 -0
- package/lib/migrations/runMigrations.d.ts +7 -0
- package/lib/migrations/runMigrations.js +47 -0
- package/lib/migrations/runMigrations.js.map +1 -0
- package/lib/platform-index.d.ts +2 -0
- package/lib/platform-index.js +3 -0
- package/lib/platform-index.js.map +1 -0
- package/lib/setup/generateEventTypeDefs.d.ts +1 -0
- package/lib/setup/generateEventTypeDefs.js +9 -0
- package/lib/setup/generateEventTypeDefs.js.map +1 -0
- package/lib/setup/generateRoleActionTypeDefs.d.ts +1 -0
- package/lib/setup/generateRoleActionTypeDefs.js +9 -0
- package/lib/setup/generateRoleActionTypeDefs.js.map +1 -0
- package/lib/setup/generateWorkTypeDefs.d.ts +1 -0
- package/lib/setup/generateWorkTypeDefs.js +11 -0
- package/lib/setup/generateWorkTypeDefs.js.map +1 -0
- package/lib/setup/setupAccounts.d.ts +2 -0
- package/lib/setup/setupAccounts.js +91 -0
- package/lib/setup/setupAccounts.js.map +1 -0
- package/lib/setup/setupAutoScheduling.d.ts +1 -0
- package/lib/setup/setupAutoScheduling.js +5 -0
- package/lib/setup/setupAutoScheduling.js.map +1 -0
- package/lib/setup/setupCarts.d.ts +3 -0
- package/lib/setup/setupCarts.js +14 -0
- package/lib/setup/setupCarts.js.map +1 -0
- package/lib/setup/setupTemplates.d.ts +1 -0
- package/lib/setup/setupTemplates.js +17 -0
- package/lib/setup/setupTemplates.js.map +1 -0
- package/lib/setup/setupWorkqueue.d.ts +6 -0
- package/lib/setup/setupWorkqueue.js +11 -0
- package/lib/setup/setupWorkqueue.js.map +1 -0
- package/lib/startPlatform.d.ts +8 -0
- package/lib/startPlatform.js +105 -0
- package/lib/startPlatform.js.map +1 -0
- package/lib/templates/resolveAccountActionTemplate.d.ts +2 -0
- package/lib/templates/resolveAccountActionTemplate.js +131 -0
- package/lib/templates/resolveAccountActionTemplate.js.map +1 -0
- package/lib/templates/resolveEnrollmentStatusTemplate.d.ts +2 -0
- package/lib/templates/resolveEnrollmentStatusTemplate.js +34 -0
- package/lib/templates/resolveEnrollmentStatusTemplate.js.map +1 -0
- package/lib/templates/resolveForwardDeliveryTemplate.d.ts +2 -0
- package/lib/templates/resolveForwardDeliveryTemplate.js +114 -0
- package/lib/templates/resolveForwardDeliveryTemplate.js.map +1 -0
- package/lib/templates/resolveOrderConfirmationTemplate.d.ts +2 -0
- package/lib/templates/resolveOrderConfirmationTemplate.js +111 -0
- package/lib/templates/resolveOrderConfirmationTemplate.js.map +1 -0
- package/lib/templates/resolveOrderRejectionTemplate.d.ts +2 -0
- package/lib/templates/resolveOrderRejectionTemplate.js +77 -0
- package/lib/templates/resolveOrderRejectionTemplate.js.map +1 -0
- package/lib/templates/resolveQuotationStatusTemplate.d.ts +2 -0
- package/lib/templates/resolveQuotationStatusTemplate.js +40 -0
- package/lib/templates/resolveQuotationStatusTemplate.js.map +1 -0
- package/lib/templates/utils/getOrderAttachmentsData.d.ts +8 -0
- package/lib/templates/utils/getOrderAttachmentsData.js +28 -0
- package/lib/templates/utils/getOrderAttachmentsData.js.map +1 -0
- package/lib/templates/utils/getOrderPositionsData.d.ts +6 -0
- package/lib/templates/utils/getOrderPositionsData.js +32 -0
- package/lib/templates/utils/getOrderPositionsData.js.map +1 -0
- package/package.json +58 -0
- package/src/bulk-importer/createBulkImporter.ts +120 -0
- package/src/bulk-importer/handlers/assortment/create.ts +86 -0
- package/src/bulk-importer/handlers/assortment/index.js +3 -0
- package/src/bulk-importer/handlers/assortment/remove.ts +15 -0
- package/src/bulk-importer/handlers/assortment/update.ts +85 -0
- package/src/bulk-importer/handlers/assortment/upsertAssortmentChildren.ts +51 -0
- package/src/bulk-importer/handlers/assortment/upsertAssortmentContent.ts +20 -0
- package/src/bulk-importer/handlers/assortment/upsertAssortmentFilters.ts +39 -0
- package/src/bulk-importer/handlers/assortment/upsertAssortmentProducts.ts +55 -0
- package/src/bulk-importer/handlers/assortment/upsertMedia.ts +99 -0
- package/src/bulk-importer/handlers/filter/create.ts +62 -0
- package/src/bulk-importer/handlers/filter/index.js +3 -0
- package/src/bulk-importer/handlers/filter/remove.ts +16 -0
- package/src/bulk-importer/handlers/filter/update.ts +49 -0
- package/src/bulk-importer/handlers/filter/upsertFilterContent.ts +17 -0
- package/src/bulk-importer/handlers/filter/upsertFilterOptionContent.ts +21 -0
- package/src/bulk-importer/handlers/product/create.ts +73 -0
- package/src/bulk-importer/handlers/product/index.js +3 -0
- package/src/bulk-importer/handlers/product/remove.ts +17 -0
- package/src/bulk-importer/handlers/product/transformSpecificationToProductStructure.js +19 -0
- package/src/bulk-importer/handlers/product/update.ts +65 -0
- package/src/bulk-importer/handlers/product/upsertMedia.ts +97 -0
- package/src/bulk-importer/handlers/product/upsertProductContent.ts +23 -0
- package/src/bulk-importer/handlers/product/upsertVariations.ts +77 -0
- package/src/context/index.ts +2 -0
- package/src/context/setAccessToken.ts +15 -0
- package/src/context/withAccessToken.ts +34 -0
- package/src/migrations/createMigrationRunner.js +61 -0
- package/src/migrations/migrationRepository.ts +18 -0
- package/src/migrations/runMigrations.ts +64 -0
- package/src/platform-index.ts +2 -0
- package/src/setup/generateEventTypeDefs.js +9 -0
- package/src/setup/generateRoleActionTypeDefs.js +9 -0
- package/src/setup/generateWorkTypeDefs.js +11 -0
- package/src/setup/setupAccounts.ts +129 -0
- package/src/setup/setupAutoScheduling.ts +5 -0
- package/src/setup/setupCarts.ts +27 -0
- package/src/setup/setupTemplates.ts +17 -0
- package/src/setup/setupWorkqueue.ts +17 -0
- package/src/startPlatform.ts +145 -0
- package/src/templates/resolveAccountActionTemplate.ts +144 -0
- package/src/templates/resolveEnrollmentStatusTemplate.ts +43 -0
- package/src/templates/resolveForwardDeliveryTemplate.ts +128 -0
- package/src/templates/resolveOrderConfirmationTemplate.ts +133 -0
- package/src/templates/resolveOrderRejectionTemplate.ts +85 -0
- package/src/templates/resolveQuotationStatusTemplate.ts +54 -0
- package/src/templates/utils/getOrderAttachmentsData.ts +47 -0
- package/src/templates/utils/getOrderPositionsData.ts +49 -0
- package/tsconfig.build.json +26 -0
- 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
|
+
}
|