@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.
- package/LICENSE +23 -0
- package/README.md +46 -0
- package/dist/plugin-server/api/inpost-admin.resolver.d.ts +20 -0
- package/dist/plugin-server/api/inpost-admin.resolver.js +64 -0
- package/dist/plugin-server/api/inpost-shop.resolver.d.ts +7 -0
- package/dist/plugin-server/api/inpost-shop.resolver.js +38 -0
- package/dist/plugin-server/constants.d.ts +2 -0
- package/dist/plugin-server/constants.js +5 -0
- package/dist/plugin-server/controllers/inpost.controller.d.ts +9 -0
- package/dist/plugin-server/controllers/inpost.controller.js +54 -0
- package/dist/plugin-server/entities/inpost-config-entity.d.ts +12 -0
- package/dist/plugin-server/entities/inpost-config-entity.js +49 -0
- package/dist/plugin-server/entities/inpost-ref-entity.d.ts +9 -0
- package/dist/plugin-server/entities/inpost-ref-entity.js +39 -0
- package/dist/plugin-server/extensions/inpost.extension.d.ts +1 -0
- package/dist/plugin-server/extensions/inpost.extension.js +53 -0
- package/dist/plugin-server/extensions/inpost.shop.extenstion.d.ts +1 -0
- package/dist/plugin-server/extensions/inpost.shop.extenstion.js +12 -0
- package/dist/plugin-server/guards/inpost-webhook.guard.d.ts +22 -0
- package/dist/plugin-server/guards/inpost-webhook.guard.js +96 -0
- package/dist/plugin-server/handlers/inpost.fulfillment.d.ts +20 -0
- package/dist/plugin-server/handlers/inpost.fulfillment.js +95 -0
- package/dist/plugin-server/index.d.ts +6 -0
- package/dist/plugin-server/index.js +78 -0
- package/dist/plugin-server/services/inpost.service.d.ts +46 -0
- package/dist/plugin-server/services/inpost.service.js +365 -0
- package/dist/plugin-server/types.d.ts +29 -0
- package/dist/plugin-server/types.js +2 -0
- package/dist/plugin-server/ui/Inpost.tsx +273 -0
- package/dist/plugin-server/ui/graphql/mutations.ts +14 -0
- package/dist/plugin-server/ui/graphql/queries.ts +7 -0
- package/dist/plugin-server/ui/graphql/scalars.ts +15 -0
- package/dist/plugin-server/ui/graphql/selectors.ts +0 -0
- package/dist/plugin-server/ui/providers.ts +9 -0
- package/dist/plugin-server/ui/routes.ts +1 -0
- package/dist/plugin-server/ui/styles/overwrite.css +0 -0
- package/dist/plugin-server/ui/translations/en.json +31 -0
- package/dist/plugin-server/ui/translations/pl.json +33 -0
- package/dist/plugin-server/ui/zeus/const.ts +4767 -0
- package/dist/plugin-server/ui/zeus/index.ts +21694 -0
- package/dist/plugin-server/ui/zeus/typedDocumentNode.ts +27 -0
- package/dist/plugin-server/ui.d.ts +2 -0
- package/dist/plugin-server/ui.js +17 -0
- package/dist/plugin-server/zeus/const.d.ts +6 -0
- package/dist/plugin-server/zeus/const.js +3654 -0
- package/dist/plugin-server/zeus/index.d.ts +18623 -0
- package/dist/plugin-server/zeus/index.js +1094 -0
- package/dist/plugin-server/zeus/typedDocumentNode.d.ts +3 -0
- package/dist/plugin-server/zeus/typedDocumentNode.js +13 -0
- package/dist/plugin-ui/components/Inpost.d.ts +2 -0
- package/dist/plugin-ui/components/Inpost.js +126 -0
- package/dist/plugin-ui/graphql/mutations.d.ts +12 -0
- package/dist/plugin-ui/graphql/mutations.js +10 -0
- package/dist/plugin-ui/graphql/queries.d.ts +23 -0
- package/dist/plugin-ui/graphql/queries.js +19 -0
- package/dist/plugin-ui/graphql/scalars.d.ts +16 -0
- package/dist/plugin-ui/graphql/scalars.js +14 -0
- package/dist/plugin-ui/graphql/selectors.d.ts +15 -0
- package/dist/plugin-ui/graphql/selectors.js +13 -0
- package/dist/plugin-ui/index.d.ts +1 -0
- package/dist/plugin-ui/index.js +11 -0
- package/dist/plugin-ui/locales/en/index.d.ts +35 -0
- package/dist/plugin-ui/locales/en/index.js +2 -0
- package/dist/plugin-ui/locales/en/inpost.json +34 -0
- package/dist/plugin-ui/locales/pl/index.d.ts +36 -0
- package/dist/plugin-ui/locales/pl/index.js +2 -0
- package/dist/plugin-ui/locales/pl/inpost.json +35 -0
- package/dist/plugin-ui/translation-ns.d.ts +1 -0
- package/dist/plugin-ui/translation-ns.js +1 -0
- package/dist/plugin-ui/tsconfig.json +18 -0
- package/dist/plugin-ui/zeus/const.d.ts +6 -0
- package/dist/plugin-ui/zeus/const.js +3651 -0
- package/dist/plugin-ui/zeus/index.d.ts +18623 -0
- package/dist/plugin-ui/zeus/index.js +1086 -0
- package/dist/plugin-ui/zeus/typedDocumentNode.d.ts +3 -0
- package/dist/plugin-ui/zeus/typedDocumentNode.js +9 -0
- 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,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
|
+
};
|