@deenruv/inpost-plugin 1.0.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.
Files changed (77) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +46 -0
  3. package/dist/plugin-server/api/inpost-admin.resolver.d.ts +20 -0
  4. package/dist/plugin-server/api/inpost-admin.resolver.js +64 -0
  5. package/dist/plugin-server/api/inpost-shop.resolver.d.ts +7 -0
  6. package/dist/plugin-server/api/inpost-shop.resolver.js +38 -0
  7. package/dist/plugin-server/constants.d.ts +2 -0
  8. package/dist/plugin-server/constants.js +5 -0
  9. package/dist/plugin-server/controllers/inpost.controller.d.ts +9 -0
  10. package/dist/plugin-server/controllers/inpost.controller.js +54 -0
  11. package/dist/plugin-server/entities/inpost-config-entity.d.ts +12 -0
  12. package/dist/plugin-server/entities/inpost-config-entity.js +49 -0
  13. package/dist/plugin-server/entities/inpost-ref-entity.d.ts +9 -0
  14. package/dist/plugin-server/entities/inpost-ref-entity.js +39 -0
  15. package/dist/plugin-server/extensions/inpost.extension.d.ts +1 -0
  16. package/dist/plugin-server/extensions/inpost.extension.js +53 -0
  17. package/dist/plugin-server/extensions/inpost.shop.extenstion.d.ts +1 -0
  18. package/dist/plugin-server/extensions/inpost.shop.extenstion.js +12 -0
  19. package/dist/plugin-server/guards/inpost-webhook.guard.d.ts +22 -0
  20. package/dist/plugin-server/guards/inpost-webhook.guard.js +96 -0
  21. package/dist/plugin-server/handlers/inpost.fulfillment.d.ts +20 -0
  22. package/dist/plugin-server/handlers/inpost.fulfillment.js +95 -0
  23. package/dist/plugin-server/index.d.ts +6 -0
  24. package/dist/plugin-server/index.js +78 -0
  25. package/dist/plugin-server/services/inpost.service.d.ts +46 -0
  26. package/dist/plugin-server/services/inpost.service.js +365 -0
  27. package/dist/plugin-server/types.d.ts +29 -0
  28. package/dist/plugin-server/types.js +2 -0
  29. package/dist/plugin-server/ui/Inpost.tsx +273 -0
  30. package/dist/plugin-server/ui/graphql/mutations.ts +14 -0
  31. package/dist/plugin-server/ui/graphql/queries.ts +7 -0
  32. package/dist/plugin-server/ui/graphql/scalars.ts +15 -0
  33. package/dist/plugin-server/ui/graphql/selectors.ts +0 -0
  34. package/dist/plugin-server/ui/providers.ts +9 -0
  35. package/dist/plugin-server/ui/routes.ts +1 -0
  36. package/dist/plugin-server/ui/styles/overwrite.css +0 -0
  37. package/dist/plugin-server/ui/translations/en.json +31 -0
  38. package/dist/plugin-server/ui/translations/pl.json +33 -0
  39. package/dist/plugin-server/ui/zeus/const.ts +4767 -0
  40. package/dist/plugin-server/ui/zeus/index.ts +21694 -0
  41. package/dist/plugin-server/ui/zeus/typedDocumentNode.ts +27 -0
  42. package/dist/plugin-server/ui.d.ts +2 -0
  43. package/dist/plugin-server/ui.js +17 -0
  44. package/dist/plugin-server/zeus/const.d.ts +6 -0
  45. package/dist/plugin-server/zeus/const.js +3654 -0
  46. package/dist/plugin-server/zeus/index.d.ts +18623 -0
  47. package/dist/plugin-server/zeus/index.js +1094 -0
  48. package/dist/plugin-server/zeus/typedDocumentNode.d.ts +3 -0
  49. package/dist/plugin-server/zeus/typedDocumentNode.js +13 -0
  50. package/dist/plugin-ui/components/Inpost.d.ts +2 -0
  51. package/dist/plugin-ui/components/Inpost.js +126 -0
  52. package/dist/plugin-ui/graphql/mutations.d.ts +12 -0
  53. package/dist/plugin-ui/graphql/mutations.js +10 -0
  54. package/dist/plugin-ui/graphql/queries.d.ts +23 -0
  55. package/dist/plugin-ui/graphql/queries.js +19 -0
  56. package/dist/plugin-ui/graphql/scalars.d.ts +16 -0
  57. package/dist/plugin-ui/graphql/scalars.js +14 -0
  58. package/dist/plugin-ui/graphql/selectors.d.ts +15 -0
  59. package/dist/plugin-ui/graphql/selectors.js +13 -0
  60. package/dist/plugin-ui/index.d.ts +1 -0
  61. package/dist/plugin-ui/index.js +11 -0
  62. package/dist/plugin-ui/locales/en/index.d.ts +35 -0
  63. package/dist/plugin-ui/locales/en/index.js +2 -0
  64. package/dist/plugin-ui/locales/en/inpost.json +34 -0
  65. package/dist/plugin-ui/locales/pl/index.d.ts +36 -0
  66. package/dist/plugin-ui/locales/pl/index.js +2 -0
  67. package/dist/plugin-ui/locales/pl/inpost.json +35 -0
  68. package/dist/plugin-ui/translation-ns.d.ts +1 -0
  69. package/dist/plugin-ui/translation-ns.js +1 -0
  70. package/dist/plugin-ui/tsconfig.json +18 -0
  71. package/dist/plugin-ui/zeus/const.d.ts +6 -0
  72. package/dist/plugin-ui/zeus/const.js +3651 -0
  73. package/dist/plugin-ui/zeus/index.d.ts +18623 -0
  74. package/dist/plugin-ui/zeus/index.js +1086 -0
  75. package/dist/plugin-ui/zeus/typedDocumentNode.d.ts +3 -0
  76. package/dist/plugin-ui/zeus/typedDocumentNode.js +9 -0
  77. package/package.json +55 -0
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.inpostFulfillmentHandler = exports.inpostFulfillmentHandlerCode = void 0;
4
+ const core_1 = require("@deenruv/core");
5
+ const inpost_service_js_1 = require("../services/inpost.service.js");
6
+ exports.inpostFulfillmentHandlerCode = "inpost-fulfillment";
7
+ /**
8
+ * The handler for Inpost shipping.
9
+ */
10
+ const inpostFulfillmentHandler = () => {
11
+ let inpostService;
12
+ return new core_1.FulfillmentHandler({
13
+ code: exports.inpostFulfillmentHandlerCode,
14
+ description: [
15
+ {
16
+ languageCode: core_1.LanguageCode.pl,
17
+ value: "Dostawa InPost",
18
+ },
19
+ {
20
+ languageCode: core_1.LanguageCode.en,
21
+ value: "InPost fulifillment",
22
+ },
23
+ ],
24
+ args: {
25
+ dimensions: {
26
+ type: "string",
27
+ ui: {
28
+ component: "select-form-input",
29
+ options: [
30
+ {
31
+ value: "small",
32
+ label: [
33
+ {
34
+ languageCode: core_1.LanguageCode.en,
35
+ value: "A",
36
+ },
37
+ {
38
+ languageCode: core_1.LanguageCode.pl,
39
+ value: "A",
40
+ },
41
+ ],
42
+ },
43
+ {
44
+ value: "medium",
45
+ label: [
46
+ {
47
+ languageCode: core_1.LanguageCode.en,
48
+ value: "B",
49
+ },
50
+ {
51
+ languageCode: core_1.LanguageCode.pl,
52
+ value: "B",
53
+ },
54
+ ],
55
+ },
56
+ {
57
+ value: "large",
58
+ label: [
59
+ {
60
+ languageCode: core_1.LanguageCode.en,
61
+ value: "C",
62
+ },
63
+ {
64
+ languageCode: core_1.LanguageCode.pl,
65
+ value: "C",
66
+ },
67
+ ],
68
+ },
69
+ {
70
+ value: "xlarge",
71
+ label: [
72
+ {
73
+ languageCode: core_1.LanguageCode.en,
74
+ value: "D",
75
+ },
76
+ {
77
+ languageCode: core_1.LanguageCode.pl,
78
+ value: "D",
79
+ },
80
+ ],
81
+ },
82
+ ],
83
+ },
84
+ },
85
+ },
86
+ init(injector) {
87
+ inpostService = injector.get(inpost_service_js_1.InpostService);
88
+ },
89
+ async createFulfillment(ctx, orders, lines, args) {
90
+ const shipment = await inpostService.createShipmentForOrders(ctx, orders, lines, args.dimensions);
91
+ return { trackingCode: `${shipment.id}` };
92
+ },
93
+ });
94
+ };
95
+ exports.inpostFulfillmentHandler = inpostFulfillmentHandler;
@@ -0,0 +1,6 @@
1
+ import { InpostPluginOptions } from "./types.js";
2
+ declare class InpostPlugin {
3
+ static options: InpostPluginOptions;
4
+ static init(options?: InpostPluginOptions): typeof InpostPlugin;
5
+ }
6
+ export { InpostPlugin };
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.InpostPlugin = void 0;
10
+ const core_1 = require("@deenruv/core");
11
+ const inpost_service_js_1 = require("./services/inpost.service.js");
12
+ const constants_js_1 = require("./constants.js");
13
+ const inpost_extension_js_1 = require("./extensions/inpost.extension.js");
14
+ const inpost_admin_resolver_js_1 = require("./api/inpost-admin.resolver.js");
15
+ const inpost_controller_js_1 = require("./controllers/inpost.controller.js");
16
+ const inpost_fulfillment_js_1 = require("./handlers/inpost.fulfillment.js");
17
+ const inpost_config_entity_js_1 = require("./entities/inpost-config-entity.js");
18
+ const inpost_ref_entity_js_1 = require("./entities/inpost-ref-entity.js");
19
+ const inpost_shop_resolver_js_1 = require("./api/inpost-shop.resolver.js");
20
+ const inpost_shop_extenstion_js_1 = require("./extensions/inpost.shop.extenstion.js");
21
+ let InpostPlugin = class InpostPlugin {
22
+ static init(options = {}) {
23
+ this.options = options;
24
+ return this;
25
+ }
26
+ };
27
+ exports.InpostPlugin = InpostPlugin;
28
+ exports.InpostPlugin = InpostPlugin = __decorate([
29
+ (0, core_1.DeenruvPlugin)({
30
+ imports: [core_1.PluginCommonModule],
31
+ compatibility: "^0.1.0",
32
+ entities: [inpost_config_entity_js_1.InpostConfigEntity, inpost_ref_entity_js_1.InpostRefEntity],
33
+ providers: [
34
+ { provide: constants_js_1.INPOST_PLUGIN_OPTIONS, useValue: InpostPlugin.options },
35
+ inpost_service_js_1.InpostService,
36
+ ],
37
+ controllers: [inpost_controller_js_1.InpostController],
38
+ configuration: (config) => {
39
+ config.shippingOptions.fulfillmentHandlers.push((0, inpost_fulfillment_js_1.inpostFulfillmentHandler)());
40
+ config.customFields.Fulfillment.push({
41
+ name: "inpostLabel",
42
+ type: "relation",
43
+ entity: core_1.Asset,
44
+ label: [
45
+ {
46
+ languageCode: core_1.LanguageCode.en,
47
+ value: "Inpost label",
48
+ },
49
+ {
50
+ languageCode: core_1.LanguageCode.pl,
51
+ value: "Etykieta inpost",
52
+ },
53
+ ],
54
+ });
55
+ const existingPickupPointField = config.customFields.Order.find((field) => field.name === "pickupPointId");
56
+ if (!existingPickupPointField) {
57
+ config.customFields.Order.push({
58
+ name: "pickupPointId",
59
+ type: "string",
60
+ nullable: true,
61
+ label: [
62
+ { languageCode: core_1.LanguageCode.en, value: "Pickup Point ID" },
63
+ { languageCode: core_1.LanguageCode.pl, value: "ID punktu odbioru" },
64
+ ],
65
+ });
66
+ }
67
+ return config;
68
+ },
69
+ adminApiExtensions: {
70
+ schema: inpost_extension_js_1.AdminExtension,
71
+ resolvers: [inpost_admin_resolver_js_1.InpostAdminResolver],
72
+ },
73
+ shopApiExtensions: {
74
+ schema: inpost_shop_extenstion_js_1.ShopExtension,
75
+ resolvers: [inpost_shop_resolver_js_1.InpostShopResolver],
76
+ },
77
+ })
78
+ ], InpostPlugin);
@@ -0,0 +1,46 @@
1
+ import { OnModuleInit } from "@nestjs/common";
2
+ import { Asset, AssetService, CustomerService, JobQueueService, Order, RequestContext, TransactionalConnection, type ID, FulfillmentService, ProcessContext } from "@deenruv/core";
3
+ import { Shipment } from "@deenruv/inpost";
4
+ import { InpostConfigEntity } from "../entities/inpost-config-entity.js";
5
+ import { InpostWebhookEvent, SetInpostShippingMethodConfigInput } from "../types.js";
6
+ declare module "@deenruv/core/dist/entity/custom-entity-fields" {
7
+ interface CustomFulfillmentFields {
8
+ inpostLabel?: Asset;
9
+ }
10
+ interface CustomOrderFields {
11
+ pickupPointId?: string;
12
+ }
13
+ }
14
+ export declare class InpostService implements OnModuleInit {
15
+ private processContext;
16
+ private connection;
17
+ private jobQueueService;
18
+ private assetService;
19
+ private customerService;
20
+ private fulfillmentService;
21
+ private orderProgressJob;
22
+ constructor(processContext: ProcessContext, connection: TransactionalConnection, jobQueueService: JobQueueService, assetService: AssetService, customerService: CustomerService, fulfillmentService: FulfillmentService);
23
+ onModuleInit(): Promise<void>;
24
+ getConfig(ctx: RequestContext): Promise<InpostConfigEntity | undefined>;
25
+ getGeowidgetKey(ctx: RequestContext): Promise<string | null>;
26
+ getInpostConfig(ctx: RequestContext): Promise<InpostConfigEntity | undefined>;
27
+ getInpostOrganizations(ctx: RequestContext, input: {
28
+ host: string;
29
+ apiKey: string;
30
+ }): Promise<{
31
+ items: {
32
+ id: number;
33
+ name: string;
34
+ services: import("@deenruv/inpost").Service[];
35
+ }[];
36
+ }>;
37
+ private buyShipment;
38
+ private purchasingShipment;
39
+ private labelShipment;
40
+ private processInpostShipment;
41
+ createShipmentForOrders(ctx: RequestContext, orders: Order[], lines: {
42
+ orderLineId: ID;
43
+ }[], size: "small" | "medium" | "large" | "xlarge"): Promise<Shipment>;
44
+ handleUpdateEvent(ctx: RequestContext, body: InpostWebhookEvent): Promise<void>;
45
+ setInpostConfig(ctx: RequestContext, { shippingMethodId, ...rest }: SetInpostShippingMethodConfigInput): Promise<void>;
46
+ }
@@ -0,0 +1,365 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __rest = (this && this.__rest) || function (s, e) {
12
+ var t = {};
13
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
14
+ t[p] = s[p];
15
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
16
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
17
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
18
+ t[p[i]] = s[p[i]];
19
+ }
20
+ return t;
21
+ };
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.InpostService = void 0;
24
+ const common_1 = require("@nestjs/common");
25
+ const core_1 = require("@deenruv/core");
26
+ const inpost_1 = require("@deenruv/inpost");
27
+ const inpost_config_entity_js_1 = require("../entities/inpost-config-entity.js");
28
+ const inpost_ref_entity_js_1 = require("../entities/inpost-ref-entity.js");
29
+ const constants_js_1 = require("../constants.js");
30
+ const node_path_1 = require("node:path");
31
+ const node_os_1 = require("node:os");
32
+ const promises_1 = require("node:fs/promises");
33
+ const fs_1 = require("fs");
34
+ const node_stream_1 = require("node:stream");
35
+ const crypto_1 = require("crypto");
36
+ let InpostService = class InpostService {
37
+ constructor(processContext, connection, jobQueueService, assetService, customerService, fulfillmentService) {
38
+ this.processContext = processContext;
39
+ this.connection = connection;
40
+ this.jobQueueService = jobQueueService;
41
+ this.assetService = assetService;
42
+ this.customerService = customerService;
43
+ this.fulfillmentService = fulfillmentService;
44
+ }
45
+ async onModuleInit() {
46
+ this.orderProgressJob =
47
+ await this.jobQueueService.createQueue({
48
+ name: "process-inpost-shipment",
49
+ process: async (job) => {
50
+ if (this.processContext.isServer)
51
+ return;
52
+ const ctx = core_1.RequestContext.deserialize(job.data.context);
53
+ await this.processInpostShipment(ctx, job.data.shipmentId, job.data.inpostConfigId, Object.assign(Object.assign({}, job.data), { progress: job.setProgress }));
54
+ },
55
+ });
56
+ }
57
+ async getConfig(ctx) {
58
+ const configs = await this.connection
59
+ .getRepository(ctx, inpost_config_entity_js_1.InpostConfigEntity)
60
+ .find({ take: 1, order: { createdAt: "DESC" } });
61
+ if (configs.length === 0) {
62
+ core_1.Logger.error(`No inpost config found, please set up inpost config first`, constants_js_1.LOGGER_CTX);
63
+ return undefined;
64
+ }
65
+ const config = configs.at(0);
66
+ if (!(config === null || config === void 0 ? void 0 : config.host) || !(config === null || config === void 0 ? void 0 : config.apiKey) || !(config === null || config === void 0 ? void 0 : config.inpostOrganization)) {
67
+ core_1.Logger.error(`Misconfigured inpost config, host, apiKey and organization id are required`, constants_js_1.LOGGER_CTX);
68
+ return undefined;
69
+ }
70
+ return config;
71
+ }
72
+ async getGeowidgetKey(ctx) {
73
+ const config = await this.getConfig(ctx);
74
+ if (!(config === null || config === void 0 ? void 0 : config.host) || !(config === null || config === void 0 ? void 0 : config.apiKey) || !(config === null || config === void 0 ? void 0 : config.inpostOrganization)) {
75
+ core_1.Logger.error(`Misconfigured inpost config, host, apiKey and organization id are required`, constants_js_1.LOGGER_CTX);
76
+ return null;
77
+ }
78
+ return config.geowidgetKey;
79
+ }
80
+ async getInpostConfig(ctx) {
81
+ return this.getConfig(ctx);
82
+ }
83
+ async getInpostOrganizations(ctx, input) {
84
+ const client = new inpost_1.Client(input);
85
+ const organizations = await client.organizations().list();
86
+ return {
87
+ items: organizations.items.map((org) => ({
88
+ id: org.id,
89
+ name: org.name,
90
+ services: org.services,
91
+ })),
92
+ };
93
+ }
94
+ async buyShipment(ctx, shipment, config, client) {
95
+ var _a;
96
+ if (!shipment.status || shipment.status === "created") {
97
+ // repeat buyShipment function after 1 second
98
+ await this.orderProgressJob.add({
99
+ context: ctx.serialize(),
100
+ inpostConfigId: config.id,
101
+ nextStep: "buy",
102
+ shipmentId: shipment.id || 0,
103
+ delay: 1000,
104
+ });
105
+ return;
106
+ }
107
+ await client
108
+ .shipments()
109
+ .get(shipment.id || 0)
110
+ .buy({ offer_id: ((_a = shipment.offers) === null || _a === void 0 ? void 0 : _a[0].id) || 0 });
111
+ await this.orderProgressJob.add({
112
+ context: ctx.serialize(),
113
+ inpostConfigId: config.id,
114
+ nextStep: "purchasing",
115
+ shipmentId: shipment.id || 0,
116
+ delay: 1000,
117
+ });
118
+ }
119
+ async purchasingShipment(ctx, shipment, config, client) {
120
+ var _a, _b;
121
+ const response = await client
122
+ .shipments()
123
+ .get(shipment.id || 0)
124
+ .fetch();
125
+ const found = (_a = response.transactions) === null || _a === void 0 ? void 0 : _a.find((t) => t.status === "success");
126
+ if (found) {
127
+ // shipment purchased, generate label
128
+ await this.orderProgressJob.add({
129
+ context: ctx.serialize(),
130
+ inpostConfigId: config.id,
131
+ nextStep: "label",
132
+ shipmentId: shipment.id || 0,
133
+ delay: 1000,
134
+ });
135
+ return;
136
+ }
137
+ const failure = (_b = response.transactions) === null || _b === void 0 ? void 0 : _b.find((t) => { var _a; return t.status === "failure" && t.offer_id === ((_a = response.selected_offer) === null || _a === void 0 ? void 0 : _a.id); });
138
+ if (failure) {
139
+ // repeat buyShipment because payment failed
140
+ await this.orderProgressJob.add({
141
+ context: ctx.serialize(),
142
+ inpostConfigId: config.id,
143
+ nextStep: "buy",
144
+ shipmentId: shipment.id || 0,
145
+ delay: 1000,
146
+ });
147
+ return;
148
+ }
149
+ await this.orderProgressJob.add({
150
+ context: ctx.serialize(),
151
+ inpostConfigId: config.id,
152
+ nextStep: "purchasing",
153
+ shipmentId: shipment.id || 0,
154
+ delay: 1000,
155
+ });
156
+ }
157
+ async labelShipment(ctx, shipment, config, client) {
158
+ if (!shipment.status ||
159
+ shipment.status === "created" ||
160
+ shipment.status === "offer_selected") {
161
+ await this.orderProgressJob.add({
162
+ context: ctx.serialize(),
163
+ inpostConfigId: config.id,
164
+ nextStep: "label",
165
+ shipmentId: shipment.id || 0,
166
+ delay: 1000,
167
+ });
168
+ return;
169
+ }
170
+ const label = await client
171
+ .shipments()
172
+ .get(shipment.id || 0)
173
+ .label();
174
+ const tmp = await (0, promises_1.mkdtemp)((0, node_path_1.join)((0, node_os_1.tmpdir)(), "label-gen"));
175
+ const labelFile = (0, node_path_1.join)(tmp, `${(0, crypto_1.randomBytes)(24).toString("hex")}.pdf`);
176
+ await (label === null || label === void 0 ? void 0 : label.pipeTo(node_stream_1.Writable.toWeb((0, fs_1.createWriteStream)(labelFile))));
177
+ const asset = await this.assetService.createFromFileStream((0, fs_1.createReadStream)(labelFile), ctx);
178
+ if (asset instanceof core_1.Asset) {
179
+ await this.connection.getRepository(ctx, core_1.Fulfillment).update({ trackingCode: `${shipment.id}` }, {
180
+ customFields: {
181
+ inpostLabel: asset,
182
+ },
183
+ });
184
+ }
185
+ await (0, promises_1.rm)(tmp, { force: true, recursive: true });
186
+ }
187
+ async processInpostShipment(ctx, shipmentId, inpostConfigId, { delay, nextStep, }) {
188
+ if (delay)
189
+ await new Promise((resolve) => setTimeout(resolve, delay));
190
+ const config = await this.connection
191
+ .getRepository(ctx, inpost_config_entity_js_1.InpostConfigEntity)
192
+ .findOneOrFail({ where: { id: inpostConfigId } });
193
+ const client = new inpost_1.Client({ host: config.host, apiKey: config.apiKey });
194
+ const shipment = await client.shipments().get(shipmentId).fetch();
195
+ switch (nextStep) {
196
+ case "buy":
197
+ await this.buyShipment(ctx, shipment, config, client);
198
+ break;
199
+ case "purchasing":
200
+ await this.purchasingShipment(ctx, shipment, config, client);
201
+ break;
202
+ case "label":
203
+ await this.labelShipment(ctx, shipment, config, client);
204
+ break;
205
+ }
206
+ }
207
+ async createShipmentForOrders(ctx, orders, lines, size) {
208
+ var _a, _b, _c, _d;
209
+ const targetPoint = orders[0].customFields.pickupPointId;
210
+ if (!targetPoint) {
211
+ core_1.Logger.error(`Order ${orders[0].id} is missing pickup point id`, constants_js_1.LOGGER_CTX);
212
+ throw new Error("Missing pickup point ID");
213
+ }
214
+ const shippingLines = (await Promise.all(orders.map(async (o) => this.connection
215
+ .getRepository(ctx, core_1.ShippingLine)
216
+ .find({ where: { order: { id: o.id } } })))).flat();
217
+ const shippingMethodId = (_a = shippingLines[0]) === null || _a === void 0 ? void 0 : _a.shippingMethodId;
218
+ if (!shippingMethodId ||
219
+ shippingLines.find((el) => el.shippingMethodId !== shippingMethodId)) {
220
+ core_1.Logger.error(`Mismatch on shipping method, multiplie shipping methods for fulfillment not supported`, constants_js_1.LOGGER_CTX);
221
+ throw new Error("all orders must use same shipping method to dispatch create inpost fulfillment");
222
+ }
223
+ const config = await this.connection
224
+ .getRepository(ctx, inpost_config_entity_js_1.InpostConfigEntity)
225
+ .findOne({
226
+ where: {
227
+ shippingMethod: { id: shippingMethodId },
228
+ },
229
+ });
230
+ if (!(config === null || config === void 0 ? void 0 : config.host) ||
231
+ !(config === null || config === void 0 ? void 0 : config.apiKey) ||
232
+ !(config === null || config === void 0 ? void 0 : config.service) ||
233
+ !(config === null || config === void 0 ? void 0 : config.inpostOrganization)) {
234
+ core_1.Logger.error(`Misconfigured inpost config for shipping method ${shippingMethodId}`, constants_js_1.LOGGER_CTX);
235
+ throw new Error("misconfigured inpost shipping method, host, apiKey, service and organization id are required");
236
+ }
237
+ const { shippingAddress, billingAddress } = orders[0];
238
+ const customerId = orders[0].customerId;
239
+ if (!customerId) {
240
+ core_1.Logger.error(`Order ${orders[0].id} customer is missing id`, constants_js_1.LOGGER_CTX);
241
+ throw new Error("missing cutomser id");
242
+ }
243
+ const customer = ((_b = orders[0]) === null || _b === void 0 ? void 0 : _b.customer) ||
244
+ (await this.customerService.findOne(ctx, customerId));
245
+ if (!customer) {
246
+ core_1.Logger.error(`Could not find customer for order ${orders[0].id}`, constants_js_1.LOGGER_CTX);
247
+ throw new Error("missing customer");
248
+ }
249
+ const address = shippingAddress || billingAddress;
250
+ const client = new inpost_1.Client({ host: config.host, apiKey: config.apiKey });
251
+ const refRepo = this.connection.getRepository(ctx, inpost_ref_entity_js_1.InpostRefEntity);
252
+ const ref = await refRepo.insert({
253
+ orderLines: lines.map(({ orderLineId: id }) => new core_1.OrderLine({ id })),
254
+ inpostConfig: config,
255
+ });
256
+ const phone = (shippingAddress === null || shippingAddress === void 0 ? void 0 : shippingAddress.phoneNumber) ||
257
+ (billingAddress === null || billingAddress === void 0 ? void 0 : billingAddress.phoneNumber) ||
258
+ (customer === null || customer === void 0 ? void 0 : customer.phoneNumber);
259
+ if (!phone) {
260
+ core_1.Logger.error(`Could not find customer phone number for order ${orders[0].id}`, constants_js_1.LOGGER_CTX);
261
+ throw new Error("phone number is required");
262
+ }
263
+ const email = customer.emailAddress;
264
+ if (!email) {
265
+ core_1.Logger.error(`Could not find customer email for order ${orders[0].id}`, constants_js_1.LOGGER_CTX);
266
+ throw new Error("email is required");
267
+ }
268
+ const shipment = await client
269
+ .organizations()
270
+ .get(config.inpostOrganization)
271
+ .shipments()
272
+ .create({
273
+ receiver: {
274
+ first_name: (_c = address.fullName) === null || _c === void 0 ? void 0 : _c.split(" ")[0],
275
+ last_name: (_d = address.fullName) === null || _d === void 0 ? void 0 : _d.split(" ").at(-1),
276
+ company_name: address.company,
277
+ email,
278
+ phone,
279
+ address: {
280
+ line1: address.streetLine1 || "",
281
+ line2: address.streetLine1 || "",
282
+ city: address.city || "",
283
+ country_code: address.countryCode ||
284
+ "PL" /* CountryCode.pl */,
285
+ post_code: address.postalCode || "",
286
+ },
287
+ },
288
+ parcels: [{ template: size }],
289
+ service: config.service,
290
+ custom_attributes: { target_point: targetPoint },
291
+ reference: `INP${ref.identifiers[0]["id"]}`,
292
+ });
293
+ await refRepo.update(ref.identifiers[0], { inpostShipmentId: shipment.id });
294
+ await this.orderProgressJob.add({
295
+ context: ctx.serialize(),
296
+ inpostConfigId: config.id,
297
+ nextStep: "buy",
298
+ shipmentId: shipment.id || 0,
299
+ delay: 300,
300
+ }, { retries: 3 });
301
+ return shipment;
302
+ }
303
+ async handleUpdateEvent(ctx, body) {
304
+ if (!body ||
305
+ !body.payload ||
306
+ !("status" in body.payload) ||
307
+ !body.payload.status ||
308
+ !body.payload.shipment_id) {
309
+ core_1.Logger.error(`Invalid inpost webhook event received: ${JSON.stringify(body)}`, constants_js_1.LOGGER_CTX);
310
+ return;
311
+ }
312
+ const shipment = await this.connection
313
+ .getRepository(ctx, inpost_ref_entity_js_1.InpostRefEntity)
314
+ .findOne({
315
+ where: { inpostShipmentId: body.payload.shipment_id },
316
+ relations: ["inpostConfig", "orderLines"],
317
+ });
318
+ if (!shipment) {
319
+ core_1.Logger.error(`Could not find inpost shipment with id ${body.payload.shipment_id}`, constants_js_1.LOGGER_CTX);
320
+ return;
321
+ }
322
+ const fulfillment = await this.connection
323
+ .getRepository(ctx, core_1.Fulfillment)
324
+ .findOne({ where: { trackingCode: `${shipment.inpostShipmentId}` } });
325
+ if (!fulfillment) {
326
+ core_1.Logger.error(`Could not find fulfillment with tracking code ${shipment.inpostShipmentId}`, constants_js_1.LOGGER_CTX);
327
+ return;
328
+ }
329
+ switch (body.payload.status) {
330
+ case "delivered":
331
+ await this.fulfillmentService.transitionToState(ctx, fulfillment === null || fulfillment === void 0 ? void 0 : fulfillment.id, "Delivered");
332
+ break;
333
+ case "taken_by_courier":
334
+ case "taken_by_courier_from_pok":
335
+ await this.fulfillmentService.transitionToState(ctx, fulfillment === null || fulfillment === void 0 ? void 0 : fulfillment.id, "Shipped");
336
+ break;
337
+ case "canceled":
338
+ await this.fulfillmentService.transitionToState(ctx, fulfillment === null || fulfillment === void 0 ? void 0 : fulfillment.id, "Cancelled");
339
+ break;
340
+ }
341
+ }
342
+ async setInpostConfig(ctx, _a) {
343
+ var { shippingMethodId } = _a, rest = __rest(_a, ["shippingMethodId"]);
344
+ const existingConfig = await this.connection
345
+ .getRepository(ctx, inpost_config_entity_js_1.InpostConfigEntity)
346
+ .findOne({ where: { shippingMethod: { id: shippingMethodId } } });
347
+ if (existingConfig) {
348
+ await this.connection
349
+ .getRepository(ctx, inpost_config_entity_js_1.InpostConfigEntity)
350
+ .update({ id: existingConfig.id }, Object.assign(Object.assign({}, rest), { shippingMethod: { id: shippingMethodId } }));
351
+ return;
352
+ }
353
+ await this.connection.getRepository(ctx, inpost_config_entity_js_1.InpostConfigEntity).insert(new inpost_config_entity_js_1.InpostConfigEntity(Object.assign(Object.assign({}, rest), { shippingMethod: { id: shippingMethodId } })));
354
+ }
355
+ };
356
+ exports.InpostService = InpostService;
357
+ exports.InpostService = InpostService = __decorate([
358
+ (0, common_1.Injectable)(),
359
+ __metadata("design:paramtypes", [core_1.ProcessContext,
360
+ core_1.TransactionalConnection,
361
+ core_1.JobQueueService,
362
+ core_1.AssetService,
363
+ core_1.CustomerService,
364
+ core_1.FulfillmentService])
365
+ ], InpostService);
@@ -0,0 +1,29 @@
1
+ import { SerializedRequestContext, type ID } from "@deenruv/core";
2
+ import { Service } from "@deenruv/inpost";
3
+ export type InpostPluginOptions = object;
4
+ export interface SetInpostShippingMethodConfigInput {
5
+ shippingMethodId: ID;
6
+ host: string;
7
+ apiKey: string;
8
+ geowidgetKey?: string;
9
+ inpostOrganization: number;
10
+ service: Service;
11
+ }
12
+ export type OrderProgressStep = "buy" | "purchasing" | "label";
13
+ export interface OrderProgressJob {
14
+ context: SerializedRequestContext;
15
+ inpostConfigId: ID;
16
+ shipmentId: number;
17
+ nextStep: OrderProgressStep;
18
+ delay?: number;
19
+ }
20
+ export type InpostWebhookEvent = {
21
+ event_ts: string;
22
+ event: string;
23
+ organization_id: number;
24
+ payload: {
25
+ shipment_id: number;
26
+ tracking_number?: string;
27
+ status?: "delivered" | "taken_by_courier" | "taken_by_courier_from_pok" | "canceled";
28
+ };
29
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });