@pinelab/vendure-plugin-qls-fulfillment 1.7.0 → 1.8.1

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/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # 1.8.1 (2026-04-24)
2
+
3
+ - Replaced `saveRawWarehouseStockData` boolean with `saveAdditionalData` hook, allowing you to handle and persist any QLS product data yourself
4
+
5
+ # 1.8.0 (2026-04-21)
6
+
7
+ - Added configurable `saveRawWarehouseStockData` option
8
+
1
9
  # 1.7.0 (2026-03-15)
2
10
 
3
11
  - Pass order phone number to QLS
@@ -2,6 +2,7 @@ import { CustomFieldConfig } from '@vendure/core';
2
2
  declare module '@vendure/core' {
3
3
  interface CustomProductVariantFields {
4
4
  qlsProductId?: string;
5
+ qlsRawWarehouseStockData?: string;
5
6
  }
6
7
  interface CustomOrderFields {
7
8
  qlsServicePointId?: string;
@@ -69,6 +69,7 @@ export type FulfillmentProduct = {
69
69
  * All EANs of the product, including the main EAN
70
70
  */
71
71
  barcodes_and_ean: string[];
72
+ warehouse_stocks?: unknown[];
72
73
  };
73
74
  export interface FulfillmentOrderInput {
74
75
  brand_id: string;
@@ -15,6 +15,7 @@ export declare class QlsClient {
15
15
  * Returns the first product found, or undefined if no product is found.
16
16
  */
17
17
  getFulfillmentProductBySku(sku: string): Promise<FulfillmentProduct | undefined>;
18
+ getFulfillmentProductById(fulfillmentProductId: string): Promise<FulfillmentProduct | undefined>;
18
19
  /**
19
20
  * Get stock for all fulfillment products.
20
21
  * Might require multiple requests if the result is paginated.
@@ -34,6 +34,13 @@ class QlsClient {
34
34
  }
35
35
  return result.data[0];
36
36
  }
37
+ async getFulfillmentProductById(fulfillmentProductId) {
38
+ const result = await this.rawRequest('GET', `fulfillment/products/${fulfillmentProductId}`);
39
+ if (!result.data) {
40
+ return undefined;
41
+ }
42
+ return result.data;
43
+ }
37
44
  /**
38
45
  * Get stock for all fulfillment products.
39
46
  * Might require multiple requests if the result is paginated.
@@ -62,7 +62,10 @@ export declare class QlsProductService implements OnModuleInit, OnApplicationBoo
62
62
  /**
63
63
  * Determines if a product needs to be created or updated in QLS based on the given variant and existing QLS product.
64
64
  */
65
- createOrUpdateProductInQls(ctx: RequestContext, client: QlsClient, variant: ProductVariant, existingProduct: FulfillmentProduct | null): Promise<'created' | 'updated' | 'not-changed'>;
65
+ createOrUpdateProductInQls(ctx: RequestContext, client: QlsClient, variant: ProductVariant, existingProduct: FulfillmentProduct | null): Promise<{
66
+ status: 'created' | 'updated' | 'not-changed';
67
+ qlsProductId?: string;
68
+ }>;
66
69
  /**
67
70
  * Update the additional EANs/barcodes for a product in QLS if needed
68
71
  */
@@ -127,13 +127,13 @@ let QlsProductService = class QlsProductService {
127
127
  try {
128
128
  const existingQlsProduct = allQlsProducts.find((p) => p.sku == variant.sku);
129
129
  const result = await this.createOrUpdateProductInQls(ctx, client, variant, existingQlsProduct ?? null);
130
- if (result === 'created') {
130
+ if (result.status === 'created') {
131
131
  createdQlsProducts.push(variant);
132
132
  }
133
- else if (result === 'updated') {
133
+ else if (result.status === 'updated') {
134
134
  updatedQlsProducts.push(variant);
135
135
  }
136
- if (result === 'created' || result === 'updated') {
136
+ if (result.status === 'created' || result.status === 'updated') {
137
137
  // Wait only if we created or updated a product, otherwise no calls have been made yet.
138
138
  await waitToPreventRateLimit();
139
139
  }
@@ -212,12 +212,23 @@ let QlsProductService = class QlsProductService {
212
212
  try {
213
213
  const existingQlsProduct = await client.getFulfillmentProductBySku(variant.sku);
214
214
  const result = await this.createOrUpdateProductInQls(ctx, client, variant, existingQlsProduct ?? null);
215
- if (result === 'created') {
215
+ if (result.status === 'created') {
216
216
  createdInQls.push(variant);
217
217
  }
218
- else if (result === 'updated') {
218
+ else if (result.status === 'updated') {
219
219
  updatedInQls.push(variant);
220
220
  }
221
+ if (result.qlsProductId && this.options.saveAdditionalData) {
222
+ try {
223
+ const qlsProduct = await client.getFulfillmentProductById(result.qlsProductId);
224
+ if (qlsProduct) {
225
+ await this.options.saveAdditionalData(ctx, new core_1.Injector(this.moduleRef), qlsProduct);
226
+ }
227
+ }
228
+ catch (e) {
229
+ core_1.Logger.error(`Error in saveAdditionalData for variant '${variant.sku}': ${(0, catch_unknown_1.asError)(e).message}`, constants_1.loggerCtx);
230
+ }
231
+ }
221
232
  }
222
233
  catch (e) {
223
234
  const error = (0, catch_unknown_1.asError)(e);
@@ -280,7 +291,7 @@ let QlsProductService = class QlsProductService {
280
291
  async createOrUpdateProductInQls(ctx, client, variant, existingProduct) {
281
292
  if (await this.options.excludeVariantFromSync?.(ctx, new core_1.Injector(this.moduleRef), variant)) {
282
293
  core_1.Logger.info(`Variant '${variant.sku}' excluded from sync to QLS.`, constants_1.loggerCtx);
283
- return 'not-changed';
294
+ return { status: 'not-changed' };
284
295
  }
285
296
  if (!variant.enabled || !variant.product?.enabled) {
286
297
  const disabledEntity = !variant.enabled ? 'Variant' : 'Product';
@@ -290,7 +301,7 @@ let QlsProductService = class QlsProductService {
290
301
  else {
291
302
  core_1.Logger.info(`${disabledEntity} '${variant.sku}' is disabled, skipping sync to QLS.`, constants_1.loggerCtx);
292
303
  }
293
- return 'not-changed';
304
+ return { status: 'not-changed', qlsProductId: existingProduct?.id };
294
305
  }
295
306
  let qlsProduct = existingProduct;
296
307
  let createdOrUpdated = 'not-changed';
@@ -332,7 +343,7 @@ let QlsProductService = class QlsProductService {
332
343
  if (createdOrUpdated === 'not-changed') {
333
344
  core_1.Logger.info(`Variant '${variant.sku}' not updated in QLS, because no changes were found.`, constants_1.loggerCtx);
334
345
  }
335
- return createdOrUpdated;
346
+ return { status: createdOrUpdated, qlsProductId: qlsProduct?.id };
336
347
  }
337
348
  /**
338
349
  * Update the additional EANs/barcodes for a product in QLS if needed
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ID, Injector, Order, ProductVariant, RequestContext, SerializedRequestContext } from '@vendure/core';
2
- import { CustomValue, FulfillmentOrderInput, FulfillmentOrderLineInput, FulfillmentProductInput } from './lib/client-types';
2
+ import { CustomValue, FulfillmentOrderInput, FulfillmentOrderLineInput, FulfillmentProduct, FulfillmentProductInput } from './lib/client-types';
3
3
  export interface QlsPluginOptions {
4
4
  /**
5
5
  * Get the QLS client config for the current channel based on given context
@@ -53,6 +53,13 @@ export interface QlsPluginOptions {
53
53
  * Defaults to 'QLS'.
54
54
  */
55
55
  qlsProductIdUiTab?: string | null;
56
+ /**
57
+ * Optional hook called after syncing a variant to QLS.
58
+ * Receives the full QLS product, a RequestContext, and an Injector, allowing
59
+ * you to save any additional data to your own database. The saving itself
60
+ * happens inside this hook — if not provided, nothing is persisted.
61
+ */
62
+ saveAdditionalData?: (ctx: RequestContext, injector: Injector, qlsProduct: FulfillmentProduct) => Promise<void> | void;
56
63
  /**
57
64
  * Additional order items to add to the QLS order.
58
65
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pinelab/vendure-plugin-qls-fulfillment",
3
- "version": "1.7.0",
3
+ "version": "1.8.1",
4
4
  "description": "Vendure plugin to fulfill orders via QLS.",
5
5
  "keywords": [
6
6
  "fulfillment",