@unchainedshop/core-delivery 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 (57) hide show
  1. package/.npm/package/README +7 -0
  2. package/.npm/package/npm-shrinkwrap.json +190 -0
  3. package/.versions +54 -0
  4. package/README.md +3 -0
  5. package/lib/db/DeliveryProvidersCollection.d.ts +3 -0
  6. package/lib/db/DeliveryProvidersCollection.js +7 -0
  7. package/lib/db/DeliveryProvidersCollection.js.map +1 -0
  8. package/lib/db/DeliveryProvidersSchema.d.ts +1 -0
  9. package/lib/db/DeliveryProvidersSchema.js +13 -0
  10. package/lib/db/DeliveryProvidersSchema.js.map +1 -0
  11. package/lib/delivery-index.d.ts +8 -0
  12. package/lib/delivery-index.js +9 -0
  13. package/lib/delivery-index.js.map +1 -0
  14. package/lib/delivery-settings.d.ts +2 -0
  15. package/lib/delivery-settings.js +29 -0
  16. package/lib/delivery-settings.js.map +1 -0
  17. package/lib/director/DeliveryAdapter.d.ts +2 -0
  18. package/lib/director/DeliveryAdapter.js +44 -0
  19. package/lib/director/DeliveryAdapter.js.map +1 -0
  20. package/lib/director/DeliveryDirector.d.ts +2 -0
  21. package/lib/director/DeliveryDirector.js +69 -0
  22. package/lib/director/DeliveryDirector.js.map +1 -0
  23. package/lib/director/DeliveryError.d.ts +6 -0
  24. package/lib/director/DeliveryError.js +8 -0
  25. package/lib/director/DeliveryError.js.map +1 -0
  26. package/lib/director/DeliveryPricingAdapter.d.ts +2 -0
  27. package/lib/director/DeliveryPricingAdapter.js +25 -0
  28. package/lib/director/DeliveryPricingAdapter.js.map +1 -0
  29. package/lib/director/DeliveryPricingDirector.d.ts +2 -0
  30. package/lib/director/DeliveryPricingDirector.js +50 -0
  31. package/lib/director/DeliveryPricingDirector.js.map +1 -0
  32. package/lib/director/DeliveryPricingSheet.d.ts +3 -0
  33. package/lib/director/DeliveryPricingSheet.js +92 -0
  34. package/lib/director/DeliveryPricingSheet.js.map +1 -0
  35. package/lib/director/DeliveryProviderType.d.ts +4 -0
  36. package/lib/director/DeliveryProviderType.js +6 -0
  37. package/lib/director/DeliveryProviderType.js.map +1 -0
  38. package/lib/module/configureDeliveryModule.d.ts +3 -0
  39. package/lib/module/configureDeliveryModule.js +137 -0
  40. package/lib/module/configureDeliveryModule.js.map +1 -0
  41. package/package.js +33 -0
  42. package/package.json +43 -0
  43. package/src/db/DeliveryProvidersCollection.ts +11 -0
  44. package/src/db/DeliveryProvidersSchema.js +16 -0
  45. package/src/delivery-index.ts +11 -0
  46. package/src/delivery-settings.ts +46 -0
  47. package/src/director/DeliveryAdapter.ts +56 -0
  48. package/src/director/DeliveryDirector.ts +76 -0
  49. package/src/director/DeliveryError.ts +6 -0
  50. package/src/director/DeliveryPricingAdapter.ts +39 -0
  51. package/src/director/DeliveryPricingDirector.ts +68 -0
  52. package/src/director/DeliveryPricingSheet.ts +112 -0
  53. package/src/director/DeliveryProviderType.ts +4 -0
  54. package/src/module/configureDeliveryModule.ts +206 -0
  55. package/tests/delivery-index.test.ts +22 -0
  56. package/tsconfig.build.json +26 -0
  57. package/tsconfig.json +8 -0
