@unchainedshop/core 5.0.0-alpha.5 → 5.0.0-alpha.8

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 (56) hide show
  1. package/README.md +92 -546
  2. package/lib/bulk-importer/handlers/product/create.d.ts +132 -29
  3. package/lib/bulk-importer/handlers/product/create.js +31 -14
  4. package/lib/bulk-importer/handlers/product/update.d.ts +60 -30
  5. package/lib/bulk-importer/handlers/product/update.js +5 -48
  6. package/lib/core-index.d.ts +1 -2
  7. package/lib/core-index.js +2 -18
  8. package/lib/directors/BaseDiscountAdapter.d.ts +3 -0
  9. package/lib/directors/BaseDiscountDirector.d.ts +2 -2
  10. package/lib/directors/BaseDiscountDirector.js +7 -9
  11. package/lib/directors/BasePricingDirector.d.ts +2 -2
  12. package/lib/directors/BasePricingDirector.js +3 -6
  13. package/lib/directors/DeliveryDirector.d.ts +1 -1
  14. package/lib/directors/DeliveryDirector.js +2 -12
  15. package/lib/directors/DeliveryPricingDirector.js +1 -10
  16. package/lib/directors/EnrollmentAdapter.js +0 -1
  17. package/lib/directors/EnrollmentDirector.d.ts +1 -1
  18. package/lib/directors/EnrollmentDirector.js +3 -15
  19. package/lib/directors/FileDirector.d.ts +4 -4
  20. package/lib/directors/FileDirector.js +2 -13
  21. package/lib/directors/FilterDirector.d.ts +1 -1
  22. package/lib/directors/FilterDirector.js +2 -14
  23. package/lib/directors/OrderDiscountDirector.d.ts +1 -15
  24. package/lib/directors/OrderDiscountDirector.js +1 -13
  25. package/lib/directors/OrderPricingDirector.js +1 -10
  26. package/lib/directors/OrderPricingSheet.d.ts +1 -0
  27. package/lib/directors/OrderPricingSheet.js +17 -17
  28. package/lib/directors/PaymentDirector.d.ts +1 -1
  29. package/lib/directors/PaymentDirector.js +2 -12
  30. package/lib/directors/PaymentPricingDirector.js +1 -10
  31. package/lib/directors/ProductDiscountDirector.d.ts +1 -15
  32. package/lib/directors/ProductDiscountDirector.js +1 -13
  33. package/lib/directors/ProductPricingDirector.js +1 -10
  34. package/lib/directors/QuotationDirector.d.ts +1 -1
  35. package/lib/directors/QuotationDirector.js +2 -14
  36. package/lib/directors/WarehousingDirector.js +16 -34
  37. package/lib/directors/WorkerDirector.d.ts +1 -1
  38. package/lib/directors/WorkerDirector.js +2 -14
  39. package/lib/directors/registryDirector.d.ts +2 -0
  40. package/lib/directors/registryDirector.js +6 -0
  41. package/lib/factory/registerVirtualWarehousing.js +1 -1
  42. package/lib/plugins/PluginRegistry.d.ts +1 -0
  43. package/lib/plugins/PluginRegistry.js +8 -1
  44. package/lib/services/checkoutOrder.js +4 -0
  45. package/lib/services/index.d.ts +2 -1
  46. package/lib/services/index.js +2 -1
  47. package/lib/services/reserveOrderDiscountsForCheckout.d.ts +5 -0
  48. package/lib/services/reserveOrderDiscountsForCheckout.js +34 -0
  49. package/lib/services/simulateProductDispatching.d.ts +3 -1
  50. package/lib/services/simulateProductDispatching.js +3 -3
  51. package/lib/services/simulateProductInventory.d.ts +3 -1
  52. package/lib/services/simulateProductInventory.js +3 -3
  53. package/lib/services/supportedDeliveryProviders.js +9 -0
  54. package/lib/services/supportedPaymentProviders.js +9 -0
  55. package/lib/services/supportedWarehousingProviders.js +9 -0
  56. package/package.json +22 -22
@@ -1,22 +1,10 @@
1
- import { BaseDirector } from '@unchainedshop/utils';
2
1
  import { WorkerAdapter } from "./WorkerAdapter.js";
