@unchainedshop/core 4.8.18 → 4.8.20
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/lib/bulk-importer/handlers/product/create.d.ts +15 -3
- package/lib/bulk-importer/handlers/product/create.js +4 -2
- package/lib/bulk-importer/handlers/product/update.d.ts +15 -3
- package/lib/bulk-importer/handlers/product/update.js +4 -1
- package/lib/directors/FilterDirector.js +23 -18
- package/lib/directors/WorkerDirector.js +1 -1
- package/lib/errors.d.ts +1 -0
- package/lib/errors.js +5 -0
- package/lib/factory/registerDeliveryPricing.d.ts +7 -0
- package/lib/factory/registerDeliveryPricing.js +30 -0
- package/lib/factory/registerDeliveryProvider.d.ts +12 -0
- package/lib/factory/registerDeliveryProvider.js +46 -0
- package/lib/factory/registerEnrollment.d.ts +18 -0
- package/lib/factory/registerEnrollment.js +43 -0
- package/lib/factory/registerFileAdapter.d.ts +17 -0
- package/lib/factory/registerFileAdapter.js +24 -0
- package/lib/factory/registerOrderDiscount.d.ts +13 -0
- package/lib/factory/registerOrderDiscount.js +39 -0
- package/lib/factory/registerOrderPricing.d.ts +7 -0
- package/lib/factory/registerOrderPricing.js +30 -0
- package/lib/factory/registerPaymentPricing.d.ts +7 -0
- package/lib/factory/registerPaymentPricing.js +30 -0
- package/lib/factory/registerPaymentProvider.d.ts +15 -0
- package/lib/factory/registerPaymentProvider.js +53 -0
- package/lib/factory/registerProductDiscount.d.ts +20 -0
- package/lib/factory/registerProductDiscount.js +47 -0
- package/lib/factory/registerProductPricing.d.ts +7 -0
- package/lib/factory/registerProductPricing.js +30 -0
- package/lib/factory/registerQuotation.d.ts +12 -0
- package/lib/factory/registerQuotation.js +52 -0
- package/lib/services/addMultipleCartProducts.js +3 -2
- package/lib/services/createFilter.d.ts +3 -0
- package/lib/services/createFilter.js +6 -0
- package/lib/services/createFilterOption.d.ts +5 -0
- package/lib/services/createFilterOption.js +8 -0
- package/lib/services/createSignedURL.js +2 -1
- package/lib/services/index.d.ts +8 -0
- package/lib/services/index.js +8 -0
- package/lib/services/loadFilterOptions.js +2 -2
- package/lib/services/processEnrollment.js +2 -1
- package/lib/services/processOrder.js +3 -2
- package/lib/services/processQuotation.js +11 -13
- package/lib/services/proposeQuotation.js +3 -0
- package/lib/services/removeFilterOption.d.ts +6 -0
- package/lib/services/removeFilterOption.js +8 -0
- package/lib/services/removeProduct.js +2 -1
- package/lib/services/updateCalculation.js +2 -1
- package/lib/services/updateFilter.d.ts +3 -0
- package/lib/services/updateFilter.js +8 -0
- package/lib/services/uploadFileFromStream.js +2 -1
- package/lib/services/validateOrder.js +7 -8
- package/package.json +2 -2
|
@@ -10,7 +10,11 @@ export declare const ProductCreateSpecificationSchema: z.ZodMiniObject<{
|
|
|
10
10
|
readonly TOKENIZED_PRODUCT: "TOKENIZED_PRODUCT";
|
|
11
11
|
}>;
|
|
12
12
|
sequence: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
|
|
13
|
-
status: z.ZodMiniOptional<z.ZodMiniNullable<z.
|
|
13
|
+
status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniEnum<{
|
|
14
|
+
readonly DRAFT: "DRAFT";
|
|
15
|
+
readonly ACTIVE: "ACTIVE";
|
|
16
|
+
readonly DELETED: "DELETED";
|
|
17
|
+
}>>>;
|
|
14
18
|
published: z.ZodMiniOptional<z.ZodMiniNullable<z.iso.ZodMiniISODateTime>>;
|
|
15
19
|
tags: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
|
|
16
20
|
commerce: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
@@ -67,7 +71,11 @@ export declare const ProductCreatePayloadSchema: z.ZodMiniObject<{
|
|
|
67
71
|
readonly TOKENIZED_PRODUCT: "TOKENIZED_PRODUCT";
|
|
68
72
|
}>;
|
|
69
73
|
sequence: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
|
|
70
|
-
status: z.ZodMiniOptional<z.ZodMiniNullable<z.
|
|
74
|
+
status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniEnum<{
|
|
75
|
+
readonly DRAFT: "DRAFT";
|
|
76
|
+
readonly ACTIVE: "ACTIVE";
|
|
77
|
+
readonly DELETED: "DELETED";
|
|
78
|
+
}>>>;
|
|
71
79
|
published: z.ZodMiniOptional<z.ZodMiniNullable<z.iso.ZodMiniISODateTime>>;
|
|
72
80
|
tags: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
|
|
73
81
|
commerce: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
@@ -170,7 +178,11 @@ declare namespace createProduct {
|
|
|
170
178
|
readonly TOKENIZED_PRODUCT: "TOKENIZED_PRODUCT";
|
|
171
179
|
}>;
|
|
172
180
|
sequence: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
|
|
173
|
-
status: z.ZodMiniOptional<z.ZodMiniNullable<z.
|
|
181
|
+
status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniEnum<{
|
|
182
|
+
readonly DRAFT: "DRAFT";
|
|
183
|
+
readonly ACTIVE: "ACTIVE";
|
|
184
|
+
readonly DELETED: "DELETED";
|
|
185
|
+
}>>>;
|
|
174
186
|
published: z.ZodMiniOptional<z.ZodMiniNullable<z.iso.ZodMiniISODateTime>>;
|
|
175
187
|
tags: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
|
|
176
188
|
commerce: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
@@ -3,11 +3,11 @@ import upsertVariations, { ProductVariationSchema } from "./upsertVariations.js"
|
|
|
3
3
|
import upsertMedia from "./upsertMedia.js";
|
|
4
4
|
import { MediaSchema } from "../assortment/upsertMedia.js";
|
|
5
5
|
import convertTagsToLowerCase from "../utils/convertTagsToLowerCase.js";
|
|
6
|
-
import { ProductType } from '@unchainedshop/core-products';
|
|
6
|
+
import { ProductStatus, ProductType } from '@unchainedshop/core-products';
|
|
7
7
|
export const ProductCreateSpecificationSchema = z.object({
|
|
8
8
|
type: z.enum(ProductType),
|
|
9
9
|
sequence: z.optional(z.number()),
|
|
10
|
-
status: z.nullish(z.
|
|
10
|
+
status: z.nullish(z.enum(ProductStatus)),
|
|
11
11
|
published: z.nullish(z.iso.datetime()),
|
|
12
12
|
tags: z.optional(z.array(z.string())),
|
|
13
13
|
commerce: z.optional(z.object({
|
|
@@ -59,6 +59,7 @@ export const ProductCreatePayloadSchema = z.object({
|
|
|
59
59
|
media: z.optional(z.array(MediaSchema)),
|
|
60
60
|
variations: z.optional(z.array(ProductVariationSchema)),
|
|
61
61
|
});
|
|
62
|
+
const normalizeStatus = (status) => (status === ProductStatus.DRAFT ? null : status);
|
|
62
63
|
const transformSpecification = (specification) => {
|
|
63
64
|
const { variationResolvers: assignments, content, supply, warehousing, sequence, ...productData } = specification;
|
|
64
65
|
const tags = productData?.tags ? convertTagsToLowerCase(productData.tags) : [];
|
|
@@ -66,6 +67,7 @@ const transformSpecification = (specification) => {
|
|
|
66
67
|
return {
|
|
67
68
|
...productData,
|
|
68
69
|
published: productData.published ? new Date(productData.published) : undefined,
|
|
70
|
+
...(productData.status !== undefined && { status: normalizeStatus(productData.status) }),
|
|
69
71
|
tags,
|
|
70
72
|
warehousing,
|
|
71
73
|
supply,
|
|
@@ -4,7 +4,11 @@ import type { Services } from '../../../services/index.ts';
|
|
|
4
4
|
export declare const ProductUpdateSpecificationSchema: z.ZodMiniObject<{
|
|
5
5
|
type: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
6
6
|
sequence: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
|
|
7
|
-
status: z.ZodMiniOptional<z.ZodMiniNullable<z.
|
|
7
|
+
status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniEnum<{
|
|
8
|
+
readonly DRAFT: "DRAFT";
|
|
9
|
+
readonly ACTIVE: "ACTIVE";
|
|
10
|
+
readonly DELETED: "DELETED";
|
|
11
|
+
}>>>;
|
|
8
12
|
published: z.ZodMiniOptional<z.ZodMiniNullable<z.iso.ZodMiniISODateTime>>;
|
|
9
13
|
tags: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
|
|
10
14
|
commerce: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
@@ -55,7 +59,11 @@ export declare const ProductUpdatePayloadSchema: z.ZodMiniObject<{
|
|
|
55
59
|
specification: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
56
60
|
type: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
57
61
|
sequence: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
|
|
58
|
-
status: z.ZodMiniOptional<z.ZodMiniNullable<z.
|
|
62
|
+
status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniEnum<{
|
|
63
|
+
readonly DRAFT: "DRAFT";
|
|
64
|
+
readonly ACTIVE: "ACTIVE";
|
|
65
|
+
readonly DELETED: "DELETED";
|
|
66
|
+
}>>>;
|
|
59
67
|
published: z.ZodMiniOptional<z.ZodMiniNullable<z.iso.ZodMiniISODateTime>>;
|
|
60
68
|
tags: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
|
|
61
69
|
commerce: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
@@ -152,7 +160,11 @@ declare namespace updateProduct {
|
|
|
152
160
|
specification: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
153
161
|
type: z.ZodMiniOptional<z.ZodMiniString<string>>;
|
|
154
162
|
sequence: z.ZodMiniOptional<z.ZodMiniNumber<number>>;
|
|
155
|
-
status: z.ZodMiniOptional<z.ZodMiniNullable<z.
|
|
163
|
+
status: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniEnum<{
|
|
164
|
+
readonly DRAFT: "DRAFT";
|
|
165
|
+
readonly ACTIVE: "ACTIVE";
|
|
166
|
+
readonly DELETED: "DELETED";
|
|
167
|
+
}>>>;
|
|
156
168
|
published: z.ZodMiniOptional<z.ZodMiniNullable<z.iso.ZodMiniISODateTime>>;
|
|
157
169
|
tags: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniString<string>>>;
|
|
158
170
|
commerce: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
@@ -3,10 +3,11 @@ import upsertVariations, { ProductVariationSchema } from "./upsertVariations.js"
|
|
|
3
3
|
import upsertMedia, { MediaSchema } from "./upsertMedia.js";
|
|
4
4
|
import createProduct, { ProductCreatePayloadSchema } from "./create.js";
|
|
5
5
|
import convertTagsToLowerCase from "../utils/convertTagsToLowerCase.js";
|
|
6
|
+
import { ProductStatus } from '@unchainedshop/core-products';
|
|
6
7
|
export const ProductUpdateSpecificationSchema = z.object({
|
|
7
8
|
type: z.optional(z.string()),
|
|
8
9
|
sequence: z.optional(z.number()),
|
|
9
|
-
status: z.nullish(z.
|
|
10
|
+
status: z.nullish(z.enum(ProductStatus)),
|
|
10
11
|
published: z.nullish(z.iso.datetime()),
|
|
11
12
|
tags: z.optional(z.array(z.string())),
|
|
12
13
|
commerce: z.optional(z.object({
|
|
@@ -58,6 +59,7 @@ export const ProductUpdatePayloadSchema = z.object({
|
|
|
58
59
|
media: z.optional(z.array(MediaSchema)),
|
|
59
60
|
variations: z.optional(z.array(ProductVariationSchema)),
|
|
60
61
|
});
|
|
62
|
+
const normalizeStatus = (status) => (status === ProductStatus.DRAFT ? null : status);
|
|
61
63
|
const transformSpecification = (specification) => {
|
|
62
64
|
const { variationResolvers: assignments, content, supply, warehousing, ...productData } = specification;
|
|
63
65
|
const tags = productData?.tags ? convertTagsToLowerCase(productData.tags) : [];
|
|
@@ -65,6 +67,7 @@ const transformSpecification = (specification) => {
|
|
|
65
67
|
return {
|
|
66
68
|
...productData,
|
|
67
69
|
published: productData.published ? new Date(productData.published) : undefined,
|
|
70
|
+
...(productData.status !== undefined && { status: normalizeStatus(productData.status) }),
|
|
68
71
|
tags,
|
|
69
72
|
warehousing,
|
|
70
73
|
supply,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mongodb } from '@unchainedshop/mongodb';
|
|
2
2
|
import { BaseDirector } from '@unchainedshop/utils';
|
|
3
|
-
import { filtersSettings, FilterType, } from '@unchainedshop/core-filters';
|
|
3
|
+
import { filterCacheGeneration, filtersSettings, FilterType, } from '@unchainedshop/core-filters';
|
|
4
4
|
export const parseQueryArray = (query) => (query || []).reduce((accumulator, { key, value }) => ({
|
|
5
5
|
...accumulator,
|
|
6
6
|
[key]: accumulator[key] ? accumulator[key].concat(value) : [value],
|
|
@@ -70,18 +70,19 @@ export const FilterDirector = {
|
|
|
70
70
|
},
|
|
71
71
|
async buildProductIdMap(filter, unchainedAPI) {
|
|
72
72
|
const allProductIds = await this.findProductIds(filter, {}, unchainedAPI);
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
73
|
+
if (filter.type === FilterType.SWITCH) {
|
|
74
|
+
return [
|
|
75
|
+
allProductIds,
|
|
76
|
+
{
|
|
77
|
+
true: await this.findProductIds(filter, { value: true }, unchainedAPI),
|
|
78
|
+
false: await this.findProductIds(filter, { value: { $in: [null, false] } }, unchainedAPI),
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
const productIdsMap = Object.create(null);
|
|
83
|
+
for (const option of filter.options || []) {
|
|
84
|
+
productIdsMap[option] = await this.findProductIds(filter, { value: option }, unchainedAPI);
|
|
85
|
+
}
|
|
85
86
|
return [allProductIds, productIdsMap];
|
|
86
87
|
},
|
|
87
88
|
async filterProductIds(filter, { values, forceLiveCollection }, unchainedAPI) {
|
|
@@ -92,11 +93,13 @@ export const FilterDirector = {
|
|
|
92
93
|
return new Set(allProductIds);
|
|
93
94
|
const result = new Set();
|
|
94
95
|
for (const key of filteredKeys) {
|
|
96
|
+
if (!Object.hasOwn(keyToProductIdMap, key))
|
|
97
|
+
continue;
|
|
95
98
|
const additionalValues = keyToProductIdMap[key];
|
|
96
|
-
if (additionalValues)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
if (!additionalValues)
|
|
100
|
+
continue;
|
|
101
|
+
for (const val of additionalValues)
|
|
102
|
+
result.add(val);
|
|
100
103
|
}
|
|
101
104
|
return result;
|
|
102
105
|
},
|
|
@@ -165,6 +168,8 @@ export const FilterDirector = {
|
|
|
165
168
|
if (!filter)
|
|
166
169
|
return;
|
|
167
170
|
const [productIds, productIdMap] = await this.buildProductIdMap(filter, unchainedAPI);
|
|
168
|
-
await
|
|
171
|
+
if (!(await unchainedAPI.modules.filters.filterExists({ filterId: filter._id })))
|
|
172
|
+
return;
|
|
173
|
+
await filtersSettings.setCachedProductIds(filter._id, productIds, productIdMap, filterCacheGeneration(filter));
|
|
169
174
|
},
|
|
170
175
|
};
|
|
@@ -54,7 +54,7 @@ export const WorkerDirector = {
|
|
|
54
54
|
logger.warn(`WorkerDirector: No registered adapter for type: ${type}`);
|
|
55
55
|
}
|
|
56
56
|
try {
|
|
57
|
-
const output = await adapter.doWork(input, unchainedAPI, workId);
|
|
57
|
+
const output = await adapter.doWork(input ?? {}, unchainedAPI, workId);
|
|
58
58
|
return output;
|
|
59
59
|
}
|
|
60
60
|
catch (error) {
|
package/lib/errors.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const createServiceError: (name: string, message: string) => Error;
|
package/lib/errors.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type IPlugin, type IDeliveryPricingSheet, type DeliveryPricingAdapterContext } from '../core-index.ts';
|
|
2
|
+
export default function registerDeliveryPricing({ adapterId, orderIndex, isActivatedFor, calculate, }: {
|
|
3
|
+
adapterId: string;
|
|
4
|
+
orderIndex?: number;
|
|
5
|
+
isActivatedFor?: (context: DeliveryPricingAdapterContext) => boolean;
|
|
6
|
+
calculate: (sheet: IDeliveryPricingSheet, context: DeliveryPricingAdapterContext) => Promise<void>;
|
|
7
|
+
}): IPlugin;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { DeliveryPricingAdapter, } from "../core-index.js";
|
|
2
|
+
import { pluginRegistry } from "../plugins/PluginRegistry.js";
|
|
3
|
+
export default function registerDeliveryPricing({ adapterId, orderIndex, isActivatedFor, calculate, }) {
|
|
4
|
+
const adapter = {
|
|
5
|
+
...DeliveryPricingAdapter,
|
|
6
|
+
key: `shop.unchained.pricing.delivery-${adapterId}`,
|
|
7
|
+
label: 'Delivery Pricing: ' + adapterId,
|
|
8
|
+
version: '1.0.0',
|
|
9
|
+
orderIndex: orderIndex ?? 0,
|
|
10
|
+
isActivatedFor: (context) => (isActivatedFor ? isActivatedFor(context) : true),
|
|
11
|
+
actions: (params) => {
|
|
12
|
+
const pricingAdapter = DeliveryPricingAdapter.actions(params);
|
|
13
|
+
return {
|
|
14
|
+
...pricingAdapter,
|
|
15
|
+
calculate: async () => {
|
|
16
|
+
await calculate(pricingAdapter.resultSheet(), params.context);
|
|
17
|
+
return pricingAdapter.calculate();
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
const plugin = {
|
|
23
|
+
key: adapter.key,
|
|
24
|
+
label: adapter.label,
|
|
25
|
+
version: adapter.version,
|
|
26
|
+
adapters: [adapter],
|
|
27
|
+
};
|
|
28
|
+
pluginRegistry.register(plugin);
|
|
29
|
+
return plugin;
|
|
30
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DeliveryConfiguration } from '@unchainedshop/core-delivery';
|
|
2
|
+
import { DeliveryProviderType } from '@unchainedshop/core-delivery';
|
|
3
|
+
import { type DeliveryContext, type IPlugin } from '../core-index.ts';
|
|
4
|
+
import type { Work } from '@unchainedshop/core-worker';
|
|
5
|
+
export default function registerDeliveryProvider({ adapterId, type, active, autoReleaseAllowed, estimatedDeliveryThroughput, send, }: {
|
|
6
|
+
adapterId: string;
|
|
7
|
+
type?: DeliveryProviderType;
|
|
8
|
+
active?: boolean;
|
|
9
|
+
autoReleaseAllowed?: boolean;
|
|
10
|
+
estimatedDeliveryThroughput?: (warehousingThroughputTime: number, context: DeliveryContext) => Promise<number | null>;
|
|
11
|
+
send: boolean | ((configuration: DeliveryConfiguration, context: DeliveryContext) => Promise<boolean | Work>);
|
|
12
|
+
}): IPlugin;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { DeliveryProviderType } from '@unchainedshop/core-delivery';
|
|
2
|
+
import { DeliveryAdapter, } from "../core-index.js";
|
|
3
|
+
import { pluginRegistry } from "../plugins/PluginRegistry.js";
|
|
4
|
+
export default function registerDeliveryProvider({ adapterId, type = DeliveryProviderType.SHIPPING, active, autoReleaseAllowed, estimatedDeliveryThroughput, send, }) {
|
|
5
|
+
const adapter = {
|
|
6
|
+
...DeliveryAdapter,
|
|
7
|
+
key: `shop.unchained.delivery.${adapterId}`,
|
|
8
|
+
label: 'Delivery: ' + adapterId,
|
|
9
|
+
version: '1.0.0',
|
|
10
|
+
initialConfiguration: [],
|
|
11
|
+
typeSupported: (deliveryType) => {
|
|
12
|
+
return deliveryType === type;
|
|
13
|
+
},
|
|
14
|
+
actions: (config, context) => {
|
|
15
|
+
return {
|
|
16
|
+
...DeliveryAdapter.actions(config, context),
|
|
17
|
+
isActive: () => {
|
|
18
|
+
return active ?? true;
|
|
19
|
+
},
|
|
20
|
+
isAutoReleaseAllowed: () => {
|
|
21
|
+
return autoReleaseAllowed ?? true;
|
|
22
|
+
},
|
|
23
|
+
configurationError: () => {
|
|
24
|
+
return null;
|
|
25
|
+
},
|
|
26
|
+
estimatedDeliveryThroughput: async (warehousingThroughputTime) => {
|
|
27
|
+
if (estimatedDeliveryThroughput) {
|
|
28
|
+
return estimatedDeliveryThroughput(warehousingThroughputTime, context);
|
|
29
|
+
}
|
|
30
|
+
return 0;
|
|
31
|
+
},
|
|
32
|
+
send: async () => {
|
|
33
|
+
return typeof send === 'function' ? await send(config, context) : send;
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
const plugin = {
|
|
39
|
+
key: adapter.key,
|
|
40
|
+
label: adapter.label,
|
|
41
|
+
version: adapter.version,
|
|
42
|
+
adapters: [adapter],
|
|
43
|
+
};
|
|
44
|
+
pluginRegistry.register(plugin);
|
|
45
|
+
return plugin;
|
|
46
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { EnrollmentOrderPositionTemplate, EnrollmentPeriod, EnrollmentPlan } from '@unchainedshop/core-enrollments';
|
|
2
|
+
import type { ProductPlan } from '@unchainedshop/core-products';
|
|
3
|
+
import type { OrderPosition } from '@unchainedshop/core-orders';
|
|
4
|
+
import { type EnrollmentContext, type IPlugin } from '../core-index.ts';
|
|
5
|
+
export default function registerEnrollment({ adapterId, isActivatedFor, transformOrderItem, configurationForOrder, isOverdue, isValidForActivation, nextPeriod, }: {
|
|
6
|
+
adapterId: string;
|
|
7
|
+
isActivatedFor?: (productPlan?: ProductPlan) => boolean;
|
|
8
|
+
transformOrderItem?: (orderPosition: OrderPosition, unchainedAPI: any) => Promise<EnrollmentPlan>;
|
|
9
|
+
configurationForOrder: (params: {
|
|
10
|
+
period: EnrollmentPeriod;
|
|
11
|
+
}, context: EnrollmentContext) => Promise<{
|
|
12
|
+
orderContext?: Record<string, any>;
|
|
13
|
+
orderPositionTemplates: EnrollmentOrderPositionTemplate[];
|
|
14
|
+
} | null>;
|
|
15
|
+
isOverdue?: (context: EnrollmentContext) => Promise<boolean>;
|
|
16
|
+
isValidForActivation?: (context: EnrollmentContext) => Promise<boolean>;
|
|
17
|
+
nextPeriod?: (context: EnrollmentContext) => Promise<EnrollmentPeriod | null>;
|
|
18
|
+
}): IPlugin;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { EnrollmentAdapter, } from "../core-index.js";
|
|
2
|
+
import { pluginRegistry } from "../plugins/PluginRegistry.js";
|
|
3
|
+
export default function registerEnrollment({ adapterId, isActivatedFor, transformOrderItem, configurationForOrder, isOverdue, isValidForActivation, nextPeriod, }) {
|
|
4
|
+
const adapter = {
|
|
5
|
+
...EnrollmentAdapter,
|
|
6
|
+
key: `shop.unchained.enrollment.${adapterId}`,
|
|
7
|
+
label: 'Enrollment: ' + adapterId,
|
|
8
|
+
version: '1.0.0',
|
|
9
|
+
isActivatedFor: (productPlan) => {
|
|
10
|
+
return isActivatedFor ? isActivatedFor(productPlan) : true;
|
|
11
|
+
},
|
|
12
|
+
transformOrderItemToEnrollmentPlan: async (orderPosition, unchainedAPI) => {
|
|
13
|
+
return transformOrderItem
|
|
14
|
+
? transformOrderItem(orderPosition, unchainedAPI)
|
|
15
|
+
: EnrollmentAdapter.transformOrderItemToEnrollmentPlan(orderPosition, unchainedAPI);
|
|
16
|
+
},
|
|
17
|
+
actions: (context) => {
|
|
18
|
+
return {
|
|
19
|
+
...EnrollmentAdapter.actions(context),
|
|
20
|
+
configurationForOrder: async (params) => {
|
|
21
|
+
return configurationForOrder(params, context);
|
|
22
|
+
},
|
|
23
|
+
isOverdue: async () => {
|
|
24
|
+
return isOverdue ? isOverdue(context) : false;
|
|
25
|
+
},
|
|
26
|
+
isValidForActivation: async () => {
|
|
27
|
+
return isValidForActivation ? isValidForActivation(context) : false;
|
|
28
|
+
},
|
|
29
|
+
nextPeriod: async () => {
|
|
30
|
+
return nextPeriod ? nextPeriod(context) : EnrollmentAdapter.actions(context).nextPeriod();
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
const plugin = {
|
|
36
|
+
key: adapter.key,
|
|
37
|
+
label: adapter.label,
|
|
38
|
+
version: adapter.version,
|
|
39
|
+
adapters: [adapter],
|
|
40
|
+
};
|
|
41
|
+
pluginRegistry.register(plugin);
|
|
42
|
+
return plugin;
|
|
43
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type UploadedFile, type UploadFileData } from '@unchainedshop/core-files';
|
|
2
|
+
import { type IPlugin } from '../core-index.ts';
|
|
3
|
+
export default function registerFileAdapter<Context = unknown>({ adapterId, createSignedURL, uploadFileFromStream, createDownloadURL, removeFiles, uploadFileFromURL, }: {
|
|
4
|
+
adapterId: string;
|
|
5
|
+
createSignedURL: (directoryName: string, fileName: string, unchainedAPI: Context) => Promise<(UploadFileData & {
|
|
6
|
+
putURL: string;
|
|
7
|
+
}) | null>;
|
|
8
|
+
uploadFileFromStream: (directoryName: string, rawFile: any, unchainedAPI: Context, options?: Record<string, any>) => Promise<UploadFileData>;
|
|
9
|
+
createDownloadURL?: (file: UploadedFile, expiry?: number) => Promise<string | null>;
|
|
10
|
+
removeFiles?: (files: UploadedFile[], unchainedContext: Context) => Promise<void>;
|
|
11
|
+
uploadFileFromURL?: (directoryName: string, fileInput: {
|
|
12
|
+
fileLink: string;
|
|
13
|
+
fileName: string;
|
|
14
|
+
fileId?: string;
|
|
15
|
+
headers?: Record<string, unknown>;
|
|
16
|
+
}, unchainedAPI: Context) => Promise<UploadFileData>;
|
|
17
|
+
}): IPlugin;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { FileAdapter, } from '@unchainedshop/core-files';
|
|
2
|
+
import {} from "../core-index.js";
|
|
3
|
+
import { pluginRegistry } from "../plugins/PluginRegistry.js";
|
|
4
|
+
export default function registerFileAdapter({ adapterId, createSignedURL, uploadFileFromStream, createDownloadURL, removeFiles, uploadFileFromURL, }) {
|
|
5
|
+
const adapter = {
|
|
6
|
+
...FileAdapter,
|
|
7
|
+
key: `shop.unchained.file-upload.${adapterId}`,
|
|
8
|
+
label: 'File Adapter: ' + adapterId,
|
|
9
|
+
version: '1.0.0',
|
|
10
|
+
createSignedURL,
|
|
11
|
+
uploadFileFromStream,
|
|
12
|
+
...(createDownloadURL ? { createDownloadURL } : {}),
|
|
13
|
+
...(removeFiles ? { removeFiles } : {}),
|
|
14
|
+
...(uploadFileFromURL ? { uploadFileFromURL } : {}),
|
|
15
|
+
};
|
|
16
|
+
const plugin = {
|
|
17
|
+
key: adapter.key,
|
|
18
|
+
label: adapter.label,
|
|
19
|
+
version: adapter.version,
|
|
20
|
+
adapters: [adapter],
|
|
21
|
+
};
|
|
22
|
+
pluginRegistry.register(plugin);
|
|
23
|
+
return plugin;
|
|
24
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PricingCalculation } from '@unchainedshop/utils';
|
|
2
|
+
import { type DiscountContext, type IPricingSheet, type OrderDiscountConfiguration, type IPlugin } from '../core-index.ts';
|
|
3
|
+
export default function registerOrderDiscount({ adapterId, isValidForSystemTriggering, isValidForCodeTriggering, discountForPricingAdapterKey, reserve, release, }: {
|
|
4
|
+
adapterId: string;
|
|
5
|
+
isValidForSystemTriggering?: (context: DiscountContext) => Promise<boolean>;
|
|
6
|
+
isValidForCodeTriggering?: (code: string, context: DiscountContext) => Promise<boolean>;
|
|
7
|
+
discountForPricingAdapterKey: (params: {
|
|
8
|
+
pricingAdapterKey: string;
|
|
9
|
+
calculationSheet: IPricingSheet<PricingCalculation>;
|
|
10
|
+
}, context: DiscountContext) => OrderDiscountConfiguration | null;
|
|
11
|
+
reserve?: (code: string | undefined, context: DiscountContext) => Promise<any>;
|
|
12
|
+
release?: (context: DiscountContext) => Promise<void>;
|
|
13
|
+
}): IPlugin;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { OrderDiscountAdapter, } from "../core-index.js";
|
|
2
|
+
import { pluginRegistry } from "../plugins/PluginRegistry.js";
|
|
3
|
+
export default function registerOrderDiscount({ adapterId, isValidForSystemTriggering, isValidForCodeTriggering, discountForPricingAdapterKey, reserve, release, }) {
|
|
4
|
+
const adapter = {
|
|
5
|
+
...OrderDiscountAdapter,
|
|
6
|
+
key: `shop.unchained.discount.order-${adapterId}`,
|
|
7
|
+
label: 'Order Discount: ' + adapterId,
|
|
8
|
+
version: '1.0.0',
|
|
9
|
+
actions: async ({ context }) => {
|
|
10
|
+
return {
|
|
11
|
+
...(await OrderDiscountAdapter.actions({ context })),
|
|
12
|
+
isValidForSystemTriggering: async () => {
|
|
13
|
+
return isValidForSystemTriggering ? isValidForSystemTriggering(context) : false;
|
|
14
|
+
},
|
|
15
|
+
isValidForCodeTriggering: async ({ code }) => {
|
|
16
|
+
return isValidForCodeTriggering ? isValidForCodeTriggering(code, context) : false;
|
|
17
|
+
},
|
|
18
|
+
discountForPricingAdapterKey: (params) => {
|
|
19
|
+
return discountForPricingAdapterKey(params, context);
|
|
20
|
+
},
|
|
21
|
+
reserve: async ({ code }) => {
|
|
22
|
+
return reserve ? reserve(code, context) : {};
|
|
23
|
+
},
|
|
24
|
+
release: async () => {
|
|
25
|
+
if (release)
|
|
26
|
+
await release(context);
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
const plugin = {
|
|
32
|
+
key: adapter.key,
|
|
33
|
+
label: adapter.label,
|
|
34
|
+
version: adapter.version,
|
|
35
|
+
adapters: [adapter],
|
|
36
|
+
};
|
|
37
|
+
pluginRegistry.register(plugin);
|
|
38
|
+
return plugin;
|
|
39
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type IPlugin, type IOrderPricingSheet, type OrderPricingAdapterContext } from '../core-index.ts';
|
|
2
|
+
export default function registerOrderPricing({ adapterId, orderIndex, isActivatedFor, calculate, }: {
|
|
3
|
+
adapterId: string;
|
|
4
|
+
orderIndex?: number;
|
|
5
|
+
isActivatedFor?: (context: OrderPricingAdapterContext) => boolean;
|
|
6
|
+
calculate: (sheet: IOrderPricingSheet, context: OrderPricingAdapterContext) => Promise<void>;
|
|
7
|
+
}): IPlugin;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { OrderPricingAdapter, } from "../core-index.js";
|
|
2
|
+
import { pluginRegistry } from "../plugins/PluginRegistry.js";
|
|
3
|
+
export default function registerOrderPricing({ adapterId, orderIndex, isActivatedFor, calculate, }) {
|
|
4
|
+
const adapter = {
|
|
5
|
+
...OrderPricingAdapter,
|
|
6
|
+
key: `shop.unchained.pricing.order-${adapterId}`,
|
|
7
|
+
label: 'Order Pricing: ' + adapterId,
|
|
8
|
+
version: '1.0.0',
|
|
9
|
+
orderIndex: orderIndex ?? 0,
|
|
10
|
+
isActivatedFor: (context) => (isActivatedFor ? isActivatedFor(context) : true),
|
|
11
|
+
actions: (params) => {
|
|
12
|
+
const pricingAdapter = OrderPricingAdapter.actions(params);
|
|
13
|
+
return {
|
|
14
|
+
...pricingAdapter,
|
|
15
|
+
calculate: async () => {
|
|
16
|
+
await calculate(pricingAdapter.resultSheet(), params.context);
|
|
17
|
+
return pricingAdapter.calculate();
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
const plugin = {
|
|
23
|
+
key: adapter.key,
|
|
24
|
+
label: adapter.label,
|
|
25
|
+
version: adapter.version,
|
|
26
|
+
adapters: [adapter],
|
|
27
|
+
};
|
|
28
|
+
pluginRegistry.register(plugin);
|
|
29
|
+
return plugin;
|
|
30
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type IPlugin, type IPaymentPricingSheet, type PaymentPricingAdapterContext } from '../core-index.ts';
|
|
2
|
+
export default function registerPaymentPricing({ adapterId, orderIndex, isActivatedFor, calculate, }: {
|
|
3
|
+
adapterId: string;
|
|
4
|
+
orderIndex?: number;
|
|
5
|
+
isActivatedFor?: (context: PaymentPricingAdapterContext) => boolean;
|
|
6
|
+
calculate: (sheet: IPaymentPricingSheet, context: PaymentPricingAdapterContext) => Promise<void>;
|
|
7
|
+
}): IPlugin;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { PaymentPricingAdapter, } from "../core-index.js";
|
|
2
|
+
import { pluginRegistry } from "../plugins/PluginRegistry.js";
|
|
3
|
+
export default function registerPaymentPricing({ adapterId, orderIndex, isActivatedFor, calculate, }) {
|
|
4
|
+
const adapter = {
|
|
5
|
+
...PaymentPricingAdapter,
|
|
6
|
+
key: `shop.unchained.pricing.payment-${adapterId}`,
|
|
7
|
+
label: 'Payment Pricing: ' + adapterId,
|
|
8
|
+
version: '1.0.0',
|
|
9
|
+
orderIndex: orderIndex ?? 0,
|
|
10
|
+
isActivatedFor: (context) => (isActivatedFor ? isActivatedFor(context) : true),
|
|
11
|
+
actions: (params) => {
|
|
12
|
+
const pricingAdapter = PaymentPricingAdapter.actions(params);
|
|
13
|
+
return {
|
|
14
|
+
...pricingAdapter,
|
|
15
|
+
calculate: async () => {
|
|
16
|
+
await calculate(pricingAdapter.resultSheet(), params.context);
|
|
17
|
+
return pricingAdapter.calculate();
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
const plugin = {
|
|
23
|
+
key: adapter.key,
|
|
24
|
+
label: adapter.label,
|
|
25
|
+
version: adapter.version,
|
|
26
|
+
adapters: [adapter],
|
|
27
|
+
};
|
|
28
|
+
pluginRegistry.register(plugin);
|
|
29
|
+
return plugin;
|
|
30
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PaymentConfiguration } from '@unchainedshop/core-payment';
|
|
2
|
+
import { PaymentProviderType } from '@unchainedshop/core-payment';
|
|
3
|
+
import { type PaymentContext, type PaymentChargeActionResult, type PaymentError, type IPlugin } from '../core-index.ts';
|
|
4
|
+
export default function registerPaymentProvider({ adapterId, type, charge, sign, validate, isActive, isPayLaterAllowed, configurationError, cancel, confirm, }: {
|
|
5
|
+
adapterId: string;
|
|
6
|
+
type?: PaymentProviderType;
|
|
7
|
+
charge: false | ((configuration: PaymentConfiguration, context: PaymentContext) => Promise<PaymentChargeActionResult | false>);
|
|
8
|
+
sign?: (configuration: PaymentConfiguration, context: PaymentContext) => Promise<string | null>;
|
|
9
|
+
validate?: (configuration: PaymentConfiguration, context: PaymentContext) => Promise<boolean>;
|
|
10
|
+
isActive?: boolean;
|
|
11
|
+
isPayLaterAllowed?: boolean;
|
|
12
|
+
configurationError?: PaymentError | null;
|
|
13
|
+
cancel?: (configuration: PaymentConfiguration, context: PaymentContext) => Promise<boolean>;
|
|
14
|
+
confirm?: (configuration: PaymentConfiguration, context: PaymentContext) => Promise<boolean>;
|
|
15
|
+
}): IPlugin;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { PaymentProviderType } from '@unchainedshop/core-payment';
|
|
2
|
+
import { PaymentAdapter, } from "../core-index.js";
|
|
3
|
+
import { pluginRegistry } from "../plugins/PluginRegistry.js";
|
|
4
|
+
export default function registerPaymentProvider({ adapterId, type, charge, sign, validate, isActive, isPayLaterAllowed, configurationError, cancel, confirm, }) {
|
|
5
|
+
const providerType = type ?? PaymentProviderType.GENERIC;
|
|
6
|
+
const adapter = {
|
|
7
|
+
...PaymentAdapter,
|
|
8
|
+
key: `shop.unchained.payment.${adapterId}`,
|
|
9
|
+
label: 'Payment: ' + adapterId,
|
|
10
|
+
version: '1.0.0',
|
|
11
|
+
initialConfiguration: [],
|
|
12
|
+
typeSupported: (t) => {
|
|
13
|
+
return t === providerType;
|
|
14
|
+
},
|
|
15
|
+
actions: (config, context) => {
|
|
16
|
+
return {
|
|
17
|
+
...PaymentAdapter.actions(config, context),
|
|
18
|
+
isActive: () => {
|
|
19
|
+
return isActive ?? true;
|
|
20
|
+
},
|
|
21
|
+
isPayLaterAllowed: () => {
|
|
22
|
+
return isPayLaterAllowed ?? false;
|
|
23
|
+
},
|
|
24
|
+
configurationError: () => {
|
|
25
|
+
return configurationError ?? null;
|
|
26
|
+
},
|
|
27
|
+
sign: async () => {
|
|
28
|
+
return sign ? sign(config, context) : null;
|
|
29
|
+
},
|
|
30
|
+
validate: async () => {
|
|
31
|
+
return validate ? validate(config, context) : false;
|
|
32
|
+
},
|
|
33
|
+
cancel: async () => {
|
|
34
|
+
return cancel ? cancel(config, context) : false;
|
|
35
|
+
},
|
|
36
|
+
confirm: async () => {
|
|
37
|
+
return confirm ? confirm(config, context) : false;
|
|
38
|
+
},
|
|
39
|
+
charge: async () => {
|
|
40
|
+
return typeof charge === 'function' ? await charge(config, context) : charge;
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
const plugin = {
|
|
46
|
+
key: adapter.key,
|
|
47
|
+
label: adapter.label,
|
|
48
|
+
version: adapter.version,
|
|
49
|
+
adapters: [adapter],
|
|
50
|
+
};
|
|
51
|
+
pluginRegistry.register(plugin);
|
|
52
|
+
return plugin;
|
|
53
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type IPlugin, type IPricingSheet, type ProductDiscountConfiguration } from '../core-index.ts';
|
|
2
|
+
import type { PricingCalculation } from '@unchainedshop/utils';
|
|
3
|
+
export default function registerProductDiscount({ adapterId, orderIndex, isManualAdditionAllowed, isManualRemovalAllowed, isValidForSystemTriggering, isValidForCodeTriggering, discountForPricingAdapterKey, reserve, release, }: {
|
|
4
|
+
adapterId: string;
|
|
5
|
+
orderIndex?: number;
|
|
6
|
+
isManualAdditionAllowed?: (code?: string) => Promise<boolean>;
|
|
7
|
+
isManualRemovalAllowed?: () => Promise<boolean>;
|
|
8
|
+
isValidForSystemTriggering?: () => Promise<boolean>;
|
|
9
|
+
isValidForCodeTriggering?: (params: {
|
|
10
|
+
code: string;
|
|
11
|
+
}) => Promise<boolean>;
|
|
12
|
+
discountForPricingAdapterKey: (params: {
|
|
13
|
+
pricingAdapterKey: string;
|
|
14
|
+
calculationSheet: IPricingSheet<PricingCalculation>;
|
|
15
|
+
}) => ProductDiscountConfiguration | null;
|
|
16
|
+
reserve?: (params: {
|
|
17
|
+
code?: string;
|
|
18
|
+
}) => Promise<any>;
|
|
19
|
+
release?: () => Promise<void>;
|
|
20
|
+
}): IPlugin;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ProductDiscountAdapter, } from "../core-index.js";
|
|
2
|
+
import { pluginRegistry } from "../plugins/PluginRegistry.js";
|
|
3
|
+
export default function registerProductDiscount({ adapterId, orderIndex, isManualAdditionAllowed, isManualRemovalAllowed, isValidForSystemTriggering, isValidForCodeTriggering, discountForPricingAdapterKey, reserve, release, }) {
|
|
4
|
+
const adapter = {
|
|
5
|
+
...ProductDiscountAdapter,
|
|
6
|
+
key: `shop.unchained.discount.product-${adapterId}`,
|
|
7
|
+
label: 'Product Discount: ' + adapterId,
|
|
8
|
+
version: '1.0.0',
|
|
9
|
+
orderIndex: orderIndex ?? 0,
|
|
10
|
+
isManualAdditionAllowed: async (code) => {
|
|
11
|
+
return isManualAdditionAllowed
|
|
12
|
+
? isManualAdditionAllowed(code)
|
|
13
|
+
: ProductDiscountAdapter.isManualAdditionAllowed(code);
|
|
14
|
+
},
|
|
15
|
+
isManualRemovalAllowed: async () => {
|
|
16
|
+
return isManualRemovalAllowed
|
|
17
|
+
? isManualRemovalAllowed()
|
|
18
|
+
: ProductDiscountAdapter.isManualRemovalAllowed();
|
|
19
|
+
},
|
|
20
|
+
actions: async (params) => {
|
|
21
|
+
return {
|
|
22
|
+
...(await ProductDiscountAdapter.actions(params)),
|
|
23
|
+
isValidForSystemTriggering: async () => {
|
|
24
|
+
return isValidForSystemTriggering ? isValidForSystemTriggering() : false;
|
|
25
|
+
},
|
|
26
|
+
isValidForCodeTriggering: async ({ code }) => {
|
|
27
|
+
return isValidForCodeTriggering ? isValidForCodeTriggering({ code }) : false;
|
|
28
|
+
},
|
|
29
|
+
discountForPricingAdapterKey,
|
|
30
|
+
reserve: async ({ code }) => {
|
|
31
|
+
return reserve ? reserve({ code }) : {};
|
|
32
|
+
},
|
|
33
|
+
release: async () => {
|
|
34
|
+
return release ? release() : undefined;
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
const plugin = {
|
|
40
|
+
key: adapter.key,
|
|
41
|
+
label: adapter.label,
|
|
42
|
+
version: adapter.version,
|
|
43
|
+
adapters: [adapter],
|
|
44
|
+
};
|
|
45
|
+
pluginRegistry.register(plugin);
|
|
46
|
+
return plugin;
|
|
47
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type IPlugin, type IProductPricingSheet, type ProductPricingAdapterContext } from '../core-index.ts';
|
|
2
|
+
export default function registerProductPricing({ adapterId, orderIndex, isActivatedFor, calculate, }: {
|
|
3
|
+
adapterId: string;
|
|
4
|
+
orderIndex?: number;
|
|
5
|
+
isActivatedFor?: (context: ProductPricingAdapterContext) => boolean;
|
|
6
|
+
calculate: (sheet: IProductPricingSheet, context: ProductPricingAdapterContext) => Promise<void>;
|
|
7
|
+
}): IPlugin;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ProductPricingAdapter, } from "../core-index.js";
|
|
2
|
+
import { pluginRegistry } from "../plugins/PluginRegistry.js";
|
|
3
|
+
export default function registerProductPricing({ adapterId, orderIndex, isActivatedFor, calculate, }) {
|
|
4
|
+
const adapter = {
|
|
5
|
+
...ProductPricingAdapter,
|
|
6
|
+
key: `shop.unchained.pricing.product-${adapterId}`,
|
|
7
|
+
label: 'Product Pricing: ' + adapterId,
|
|
8
|
+
version: '1.0.0',
|
|
9
|
+
orderIndex: orderIndex ?? 0,
|
|
10
|
+
isActivatedFor: (context) => (isActivatedFor ? isActivatedFor(context) : true),
|
|
11
|
+
actions: (params) => {
|
|
12
|
+
const pricingAdapter = ProductPricingAdapter.actions(params);
|
|
13
|
+
return {
|
|
14
|
+
...pricingAdapter,
|
|
15
|
+
calculate: async () => {
|
|
16
|
+
await calculate(pricingAdapter.resultSheet(), params.context);
|
|
17
|
+
return pricingAdapter.calculate();
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
const plugin = {
|
|
23
|
+
key: adapter.key,
|
|
24
|
+
label: adapter.label,
|
|
25
|
+
version: adapter.version,
|
|
26
|
+
adapters: [adapter],
|
|
27
|
+
};
|
|
28
|
+
pluginRegistry.register(plugin);
|
|
29
|
+
return plugin;
|
|
30
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { QuotationItemConfiguration, QuotationProposal } from '@unchainedshop/core-quotations';
|
|
2
|
+
import { type QuotationContext, type IPlugin } from '../core-index.ts';
|
|
3
|
+
export default function registerQuotation({ adapterId, isManualRequestVerificationRequired, isManualProposalRequired, quote, submitRequest, verifyRequest, rejectRequest, transformItemConfiguration, }: {
|
|
4
|
+
adapterId: string;
|
|
5
|
+
isManualRequestVerificationRequired?: boolean;
|
|
6
|
+
isManualProposalRequired?: boolean;
|
|
7
|
+
quote?: (context: QuotationContext) => Promise<QuotationProposal>;
|
|
8
|
+
submitRequest?: (context: QuotationContext) => Promise<boolean>;
|
|
9
|
+
verifyRequest?: (context: QuotationContext) => Promise<boolean>;
|
|
10
|
+
rejectRequest?: (context: QuotationContext) => Promise<boolean>;
|
|
11
|
+
transformItemConfiguration?: (params: QuotationItemConfiguration, context: QuotationContext) => Promise<QuotationItemConfiguration | null>;
|
|
12
|
+
}): IPlugin;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { QuotationAdapter, } from "../core-index.js";
|
|
2
|
+
import { pluginRegistry } from "../plugins/PluginRegistry.js";
|
|
3
|
+
export default function registerQuotation({ adapterId, isManualRequestVerificationRequired, isManualProposalRequired, quote, submitRequest, verifyRequest, rejectRequest, transformItemConfiguration, }) {
|
|
4
|
+
const adapter = {
|
|
5
|
+
...QuotationAdapter,
|
|
6
|
+
key: `shop.unchained.quotation.${adapterId}`,
|
|
7
|
+
label: 'Quotation: ' + adapterId,
|
|
8
|
+
version: '1.0.0',
|
|
9
|
+
isActivatedFor: () => {
|
|
10
|
+
return true;
|
|
11
|
+
},
|
|
12
|
+
actions: (context) => {
|
|
13
|
+
return {
|
|
14
|
+
...QuotationAdapter.actions(context),
|
|
15
|
+
configurationError: () => {
|
|
16
|
+
return null;
|
|
17
|
+
},
|
|
18
|
+
isManualRequestVerificationRequired: async () => {
|
|
19
|
+
return isManualRequestVerificationRequired ?? true;
|
|
20
|
+
},
|
|
21
|
+
isManualProposalRequired: async () => {
|
|
22
|
+
return isManualProposalRequired ?? true;
|
|
23
|
+
},
|
|
24
|
+
quote: async () => {
|
|
25
|
+
return quote ? quote(context) : {};
|
|
26
|
+
},
|
|
27
|
+
submitRequest: async () => {
|
|
28
|
+
return submitRequest ? submitRequest(context) : true;
|
|
29
|
+
},
|
|
30
|
+
verifyRequest: async () => {
|
|
31
|
+
return verifyRequest ? verifyRequest(context) : true;
|
|
32
|
+
},
|
|
33
|
+
rejectRequest: async () => {
|
|
34
|
+
return rejectRequest ? rejectRequest(context) : true;
|
|
35
|
+
},
|
|
36
|
+
transformItemConfiguration: async (params) => {
|
|
37
|
+
return transformItemConfiguration
|
|
38
|
+
? transformItemConfiguration(params, context)
|
|
39
|
+
: { quantity: params.quantity, configuration: params.configuration };
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
const plugin = {
|
|
45
|
+
key: adapter.key,
|
|
46
|
+
label: adapter.label,
|
|
47
|
+
version: adapter.version,
|
|
48
|
+
adapters: [adapter],
|
|
49
|
+
};
|
|
50
|
+
pluginRegistry.register(plugin);
|
|
51
|
+
return plugin;
|
|
52
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ordersSettings } from '@unchainedshop/core-orders';
|
|
2
|
+
import { createServiceError } from "../errors.js";
|
|
2
3
|
export async function addMultipleCartProductsService({ orderId, items, context, }) {
|
|
3
4
|
const order = await this.orders.findOrder({ orderId });
|
|
4
5
|
if (!order)
|
|
@@ -6,10 +7,10 @@ export async function addMultipleCartProductsService({ orderId, items, context,
|
|
|
6
7
|
for (const { productId, quantity, configuration } of items) {
|
|
7
8
|
const originalProduct = await this.products.findProduct({ productId });
|
|
8
9
|
if (!originalProduct) {
|
|
9
|
-
throw
|
|
10
|
+
throw createServiceError('ProductNotFoundError', `Product not found: ${productId}`);
|
|
10
11
|
}
|
|
11
12
|
if (quantity < 1) {
|
|
12
|
-
throw
|
|
13
|
+
throw createServiceError('InvalidQuantityError', `Invalid quantity for product: ${productId}`);
|
|
13
14
|
}
|
|
14
15
|
const product = await this.products.resolveOrderableProduct(originalProduct, { configuration });
|
|
15
16
|
await ordersSettings.validateOrderPosition({ order, product, configuration, quantityDiff: quantity }, { modules: this, ...context });
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { FilterDirector } from "../core-index.js";
|
|
2
|
+
export async function createFilterOptionService(filterId, { value }) {
|
|
3
|
+
const filter = await this.filters.createFilterOption(filterId, { value });
|
|
4
|
+
if (filter) {
|
|
5
|
+
await FilterDirector.invalidateProductIdCache(filter, { modules: this });
|
|
6
|
+
}
|
|
7
|
+
return filter;
|
|
8
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { getFileFromFileData, getFileAdapter } from '@unchainedshop/core-files';
|
|
2
|
+
import { createServiceError } from "../errors.js";
|
|
2
3
|
export async function createSignedURLService({ directoryName, fileName, meta }) {
|
|
3
4
|
const fileUploadAdapter = getFileAdapter();
|
|
4
5
|
const preparedFileData = await fileUploadAdapter.createSignedURL(directoryName, fileName, {
|
|
5
6
|
modules: this,
|
|
6
7
|
});
|
|
7
8
|
if (!preparedFileData)
|
|
8
|
-
throw
|
|
9
|
+
throw createServiceError('SignedURLPreparationError', 'Could not prepare signed URL');
|
|
9
10
|
const fileData = getFileFromFileData(preparedFileData, meta);
|
|
10
11
|
const fileId = await this.files.create(fileData);
|
|
11
12
|
const file = await this.files.findFile({ fileId });
|
package/lib/services/index.d.ts
CHANGED
|
@@ -41,6 +41,10 @@ import { verifyQuotationService } from './verifyQuotation.ts';
|
|
|
41
41
|
import { loadFiltersService } from './loadFilters.ts';
|
|
42
42
|
import { loadFilterOptionsService } from './loadFilterOptions.ts';
|
|
43
43
|
import { removeFilterService } from './removeFilter.ts';
|
|
44
|
+
import { createFilterService } from './createFilter.ts';
|
|
45
|
+
import { updateFilterService } from './updateFilter.ts';
|
|
46
|
+
import { createFilterOptionService } from './createFilterOption.ts';
|
|
47
|
+
import { removeFilterOptionService } from './removeFilterOption.ts';
|
|
44
48
|
import { removeCartDiscountService } from './removeCartDiscount.ts';
|
|
45
49
|
import { addMultipleCartProductsService } from './addMultipleCartProducts.ts';
|
|
46
50
|
import { ercMetadataService } from './ercMetadata.ts';
|
|
@@ -131,6 +135,10 @@ export default function initServices(modules: Modules, customServices?: CustomSe
|
|
|
131
135
|
loadFilters: Bound<typeof loadFiltersService>;
|
|
132
136
|
loadFilterOptions: Bound<typeof loadFilterOptionsService>;
|
|
133
137
|
removeFilter: Bound<typeof removeFilterService>;
|
|
138
|
+
createFilter: Bound<typeof createFilterService>;
|
|
139
|
+
updateFilter: Bound<typeof updateFilterService>;
|
|
140
|
+
createFilterOption: Bound<typeof createFilterOptionService>;
|
|
141
|
+
removeFilterOption: Bound<typeof removeFilterOptionService>;
|
|
134
142
|
};
|
|
135
143
|
warehousing: {
|
|
136
144
|
ercMetadata: Bound<typeof ercMetadataService>;
|
package/lib/services/index.js
CHANGED
|
@@ -40,6 +40,10 @@ import { verifyQuotationService } from "./verifyQuotation.js";
|
|
|
40
40
|
import { loadFiltersService } from "./loadFilters.js";
|
|
41
41
|
import { loadFilterOptionsService } from "./loadFilterOptions.js";
|
|
42
42
|
import { removeFilterService } from "./removeFilter.js";
|
|
43
|
+
import { createFilterService } from "./createFilter.js";
|
|
44
|
+
import { updateFilterService } from "./updateFilter.js";
|
|
45
|
+
import { createFilterOptionService } from "./createFilterOption.js";
|
|
46
|
+
import { removeFilterOptionService } from "./removeFilterOption.js";
|
|
43
47
|
import { removeCartDiscountService } from "./removeCartDiscount.js";
|
|
44
48
|
import { addMultipleCartProductsService } from "./addMultipleCartProducts.js";
|
|
45
49
|
import { ercMetadataService } from "./ercMetadata.js";
|
|
@@ -142,6 +146,10 @@ export default function initServices(modules, customServices = {}) {
|
|
|
142
146
|
loadFilters: loadFiltersService,
|
|
143
147
|
loadFilterOptions: loadFilterOptionsService,
|
|
144
148
|
removeFilter: removeFilterService,
|
|
149
|
+
createFilter: createFilterService,
|
|
150
|
+
updateFilter: updateFilterService,
|
|
151
|
+
createFilterOption: createFilterOptionService,
|
|
152
|
+
removeFilterOption: removeFilterOptionService,
|
|
145
153
|
},
|
|
146
154
|
warehousing: {
|
|
147
155
|
ercMetadata: ercMetadataService,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { filterOptionValues } from '@unchainedshop/core-filters';
|
|
2
2
|
import { FilterDirector, parseQueryArray } from "../directors/FilterDirector.js";
|
|
3
3
|
export async function loadFilterOptionsService(filter, params) {
|
|
4
4
|
const { forceLiveCollection, productIdSet, searchQuery } = params;
|
|
5
5
|
const filterQueryParsed = parseQueryArray(searchQuery?.filterQuery);
|
|
6
6
|
const values = filterQueryParsed[filter.key];
|
|
7
|
-
const allOptions = (filter
|
|
7
|
+
const allOptions = filterOptionValues(filter);
|
|
8
8
|
const mappedOptions = await Promise.all(allOptions.map(async (value) => {
|
|
9
9
|
const filterOptionProductIds = await FilterDirector.filterProductIds(filter, {
|
|
10
10
|
values: [value],
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { EnrollmentStatus } from '@unchainedshop/core-enrollments';
|
|
2
2
|
import { EnrollmentDirector } from "../core-index.js";
|
|
3
|
+
import { createServiceError } from "../errors.js";
|
|
3
4
|
const findNextStatus = async (enrollment, modules) => {
|
|
4
5
|
let status = enrollment.status;
|
|
5
6
|
const product = await modules.products.findProduct({
|
|
6
7
|
productId: enrollment.productId,
|
|
7
8
|
});
|
|
8
9
|
if (!product)
|
|
9
|
-
throw
|
|
10
|
+
throw createServiceError('ProductNotFoundError', 'Product not found for enrollment');
|
|
10
11
|
const director = await EnrollmentDirector.actions({ enrollment, product }, { modules });
|
|
11
12
|
if (status === EnrollmentStatus.INITIAL || status === EnrollmentStatus.PAUSED) {
|
|
12
13
|
if (await director.isValidForActivation()) {
|
|
@@ -5,6 +5,7 @@ import { WarehousingProviderType } from '@unchainedshop/core-warehousing';
|
|
|
5
5
|
import { WarehousingDirector, DeliveryDirector, PaymentDirector } from "../directors/index.js";
|
|
6
6
|
import { fulfillQuotationService } from "./fulfillQuotation.js";
|
|
7
7
|
import { createLogger } from '@unchainedshop/logger';
|
|
8
|
+
import { createServiceError } from "../errors.js";
|
|
8
9
|
const logger = createLogger('unchained:core:processOrder');
|
|
9
10
|
const isAutoConfirmationEnabled = async ({ orderPayment, orderDelivery, }, modules) => {
|
|
10
11
|
if (orderPayment.status !== OrderPaymentStatus.PAID) {
|
|
@@ -12,7 +13,7 @@ const isAutoConfirmationEnabled = async ({ orderPayment, orderDelivery, }, modul
|
|
|
12
13
|
paymentProviderId: orderPayment.paymentProviderId,
|
|
13
14
|
});
|
|
14
15
|
if (!paymentProvider)
|
|
15
|
-
throw
|
|
16
|
+
throw createServiceError('PaymentProviderNotFoundError', `Payment provider not found: ${orderPayment.paymentProviderId}`);
|
|
16
17
|
const actions = await PaymentDirector.actions(paymentProvider, {}, { modules });
|
|
17
18
|
if (!actions.isPayLaterAllowed())
|
|
18
19
|
return false;
|
|
@@ -22,7 +23,7 @@ const isAutoConfirmationEnabled = async ({ orderPayment, orderDelivery, }, modul
|
|
|
22
23
|
deliveryProviderId: orderDelivery.deliveryProviderId,
|
|
23
24
|
});
|
|
24
25
|
if (!deliveryProvider)
|
|
25
|
-
throw
|
|
26
|
+
throw createServiceError('DeliveryProviderNotFoundError', `Delivery provider not found: ${orderDelivery.deliveryProviderId}`);
|
|
26
27
|
const director = await DeliveryDirector.actions(deliveryProvider, {}, { modules });
|
|
27
28
|
if (!director.isAutoReleaseAllowed())
|
|
28
29
|
return false;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { QuotationStatus } from '@unchainedshop/core-quotations';
|
|
2
2
|
import { QuotationDirector } from "../core-index.js";
|
|
3
3
|
import { addMessageService } from "./addMessage.js";
|
|
4
|
-
const findNextStatus = async (
|
|
4
|
+
const findNextStatus = async (director, quotation) => {
|
|
5
5
|
let status = quotation.status;
|
|
6
|
-
const director = await QuotationDirector.actions({ quotation }, { modules });
|
|
7
6
|
if (status === QuotationStatus.REQUESTED) {
|
|
8
7
|
if (!(await director.isManualRequestVerificationRequired())) {
|
|
9
8
|
status = QuotationStatus.PROCESSING;
|
|
@@ -19,27 +18,26 @@ const findNextStatus = async (quotation, modules) => {
|
|
|
19
18
|
export async function processQuotationService(initialQuotation, params) {
|
|
20
19
|
const quotationId = initialQuotation._id;
|
|
21
20
|
let quotation = initialQuotation;
|
|
22
|
-
let nextStatus = await findNextStatus(quotation, this);
|
|
23
21
|
const director = await QuotationDirector.actions({ quotation }, { modules: this });
|
|
22
|
+
const runHook = async (hook) => {
|
|
23
|
+
await hook(params.quotationContext);
|
|
24
|
+
quotation = (await this.quotations.findQuotation({ quotationId }));
|
|
25
|
+
return findNextStatus(director, quotation);
|
|
26
|
+
};
|
|
27
|
+
let nextStatus = await findNextStatus(director, quotation);
|
|
24
28
|
if (quotation.status === QuotationStatus.REQUESTED && nextStatus !== QuotationStatus.REQUESTED) {
|
|
25
|
-
await director.submitRequest
|
|
29
|
+
nextStatus = await runHook(director.submitRequest);
|
|
26
30
|
}
|
|
27
|
-
quotation = (await this.quotations.findQuotation({ quotationId }));
|
|
28
|
-
nextStatus = await findNextStatus(quotation, this);
|
|
29
31
|
if (nextStatus !== QuotationStatus.PROCESSING) {
|
|
30
|
-
await director.verifyRequest
|
|
32
|
+
nextStatus = await runHook(director.verifyRequest);
|
|
31
33
|
}
|
|
32
|
-
quotation = (await this.quotations.findQuotation({ quotationId }));
|
|
33
|
-
nextStatus = await findNextStatus(quotation, this);
|
|
34
34
|
if (nextStatus === QuotationStatus.REJECTED) {
|
|
35
|
-
await director.rejectRequest
|
|
35
|
+
nextStatus = await runHook(director.rejectRequest);
|
|
36
36
|
}
|
|
37
|
-
quotation = (await this.quotations.findQuotation({ quotationId }));
|
|
38
|
-
nextStatus = await findNextStatus(quotation, this);
|
|
39
37
|
if (nextStatus === QuotationStatus.PROPOSED) {
|
|
40
38
|
const proposal = await director.quote();
|
|
41
39
|
quotation = (await this.quotations.updateProposal(quotation._id, proposal));
|
|
42
|
-
nextStatus = await findNextStatus(
|
|
40
|
+
nextStatus = await findNextStatus(director, quotation);
|
|
43
41
|
}
|
|
44
42
|
const updatedQuotation = (await this.quotations.updateStatus(quotation._id, {
|
|
45
43
|
status: nextStatus,
|
|
@@ -3,6 +3,9 @@ import { processQuotationService } from "./processQuotation.js";
|
|
|
3
3
|
export async function proposeQuotationService(quotation, { quotationContext }) {
|
|
4
4
|
if (quotation.status !== QuotationStatus.PROCESSING)
|
|
5
5
|
return quotation;
|
|
6
|
+
if (quotationContext) {
|
|
7
|
+
await this.quotations.updateContext(quotation._id, { context: quotationContext });
|
|
8
|
+
}
|
|
6
9
|
const updatedQuotation = (await this.quotations.updateStatus(quotation._id, {
|
|
7
10
|
status: QuotationStatus.PROPOSED,
|
|
8
11
|
info: 'proposed manually',
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Filter } from '@unchainedshop/core-filters';
|
|
2
|
+
import type { Modules } from '../modules.ts';
|
|
3
|
+
export declare function removeFilterOptionService(this: Modules, { filterId, filterOptionValue }: {
|
|
4
|
+
filterId: string;
|
|
5
|
+
filterOptionValue: string;
|
|
6
|
+
}): Promise<Filter | null>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { FilterDirector } from "../core-index.js";
|
|
2
|
+
export async function removeFilterOptionService({ filterId, filterOptionValue }) {
|
|
3
|
+
const filter = await this.filters.removeFilterOption({ filterId, filterOptionValue });
|
|
4
|
+
if (filter) {
|
|
5
|
+
await FilterDirector.invalidateProductIdCache(filter, { modules: this });
|
|
6
|
+
}
|
|
7
|
+
return filter;
|
|
8
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ProductStatus } from '@unchainedshop/core-products';
|
|
2
2
|
import { updateCalculationService } from "./updateCalculation.js";
|
|
3
|
+
import { createServiceError } from "../errors.js";
|
|
3
4
|
export async function removeProductService({ productId }) {
|
|
4
5
|
const product = await this.products.findProduct({ productId });
|
|
5
6
|
switch (product?.status) {
|
|
@@ -21,7 +22,7 @@ export async function removeProductService({ productId }) {
|
|
|
21
22
|
case ProductStatus.DELETED:
|
|
22
23
|
return false;
|
|
23
24
|
default:
|
|
24
|
-
throw
|
|
25
|
+
throw createServiceError('ProductWrongStatusError', `Invalid status: ${product?.status}`);
|
|
25
26
|
}
|
|
26
27
|
return true;
|
|
27
28
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { OrderDiscountTrigger, } from '@unchainedshop/core-orders';
|
|
2
2
|
import { initCartProvidersService } from "./initCartProviders.js";
|
|
3
3
|
import { updateSchedulingService } from "./updateScheduling.js";
|
|
4
|
+
import { createServiceError } from "../errors.js";
|
|
4
5
|
import { OrderDiscountDirector, OrderPricingDirector, DeliveryPricingDirector, ProductPricingDirector, PaymentPricingDirector, } from "../directors/index.js";
|
|
5
6
|
export async function updateCalculationService(orderId) {
|
|
6
7
|
let order = await this.orders.findOrder({ orderId });
|
|
7
8
|
if (!order)
|
|
8
|
-
throw
|
|
9
|
+
throw createServiceError('OrderNotFoundError', 'Order not found');
|
|
9
10
|
if (order.status !== null)
|
|
10
11
|
return order;
|
|
11
12
|
const discounts = await this.orders.discounts.findOrderDiscounts({
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { FilterDirector } from "../core-index.js";
|
|
2
|
+
export async function updateFilterService(filterId, doc) {
|
|
3
|
+
const updatedFilter = await this.filters.update(filterId, doc);
|
|
4
|
+
if (updatedFilter) {
|
|
5
|
+
await FilterDirector.invalidateProductIdCache(updatedFilter, { modules: this });
|
|
6
|
+
}
|
|
7
|
+
return updatedFilter;
|
|
8
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getFileFromFileData, getFileAdapter } from '@unchainedshop/core-files';
|
|
2
|
+
import { createServiceError } from "../errors.js";
|
|
2
3
|
export async function uploadFileFromStreamService({ directoryName, rawFile, meta, ...options }) {
|
|
3
4
|
const fileUploadAdapter = getFileAdapter();
|
|
4
5
|
const uploadFileData = await fileUploadAdapter.uploadFileFromStream(directoryName, rawFile, {
|
|
@@ -8,6 +9,6 @@ export async function uploadFileFromStreamService({ directoryName, rawFile, meta
|
|
|
8
9
|
const fileId = await this.files.create(fileData);
|
|
9
10
|
const file = await this.files.findFile({ fileId });
|
|
10
11
|
if (!file)
|
|
11
|
-
throw
|
|
12
|
+
throw createServiceError('FileNotFoundError', 'File not found after upload');
|
|
12
13
|
return file;
|
|
13
14
|
}
|
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import { ordersSettings } from '@unchainedshop/core-orders';
|
|
2
|
+
import { createServiceError } from "../errors.js";
|
|
2
3
|
export async function validateOrderService(order) {
|
|
3
4
|
if (!order.contact)
|
|
4
|
-
throw
|
|
5
|
+
throw createServiceError('ContactMissingError', 'Contact data not provided');
|
|
5
6
|
if (!order.billingAddress)
|
|
6
|
-
throw
|
|
7
|
+
throw createServiceError('BillingAddressMissingError', 'Billing address not provided');
|
|
7
8
|
if (!order.deliveryId ||
|
|
8
9
|
!(await this.orders.deliveries.findDelivery({ orderDeliveryId: order.deliveryId })))
|
|
9
|
-
throw
|
|
10
|
+
throw createServiceError('NoDeliveryProviderError', 'No delivery provider selected');
|
|
10
11
|
if (!order.paymentId ||
|
|
11
12
|
!(await this.orders.payments.findOrderPayment({ orderPaymentId: order.paymentId })))
|
|
12
|
-
throw
|
|
13
|
+
throw createServiceError('NoPaymentProviderError', 'No payment provider selected');
|
|
13
14
|
const orderPositions = await this.orders.positions.findOrderPositions({ orderId: order._id });
|
|
14
15
|
if (orderPositions.length === 0) {
|
|
15
|
-
|
|
16
|
-
NoItemsError.name = 'NoItemsError';
|
|
17
|
-
throw NoItemsError;
|
|
16
|
+
throw createServiceError('NoItemsError', 'No items to checkout');
|
|
18
17
|
}
|
|
19
18
|
for (const orderPosition of orderPositions) {
|
|
20
19
|
const product = await this.products.findProduct({
|
|
@@ -31,7 +30,7 @@ export async function validateOrderService(order) {
|
|
|
31
30
|
quotationId: orderPosition.quotationId,
|
|
32
31
|
}));
|
|
33
32
|
if (quotation && !this.quotations.isProposalValid(quotation)) {
|
|
34
|
-
throw
|
|
33
|
+
throw createServiceError('QuotationInvalidError', 'Quotation expired or fulfilled, please request a new offer');
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
36
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unchainedshop/core",
|
|
3
3
|
"description": "Core orchestration package for the Unchained Engine with business services and directors",
|
|
4
|
-
"version": "4.8.
|
|
4
|
+
"version": "4.8.20",
|
|
5
5
|
"main": "lib/core-index.js",
|
|
6
6
|
"types": "lib/core-index.d.ts",
|
|
7
7
|
"type": "module",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"minipass-json-stream": "^1.0.2"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
|
-
"@types/node": "^
|
|
60
|
+
"@types/node": "^26.2.0",
|
|
61
61
|
"typescript": "^5.8.3"
|
|
62
62
|
}
|
|
63
63
|
}
|