@pinelab/vendure-plugin-qls-fulfillment 2.2.0 → 2.3.0

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
+ # 2.3.0 (2026-08-05)
2
+
3
+ - Extra prompt before adding an additional EAN
4
+
5
+ # 2.2.1 (2026-07-15)
6
+
7
+ - Emit `StockMovementEvent` with corresponding `StockAdjustment` whenever a QLS webhook updates stock of a variant.
8
+
1
9
  # 2.2.0 (2026-07-15)
2
10
 
3
11
  - Added buttons on variant and order detail to view the product and order in QLS dashboard.
@@ -66,9 +66,10 @@ export declare class QlsProductService implements OnModuleInit, OnApplicationBoo
66
66
  */
67
67
  addAdditionalEANsToQls(ctx: RequestContext, variantId: ID, additionalEANs: string[]): Promise<string[]>;
68
68
  /**
69
- * Update the stock level for a variant based on the given available stock
69
+ * Update the stock level for a variant based on the given available stock.
70
+ * Returns true if the stock changed
70
71
  */
71
- updateStockBySku(ctx: RequestContext, sku: string, availableStock: number): Promise<void>;
72
+ updateStockBySku(ctx: RequestContext, sku: string, availableStock: number): Promise<boolean>;
72
73
  /**
73
74
  * Determines if a product needs to be created or updated in QLS based on the given variant and existing QLS product.
74
75
  */
@@ -85,7 +86,8 @@ export declare class QlsProductService implements OnModuleInit, OnApplicationBoo
85
86
  */
86
87
  private getAllVariants;
87
88
  /**
88
- * Update stock level for a variant based on the given available stock
89
+ * Update stock level for a variant based on the given available stock.
90
+ * Returns true if the stock changed.
89
91
  */
90
92
  private updateStock;
91
93
  }
@@ -312,20 +312,22 @@ let QlsProductService = class QlsProductService {
312
312
  return eansToAdd;
313
313
  }
314
314
  /**
315
- * Update the stock level for a variant based on the given available stock
315
+ * Update the stock level for a variant based on the given available stock.
316
+ * Returns true if the stock changed
316
317
  */
317
318
  async updateStockBySku(ctx, sku, availableStock) {
318
319
  const result = await this.variantService.findAll(ctx, {
319
320
  filter: { sku: { eq: sku } },
320
321
  });
321
322
  if (!result.items.length) {
322
- return core_1.Logger.info(`Variant with sku '${sku}' not found, not updating stock`, constants_1.loggerCtx);
323
+ core_1.Logger.info(`Variant with sku '${sku}' not found, not updating stock`, constants_1.loggerCtx);
324
+ return false;
323
325
  }
324
326
  const variant = result.items[0];
325
327
  if (result.items.length > 1) {
326
328
  core_1.Logger.error(`Multiple variants found for sku '${sku}', using '${variant.id}'`, constants_1.loggerCtx);
327
329
  }
328
- await this.updateStock(ctx, variant.id, availableStock);
330
+ return await this.updateStock(ctx, variant.id, availableStock);
329
331
  }
330
332
  /**
331
333
  * Determines if a product needs to be created or updated in QLS based on the given variant and existing QLS product.
@@ -431,24 +433,43 @@ let QlsProductService = class QlsProductService {
431
433
  return allVariants;
432
434
  }
433
435
  /**
434
- * Update stock level for a variant based on the given available stock
436
+ * Update stock level for a variant based on the given available stock.
437
+ * Returns true if the stock changed.
435
438
  */
436
439
  async updateStock(ctx, variantId, availableStock) {
437
440
  if (!this.options.productSync.synchronizeStockLevels) {
438
441
  core_1.Logger.warn(`Stock sync disabled. Not updating stock for variant '${variantId}'`, constants_1.loggerCtx);
439
- return;
442
+ return false;
440
443
  }
441
444
  // Find default Stock Location
442
445
  const defaultStockLocation = await this.stockLocationService.defaultStockLocation(ctx);
443
- // Get current stock level id
444
- const { id: stockLevelId } = await this.stockLevelService.getStockLevel(ctx, variantId, defaultStockLocation.id);
445
- // Update stock level
446
- await this.connection.getRepository(ctx, core_1.StockLevel).save({
447
- id: stockLevelId,
448
- stockOnHand: availableStock,
449
- stockAllocated: 0, // Reset allocations, because allocation is handled by QLS
450
- });
446
+ // Get current stock level
447
+ const stockLevel = await this.stockLevelService.getStockLevel(ctx, variantId, defaultStockLocation.id);
448
+ const delta = availableStock - stockLevel.stockOnHand;
449
+ if (delta !== 0) {
450
+ const adjustment = new core_1.StockAdjustment({
451
+ quantity: delta,
452
+ stockLocation: { id: defaultStockLocation.id },
453
+ productVariant: { id: variantId },
454
+ });
455
+ // Update stock level
456
+ await this.connection.getRepository(ctx, core_1.StockLevel).save({
457
+ id: stockLevel.id,
458
+ stockOnHand: availableStock,
459
+ stockAllocated: 0, // Reset allocations, because allocation is handled by QLS
460
+ });
461
+ await this.eventBus.publish(new core_1.StockMovementEvent(ctx, [adjustment]));
462
+ }
463
+ else {
464
+ // No stock change, but still reset allocations to ensure consistency
465
+ await this.connection.getRepository(ctx, core_1.StockLevel).save({
466
+ id: stockLevel.id,
467
+ stockOnHand: availableStock,
468
+ stockAllocated: 0, // Reset allocations, because allocation is handled by QLS
469
+ });
470
+ }
451
471
  core_1.Logger.info(`Updated stock for variant ${variantId} to ${availableStock}`, constants_1.loggerCtx);
472
+ return delta !== 0;
452
473
  }
453
474
  };
454
475
  exports.QlsProductService = QlsProductService;
@@ -4,7 +4,7 @@ import {
4
4
  ModalService,
5
5
  } from '@vendure/admin-ui/core';
6
6
  import { firstValueFrom, of } from 'rxjs';
7
- import { map, catchError } from 'rxjs/operators';
7
+ import { map, catchError, take } from 'rxjs/operators';
8
8
  import gql from 'graphql-tag';
9
9
 
10
10
  export default [
@@ -188,12 +188,30 @@ export default [
188
188
  locationId: 'product-variant-detail',
189
189
  icon: 'resistor',
190
190
  requiresPermission: ['QLSFullSync'],
191
- onClick: (_, { route, dataService, notificationService }) => {
191
+ onClick: async (
192
+ _,
193
+ { route, dataService, notificationService, entity$ }
194
+ ) => {
192
195
  const ean = window.prompt('Enter additional EAN to add to QLS:');
193
196
  if (!ean) {
194
197
  return;
195
198
  }
196
199
  const variantId = route.snapshot.params.id;
200
+ try {
201
+ const variant = await firstValueFrom(entity$.pipe(take(1)));
202
+ const confirmed = window.confirm(
203
+ `Wil je EAN "${ean}" toevoegen aan "${variant?.name}"?`
204
+ );
205
+ if (!confirmed) {
206
+ return;
207
+ }
208
+ } catch (err) {
209
+ notificationService.notify({
210
+ message: (err as any).message,
211
+ type: 'error',
212
+ });
213
+ return;
214
+ }
197
215
  dataService
198
216
  .mutate(
199
217
  gql`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pinelab/vendure-plugin-qls-fulfillment",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Vendure plugin to fulfill orders via QLS.",
5
5
  "keywords": [
6
6
  "fulfillment",