3
2
  import { createLogger } from '@unchainedshop/logger';
4
- import { pluginRegistry } from "../plugins/PluginRegistry.js";
3
+ import { registryDirector } from "./registryDirector.js";
5
4
  const logger = createLogger('unchained:core');
6
5
  const AutoScheduleMap = new Map();
7
- const baseDirector = BaseDirector('WorkerDirector', {
8
- adapterKeyField: 'key',
9
- });
10
6
  export const WorkerDirector = {
11
- ...baseDirector,
12
- getAdapter: (key) => {
13
- const adapters = pluginRegistry.getAdapters(WorkerAdapter.adapterType);
14
- return adapters.find((adapter) => adapter.key === key) || null;
15
- },
16
- getAdapters: ({ adapterFilter } = {}) => {
17
- const adapters = pluginRegistry.getAdapters(WorkerAdapter.adapterType);
18
- return adapters.filter(adapterFilter || (() => true));
19
- },
7
+ ...registryDirector(WorkerAdapter.adapterType),
20
8
  getActivePluginTypes: ({ external } = {}) => {
21
9
  return WorkerDirector.getAdapters()
22
10
  .filter((adapter) => {
@@ -0,0 +1,2 @@
1
+ import type { IBaseAdapter, IBaseDirector } from '@unchainedshop/utils';
2
+ export declare const registryDirector: <Adapter extends IBaseAdapter>(adapterType: symbol) => IBaseDirector<Adapter>;
@@ -0,0 +1,6 @@
1
+ import { pluginRegistry } from "../plugins/PluginRegistry.js";
2
+ export const registryDirector = (adapterType) => ({
3
+ getAdapter: (key) => pluginRegistry.getAdapters(adapterType).find((adapter) => adapter.key === key) ||
4
+ null,
5
+ getAdapters: ({ adapterFilter } = {}) => pluginRegistry.getAdapters(adapterType).filter(adapterFilter || (() => true)),
6
+ });
@@ -5,7 +5,7 @@ export default function registerVirtualWarehousing({ adapterId, orderIndex = 0,
5
5
  const adapter = {
6
6
  ...WarehousingAdapter,
7
7
  key: 'shop.unchained.warehousing.virtual.' + adapterId,
8
- label: 'Virtual Wareshousing: ' + adapterId,
8
+ label: 'Virtual Warehousing: ' + adapterId,
9
9
  version: '1.0.0',
10
10
  orderIndex,
11
11
  initialConfiguration: [{ key: 'shipping-hub', value: 'Shipping Hub' }],
@@ -35,6 +35,7 @@ declare class PluginRegistry {
35
35
  getPlugin(key: string): IPlugin | undefined;
36
36
  getAllPlugins(): IPlugin[];
37
37
  getAdapters(adapterType: symbol): IBaseAdapter[];
38
+ getAllAdapters(): IBaseAdapter[];
38
39
  hasPlugin(key: string): boolean;
39
40
  clear(): void;
40
41
  }
@@ -5,9 +5,11 @@ class PluginRegistry {
5
5
  moduleFactories = [];
6
6
  skippedPlugins = new Set();
7
7
  register(plugin) {
8
- if (this.plugins.has(plugin.key)) {
8
+ const registered = this.plugins.get(plugin.key);
9
+ if (registered) {
9
10
  logger.warn(`Plugin ${plugin.key} already registered, skipping`, {
10
11
  label: plugin.label,
12
+ registeredLabel: registered.label,
11
13
  });
12
14
  return;
13
15
  }
@@ -103,6 +105,11 @@ class PluginRegistry {
103
105
  }
104
106
  return result.toSorted((left, right) => (left.orderIndex ?? 0) - (right.orderIndex ?? 0));
105
107
  }
108
+ getAllAdapters() {
109
+ return this.getAllPlugins()
110
+ .filter((plugin) => !this.skippedPlugins.has(plugin.key))
111
+ .flatMap((plugin) => plugin.adapters ?? []);
112
+ }
106
113
  hasPlugin(key) {
107
114
  return this.plugins.has(key);
108
115
  }
@@ -2,6 +2,7 @@ import { OrderStatus } from '@unchainedshop/core-orders';
2
2
  import { nextUserCartService } from "./nextUserCart.js";
3
3
  import { validateOrderService } from "./validateOrder.js";
4
4
  import { processOrderService } from "./processOrder.js";
5
+ import { reserveOrderDiscountsForCheckout } from "./reserveOrderDiscountsForCheckout.js";
5
6
  export async function checkoutOrderService(orderId, transactionContext) {
6
7
  const order = await this.orders.findOrder({ orderId });
7
8
  if (!order)
@@ -10,7 +11,9 @@ export async function checkoutOrderService(orderId, transactionContext) {
10
11
  return order;
11
12
  await validateOrderService.bind(this)(order);
12
13
  const lock = await this.orders.acquireLock(order._id, 'checkout');
14
+ let discounts;
13
15
  try {
16
+ discounts = await reserveOrderDiscountsForCheckout.call(this, order);
14
17
  const processedOrder = await processOrderService.bind(this)(order, transactionContext);
15
18
  if (processedOrder.billingAddress) {
16
19
  await this.users.updateLastBillingAddress(processedOrder.userId, processedOrder.billingAddress);
@@ -27,6 +30,7 @@ export async function checkoutOrderService(orderId, transactionContext) {
27
30
  return processedOrder;
28
31
  }
29
32
  finally {
33
+ await discounts?.release();
30
34
  await lock.release();
31
35
  }
32
36
  }
@@ -24,6 +24,7 @@ import { searchProductsService } from './searchProducts.ts';
24
24
  import { calculateDiscountTotalService } from './calculateDiscountTotal.ts';
25
25
  import { registerPaymentCredentialsService } from './registerPaymentCredentials.ts';
26
26
  import { processOrderService } from './processOrder.ts';
27
+ import { processEnrollmentService } from './processEnrollment.ts';
27
28
  import { checkoutOrderService } from './checkoutOrder.ts';
28
29
  import { confirmOrderService } from './confirmOrder.ts';
29
30
  import { rejectOrderService } from './rejectOrder.ts';
@@ -126,7 +127,7 @@ export default function initServices(modules: Modules, customServices?: CustomSe
126
127
  enrollments: {
127
128
  createEnrollmentFromCheckout: Bound<typeof createEnrollmentFromCheckoutService>;
128
129
  generateOrderFromEnrollment: Bound<typeof generateOrderFromEnrollmentService>;
129
- processEnrollment: Bound<typeof processOrderService>;
130
+ processEnrollment: Bound<typeof processEnrollmentService>;
130
131
  initializeEnrollment: Bound<typeof initializeEnrollmentService>;
131
132
  activateEnrollment: Bound<typeof activateEnrollmentService>;
132
133
  terminateEnrollment: Bound<typeof terminateEnrollmentService>;
@@ -23,6 +23,7 @@ import { searchProductsService } from "./searchProducts.js";
23
23
  import { calculateDiscountTotalService } from "./calculateDiscountTotal.js";
24
24
  import { registerPaymentCredentialsService } from "./registerPaymentCredentials.js";
25
25
  import { processOrderService } from "./processOrder.js";
26
+ import { processEnrollmentService } from "./processEnrollment.js";
26
27
  import { checkoutOrderService } from "./checkoutOrder.js";
27
28
  import { confirmOrderService } from "./confirmOrder.js";
28
29
  import { rejectOrderService } from "./rejectOrder.js";
@@ -137,7 +138,7 @@ export default function initServices(modules, customServices = {}) {
137
138
  enrollments: {
138
139
  createEnrollmentFromCheckout: createEnrollmentFromCheckoutService,
139
140
  generateOrderFromEnrollment: generateOrderFromEnrollmentService,
140
- processEnrollment: processOrderService,
141
+ processEnrollment: processEnrollmentService,
141
142
  initializeEnrollment: initializeEnrollmentService,
142
143
  activateEnrollment: activateEnrollmentService,
143
144
  terminateEnrollment: terminateEnrollmentService,
@@ -0,0 +1,5 @@
1
+ import type { Order } from '@unchainedshop/core-orders';
2
+ import type { Modules } from '../modules.ts';
3
+ export declare function reserveOrderDiscountsForCheckout(this: Modules, order: Order): Promise<{
4
+ release: () => Promise<void>;
5
+ }>;
@@ -0,0 +1,34 @@
1
+ import { createLogger } from '@unchainedshop/logger';
2
+ import { OrderDiscountDirector } from "../directors/OrderDiscountDirector.js";
3
+ const logger = createLogger('unchained:core:checkoutOrder');
4
+ export async function reserveOrderDiscountsForCheckout(order) {
5
+ const reservations = [];
6
+ const release = async () => {
7
+ const results = await Promise.allSettled(reservations.map((reservation) => reservation.release()));
8
+ for (const result of results) {
9
+ if (result.status === 'rejected') {
10
+ logger.error(`Could not release a discount reservation of order ${order._id}`, {
11
+ error: result.reason,
12
+ });
13
+ }
14
+ }
15
+ };
16
+ try {
17
+ const discounts = await this.orders.discounts.findOrderDiscounts({ orderId: order._id });
18
+ for (const orderDiscount of discounts) {
19
+ const Adapter = OrderDiscountDirector.getAdapter(orderDiscount.discountKey);
20
+ if (!Adapter)
21
+ continue;
22
+ const adapter = await Adapter.actions({
23
+ context: { order, orderDiscount, code: orderDiscount.code, modules: this },
24
+ });
25
+ if (adapter.reserveForCheckout)
26
+ reservations.push(await adapter.reserveForCheckout());
27
+ }
28
+ return { release };
29
+ }
30
+ catch (error) {
31
+ await release();
32
+ throw error;
33
+ }
34
+ }
@@ -3,10 +3,12 @@ import type { Product } from '@unchainedshop/core-products';
3
3
  import { type EstimatedDispatch } from '../directors/WarehousingDirector.ts';
4
4
  import type { WarehousingContext } from '../directors/WarehousingAdapter.ts';
5
5
  import type { WarehousingProvider } from '@unchainedshop/core-warehousing';
6
- export declare function simulateProductDispatchingService(this: Modules, { product, quantity, referenceDate, }: {
6
+ import type { DeliveryProviderType } from '@unchainedshop/core-delivery';
7
+ export declare function simulateProductDispatchingService(this: Modules, { product, quantity, referenceDate, deliveryProviderType, }: {
7
8
  product: Product;
8
9
  quantity: number;
9
10
  referenceDate?: Date;
11
+ deliveryProviderType?: DeliveryProviderType | null;
10
12
  }): Promise<(WarehousingContext & EstimatedDispatch & {
11
13
  warehousingProvider: WarehousingProvider;
12
14
  })[]>;
@@ -1,7 +1,7 @@
1
1
  import { supportedWarehousingProvidersService } from "./supportedWarehousingProviders.js";
2
2
  import { WarehousingDirector } from "../directors/WarehousingDirector.js";
3
- export async function simulateProductDispatchingService({ product, quantity, referenceDate, }) {
4
- const deliveryProviders = await this.delivery.allProviders();
3
+ export async function simulateProductDispatchingService({ product, quantity, referenceDate, deliveryProviderType, }) {
4
+ const deliveryProviders = (await this.delivery.allProviders()).filter(({ type }) => !deliveryProviderType || type === deliveryProviderType);
5
5
  return deliveryProviders.reduce(async (oldResult, deliveryProvider) => {
6
6
  const result = await oldResult;
7
7
  const warehousingProviders = await supportedWarehousingProvidersService.bind(this)({
@@ -25,6 +25,6 @@ export async function simulateProductDispatchingService({ product, quantity, ref
25
25
  ...dispatch,
26
26
  };
27
27
  }));
28
- return result.concat(result, mappedWarehousingProviders);
28
+ return result.concat(mappedWarehousingProviders);
29
29
  }, Promise.resolve([]));
30
30
  }
@@ -2,9 +2,11 @@ import type { Modules } from '../modules.ts';
2
2
  import type { Product } from '@unchainedshop/core-products';
3
3
  import type { WarehousingContext } from '../directors/WarehousingAdapter.ts';
4
4
  import type { WarehousingProvider } from '@unchainedshop/core-warehousing';
5
- export declare function simulateProductInventoryService(this: Modules, { product, referenceDate, }: {
5
+ import type { DeliveryProviderType } from '@unchainedshop/core-delivery';
6
+ export declare function simulateProductInventoryService(this: Modules, { product, referenceDate, deliveryProviderType, }: {
6
7
  product: Product;
7
8
  referenceDate?: Date;
9
+ deliveryProviderType?: DeliveryProviderType | null;
8
10
  }): Promise<(WarehousingContext & {
9
11
  quantity?: number;
10
12
  } & {
@@ -1,7 +1,7 @@
1
1
  import { supportedWarehousingProvidersService } from "./supportedWarehousingProviders.js";
2
2
  import { WarehousingDirector } from "../directors/WarehousingDirector.js";
3
- export async function simulateProductInventoryService({ product, referenceDate, }) {
4
- const deliveryProviders = await this.delivery.allProviders();
3
+ export async function simulateProductInventoryService({ product, referenceDate, deliveryProviderType, }) {
4
+ const deliveryProviders = (await this.delivery.allProviders()).filter(({ type }) => !deliveryProviderType || type === deliveryProviderType);
5
5
  return deliveryProviders.reduce(async (oldResult, deliveryProvider) => {
6
6
  const result = await oldResult;
7
7
  const warehousingProviders = await supportedWarehousingProvidersService.bind(this)({
@@ -24,6 +24,6 @@ export async function simulateProductInventoryService({ product, referenceDate,
24
24
  ...stock,
25
25
  };
26
26
  }));
27
- return result.concat(result, mappedWarehousingProviders);
27
+ return result.concat(mappedWarehousingProviders);
28
28
  }, Promise.resolve([]));
29
29
  }
@@ -1,8 +1,17 @@
1
1
  import { deliverySettings } from '@unchainedshop/core-delivery';
2
+ import { createLogger } from '@unchainedshop/logger';
2
3
  import { DeliveryDirector } from "../directors/index.js";
4
+ const logger = createLogger('unchained:core');
3
5
  export async function supportedDeliveryProvidersService(params) {
4
6
  const allProviders = await this.delivery.allProviders();
5
7
  const providers = (await Promise.all(allProviders.map(async (provider) => {
8
+ if (!DeliveryDirector.getAdapter(provider.adapterKey)) {
9
+ logger.warn('Delivery provider skipped, its adapter is not registered', {
10
+ deliveryProviderId: provider._id,
11
+ adapterKey: provider.adapterKey,
12
+ });
13
+ return [];
14
+ }
6
15
  const adapter = await DeliveryDirector.actions(provider, params, { modules: this });
7
16
  return adapter.isActive() ? [provider] : [];
8
17
  }))).flat();
@@ -1,8 +1,17 @@
1
1
  import { paymentSettings } from '@unchainedshop/core-payment';
2
+ import { createLogger } from '@unchainedshop/logger';
2
3
  import { PaymentDirector } from "../directors/PaymentDirector.js";
4
+ const logger = createLogger('unchained:core');
3
5
  export async function supportedPaymentProvidersService(params) {
4
6
  const allProviders = await this.payment.paymentProviders.allProviders();
5
7
  const providers = (await Promise.all(allProviders.map(async (provider) => {
8
+ if (!PaymentDirector.getAdapter(provider.adapterKey)) {
9
+ logger.warn('Payment provider skipped, its adapter is not registered', {
10
+ paymentProviderId: provider._id,
11
+ adapterKey: provider.adapterKey,
12
+ });
13
+ return [];
14
+ }
6
15
  const adapter = await PaymentDirector.actions(provider, params, { modules: this });
7
16
  return adapter.isActive() ? [provider] : [];
8
17
  }))).flat();
@@ -1,7 +1,16 @@
1
+ import { createLogger } from '@unchainedshop/logger';
1
2
  import { WarehousingDirector } from "../directors/index.js";
3
+ const logger = createLogger('unchained:core');
2
4
  export async function supportedWarehousingProvidersService(params) {
3
5
  const allProviders = await this.warehousing.allProviders();
4
6
  const providers = (await Promise.all(allProviders.map(async (provider) => {
7
+ if (!WarehousingDirector.getAdapter(provider.adapterKey)) {
8
+ logger.warn('Warehousing provider skipped, its adapter is not registered', {
9
+ warehousingProviderId: provider._id,
10
+ adapterKey: provider.adapterKey,
11
+ });
12
+ return [];
13
+ }
5
14
  const adapter = await WarehousingDirector.actions(provider, params, { modules: this });
6
15
  return adapter.isActive() ? [provider] : [];
7
16
  }))).flat();
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": "5.0.0-alpha.5",
4
+ "version": "5.0.0-alpha.8",
5
5
  "main": "lib/core-index.js",
6
6
  "types": "lib/core-index.d.ts",
7
7
  "type": "module",
@@ -35,27 +35,27 @@
35
35
  },
36
36
  "homepage": "https://github.com/unchainedshop/unchained#readme",
37
37
  "dependencies": {
38
- "@unchainedshop/core-assortments": "^5.0.0-alpha.5",
39
- "@unchainedshop/core-bookmarks": "^5.0.0-alpha.5",
40
- "@unchainedshop/core-countries": "^5.0.0-alpha.5",
41
- "@unchainedshop/core-currencies": "^5.0.0-alpha.5",
42
- "@unchainedshop/core-delivery": "^5.0.0-alpha.5",
43
- "@unchainedshop/core-enrollments": "^5.0.0-alpha.5",
44
- "@unchainedshop/core-events": "^5.0.0-alpha.5",
45
- "@unchainedshop/core-files": "^5.0.0-alpha.5",
46
- "@unchainedshop/core-filters": "^5.0.0-alpha.5",
47
- "@unchainedshop/core-languages": "^5.0.0-alpha.5",
48
- "@unchainedshop/core-orders": "^5.0.0-alpha.5",
49
- "@unchainedshop/core-payment": "^5.0.0-alpha.5",
50
- "@unchainedshop/core-products": "^5.0.0-alpha.5",
51
- "@unchainedshop/core-quotations": "^5.0.0-alpha.5",
52
- "@unchainedshop/core-users": "^5.0.0-alpha.5",
53
- "@unchainedshop/core-warehousing": "^5.0.0-alpha.5",
54
- "@unchainedshop/core-worker": "^5.0.0-alpha.5",
55
- "@unchainedshop/events": "^5.0.0-alpha.5",
56
- "@unchainedshop/logger": "^5.0.0-alpha.5",
57
- "@unchainedshop/mongodb": "^5.0.0-alpha.5",
58
- "@unchainedshop/utils": "^5.0.0-alpha.5",
38
+ "@unchainedshop/core-assortments": "^5.0.0-alpha.8",
39
+ "@unchainedshop/core-bookmarks": "^5.0.0-alpha.8",
40
+ "@unchainedshop/core-countries": "^5.0.0-alpha.8",
41
+ "@unchainedshop/core-currencies": "^5.0.0-alpha.8",
42
+ "@unchainedshop/core-delivery": "^5.0.0-alpha.8",
43
+ "@unchainedshop/core-enrollments": "^5.0.0-alpha.8",
44
+ "@unchainedshop/core-events": "^5.0.0-alpha.8",
45
+ "@unchainedshop/core-files": "^5.0.0-alpha.8",
46
+ "@unchainedshop/core-filters": "^5.0.0-alpha.8",
47
+ "@unchainedshop/core-languages": "^5.0.0-alpha.8",
48
+ "@unchainedshop/core-orders": "^5.0.0-alpha.8",
49
+ "@unchainedshop/core-payment": "^5.0.0-alpha.8",
50
+ "@unchainedshop/core-products": "^5.0.0-alpha.8",
51
+ "@unchainedshop/core-quotations": "^5.0.0-alpha.8",
52
+ "@unchainedshop/core-users": "^5.0.0-alpha.8",
53
+ "@unchainedshop/core-warehousing": "^5.0.0-alpha.8",
54
+ "@unchainedshop/core-worker": "^5.0.0-alpha.8",
55
+ "@unchainedshop/events": "^5.0.0-alpha.8",
56
+ "@unchainedshop/logger": "^5.0.0-alpha.8",
57
+ "@unchainedshop/mongodb": "^5.0.0-alpha.8",
58
+ "@unchainedshop/utils": "^5.0.0-alpha.8",
59
59
  "minipass-json-stream": "^1.0.2",
60
60
  "zod": "^4.2.0"
61
61
  },