@@ -0,0 +1,92 @@
1
+ import { BasePricingSheet } from '@unchainedshop/utils';
2
+ import { DeliveryPricingRowCategory, } from '@unchainedshop/types/delivery.pricing';
3
+ export const DeliveryPricingSheet = (params) => {
4
+ const basePricingSheet = BasePricingSheet(params);
5
+ const pricingSheet = {
6
+ ...basePricingSheet,
7
+ addDiscount({ amount, isTaxable, isNetPrice, discountId, meta }) {
8
+ basePricingSheet.calculation.push({
9
+ category: DeliveryPricingRowCategory.Discount,
10
+ amount,
11
+ isTaxable,
12
+ isNetPrice,
13
+ discountId,
14
+ meta,
15
+ });
16
+ },
17
+ addFee({ amount, isTaxable, isNetPrice, meta }) {
18
+ basePricingSheet.calculation.push({
19
+ amount,
20
+ category: DeliveryPricingRowCategory.Delivery,
21
+ isNetPrice,
22
+ isTaxable,
23
+ meta,
24
+ });
25
+ },
26
+ addTax({ amount, rate, meta }) {
27
+ basePricingSheet.calculation.push({
28
+ amount,
29
+ category: DeliveryPricingRowCategory.Tax,
30
+ isNetPrice: false,
31
+ isTaxable: false,
32
+ meta,
33
+ rate,
34
+ });
35
+ },
36
+ taxSum() {
37
+ return basePricingSheet.sum({
38
+ category: DeliveryPricingRowCategory.Tax,
39
+ });
40
+ },
41
+ feeSum() {
42
+ return basePricingSheet.sum({
43
+ category: DeliveryPricingRowCategory.Delivery,
44
+ });
45
+ },
46
+ discountSum(discountId) {
47
+ return basePricingSheet.sum({
48
+ category: DeliveryPricingRowCategory.Discount,
49
+ discountId,
50
+ });
51
+ },
52
+ discountPrices(explicitDiscountId) {
53
+ const discountIds = pricingSheet
54
+ .getDiscountRows(explicitDiscountId)
55
+ .map(({ discountId }) => discountId);
56
+ return [...new Set(discountIds)]
57
+ .map((discountId) => {
58
+ const amount = basePricingSheet.sum({
59
+ category: DeliveryPricingRowCategory.Discount,
60
+ discountId,
61
+ });
62
+ if (!amount) {
63
+ return null;
64
+ }
65
+ return {
66
+ discountId,
67
+ amount: Math.round(amount),
68
+ currency: basePricingSheet.currency,
69
+ };
70
+ })
71
+ .filter(Boolean);
72
+ },
73
+ getFeeRows() {
74
+ return basePricingSheet.filterBy({
75
+ category: DeliveryPricingRowCategory.Item,
76
+ });
77
+ },
78
+ getDiscountRows(discountId) {
79
+ return basePricingSheet.filterBy({
80
+ category: DeliveryPricingRowCategory.Discount,
81
+ discountId,
82
+ });
83
+ },
84
+ getTaxRows() {
85
+ return basePricingSheet.filterBy({
86
+ category: DeliveryPricingRowCategory.Tax,
87
+ });
88
+ },
89
+ };
90
+ return pricingSheet;
91
+ };
92
+ //# sourceMappingURL=DeliveryPricingSheet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeliveryPricingSheet.js","sourceRoot":"","sources":["../../src/director/DeliveryPricingSheet.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare enum DeliveryProviderType {
2
+ SHIPPING = "SHIPPING",
3
+ PICKUP = "PICKUP"
4
+ }
@@ -0,0 +1,6 @@
1
+ export var DeliveryProviderType;
2
+ (function (DeliveryProviderType) {
3
+ DeliveryProviderType["SHIPPING"] = "SHIPPING";
4
+ DeliveryProviderType["PICKUP"] = "PICKUP";
5
+ })(DeliveryProviderType || (DeliveryProviderType = {}));
6
+ //# sourceMappingURL=DeliveryProviderType.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeliveryProviderType.js","sourceRoot":"","sources":["../../src/director/DeliveryProviderType.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,oBAGX;AAHD,WAAY,oBAAoB;IAC9B,6CAAqB,CAAA;IACrB,yCAAiB,CAAA;AACnB,CAAC,EAHW,oBAAoB,KAApB,oBAAoB,QAG/B"}
@@ -0,0 +1,3 @@
1
+ import { ModuleInput } from '@unchainedshop/types/common';
2
+ import { DeliveryModule, DeliverySettingsOptions } from '@unchainedshop/types/delivery';
3
+ export declare const configureDeliveryModule: ({ db, options: deliveryOptions, }: ModuleInput<DeliverySettingsOptions>) => Promise<DeliveryModule>;
@@ -0,0 +1,137 @@
1
+ import { emit, registerEvents } from '@unchainedshop/events';
2
+ import { generateDbFilterById, generateDbMutations } from '@unchainedshop/utils';
3
+ import { DeliveryPricingSheet } from '../director/DeliveryPricingSheet';
4
+ import { DeliveryProvidersCollection } from '../db/DeliveryProvidersCollection';
5
+ import { DeliveryProvidersSchema } from '../db/DeliveryProvidersSchema';
6
+ import { deliverySettings } from '../delivery-settings';
7
+ import { DeliveryDirector } from '../director/DeliveryDirector';
8
+ import { DeliveryPricingDirector } from '../director/DeliveryPricingDirector';
9
+ const DELIVERY_PROVIDER_EVENTS = [
10
+ 'DELIVERY_PROVIDER_CREATE',
11
+ 'DELIVERY_PROVIDER_UPDATE',
12
+ 'DELIVERY_PROVIDER_REMOVE',
13
+ ];
14
+ const asyncFilter = async (arr, predicate) => {
15
+ const results = await Promise.all(arr.map(predicate));
16
+ return arr.filter((_v, index) => results[index]);
17
+ };
18
+ const buildFindSelector = ({ type } = {}) => {
19
+ return { ...(type ? { type } : {}), deleted: null };
20
+ };
21
+ export const configureDeliveryModule = async ({ db, options: deliveryOptions = {}, }) => {
22
+ registerEvents(DELIVERY_PROVIDER_EVENTS);
23
+ deliverySettings.configureSettings(deliveryOptions);
24
+ const DeliveryProviders = await DeliveryProvidersCollection(db);
25
+ const mutations = generateDbMutations(DeliveryProviders, DeliveryProvidersSchema);
26
+ const getDeliveryAdapter = async (deliveryProviderId, deliveryContext, requestContext) => {
27
+ const provider = await DeliveryProviders.findOne(generateDbFilterById(deliveryProviderId), {});
28
+ return DeliveryDirector.actions(provider, deliveryContext, requestContext);
29
+ };
30
+ return {
31
+ // Queries
32
+ count: async (query) => {
33
+ const providerCount = await DeliveryProviders.countDocuments(buildFindSelector(query));
34
+ return providerCount;
35
+ },
36
+ findProvider: async ({ deliveryProviderId, ...query }, options) => {
37
+ return DeliveryProviders.findOne(deliveryProviderId ? generateDbFilterById(deliveryProviderId) : query, options);
38
+ },
39
+ findProviders: async (query, options) => {
40
+ const providers = DeliveryProviders.find(buildFindSelector(query), options);
41
+ return providers.toArray();
42
+ },
43
+ providerExists: async ({ deliveryProviderId }) => {
44
+ const providerCount = await DeliveryProviders.countDocuments(generateDbFilterById(deliveryProviderId, { deleted: null }), { limit: 1 });
45
+ return !!providerCount;
46
+ },
47
+ // Delivery Adapter
48
+ findInterface: (deliveryProvider) => {
49
+ return DeliveryDirector.getAdapter(deliveryProvider.adapterKey);
50
+ },
51
+ findInterfaces: ({ type }) => {
52
+ return DeliveryDirector.getAdapters({
53
+ adapterFilter: (Adapter) => Adapter.typeSupported(type),
54
+ }).map((Adapter) => ({
55
+ _id: Adapter.key,
56
+ label: Adapter.label,
57
+ version: Adapter.version,
58
+ }));
59
+ },
60
+ findSupported: async (deliveryContext, requestContext) => {
61
+ const foundProviders = await DeliveryProviders.find(buildFindSelector({})).toArray();
62
+ const providers = await asyncFilter(foundProviders, async (provider) => {
63
+ try {
64
+ const director = await DeliveryDirector.actions(provider, deliveryContext, requestContext);
65
+ return director.isActive();
66
+ }
67
+ catch {
68
+ return false;
69
+ }
70
+ });
71
+ return deliverySettings.filterSupportedProviders({
72
+ providers,
73
+ order: deliveryContext.order,
74
+ }, requestContext);
75
+ },
76
+ determineDefault: async (deliveryProviders, deliveryContext, requestContext) => {
77
+ return deliverySettings.determineDefaultProvider({
78
+ providers: deliveryProviders,
79
+ ...deliveryContext,
80
+ }, requestContext);
81
+ },
82
+ configurationError: async (deliveryProvider, requestContext) => {
83
+ const director = await DeliveryDirector.actions(deliveryProvider, {}, requestContext);
84
+ return director.configurationError();
85
+ },
86
+ isActive: async (deliveryProvider, requestContext) => {
87
+ const director = await DeliveryDirector.actions(deliveryProvider, {}, requestContext);
88
+ return Boolean(director.isActive());
89
+ },
90
+ isAutoReleaseAllowed: async (deliveryProvider, requestContext) => {
91
+ const director = await DeliveryDirector.actions(deliveryProvider, {}, requestContext);
92
+ return Boolean(director.isAutoReleaseAllowed());
93
+ },
94
+ calculate: async (pricingContext, requestContext) => {
95
+ const pricing = await DeliveryPricingDirector.actions(pricingContext, requestContext);
96
+ return pricing.calculate();
97
+ },
98
+ send: async (deliveryProviderId, deliveryContext, requestContext) => {
99
+ const adapter = await getDeliveryAdapter(deliveryProviderId, deliveryContext, requestContext);
100
+ return adapter.send();
101
+ },
102
+ pricingSheet: (params) => {
103
+ return DeliveryPricingSheet(params);
104
+ },
105
+ // Mutations
106
+ create: async (doc, userId) => {
107
+ const Adapter = DeliveryDirector.getAdapter(doc.adapterKey);
108
+ if (!Adapter)
109
+ return null;
110
+ const deliveryProviderId = await mutations.create({
111
+ configuration: Adapter.initialConfiguration,
112
+ ...doc,
113
+ }, userId);
114
+ const deliveryProvider = await DeliveryProviders.findOne(generateDbFilterById(deliveryProviderId), {});
115
+ emit('DELIVERY_PROVIDER_CREATE', { deliveryProvider });
116
+ return deliveryProvider;
117
+ },
118
+ update: async (_id, doc, userId) => {
119
+ await mutations.update(_id, doc, userId);
120
+ const deliveryProvider = await DeliveryProviders.findOne(generateDbFilterById(_id), {});
121
+ emit('DELIVERY_PROVIDER_UPDATE', { deliveryProvider });
122
+ return deliveryProvider;
123
+ },
124
+ delete: async (_id, userId) => {
125
+ await mutations.delete(_id, userId);
126
+ const deliveryProvider = await DeliveryProviders.findOne(generateDbFilterById(_id), {});
127
+ emit('DELIVERY_PROVIDER_REMOVE', { deliveryProvider });
128
+ return deliveryProvider;
129
+ },
130
+ deletePermanently: async (_id, userId) => {
131
+ const deliveryProvider = await DeliveryProviders.findOne(generateDbFilterById(_id), {});
132
+ await mutations.deletePermanently(_id, userId);
133
+ return deliveryProvider;
134
+ },
135
+ };
136
+ };
137
+ //# sourceMappingURL=configureDeliveryModule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configureDeliveryModule.js","sourceRoot":"","sources":["../../src/module/configureDeliveryModule.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,2BAA2B,EAAE,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAE9E,MAAM,wBAAwB,GAAa;IACzC,0BAA0B;IAC1B,0BAA0B;IAC1B,0BAA0B;CAC3B,CAAC;AAEF,MAAM,WAAW,GAAG,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE;IAC3C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;IAEtD,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;AACnD,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,EAAE,IAAI,KAA4B,EAAE,EAAE,EAAE;IACjE,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACtD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,KAAK,EAAE,EAC5C,EAAE,EACF,OAAO,EAAE,eAAe,GAAG,EAAE,GACQ,EAA2B,EAAE;IAClE,cAAc,CAAC,wBAAwB,CAAC,CAAC;IAEzC,gBAAgB,CAAC,iBAAiB,CAAC,eAAe,CAAC,CAAC;IAEpD,MAAM,iBAAiB,GAAG,MAAM,2BAA2B,CAAC,EAAE,CAAC,CAAC;IAEhE,MAAM,SAAS,GAAG,mBAAmB,CACnC,iBAAiB,EACjB,uBAAuB,CACa,CAAC;IAEvC,MAAM,kBAAkB,GAAG,KAAK,EAC9B,kBAA0B,EAC1B,eAAgC,EAChC,cAAuB,EACvB,EAAE;QACF,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,OAAO,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,EAAE,EAAE,CAAC,CAAC;QAE/F,OAAO,gBAAgB,CAAC,OAAO,CAAC,QAAQ,EAAE,eAAe,EAAE,cAAc,CAAC,CAAC;IAC7E,CAAC,CAAC;IAEF,OAAO;QACL,UAAU;QACV,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YACrB,MAAM,aAAa,GAAG,MAAM,iBAAiB,CAAC,cAAc,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;YACvF,OAAO,aAAa,CAAC;QACvB,CAAC;QAED,YAAY,EAAE,KAAK,EAAE,EAAE,kBAAkB,EAAE,GAAG,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE;YAChE,OAAO,iBAAiB,CAAC,OAAO,CAC9B,kBAAkB,CAAC,CAAC,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,KAAK,EACrE,OAAO,CACR,CAAC;QACJ,CAAC;QAED,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;YACtC,MAAM,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;YAC5E,OAAO,SAAS,CAAC,OAAO,EAAE,CAAC;QAC7B,CAAC;QAED,cAAc,EAAE,KAAK,EAAE,EAAE,kBAAkB,EAAE,EAAE,EAAE;YAC/C,MAAM,aAAa,GAAG,MAAM,iBAAiB,CAAC,cAAc,CAC1D,oBAAoB,CAAC,kBAAkB,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAC3D,EAAE,KAAK,EAAE,CAAC,EAAE,CACb,CAAC;YACF,OAAO,CAAC,CAAC,aAAa,CAAC;QACzB,CAAC;QAED,mBAAmB;QAEnB,aAAa,EAAE,CAAC,gBAAgB,EAAE,EAAE;YAClC,OAAO,gBAAgB,CAAC,UAAU,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAClE,CAAC;QAED,cAAc,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;YAC3B,OAAO,gBAAgB,CAAC,WAAW,CAAC;gBAClC,aAAa,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC;aACxD,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;gBACnB,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,OAAO,EAAE,OAAO,CAAC,OAAO;aACzB,CAAC,CAAC,CAAC;QACN,CAAC;QAED,aAAa,EAAE,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,EAAE;YACvD,MAAM,cAAc,GAAG,MAAM,iBAAiB,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;YACrF,MAAM,SAAS,GAAsB,MAAM,WAAW,CACpD,cAAc,EACd,KAAK,EAAE,QAA0B,EAAE,EAAE;gBACnC,IAAI;oBACF,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,QAAQ,EAAE,eAAe,EAAE,cAAc,CAAC,CAAC;oBAC3F,OAAO,QAAQ,CAAC,QAAQ,EAAE,CAAC;iBAC5B;gBAAC,MAAM;oBACN,OAAO,KAAK,CAAC;iBACd;YACH,CAAC,CACF,CAAC;YAEF,OAAO,gBAAgB,CAAC,wBAAwB,CAC9C;gBACE,SAAS;gBACT,KAAK,EAAE,eAAe,CAAC,KAAK;aAC7B,EACD,cAAc,CACf,CAAC;QACJ,CAAC;QAED,gBAAgB,EAAE,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,EAAE;YAC7E,OAAO,gBAAgB,CAAC,wBAAwB,CAC9C;gBACE,SAAS,EAAE,iBAAiB;gBAC5B,GAAG,eAAe;aACnB,EACD,cAAc,CACf,CAAC;QACJ,CAAC;QAED,kBAAkB,EAAE,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,EAAE;YAC7D,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,EAAE,cAAc,CAAC,CAAC;YACtF,OAAO,QAAQ,CAAC,kBAAkB,EAAE,CAAC;QACvC,CAAC;QAED,QAAQ,EAAE,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,EAAE;YACnD,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,EAAE,cAAc,CAAC,CAAC;YACtF,OAAO,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;QACtC,CAAC;QAED,oBAAoB,EAAE,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,EAAE;YAC/D,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,EAAE,cAAc,CAAC,CAAC;YACtF,OAAO,OAAO,CAAC,QAAQ,CAAC,oBAAoB,EAAE,CAAC,CAAC;QAClD,CAAC;QAED,SAAS,EAAE,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,EAAE;YAClD,MAAM,OAAO,GAAG,MAAM,uBAAuB,CAAC,OAAO,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;YACtF,OAAO,OAAO,CAAC,SAAS,EAAE,CAAC;QAC7B,CAAC;QAED,IAAI,EAAE,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,cAAc,EAAE,EAAE;YAClE,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,kBAAkB,EAAE,eAAe,EAAE,cAAc,CAAC,CAAC;YAC9F,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;QACxB,CAAC;QAED,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE;YACvB,OAAO,oBAAoB,CAAC,MAAM,CAAC,CAAC;QACtC,CAAC;QAED,YAAY;QACZ,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE;YAC5B,MAAM,OAAO,GAAG,gBAAgB,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YAC5D,IAAI,CAAC,OAAO;gBAAE,OAAO,IAAI,CAAC;YAE1B,MAAM,kBAAkB,GAAG,MAAM,SAAS,CAAC,MAAM,CAC/C;gBACE,aAAa,EAAE,OAAO,CAAC,oBAAoB;gBAC3C,GAAG,GAAG;aACP,EACD,MAAM,CACP,CAAC;YACF,MAAM,gBAAgB,GAAG,MAAM,iBAAiB,CAAC,OAAO,CACtD,oBAAoB,CAAC,kBAAkB,CAAC,EACxC,EAAE,CACH,CAAC;YACF,IAAI,CAAC,0BAA0B,EAAE,EAAE,gBAAgB,EAAE,CAAC,CAAC;YACvD,OAAO,gBAAgB,CAAC;QAC1B,CAAC;QAED,MAAM,EAAE,KAAK,EAAE,GAAW,EAAE,GAAqB,EAAE,MAAc,EAAE,EAAE;YACnE,MAAM,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;YACzC,MAAM,gBAAgB,GAAG,MAAM,iBAAiB,CAAC,OAAO,CAAC,oBAAoB,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;YACxF,IAAI,CAAC,0BAA0B,EAAE,EAAE,gBAAgB,EAAE,CAAC,CAAC;YACvD,OAAO,gBAAgB,CAAC;QAC1B,CAAC;QAED,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE;YAC5B,MAAM,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YACpC,MAAM,gBAAgB,GAAG,MAAM,iBAAiB,CAAC,OAAO,CAAC,oBAAoB,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;YACxF,IAAI,CAAC,0BAA0B,EAAE,EAAE,gBAAgB,EAAE,CAAC,CAAC;YACvD,OAAO,gBAAgB,CAAC;QAC1B,CAAC;QAED,iBAAiB,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE;YACvC,MAAM,gBAAgB,GAAG,MAAM,iBAAiB,CAAC,OAAO,CAAC,oBAAoB,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;YACxF,MAAM,SAAS,CAAC,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC/C,OAAO,gBAAgB,CAAC;QAC1B,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
package/package.js ADDED
@@ -0,0 +1,33 @@
1
+ Package.describe({
2
+ name: 'unchained:core-delivery',
3
+ version: '1.1.3',
4
+ summary: 'Unchained Engine Core: Delivery',
5
+ git: 'https://github.com/unchainedshop/unchained',
6
+ documentation: 'README.md',
7
+ });
8
+
9
+ Npm.depends({
10
+ 'simpl-schema': '1.12.0',
11
+ '@unchainedshop/logger': '1.1.3',
12
+ '@unchainedshop/utils': '1.1.3',
13
+ // '@unchainedshop/events': '1.1.4', // PEER
14
+ });
15
+
16
+ Package.onUse((api) => {
17
+ api.versionsFrom('2.7.3');
18
+ api.use('ecmascript');
19
+ api.use('typescript');
20
+
21
+ api.mainModule('src/delivery-index.ts', 'server');
22
+ });
23
+
24
+ Package.onTest((api) => {
25
+ api.use('meteortesting:mocha');
26
+ api.use('ecmascript');
27
+ api.use('typescript');
28
+
29
+ api.use('unchained:mongodb');
30
+ api.use('unchained:core-delivery');
31
+
32
+ api.mainModule('tests/delivery-index.test.ts');
33
+ });
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@unchainedshop/core-delivery",
3
+ "version": "1.1.3",
4
+ "main": "lib/delivery-index.js",
5
+ "types": "lib/delivery-index.d.ts",
6
+ "type": "module",
7
+ "scripts": {
8
+ "clean": "rm -rf lib",
9
+ "build": "npm run clean && tsc -p tsconfig.build.json",
10
+ "watch": "tsc --watch",
11
+ "link:core": "npm link @unchainedshop/types",
12
+ "test": "cross-env METEOR_PACKAGE_DIRS=../ TEST_CLIENT=0 TEST_WATCH=1 meteor test-packages ./ --driver-package meteortesting:mocha --port 4200"
13
+ },
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/unchainedshop/unchained.git"
17
+ },
18
+ "keywords": [
19
+ "unchained",
20
+ "ecommerce",
21
+ "core"
22
+ ],
23
+ "author": "Joël Meiller",
24
+ "license": "EUPL-1.2",
25
+ "bugs": {
26
+ "url": "https://github.com/unchainedshop/unchained/issues"
27
+ },
28
+ "homepage": "https://github.com/unchainedshop/unchained#readme",
29
+ "dependencies": {
30
+ "@unchainedshop/events": "latest",
31
+ "@unchainedshop/logger": "latest",
32
+ "@unchainedshop/utils": "latest",
33
+ "simpl-schema": "^1.12.2"
34
+ },
35
+ "devDependencies": {
36
+ "@types/chai": "^4.3.1",
37
+ "@types/mocha": "^9.1.1",
38
+ "@unchainedshop/types": "latest",
39
+ "chai": "^4.3.6",
40
+ "cross-env": "^7.0.3",
41
+ "typescript": "^4.7.4"
42
+ }
43
+ }
@@ -0,0 +1,11 @@
1
+ import { Db } from '@unchainedshop/types/common';
2
+ import { DeliveryProvider } from '@unchainedshop/types/delivery';
3
+ import { buildDbIndexes } from '@unchainedshop/utils';
4
+
5
+ export const DeliveryProvidersCollection = async (db: Db) => {
6
+ const DeliveryProviders = db.collection<DeliveryProvider>('delivery-providers');
7
+
8
+ await buildDbIndexes<DeliveryProvider>(DeliveryProviders, [{ index: { type: 1 } }]);
9
+
10
+ return DeliveryProviders;
11
+ };
@@ -0,0 +1,16 @@
1
+ import { Schemas } from '@unchainedshop/utils';
2
+ import SimpleSchema from 'simpl-schema';
3
+
4
+ export const DeliveryProvidersSchema = new SimpleSchema(
5
+ {
6
+ type: { type: String, required: true },
7
+ adapterKey: { type: String, required: true },
8
+ authorId: { type: String, required: true },
9
+ configuration: { type: Array },
10
+ 'configuration.$': { type: Object },
11
+ 'configuration.$.key': { type: String },
12
+ 'configuration.$.value': { type: String },
13
+ ...Schemas.timestampFields,
14
+ },
15
+ { requiredByDefault: false },
16
+ );
@@ -0,0 +1,11 @@
1
+ export { configureDeliveryModule } from './module/configureDeliveryModule';
2
+
3
+ export { deliverySettings } from './delivery-settings';
4
+
5
+ export { DeliveryAdapter } from './director/DeliveryAdapter';
6
+ export { DeliveryDirector } from './director/DeliveryDirector';
7
+ export { DeliveryError } from './director/DeliveryError';
8
+ export { DeliveryProviderType } from './director/DeliveryProviderType';
9
+
10
+ export { DeliveryPricingAdapter } from './director/DeliveryPricingAdapter';
11
+ export { DeliveryPricingDirector } from './director/DeliveryPricingDirector';
@@ -0,0 +1,46 @@
1
+ import {
2
+ DeliveryProvider,
3
+ DeliverySettings,
4
+ DetermineDefaultProvider,
5
+ FilterProviders,
6
+ } from '@unchainedshop/types/delivery';
7
+ import { createLogger } from '@unchainedshop/logger';
8
+
9
+ const logger = createLogger('unchained:core-delivery');
10
+
11
+ const sortByCreationDate = (left: DeliveryProvider, right: DeliveryProvider) => {
12
+ return new Date(left.created).getTime() - new Date(right.created).getTime();
13
+ };
14
+
15
+ const allProviders: FilterProviders = async ({ providers }) => {
16
+ return providers.sort(sortByCreationDate);
17
+ };
18
+
19
+ const firstProviderIsDefault: DetermineDefaultProvider = async ({ providers }) => {
20
+ return providers?.length > 0 && providers[0];
21
+ };
22
+
23
+ const defaultFilterSupportedProviders =
24
+ (sortProviders) =>
25
+ async ({ providers }) => {
26
+ return providers.sort(sortProviders);
27
+ };
28
+
29
+ export const deliverySettings: DeliverySettings = {
30
+ filterSupportedProviders: null,
31
+ determineDefaultProvider: null,
32
+
33
+ configureSettings({
34
+ sortProviders = undefined,
35
+ filterSupportedProviders = allProviders,
36
+ determineDefaultProvider = firstProviderIsDefault,
37
+ } = {}) {
38
+ if (sortProviders) {
39
+ logger.warn('sortProviders is deprecated, please specifc filterSupportedProviders instead');
40
+ deliverySettings.filterSupportedProviders = defaultFilterSupportedProviders(sortProviders);
41
+ } else {
42
+ deliverySettings.filterSupportedProviders = filterSupportedProviders;
43
+ }
44
+ deliverySettings.determineDefaultProvider = determineDefaultProvider;
45
+ },
46
+ };
@@ -0,0 +1,56 @@
1
+ import { IDeliveryAdapter } from '@unchainedshop/types/delivery';
2
+ import { log, LogLevel } from '@unchainedshop/logger';
3
+ import { DeliveryError } from './DeliveryError';
4
+
5
+ export const DeliveryAdapter: Omit<IDeliveryAdapter, 'key' | 'label' | 'version'> = {
6
+ initialConfiguration: [],
7
+
8
+ typeSupported: () => {
9
+ return false;
10
+ },
11
+
12
+ actions: () => {
13
+ return {
14
+ configurationError: () => {
15
+ return DeliveryError.NOT_IMPLEMENTED;
16
+ },
17
+
18
+ estimatedDeliveryThroughput: async () => {
19
+ return 0;
20
+ },
21
+
22
+ isActive: () => {
23
+ return false;
24
+ },
25
+
26
+ isAutoReleaseAllowed: () => {
27
+ // if you return false here,
28
+ // the order will need manual confirmation before
29
+ // unchained will try to invoke send()
30
+ return true;
31
+ },
32
+
33
+ send: async () => {
34
+ // if you return true, the status will be changed to DELIVERED
35
+
36
+ // if you return false, the order delivery status stays the
37
+ // same but the order status might change
38
+
39
+ // if you throw an error, you cancel the whole checkout process
40
+ return false;
41
+ },
42
+
43
+ pickUpLocationById: async () => {
44
+ return null;
45
+ },
46
+
47
+ pickUpLocations: async () => {
48
+ return [];
49
+ },
50
+ };
51
+ },
52
+
53
+ log: (message: string, { level = LogLevel.Debug, ...options } = {}) => {
54
+ return log(message, { level, ...options });
55
+ },
56
+ };
@@ -0,0 +1,76 @@
1
+ import { IDeliveryAdapter, IDeliveryDirector } from '@unchainedshop/types/delivery';
2
+ import { log, LogLevel } from '@unchainedshop/logger';
3
+ import { BaseDirector } from '@unchainedshop/utils';
4
+ import { DeliveryError } from './DeliveryError';
5
+
6
+ const baseDirector = BaseDirector<IDeliveryAdapter>('DeliveryDirector');
7
+
8
+ export const DeliveryDirector: IDeliveryDirector = {
9
+ ...baseDirector,
10
+
11
+ actions: async (deliveryProvider, deliveryContext, requestContext) => {
12
+ const Adapter = baseDirector.getAdapter(deliveryProvider.adapterKey);
13
+
14
+ const context = { ...deliveryContext, ...requestContext };
15
+ const adapter = Adapter.actions(deliveryProvider.configuration, context);
16
+
17
+ return {
18
+ configurationError: () => {
19
+ try {
20
+ return adapter.configurationError();
21
+ } catch (error) {
22
+ return DeliveryError.ADAPTER_NOT_FOUND;
23
+ }
24
+ },
25
+
26
+ estimatedDeliveryThroughput: async (warehousingThroughputTime) => {
27
+ try {
28
+ const throughput = await adapter.estimatedDeliveryThroughput(warehousingThroughputTime);
29
+ return throughput;
30
+ } catch (error) {
31
+ log('Delivery Director -> Error while estimating delivery throughput', {
32
+ level: LogLevel.Warning,
33
+ ...error,
34
+ });
35
+ return null;
36
+ }
37
+ },
38
+
39
+ isActive: () => {
40
+ try {
41
+ return adapter.isActive();
42
+ } catch (error) {
43
+ log('Delivery Director -> Error while checking if is active', {
44
+ level: LogLevel.Warning,
45
+ ...error,
46
+ });
47
+ return false;
48
+ }
49
+ },
50
+
51
+ isAutoReleaseAllowed: () => {
52
+ try {
53
+ return adapter.isAutoReleaseAllowed();
54
+ } catch (error) {
55
+ log('Delivery Director -> Error while checking if auto release is allowed', {
56
+ level: LogLevel.Warning,
57
+ ...error,
58
+ });
59
+ return false;
60
+ }
61
+ },
62
+
63
+ send: async () => {
64
+ return adapter.send();
65
+ },
66
+
67
+ pickUpLocationById: async (locationId) => {
68
+ return adapter.pickUpLocationById(locationId);
69
+ },
70
+
71
+ pickUpLocations: async () => {
72
+ return adapter.pickUpLocations();
73
+ },
74
+ };
75
+ },
76
+ };
@@ -0,0 +1,6 @@
1
+ export enum DeliveryError {
2
+ ADAPTER_NOT_FOUND = 'ADAPTER_NOT_FOUND',
3
+ NOT_IMPLEMENTED = 'NOT_IMPLEMENTED',
4
+ INCOMPLETE_CONFIGURATION = 'INCOMPLETE_CONFIGURATION',
5
+ WRONG_CREDENTIALS = 'WRONG_CREDENTIALS',
6
+ }
@@ -0,0 +1,39 @@
1
+ import {
2
+ DeliveryPricingAdapterContext,
3
+ DeliveryPricingCalculation,
4
+ IDeliveryPricingAdapter,
5
+ } from '@unchainedshop/types/delivery.pricing';
6
+ import { BasePricingAdapter } from '@unchainedshop/utils';
7
+ import { DeliveryPricingSheet } from './DeliveryPricingSheet';
8
+
9
+ const basePricingAdapter = BasePricingAdapter<
10
+ DeliveryPricingAdapterContext,
11
+ DeliveryPricingCalculation
12
+ >();
13
+
14
+ export const DeliveryPricingAdapter: IDeliveryPricingAdapter = {
15
+ ...basePricingAdapter,
16
+
17
+ isActivatedFor: () => {
18
+ return false;
19
+ },
20
+
21
+ actions: (params) => {
22
+ const { context } = params;
23
+ const { currency } = context;
24
+ const baseActions = basePricingAdapter.actions(params);
25
+ const resultSheet = DeliveryPricingSheet({ currency });
26
+
27
+ return {
28
+ ...baseActions,
29
+ calculate: async () => {
30
+ const resultRaw = resultSheet.getRawPricingSheet();
31
+ resultRaw.forEach(({ amount, category }) =>
32
+ basePricingAdapter.log(`Delivery Calculation -> ${category} ${amount}`),
33
+ );
34
+ return resultRaw;
35
+ },
36
+ resultSheet: () => resultSheet,
37
+ };
38
+ },
39
+ };