@pinelab/vendure-plugin-qls-fulfillment 2.1.0 → 2.2.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,7 @@
1
+ # 2.2.0 (2026-07-15)
2
+
3
+ - Added buttons on variant and order detail to view the product and order in QLS dashboard.
4
+
1
5
  # 2.1.0 (2026-07-08)
2
6
 
3
7
  - Added `addAdditionalEANSToQLS` admin mutation to manually add additional EANs/barcodes to existing QLS products.
@@ -11,6 +11,18 @@ exports.adminApiExtensions = (0, graphql_tag_1.default) `
11
11
  QLS order id(s) for this Vendure order.
12
12
  """
13
13
  qlsOrderIds: [String!]!
14
+
15
+ """
16
+ Direct URL to the most recent QLS order for this Vendure order, or null if none exists.
17
+ """
18
+ qlsOrderUrl: String
19
+ }
20
+
21
+ extend type ProductVariant {
22
+ """
23
+ Direct URL to the QLS product for this Vendure variant, or null if none exists.
24
+ """
25
+ qlsProductUrl: String
14
26
  }
15
27
 
16
28
  extend type Mutation {
@@ -42,6 +42,13 @@ export type Order = {
42
42
  __typename?: 'Order';
43
43
  /** QLS order id(s) for this Vendure order. */
44
44
  qlsOrderIds: Array<Scalars['String']>;
45
+ /** Direct URL to the most recent QLS order for this Vendure order, or null if none exists. */
46
+ qlsOrderUrl?: Maybe<Scalars['String']>;
47
+ };
48
+ export type ProductVariant = {
49
+ __typename?: 'ProductVariant';
50
+ /** Direct URL to the QLS product for this Vendure variant, or null if none exists. */
51
+ qlsProductUrl?: Maybe<Scalars['String']>;
45
52
  };
46
53
  export type QlsServicePoint = {
47
54
  __typename?: 'QlsServicePoint';
@@ -1,4 +1,4 @@
1
- import { Order, RequestContext } from '@vendure/core';
1
+ import { Order, ProductVariant, RequestContext } from '@vendure/core';
2
2
  import { QlsOrderService } from '../services/qls-order.service';
3
3
  import { QlsProductService } from '../services/qls-product.service';
4
4
  import { MutationAddAdditionalEansToQlsArgs, MutationPushOrderToQlsArgs } from './generated/graphql';
@@ -7,6 +7,8 @@ export declare class QlsAdminResolver {
7
7
  private qlsOrderService;
8
8
  constructor(qlsProductService: QlsProductService, qlsOrderService: QlsOrderService);
9
9
  qlsOrderIds(ctx: RequestContext, order: Order): Promise<string[]>;
10
+ qlsOrderUrl(ctx: RequestContext, order: Order): Promise<string | null>;
11
+ qlsProductUrl(ctx: RequestContext, productVariant: ProductVariant): Promise<string | null>;
10
12
  triggerQlsProductSync(ctx: RequestContext): Promise<boolean>;
11
13
  addAdditionalEANSToQLS(ctx: RequestContext, input: MutationAddAdditionalEansToQlsArgs): Promise<string[]>;
12
14
  pushOrderToQls(ctx: RequestContext, input: MutationPushOrderToQlsArgs): Promise<string>;
@@ -26,6 +26,12 @@ let QlsAdminResolver = class QlsAdminResolver {
26
26
  async qlsOrderIds(ctx, order) {
27
27
  return this.qlsOrderService.getQlsOrderIdsForOrder(ctx, order.id);
28
28
  }
29
+ async qlsOrderUrl(ctx, order) {
30
+ return this.qlsOrderService.getQlsOrderUrl(ctx, order.id);
31
+ }
32
+ async qlsProductUrl(ctx, productVariant) {
33
+ return this.qlsProductService.getQlsProductUrl(ctx, productVariant);
34
+ }
29
35
  async triggerQlsProductSync(ctx) {
30
36
  await this.qlsProductService.triggerFullSync(ctx);
31
37
  return true;
@@ -50,6 +56,28 @@ __decorate([
50
56
  core_1.Order]),
51
57
  __metadata("design:returntype", Promise)
52
58
  ], QlsAdminResolver.prototype, "qlsOrderIds", null);
59
+ __decorate([
60
+ (0, graphql_1.ResolveField)(),
61
+ (0, graphql_1.Resolver)('Order'),
62
+ (0, core_1.Allow)(permissions_1.qlsPushOrderPermission.Permission),
63
+ (0, core_1.Allow)(core_1.Permission.UpdateAdministrator),
64
+ __param(0, (0, core_1.Ctx)()),
65
+ __param(1, (0, graphql_1.Parent)()),
66
+ __metadata("design:type", Function),
67
+ __metadata("design:paramtypes", [core_1.RequestContext,
68
+ core_1.Order]),
69
+ __metadata("design:returntype", Promise)
70
+ ], QlsAdminResolver.prototype, "qlsOrderUrl", null);
71
+ __decorate([
72
+ (0, graphql_1.ResolveField)(),
73
+ (0, graphql_1.Resolver)('ProductVariant'),
74
+ __param(0, (0, core_1.Ctx)()),
75
+ __param(1, (0, graphql_1.Parent)()),
76
+ __metadata("design:type", Function),
77
+ __metadata("design:paramtypes", [core_1.RequestContext,
78
+ core_1.ProductVariant]),
79
+ __metadata("design:returntype", Promise)
80
+ ], QlsAdminResolver.prototype, "qlsProductUrl", null);
53
81
  __decorate([
54
82
  (0, graphql_1.Mutation)(),
55
83
  (0, core_1.Transaction)(),
@@ -36,6 +36,11 @@ export declare class QlsOrderService implements OnModuleInit, OnApplicationBoots
36
36
  * Get QLS order id(s) for a Vendure order (for Order.qlsOrderIds field).
37
37
  */
38
38
  getQlsOrderIdsForOrder(ctx: RequestContext, orderId: ID): Promise<string[]>;
39
+ /**
40
+ * Get the direct URL to the most recent QLS order for a Vendure order (for Order.qlsOrderUrl field).
41
+ * Returns the URL or null if no QLS order exists.
42
+ */
43
+ getQlsOrderUrl(ctx: RequestContext, orderId: ID): Promise<string | null>;
39
44
  getServicePoints(ctx: RequestContext, input: QlsServicePointSearchInput): Promise<QlsServicePoint[]>;
40
45
  private getVendureOrderState;
41
46
  }
@@ -281,9 +281,30 @@ let QlsOrderService = class QlsOrderService {
281
281
  .getRepository(ctx, qls_order_entity_entity_1.QlsOrderEntity)
282
282
  .find({
283
283
  where: { vendureOrderId: orderId },
284
+ order: { createdAt: 'DESC' },
284
285
  });
285
286
  return entities.map((e) => String(e.qlsOrderId));
286
287
  }
288
+ /**
289
+ * Get the direct URL to the most recent QLS order for a Vendure order (for Order.qlsOrderUrl field).
290
+ * Returns the URL or null if no QLS order exists.
291
+ */
292
+ async getQlsOrderUrl(ctx, orderId) {
293
+ const entities = await this.connection
294
+ .getRepository(ctx, qls_order_entity_entity_1.QlsOrderEntity)
295
+ .find({
296
+ where: { vendureOrderId: orderId },
297
+ order: { createdAt: 'DESC' },
298
+ });
299
+ if (entities.length === 0) {
300
+ return null;
301
+ }
302
+ const config = await Promise.resolve(this.options.getConfig(ctx));
303
+ if (!config) {
304
+ return null;
305
+ }
306
+ return `https://mijn.pakketdienstqls.nl/company/${config.companyId}/fulfillment/order/${entities[0].qlsOrderId}`;
307
+ }
287
308
  async getServicePoints(ctx, input) {
288
309
  const client = await (0, qls_client_1.getQlsClient)(ctx, this.options);
289
310
  if (!client) {
@@ -55,6 +55,11 @@ export declare class QlsProductService implements OnModuleInit, OnApplicationBoo
55
55
  * Trigger a product sync job for particular product variants
56
56
  */
57
57
  triggerSyncVariants(ctx: RequestContext, productVariantIds: ID[]): Promise<import("@vendure/core/dist/job-queue/subscribable-job").SubscribableJob<QlsProductJobData> | undefined>;
58
+ /**
59
+ * Get the direct URL to the QLS product for a Vendure product variant.
60
+ * Returns the URL or null if no QLS product exists.
61
+ */
62
+ getQlsProductUrl(ctx: RequestContext, productVariant: ProductVariant): Promise<string | null>;
58
63
  /**
59
64
  * Add additional EANs/barcodes to an existing QLS product.
60
65
  * Removal of EANs must be done in QLS itself.
@@ -269,6 +269,21 @@ let QlsProductService = class QlsProductService {
269
269
  productVariantIds,
270
270
  }, { retries: 1 });
271
271
  }
272
+ /**
273
+ * Get the direct URL to the QLS product for a Vendure product variant.
274
+ * Returns the URL or null if no QLS product exists.
275
+ */
276
+ async getQlsProductUrl(ctx, productVariant) {
277
+ const qlsProductId = productVariant.customFields?.qlsProductId;
278
+ if (!qlsProductId) {
279
+ return null;
280
+ }
281
+ const config = await Promise.resolve(this.options.getConfig(ctx));
282
+ if (!config) {
283
+ return null;
284
+ }
285
+ return `https://mijn.pakketdienstqls.nl/company/${config.companyId}/fulfillment/product/${qlsProductId}`;
286
+ }
272
287
  /**
273
288
  * Add additional EANs/barcodes to an existing QLS product.
274
289
  * Removal of EANs must be done in QLS itself.
@@ -1,8 +1,10 @@
1
1
  import {
2
2
  addActionBarDropdownMenuItem,
3
+ addActionBarItem,
3
4
  ModalService,
4
5
  } from '@vendure/admin-ui/core';
5
- import { firstValueFrom } from 'rxjs';
6
+ import { firstValueFrom, of } from 'rxjs';
7
+ import { map, catchError } from 'rxjs/operators';
6
8
  import gql from 'graphql-tag';
7
9
 
8
10
  export default [
@@ -38,6 +40,82 @@ export default [
38
40
  });
39
41
  },
40
42
  }),
43
+ // QLS order link button on order detail page
44
+ addActionBarItem({
45
+ id: 'qls-visit-order',
46
+ label: 'QLS',
47
+ locationId: 'order-detail',
48
+ buttonColor: 'primary',
49
+ buttonStyle: 'outline',
50
+ icon: 'link',
51
+ buttonState: (context) => {
52
+ return context.entity$.pipe(
53
+ map((entity) => ({
54
+ visible: !!entity?.orderPlacedAt,
55
+ disabled: false,
56
+ }))
57
+ );
58
+ },
59
+ onClick: async (event, { route, dataService, notificationService }) => {
60
+ const orderId = route.snapshot.params.id;
61
+ const res = await firstValueFrom(
62
+ dataService.query(
63
+ gql`
64
+ query Order($orderId: ID!) {
65
+ order(id: $orderId) {
66
+ id
67
+ qlsOrderUrl
68
+ }
69
+ }
70
+ `,
71
+ { orderId }
72
+ ).single$
73
+ );
74
+ const url = (res as any).order.qlsOrderUrl;
75
+ if (url) {
76
+ window.open(url, '_blank');
77
+ } else {
78
+ notificationService.notify({
79
+ message: 'No QLS order found for this order.',
80
+ type: 'error',
81
+ });
82
+ }
83
+ },
84
+ }),
85
+ // QLS product link button on product variant detail page
86
+ addActionBarItem({
87
+ id: 'qls-visit-product',
88
+ label: 'QLS',
89
+ locationId: 'product-variant-detail',
90
+ buttonColor: 'primary',
91
+ buttonStyle: 'outline',
92
+ icon: 'link',
93
+ onClick: async (event, { route, dataService, notificationService }) => {
94
+ const variantId = route.snapshot.params.id;
95
+ const res = await firstValueFrom(
96
+ dataService.query(
97
+ gql`
98
+ query ProductVariant($id: ID!) {
99
+ productVariant(id: $id) {
100
+ id
101
+ qlsProductUrl
102
+ }
103
+ }
104
+ `,
105
+ { id: variantId }
106
+ ).single$
107
+ );
108
+ const url = (res as any).productVariant.qlsProductUrl;
109
+ if (url) {
110
+ window.open(url, '_blank');
111
+ } else {
112
+ notificationService.notify({
113
+ message: 'No QLS product found for this variant.',
114
+ type: 'error',
115
+ });
116
+ }
117
+ },
118
+ }),
41
119
  // Push order to QLS button on order detail page
42
120
  addActionBarDropdownMenuItem({
43
121
  id: 'qls-fulfillment-push-order',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pinelab/vendure-plugin-qls-fulfillment",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "Vendure plugin to fulfill orders via QLS.",
5
5
  "keywords": [
6
6
  "fulfillment",