Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added shouldSendOrder to ShipmatePluginConfig #500

Merged
merged 8 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/vendure-plugin-shipmate/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 1.3.0 (2024-08-27)

- Add `ShipmatePluginConfig.shouldSendOrder` (#498)

# 1.2.5 (2024-08-27)

- Don't throw erros from `/shipmate` endpoint (#509)
Expand Down
4 changes: 4 additions & 0 deletions packages/vendure-plugin-shipmate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ import { ShipmatePlugin } from '@pinelab/vendure-plugin-shipmate';
plugins: [
ShipmatePlugin.init({
apiUrl: 'https://api.shipmate.co.uk/v1.2', // Or https://api-staging.shipmate.co.uk/v1.2 for the testing environment
shouldSendOrder: function ( ctx: RequestContext, order: Order): Promise<boolean> | boolean {
// Sample implementation that only sends orders with less than 5 items to Shipmate
return order.totalQuantity < 5;
martijnvdbrug marked this conversation as resolved.
Show resolved Hide resolved
}
}),
AdminUiPlugin.init({
port: 3002,
Expand Down
2 changes: 1 addition & 1 deletion packages/vendure-plugin-shipmate/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pinelab/vendure-plugin-shipmate",
"version": "1.2.5",
"version": "1.3.0",
"description": "Vendure plugin for integration with Shipmate",
"icon": "truck",
"author": "Martijn van de Brug <martijn@pinelab.studio>",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,15 @@ export class ShipmateService implements OnApplicationBootstrap {
}

/**
* Created a job in the job queue to send the order to Shipmate
* Creates a job in the job queue to send the order to Shipmate
martijnvdbrug marked this conversation as resolved.
Show resolved Hide resolved
*/
async addJob(
event: OrderStateTransitionEvent | OrderPlacedEvent
): Promise<void> {
if (!this.config.shouldSendOrder(event.ctx, event.order)) {
Logger.info(`Order ${event.order.code} not sent to shipmate`);
return;
martijnvdbrug marked this conversation as resolved.
Show resolved Hide resolved
}
const { ctx, order, fromState, toState } = event;
if (event instanceof OrderPlacedEvent) {
await this.jobQueue.add(
Expand Down
11 changes: 10 additions & 1 deletion packages/vendure-plugin-shipmate/src/shipmate.plugin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { PluginCommonModule, VendurePlugin } from '@vendure/core';
import {
Order,
PluginCommonModule,
RequestContext,
VendurePlugin,
} from '@vendure/core';
import { ShipmateService } from './api/shipmate.service';
import { HttpModule } from '@nestjs/axios';
import { ShipmateConfigEntity } from './api/shipmate-config.entity';
Expand All @@ -18,6 +23,10 @@ export interface ShipmatePluginConfig {
apiUrl:
| 'https://api.shipmate.co.uk/v1.2'
| 'https://api-staging.shipmate.co.uk/v1.2';
shouldSendOrder(
ctx: RequestContext,
order: Order
): Promise<boolean> | boolean;
}

@VendurePlugin({
Expand Down
7 changes: 7 additions & 0 deletions packages/vendure-plugin-shipmate/test/dev-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
DefaultSearchPlugin,
LogLevel,
mergeConfig,
Order,
RequestContext,
} from '@vendure/core';
import { initialData } from '../../test/src/initial-data';
Expand All @@ -28,6 +29,12 @@ import { createSettledOrder } from '../../test/src/shop-utils';
plugins: [
ShipmatePlugin.init({
apiUrl: process.env.SHIPMATE_BASE_URL as any,
shouldSendOrder: function (
ctx: RequestContext,
order: Order
): Promise<boolean> | boolean {
return true;
},
}),
DefaultSearchPlugin,
AdminUiPlugin.init({
Expand Down
108 changes: 70 additions & 38 deletions packages/vendure-plugin-shipmate/test/shipmate.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
RequestContext,
isGraphQlErrorResult,
Order,
DefaultOrderCodeStrategy,
} from '@vendure/core';
import {
createTestEnvironment,
Expand All @@ -15,7 +16,16 @@ import {
SimpleGraphQLClient,
} from '@vendure/testing';
import { TestServer } from '@vendure/testing/lib/test-server';
import { afterAll, beforeAll, expect, it, describe, vi } from 'vitest';
import {
afterAll,
beforeAll,
expect,
it,
describe,
vi,
beforeEach,
afterEach,
} from 'vitest';
import { initialData } from '../../test/src/initial-data';
import nock from 'nock';

Expand All @@ -39,7 +49,7 @@ import {
} from '@vendure/common/lib/generated-types';

class MockOrderCodeStrategy implements OrderCodeStrategy {
generate(ctx: RequestContext): string | Promise<string> {
generate(ctx: RequestContext): string {
// Mock order code as 'FBJYSHC7WTRQEA14', as defined in the mock object
return mockShipment.shipment_reference;
}
Expand All @@ -62,14 +72,18 @@ describe('Shipmate plugin', async () => {
plugins: [
ShipmatePlugin.init({
apiUrl: nockBaseUrl,
//only send order if the total quantity is less than 5
shouldSendOrder: function (
ctx: RequestContext,
order: Order
): Promise<boolean> | boolean {
return order.totalQuantity < 5;
},
}),
],
paymentOptions: {
paymentMethodHandlers: [testPaymentMethod],
},
orderOptions: {
orderCodeStrategy: new MockOrderCodeStrategy(),
},
});

({ server, shopClient, adminClient } = createTestEnvironment(config));
Expand Down Expand Up @@ -104,30 +118,52 @@ describe('Shipmate plugin', async () => {

let order: Order | undefined;

// Global tokens mock, neede before each API call
nock(nockBaseUrl)
.post('/tokens', (reqBody) => {
return true;
})
.reply(200, {
message: 'Login Successful',
data: {
token: '749a75e3c1048965c498017efae8051f',
martijnvdbrug marked this conversation as resolved.
Show resolved Hide resolved
},
})
.persist(true);

// Global mock for outgoing requests to Shipmate API
let shipmentRequests: any[] = [];
nock(nockBaseUrl)
.post('/shipments', (reqBody) => {
shipmentRequests.push(reqBody);
return true;
})
.reply(200, { data: [mockShipment], message: 'Shipment Created' })
.persist(true);

it('Should not create a Shipment when an Order.totalQuantity is >= 5', async () => {
await createSettledOrder(shopClient, 'T_1', true, [
{ id: 'T_1', quantity: 2 },
{ id: 'T_2', quantity: 3 },
]);
await new Promise((resolve) => setTimeout(resolve, 1000));
const orderService = server.app.get(OrderService);
order = await orderService.findOne(ctx, 1);
// Should not have any shipments created
expect(shipmentRequests.length).toBe(0);
});

it('Should create a Shipment when an Order is placed', async () => {
nock(nockBaseUrl)
.post('/tokens', (reqBody) => {
return true;
})
.reply(200, {
message: 'Login Successful',
data: {
token: '749a75e3c1048965c498017efae8051f',
},
})
.persist(true);
let shipmentRequest: any;
nock(nockBaseUrl)
.post('/shipments', (reqBody) => {
shipmentRequest = reqBody;
return true;
})
.reply(200, { data: [mockShipment], message: 'Shipment Created' });
vi.spyOn(DefaultOrderCodeStrategy.prototype, 'generate').mockImplementation(
() => mockShipment.shipment_reference
);
await shopClient.asAnonymousUser();
await createSettledOrder(shopClient, 'T_1');
await new Promise((resolve) => setTimeout(resolve, 1000));
const orderService = server.app.get(OrderService);
order = await orderService.findOne(ctx, 1);
expect(shipmentRequest?.shipment_reference).toBe(order?.code);
order = await orderService.findOne(ctx, 2);
expect(shipmentRequests.length).toBe(1);
expect(shipmentRequests[0]?.shipment_reference).toBe(order?.code);
});

it('Should cancel and recreate order on Order Modification', async () => {
Expand All @@ -136,21 +172,14 @@ describe('Shipmate plugin', async () => {
.reply(200, cancelShipmentResponse)
.persist(true);

let shipmentRequest: any;
nock(nockBaseUrl)
.post('/shipments', (reqBody) => {
shipmentRequest = reqBody;
return true;
})
.reply(200, { data: [mockShipment], message: 'Shipment Created' });
const orderService = server.app.get(OrderService);
const ctx = await getSuperadminContext(server.app);
await adminClient.asSuperAdmin();
// Modify an order to retrigger shipment creation/update
try {
const modifyOrderInput: ModifyOrderInput = {
dryRun: true,
orderId: 1,
orderId: 2,
addItems: [
{
productVariantId: 3,
Expand All @@ -160,7 +189,7 @@ describe('Shipmate plugin', async () => {
};
const transitionToModifyingResult = await orderService.transitionToState(
ctx,
1,
2,
'Modifying'
);
if (isGraphQlErrorResult(transitionToModifyingResult)) {
Expand All @@ -173,7 +202,7 @@ describe('Shipmate plugin', async () => {
const transitionArrangingAdditionalPaymentResult =
await orderService.transitionToState(
ctx,
1,
2,
'ArrangingAdditionalPayment'
);
if (isGraphQlErrorResult(transitionArrangingAdditionalPaymentResult)) {
Expand All @@ -187,7 +216,8 @@ describe('Shipmate plugin', async () => {
await new Promise((resolve) => setTimeout(resolve, 1 * 1000));
expect(cancelShipmentScope.isDone()).toBe(true);
// Created the shipment again
expect(shipmentRequest?.shipment_reference).toBe(order?.code);
expect(shipmentRequests.length).toBe(2);
expect(shipmentRequests[1]?.shipment_reference).toBe(order?.code);
});

it('Should mark Order as Shipped when receiving "TRACKING_COLLECTED" event', async () => {
Expand All @@ -196,13 +226,14 @@ describe('Shipmate plugin', async () => {
>{
auth_token: authToken,
event: 'TRACKING_COLLECTED',
order_reference: mockShipment.shipment_reference,
shipment_reference: mockShipment.shipment_reference,
});
//shipmate's api expects a status of 201
expect(result.status).toBe(201);
// await new Promise((resolve) => setTimeout(resolve, 4000));
const orderService = server.app.get(OrderService);
const detailedOrder = await orderService.findOne(ctx, 1, ['fulfillments']);
const detailedOrder = await orderService.findOne(ctx, 2, ['fulfillments']);
expect(detailedOrder?.state).toBe('Shipped');
expect(detailedOrder?.fulfillments?.length).toBeGreaterThan(0);
});
Expand All @@ -213,13 +244,14 @@ describe('Shipmate plugin', async () => {
>{
auth_token: authToken,
event: 'TRACKING_DELIVERED',
order_reference: mockShipment.shipment_reference,
shipment_reference: mockShipment.shipment_reference,
});
//shipmate's api expects a status of 201
expect(result.status).toBe(201);
// await new Promise((resolve) => setTimeout(resolve, 4000));
const orderService = server.app.get(OrderService);
const detailedOrder = await orderService.findOne(ctx, 1, ['fulfillments']);
const detailedOrder = await orderService.findOne(ctx, 2, ['fulfillments']);
expect(detailedOrder?.state).toBe('Delivered');
expect(detailedOrder?.fulfillments?.length).toBeGreaterThan(0);
});
Expand Down
Loading
Loading