@pinelab/vendure-plugin-sendcloud 0.0.3
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/README.md +87 -0
- package/dist/util/src/index.d.ts +1 -0
- package/dist/util/src/index.js +17 -0
- package/dist/util/src/order-state-util.d.ts +19 -0
- package/dist/util/src/order-state-util.js +62 -0
- package/dist/util/src/raw-body.d.ts +6 -0
- package/dist/util/src/raw-body.js +26 -0
- package/dist/vendure-plugin-sendcloud/src/api/additional-parcel-input-items.d.ts +10 -0
- package/dist/vendure-plugin-sendcloud/src/api/additional-parcel-input-items.js +47 -0
- package/dist/vendure-plugin-sendcloud/src/api/constants.d.ts +2 -0
- package/dist/vendure-plugin-sendcloud/src/api/constants.js +5 -0
- package/dist/vendure-plugin-sendcloud/src/api/sendcloud-config.entity.d.ts +8 -0
- package/dist/vendure-plugin-sendcloud/src/api/sendcloud-config.entity.js +40 -0
- package/dist/vendure-plugin-sendcloud/src/api/sendcloud.adapter.d.ts +11 -0
- package/dist/vendure-plugin-sendcloud/src/api/sendcloud.adapter.js +62 -0
- package/dist/vendure-plugin-sendcloud/src/api/sendcloud.client.d.ts +18 -0
- package/dist/vendure-plugin-sendcloud/src/api/sendcloud.client.js +59 -0
- package/dist/vendure-plugin-sendcloud/src/api/sendcloud.controller.d.ts +8 -0
- package/dist/vendure-plugin-sendcloud/src/api/sendcloud.controller.js +65 -0
- package/dist/vendure-plugin-sendcloud/src/api/sendcloud.handler.d.ts +7 -0
- package/dist/vendure-plugin-sendcloud/src/api/sendcloud.handler.js +28 -0
- package/dist/vendure-plugin-sendcloud/src/api/sendcloud.resolver.d.ts +16 -0
- package/dist/vendure-plugin-sendcloud/src/api/sendcloud.resolver.js +75 -0
- package/dist/vendure-plugin-sendcloud/src/api/sendcloud.service.d.ts +48 -0
- package/dist/vendure-plugin-sendcloud/src/api/sendcloud.service.js +245 -0
- package/dist/vendure-plugin-sendcloud/src/api/types/sendcloud-api.types.d.ts +82 -0
- package/dist/vendure-plugin-sendcloud/src/api/types/sendcloud-api.types.js +2 -0
- package/dist/vendure-plugin-sendcloud/src/api/types/sendcloud.types.d.ts +41 -0
- package/dist/vendure-plugin-sendcloud/src/api/types/sendcloud.types.js +157 -0
- package/dist/vendure-plugin-sendcloud/src/index.d.ts +5 -0
- package/dist/vendure-plugin-sendcloud/src/index.js +21 -0
- package/dist/vendure-plugin-sendcloud/src/sendcloud.plugin.d.ts +7 -0
- package/dist/vendure-plugin-sendcloud/src/sendcloud.plugin.js +94 -0
- package/dist/vendure-plugin-sendcloud/src/ui/history-entry.component.ts +69 -0
- package/dist/vendure-plugin-sendcloud/src/ui/queries.ts +23 -0
- package/dist/vendure-plugin-sendcloud/src/ui/sendcloud-nav.module.ts +29 -0
- package/dist/vendure-plugin-sendcloud/src/ui/sendcloud.component.ts +112 -0
- package/dist/vendure-plugin-sendcloud/src/ui/sendcloud.module.ts +21 -0
- package/package.json +40 -0
|
@@ -0,0 +1,75 @@
|
|
|
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 __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.SendcloudResolver = exports.sendcloudPermission = void 0;
|
|
16
|
+
const graphql_1 = require("@nestjs/graphql");
|
|
17
|
+
const core_1 = require("@vendure/core");
|
|
18
|
+
const sendcloud_service_1 = require("./sendcloud.service");
|
|
19
|
+
exports.sendcloudPermission = new core_1.PermissionDefinition({
|
|
20
|
+
name: 'SetSendCloudConfig',
|
|
21
|
+
description: 'Allows setting SendCloud configuration',
|
|
22
|
+
});
|
|
23
|
+
let SendcloudResolver = class SendcloudResolver {
|
|
24
|
+
constructor(service, orderService) {
|
|
25
|
+
this.service = service;
|
|
26
|
+
this.orderService = orderService;
|
|
27
|
+
}
|
|
28
|
+
async sendToSendCloud(ctx, orderId) {
|
|
29
|
+
const order = await this.orderService.findOne(ctx, orderId);
|
|
30
|
+
if (!order) {
|
|
31
|
+
throw new Error(`No order with id ${orderId} exists`);
|
|
32
|
+
}
|
|
33
|
+
core_1.Logger.info(`Sync to Sendcloud mutation called by user ${ctx.activeUserId} for order ${orderId}`);
|
|
34
|
+
await this.service.createOrderInSendcloud(ctx, order);
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
async sendCloudConfig(ctx) {
|
|
38
|
+
return this.service.getConfig(ctx);
|
|
39
|
+
}
|
|
40
|
+
async updateSendCloudConfig(ctx, input) {
|
|
41
|
+
return this.service.upsertConfig(ctx, input);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
__decorate([
|
|
45
|
+
(0, graphql_1.Mutation)(),
|
|
46
|
+
(0, core_1.Allow)(core_1.Permission.UpdateOrder),
|
|
47
|
+
__param(0, (0, core_1.Ctx)()),
|
|
48
|
+
__param(1, (0, graphql_1.Args)('orderId')),
|
|
49
|
+
__metadata("design:type", Function),
|
|
50
|
+
__metadata("design:paramtypes", [core_1.RequestContext, String]),
|
|
51
|
+
__metadata("design:returntype", Promise)
|
|
52
|
+
], SendcloudResolver.prototype, "sendToSendCloud", null);
|
|
53
|
+
__decorate([
|
|
54
|
+
(0, graphql_1.Query)(),
|
|
55
|
+
(0, core_1.Allow)(exports.sendcloudPermission.Permission),
|
|
56
|
+
__param(0, (0, core_1.Ctx)()),
|
|
57
|
+
__metadata("design:type", Function),
|
|
58
|
+
__metadata("design:paramtypes", [core_1.RequestContext]),
|
|
59
|
+
__metadata("design:returntype", Promise)
|
|
60
|
+
], SendcloudResolver.prototype, "sendCloudConfig", null);
|
|
61
|
+
__decorate([
|
|
62
|
+
(0, graphql_1.Mutation)(),
|
|
63
|
+
(0, core_1.Allow)(exports.sendcloudPermission.Permission),
|
|
64
|
+
__param(0, (0, core_1.Ctx)()),
|
|
65
|
+
__param(1, (0, graphql_1.Args)('input')),
|
|
66
|
+
__metadata("design:type", Function),
|
|
67
|
+
__metadata("design:paramtypes", [core_1.RequestContext, Object]),
|
|
68
|
+
__metadata("design:returntype", Promise)
|
|
69
|
+
], SendcloudResolver.prototype, "updateSendCloudConfig", null);
|
|
70
|
+
SendcloudResolver = __decorate([
|
|
71
|
+
(0, graphql_1.Resolver)(),
|
|
72
|
+
__metadata("design:paramtypes", [sendcloud_service_1.SendcloudService,
|
|
73
|
+
core_1.OrderService])
|
|
74
|
+
], SendcloudResolver);
|
|
75
|
+
exports.SendcloudResolver = SendcloudResolver;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { OnApplicationBootstrap, OnModuleInit } from '@nestjs/common';
|
|
2
|
+
import { ModuleRef } from '@nestjs/core';
|
|
3
|
+
import { ChannelService, EntityHydrator, EventBus, HistoryService, ID, JobQueueService, Order, OrderService, RequestContext, TransactionalConnection } from '@vendure/core';
|
|
4
|
+
import { SendcloudConfigEntity } from './sendcloud-config.entity';
|
|
5
|
+
import { SendcloudClient } from './sendcloud.client';
|
|
6
|
+
import { Parcel } from './types/sendcloud-api.types';
|
|
7
|
+
import { SendcloudParcelStatus, SendcloudPluginOptions } from './types/sendcloud.types';
|
|
8
|
+
export declare class SendcloudService implements OnApplicationBootstrap, OnModuleInit {
|
|
9
|
+
private eventBus;
|
|
10
|
+
private connection;
|
|
11
|
+
private orderService;
|
|
12
|
+
private channelService;
|
|
13
|
+
private jobQueueService;
|
|
14
|
+
private moduleRef;
|
|
15
|
+
private options;
|
|
16
|
+
private entityHydrator;
|
|
17
|
+
private historyService;
|
|
18
|
+
private jobQueue;
|
|
19
|
+
constructor(eventBus: EventBus, connection: TransactionalConnection, orderService: OrderService, channelService: ChannelService, jobQueueService: JobQueueService, moduleRef: ModuleRef, options: SendcloudPluginOptions, entityHydrator: EntityHydrator, historyService: HistoryService);
|
|
20
|
+
onModuleInit(): Promise<void>;
|
|
21
|
+
onApplicationBootstrap(): void;
|
|
22
|
+
createOrderInSendcloud(userCtx: RequestContext, order: Order): Promise<Parcel | undefined>;
|
|
23
|
+
/**
|
|
24
|
+
* Update order by given orderCode, returns undefined if no action was taken
|
|
25
|
+
* Returns order if transition was successful
|
|
26
|
+
*/
|
|
27
|
+
updateOrderStatus(ctx: RequestContext, sendcloudStatus: SendcloudParcelStatus, orderCode: string, trackingNumber: string): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Fulfill and ship all items
|
|
30
|
+
*/
|
|
31
|
+
shipAll(ctx: RequestContext, order: Order, trackingNumber: string): Promise<void>;
|
|
32
|
+
upsertConfig(ctx: RequestContext, config: {
|
|
33
|
+
secret: string;
|
|
34
|
+
publicKey: string;
|
|
35
|
+
defaultPhoneNr: string;
|
|
36
|
+
}): Promise<SendcloudConfigEntity>;
|
|
37
|
+
getConfig(ctx: RequestContext): Promise<SendcloudConfigEntity | null>;
|
|
38
|
+
getClient(ctx: RequestContext): Promise<{
|
|
39
|
+
client: SendcloudClient;
|
|
40
|
+
defaultPhoneNr?: string;
|
|
41
|
+
}>;
|
|
42
|
+
createContext(channelToken: string): Promise<RequestContext>;
|
|
43
|
+
/**
|
|
44
|
+
* Sync order to Sendcloud platform
|
|
45
|
+
*/
|
|
46
|
+
private syncOrder;
|
|
47
|
+
logHistoryEntry(ctx: RequestContext, orderId: ID, error?: unknown): Promise<void>;
|
|
48
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
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 __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.SendcloudService = void 0;
|
|
16
|
+
const common_1 = require("@nestjs/common");
|
|
17
|
+
const core_1 = require("@nestjs/core");
|
|
18
|
+
const core_2 = require("@vendure/core");
|
|
19
|
+
const sendcloud_adapter_1 = require("./sendcloud.adapter");
|
|
20
|
+
const constants_1 = require("./constants");
|
|
21
|
+
const sendcloud_config_entity_1 = require("./sendcloud-config.entity");
|
|
22
|
+
const sendcloud_client_1 = require("./sendcloud.client");
|
|
23
|
+
const sendcloud_handler_1 = require("./sendcloud.handler");
|
|
24
|
+
const src_1 = require("../../../util/src");
|
|
25
|
+
let SendcloudService = class SendcloudService {
|
|
26
|
+
constructor(eventBus, connection,
|
|
27
|
+
// private rawConnection: Connection,
|
|
28
|
+
orderService, channelService, jobQueueService, moduleRef, options, entityHydrator, historyService) {
|
|
29
|
+
this.eventBus = eventBus;
|
|
30
|
+
this.connection = connection;
|
|
31
|
+
this.orderService = orderService;
|
|
32
|
+
this.channelService = channelService;
|
|
33
|
+
this.jobQueueService = jobQueueService;
|
|
34
|
+
this.moduleRef = moduleRef;
|
|
35
|
+
this.options = options;
|
|
36
|
+
this.entityHydrator = entityHydrator;
|
|
37
|
+
this.historyService = historyService;
|
|
38
|
+
}
|
|
39
|
+
async onModuleInit() {
|
|
40
|
+
this.jobQueue = await this.jobQueueService.createQueue({
|
|
41
|
+
name: 'sendcloud',
|
|
42
|
+
process: async ({ data }) => {
|
|
43
|
+
const ctx = core_2.RequestContext.deserialize(data.ctx);
|
|
44
|
+
try {
|
|
45
|
+
await this.syncOrder(ctx, data.orderCode);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
core_2.Logger.warn(`Failed to sync order ${data.orderCode} for channel ${ctx.channel.token}: ${error}`, constants_1.loggerCtx);
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
onApplicationBootstrap() {
|
|
55
|
+
// Listen for Settled orders to sync to sendcloud
|
|
56
|
+
this.eventBus.ofType(core_2.OrderPlacedEvent).subscribe(async (event) => {
|
|
57
|
+
await this.jobQueue.add({
|
|
58
|
+
orderCode: event.order.code,
|
|
59
|
+
ctx: event.ctx.serialize(),
|
|
60
|
+
}, { retries: 20 });
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
async createOrderInSendcloud(userCtx, order) {
|
|
64
|
+
if (this.options.disabled) {
|
|
65
|
+
core_2.Logger.info(`Plugin is disabled, not syncing order ${order.code}`, constants_1.loggerCtx);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const ctx = await this.createContext(userCtx.channel.token); // Recreate a ctx with the channel's default language
|
|
69
|
+
try {
|
|
70
|
+
await this.entityHydrator.hydrate(ctx, order, {
|
|
71
|
+
relations: [
|
|
72
|
+
'customer',
|
|
73
|
+
'lines.productVariant.product',
|
|
74
|
+
'shippingLines.shippingMethod',
|
|
75
|
+
],
|
|
76
|
+
});
|
|
77
|
+
const additionalParcelItems = [];
|
|
78
|
+
if (this.options.additionalParcelItemsFn) {
|
|
79
|
+
additionalParcelItems.push(...(await this.options.additionalParcelItemsFn(ctx, new core_2.Injector(this.moduleRef), order)));
|
|
80
|
+
}
|
|
81
|
+
const { client, defaultPhoneNr } = await this.getClient(ctx);
|
|
82
|
+
const parcelInput = (0, sendcloud_adapter_1.toParcelInput)(order, this.options, defaultPhoneNr);
|
|
83
|
+
parcelInput.parcel_items.unshift(...additionalParcelItems);
|
|
84
|
+
const parcel = await client.createParcel(parcelInput);
|
|
85
|
+
await this.logHistoryEntry(ctx, order.id);
|
|
86
|
+
return parcel;
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
await this.logHistoryEntry(ctx, order.id, err);
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Update order by given orderCode, returns undefined if no action was taken
|
|
95
|
+
* Returns order if transition was successful
|
|
96
|
+
*/
|
|
97
|
+
async updateOrderStatus(ctx, sendcloudStatus, orderCode, trackingNumber) {
|
|
98
|
+
let order = await this.connection
|
|
99
|
+
.getRepository(ctx, core_2.Order)
|
|
100
|
+
.findOne({ where: { code: orderCode }, relations: ['lines'] });
|
|
101
|
+
if (!order) {
|
|
102
|
+
core_2.Logger.warn(`Cannot update status from SendCloud: No order with code ${orderCode} found`, constants_1.loggerCtx);
|
|
103
|
+
throw Error(`Cannot update status from SendCloud: No order with code ${orderCode} found`);
|
|
104
|
+
}
|
|
105
|
+
if (order.state === sendcloudStatus.orderState) {
|
|
106
|
+
return core_2.Logger.info(`Not updating order with code ${orderCode}: Order already has state ${order.state}`, constants_1.loggerCtx);
|
|
107
|
+
}
|
|
108
|
+
if (sendcloudStatus.orderState === 'Shipped') {
|
|
109
|
+
await this.shipAll(ctx, order, trackingNumber);
|
|
110
|
+
return core_2.Logger.info(`Successfully update order ${orderCode} to ${sendcloudStatus.orderState}`, constants_1.loggerCtx);
|
|
111
|
+
}
|
|
112
|
+
order = await this.connection
|
|
113
|
+
.getRepository(ctx, core_2.Order)
|
|
114
|
+
.findOneOrFail({ where: { code: orderCode }, relations: ['lines'] }); // Refetch in case state was updated
|
|
115
|
+
if (sendcloudStatus.orderState === 'Delivered') {
|
|
116
|
+
//FIX ME
|
|
117
|
+
await (0, src_1.transitionToDelivered)(this.orderService, ctx, order, {
|
|
118
|
+
code: sendcloud_handler_1.sendcloudHandler.code,
|
|
119
|
+
arguments: [
|
|
120
|
+
{
|
|
121
|
+
name: 'trackingNumber',
|
|
122
|
+
value: trackingNumber,
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
});
|
|
126
|
+
return core_2.Logger.info(`Successfully update order ${orderCode} to ${sendcloudStatus.orderState}`, constants_1.loggerCtx);
|
|
127
|
+
}
|
|
128
|
+
// Fall through, means unhandled state
|
|
129
|
+
core_2.Logger.info(`Not handling state ${sendcloudStatus.orderState}`, constants_1.loggerCtx);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Fulfill and ship all items
|
|
133
|
+
*/
|
|
134
|
+
async shipAll(ctx, order, trackingNumber) {
|
|
135
|
+
await (0, src_1.transitionToShipped)(this.orderService, ctx, order, {
|
|
136
|
+
code: sendcloud_handler_1.sendcloudHandler.code,
|
|
137
|
+
arguments: [
|
|
138
|
+
{
|
|
139
|
+
name: 'trackingNumber',
|
|
140
|
+
value: trackingNumber,
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
async upsertConfig(ctx, config) {
|
|
146
|
+
const repo = this.connection.getRepository(ctx, sendcloud_config_entity_1.SendcloudConfigEntity);
|
|
147
|
+
const existing = await repo.findOne({
|
|
148
|
+
where: { channelId: String(ctx.channelId) },
|
|
149
|
+
});
|
|
150
|
+
if (existing) {
|
|
151
|
+
await repo.update(existing.id, {
|
|
152
|
+
secret: config.secret,
|
|
153
|
+
publicKey: config.publicKey,
|
|
154
|
+
defaultPhoneNr: config.defaultPhoneNr,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
await repo.insert({
|
|
159
|
+
channelId: String(ctx.channelId),
|
|
160
|
+
secret: config.secret,
|
|
161
|
+
publicKey: config.publicKey,
|
|
162
|
+
defaultPhoneNr: config.defaultPhoneNr,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
return repo.findOneOrFail({ where: { channelId: String(ctx.channelId) } });
|
|
166
|
+
}
|
|
167
|
+
async getConfig(ctx) {
|
|
168
|
+
return this.connection
|
|
169
|
+
.getRepository(ctx, sendcloud_config_entity_1.SendcloudConfigEntity)
|
|
170
|
+
.findOne({ where: { channelId: String(ctx.channelId) } });
|
|
171
|
+
}
|
|
172
|
+
async getClient(ctx) {
|
|
173
|
+
const config = await this.getConfig(ctx);
|
|
174
|
+
if (!config || !config?.secret || !config.publicKey) {
|
|
175
|
+
throw Error(`Incomplete config found for channel ${ctx.channel.token}`);
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
client: new sendcloud_client_1.SendcloudClient(config.publicKey, config.secret),
|
|
179
|
+
defaultPhoneNr: config.defaultPhoneNr,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
async createContext(channelToken) {
|
|
183
|
+
const channel = await this.channelService.getChannelFromToken(channelToken);
|
|
184
|
+
return new core_2.RequestContext({
|
|
185
|
+
apiType: 'admin',
|
|
186
|
+
isAuthorized: true,
|
|
187
|
+
authorizedAsOwnerOnly: false,
|
|
188
|
+
languageCode: channel.defaultLanguageCode,
|
|
189
|
+
channel,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Sync order to Sendcloud platform
|
|
194
|
+
*/
|
|
195
|
+
async syncOrder(ctx, orderCode) {
|
|
196
|
+
const config = await this.getConfig(ctx);
|
|
197
|
+
if (!config?.secret || !config?.publicKey) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
let order = await this.orderService.findOneByCode(ctx, orderCode, [
|
|
201
|
+
'shippingLines',
|
|
202
|
+
'shippingLines.shippingMethod',
|
|
203
|
+
'lines',
|
|
204
|
+
]);
|
|
205
|
+
if (!order) {
|
|
206
|
+
return core_2.Logger.error(`No order found with code ${orderCode}. Can not sync this order.`, constants_1.loggerCtx);
|
|
207
|
+
}
|
|
208
|
+
const hasSendcloudHandler = order.shippingLines.find((line) => line.shippingMethod?.fulfillmentHandlerCode === sendcloud_handler_1.sendcloudHandler.code);
|
|
209
|
+
if (!hasSendcloudHandler) {
|
|
210
|
+
return core_2.Logger.info(`Order ${order.code} does not have SendCloud set as handler. Not syncing this order.`, constants_1.loggerCtx);
|
|
211
|
+
}
|
|
212
|
+
core_2.Logger.info(`Syncing order ${orderCode} for channel ${ctx.channel.token}`, constants_1.loggerCtx);
|
|
213
|
+
const result = await this.createOrderInSendcloud(ctx, order);
|
|
214
|
+
if (result) {
|
|
215
|
+
core_2.Logger.info(`Order ${order.code} synced to SendCloud: ${result.id}`, constants_1.loggerCtx);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
async logHistoryEntry(ctx, orderId, error) {
|
|
219
|
+
let prettifiedError = error
|
|
220
|
+
? JSON.parse(JSON.stringify(error, Object.getOwnPropertyNames(error)))
|
|
221
|
+
: undefined; // Make sure its serializable
|
|
222
|
+
await this.historyService.createHistoryEntryForOrder({
|
|
223
|
+
ctx,
|
|
224
|
+
orderId,
|
|
225
|
+
type: 'SENDCLOUD_NOTIFICATION',
|
|
226
|
+
data: {
|
|
227
|
+
name: 'SendCloud',
|
|
228
|
+
valid: !error,
|
|
229
|
+
error: prettifiedError,
|
|
230
|
+
},
|
|
231
|
+
}, false);
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
SendcloudService = __decorate([
|
|
235
|
+
(0, common_1.Injectable)(),
|
|
236
|
+
__param(6, (0, common_1.Inject)(constants_1.PLUGIN_OPTIONS)),
|
|
237
|
+
__metadata("design:paramtypes", [core_2.EventBus,
|
|
238
|
+
core_2.TransactionalConnection,
|
|
239
|
+
core_2.OrderService,
|
|
240
|
+
core_2.ChannelService,
|
|
241
|
+
core_2.JobQueueService,
|
|
242
|
+
core_1.ModuleRef, Object, core_2.EntityHydrator,
|
|
243
|
+
core_2.HistoryService])
|
|
244
|
+
], SendcloudService);
|
|
245
|
+
exports.SendcloudService = SendcloudService;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export interface ParcelInput {
|
|
2
|
+
name: string;
|
|
3
|
+
company_name?: string;
|
|
4
|
+
address: string;
|
|
5
|
+
house_number: string;
|
|
6
|
+
city: string;
|
|
7
|
+
postal_code: string;
|
|
8
|
+
country: string;
|
|
9
|
+
telephone?: string;
|
|
10
|
+
request_label: boolean;
|
|
11
|
+
email?: string;
|
|
12
|
+
order_number?: string;
|
|
13
|
+
parcel_items: ParcelInputItem[];
|
|
14
|
+
weight: string;
|
|
15
|
+
shipping_method_checkout_name?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ParcelInputItem {
|
|
18
|
+
description: string;
|
|
19
|
+
quantity: number;
|
|
20
|
+
weight: string;
|
|
21
|
+
sku: string;
|
|
22
|
+
value: string;
|
|
23
|
+
hs_code?: string;
|
|
24
|
+
origin_country?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface Parcel {
|
|
27
|
+
id: number;
|
|
28
|
+
name: string;
|
|
29
|
+
company_name: string;
|
|
30
|
+
address: string;
|
|
31
|
+
address_divided: AddressDivided;
|
|
32
|
+
city: string;
|
|
33
|
+
postal_code: string;
|
|
34
|
+
telephone: string;
|
|
35
|
+
email: string;
|
|
36
|
+
date_created: string;
|
|
37
|
+
date_updated: string;
|
|
38
|
+
date_announced: string;
|
|
39
|
+
tracking_number: string;
|
|
40
|
+
weight: string;
|
|
41
|
+
label: Label;
|
|
42
|
+
customs_declaration: CustomsDeclaration;
|
|
43
|
+
status: Status;
|
|
44
|
+
data: any[];
|
|
45
|
+
country: Country;
|
|
46
|
+
shipment: Shipment;
|
|
47
|
+
colli_tracking_number: string;
|
|
48
|
+
colli_uuid: string;
|
|
49
|
+
collo_nr: number;
|
|
50
|
+
collo_count: number;
|
|
51
|
+
awb_tracking_number: null;
|
|
52
|
+
box_number: null;
|
|
53
|
+
order_number?: string;
|
|
54
|
+
}
|
|
55
|
+
export interface AddressDivided {
|
|
56
|
+
street: string;
|
|
57
|
+
house_number: string;
|
|
58
|
+
}
|
|
59
|
+
export interface Country {
|
|
60
|
+
iso_3: string;
|
|
61
|
+
iso_2: string;
|
|
62
|
+
name: string;
|
|
63
|
+
}
|
|
64
|
+
export interface CustomsDeclaration {
|
|
65
|
+
}
|
|
66
|
+
export interface Label {
|
|
67
|
+
normal_printer: string[];
|
|
68
|
+
label_printer: string;
|
|
69
|
+
}
|
|
70
|
+
export interface Shipment {
|
|
71
|
+
id: number;
|
|
72
|
+
name: string;
|
|
73
|
+
}
|
|
74
|
+
export interface Status {
|
|
75
|
+
id: number;
|
|
76
|
+
message: string;
|
|
77
|
+
}
|
|
78
|
+
export interface IncomingWebhookBody {
|
|
79
|
+
action: 'parcel_status_changed' | string;
|
|
80
|
+
timestamp: number;
|
|
81
|
+
parcel?: Parcel;
|
|
82
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Injector, Order, OrderLine, RequestContext } from '@vendure/core';
|
|
2
|
+
import { ParcelInputItem } from './sendcloud-api.types';
|
|
3
|
+
export interface SendcloudParcelStatus {
|
|
4
|
+
id: number;
|
|
5
|
+
message: string;
|
|
6
|
+
/**
|
|
7
|
+
* Corresponding orderState for the sendcloud status
|
|
8
|
+
*/
|
|
9
|
+
orderState?: 'Shipped' | 'Delivered' | 'Cancelled';
|
|
10
|
+
}
|
|
11
|
+
export declare const sendcloudStates: SendcloudParcelStatus[];
|
|
12
|
+
export interface SendcloudPluginOptions {
|
|
13
|
+
/**
|
|
14
|
+
* Function to specify the weight of a parcelItem
|
|
15
|
+
* based on the given orderLine
|
|
16
|
+
*/
|
|
17
|
+
weightFn?: CustomFieldFn<number>;
|
|
18
|
+
/**
|
|
19
|
+
* Function to specify the hsCode for a parcelItem
|
|
20
|
+
*/
|
|
21
|
+
hsCodeFn?: CustomFieldFn<string>;
|
|
22
|
+
originCountryFn?: CustomFieldFn<string>;
|
|
23
|
+
/**
|
|
24
|
+
* You can send additional ParcelItems (rows) to SendCloud.
|
|
25
|
+
* For example if you want the couponCodes applied on an order
|
|
26
|
+
* also on your packaging slip in SendCloud
|
|
27
|
+
*/
|
|
28
|
+
additionalParcelItemsFn?: AdditionalParcelInputFn;
|
|
29
|
+
/**
|
|
30
|
+
* Programatically disable the plugin. For example, when running in a test-env:
|
|
31
|
+
* @example
|
|
32
|
+
* disabled: !!process.env.TEST
|
|
33
|
+
*/
|
|
34
|
+
disabled?: boolean;
|
|
35
|
+
}
|
|
36
|
+
export type AdditionalParcelInputFn = (ctx: RequestContext, injector: Injector, order: Order) => Promise<ParcelInputItem[]>;
|
|
37
|
+
export type CustomFieldFn<T = string | number> = (
|
|
38
|
+
/**
|
|
39
|
+
* OrderLine with line.productVariant and line.productVariant.product
|
|
40
|
+
*/
|
|
41
|
+
line: OrderLine) => T;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sendcloudStates = void 0;
|
|
4
|
+
exports.sendcloudStates = [
|
|
5
|
+
{
|
|
6
|
+
id: 62989,
|
|
7
|
+
message: 'The package has been held at customs',
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
id: 6,
|
|
11
|
+
message: 'Not sorted',
|
|
12
|
+
orderState: 'Shipped',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: 15,
|
|
16
|
+
message: 'Error collecting',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: 62990,
|
|
20
|
+
message: 'The package is in the sorting centre',
|
|
21
|
+
orderState: 'Shipped',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: 62991,
|
|
25
|
+
message: 'The package was refused by the recipient when delivered',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: 62992,
|
|
29
|
+
message: 'The package was returned to the sender due to an issue',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 62993,
|
|
33
|
+
message: 'The delivery method was changed by the request of the recipient or due to other circumstances.',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: 1002,
|
|
37
|
+
message: 'Announcement failed',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: 1999,
|
|
41
|
+
message: 'Cancellation requested',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 62994,
|
|
45
|
+
message: 'The delivery date was changed by the request of the recipient or due to other.',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 62995,
|
|
49
|
+
message: 'The delivery address was changed by the request of the recipient or due to other circumstances.',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: 62996,
|
|
53
|
+
message: 'For unusual cases: lost, damaged, destroyed, etc.',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 1998,
|
|
57
|
+
message: 'Cancelled upstream',
|
|
58
|
+
orderState: 'Cancelled',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: 1000,
|
|
62
|
+
message: 'Ready to send',
|
|
63
|
+
orderState: 'Shipped',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: 62997,
|
|
67
|
+
message: 'The address is incorrect and the carrier needs address correction from the sender or the recipient.',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: 12,
|
|
71
|
+
message: 'Awaiting customer pickup',
|
|
72
|
+
orderState: 'Shipped',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: 11,
|
|
76
|
+
message: 'Delivered',
|
|
77
|
+
orderState: 'Delivered',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: 93,
|
|
81
|
+
message: 'Shipment collected by customer',
|
|
82
|
+
orderState: 'Delivered',
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 91,
|
|
86
|
+
message: 'Parcel en route',
|
|
87
|
+
orderState: 'Shipped',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: 80,
|
|
91
|
+
message: 'Unable to deliver',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: 22,
|
|
95
|
+
message: 'Shipment picked up by driver',
|
|
96
|
+
orderState: 'Shipped',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: 13,
|
|
100
|
+
message: 'Announced: not collected',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
id: 8,
|
|
104
|
+
message: 'Delivery attempt failed',
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
id: 7,
|
|
108
|
+
message: 'Being sorted',
|
|
109
|
+
orderState: 'Shipped',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
id: 5,
|
|
113
|
+
message: 'Sorted',
|
|
114
|
+
orderState: 'Shipped',
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: 4,
|
|
118
|
+
message: 'Delivery delayed',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: 3,
|
|
122
|
+
message: 'En route to sorting center',
|
|
123
|
+
orderState: 'Shipped',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: 1,
|
|
127
|
+
message: 'Announced',
|
|
128
|
+
orderState: 'Shipped',
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
id: 1337,
|
|
132
|
+
message: 'Unknown status - check carrier track & trace page for more insights',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: 999,
|
|
136
|
+
message: 'No label',
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
id: 1001,
|
|
140
|
+
message: 'Being announced',
|
|
141
|
+
orderState: 'Shipped',
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
id: 2000,
|
|
145
|
+
message: 'Cancelled',
|
|
146
|
+
orderState: 'Cancelled',
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
id: 2001,
|
|
150
|
+
message: 'Submitting cancellation request',
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
id: 92,
|
|
154
|
+
message: 'Driver en route',
|
|
155
|
+
orderState: 'Shipped',
|
|
156
|
+
},
|
|
157
|
+
];
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./sendcloud.plugin"), exports);
|
|
18
|
+
__exportStar(require("./api/sendcloud.handler"), exports);
|
|
19
|
+
__exportStar(require("./api/additional-parcel-input-items"), exports);
|
|
20
|
+
__exportStar(require("./api/types/sendcloud.types"), exports);
|
|
21
|
+
__exportStar(require("./api/types/sendcloud-api.types"), exports);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { AdminUiExtension } from '@vendure/ui-devkit/compiler';
|
|
2
|
+
import { SendcloudPluginOptions } from './api/types/sendcloud.types';
|
|
3
|
+
export declare class SendcloudPlugin {
|
|
4
|
+
private static options;
|
|
5
|
+
static init(options: SendcloudPluginOptions): typeof SendcloudPlugin;
|
|
6
|
+
static ui: AdminUiExtension;
|
|
7
|
+
}
|