@labdigital/commercetools-mock 2.40.0 → 2.41.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/dist/index.cjs +34 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +34 -19
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/repositories/customer/index.test.ts +53 -1
- package/src/repositories/customer/index.ts +20 -4
- package/src/repositories/order/actions.ts +26 -12
- package/src/services/my-customer.test.ts +1 -0
- package/src/services/order.test.ts +150 -0
package/package.json
CHANGED
|
@@ -3,10 +3,49 @@ import { describe, expect, test } from "vitest";
|
|
|
3
3
|
import { InMemoryStorage } from "~src/storage";
|
|
4
4
|
import { CustomerRepository } from "./index";
|
|
5
5
|
|
|
6
|
-
describe("
|
|
6
|
+
describe("Customer repository", () => {
|
|
7
7
|
const storage = new InMemoryStorage();
|
|
8
8
|
const repository = new CustomerRepository(storage);
|
|
9
9
|
|
|
10
|
+
test("query by lowercaseEmail", async () => {
|
|
11
|
+
const customer = repository.create(
|
|
12
|
+
{ projectKey: "dummy" },
|
|
13
|
+
{ email: "my-customer-UPPERCASE@email.com" },
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const result = repository.query(
|
|
17
|
+
{ projectKey: "dummy" },
|
|
18
|
+
{ where: [`lowercaseEmail = "my-customer-uppercase@email.com"`] },
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
expect(result.results).toHaveLength(1);
|
|
22
|
+
expect(result.results[0].id).toEqual(customer.id);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("updating lowercaseEmail", async () => {
|
|
26
|
+
const customer = repository.create(
|
|
27
|
+
{ projectKey: "dummy" },
|
|
28
|
+
{ email: "my-customer-UPPERCASE-v1@email.com" },
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
repository.saveUpdate({ projectKey: "dummy" }, customer.version, {
|
|
32
|
+
...customer,
|
|
33
|
+
email: "my-customer-UPPERCASE-v2@email.com",
|
|
34
|
+
version: customer.version + 1,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const result = repository.query(
|
|
38
|
+
{ projectKey: "dummy" },
|
|
39
|
+
{ where: [`lowercaseEmail = "my-customer-uppercase-v2@email.com"`] },
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
expect(result.results).toHaveLength(1);
|
|
43
|
+
expect(result.results[0].id).toEqual(customer.id);
|
|
44
|
+
expect(result.results[0].email).toEqual(
|
|
45
|
+
"my-customer-UPPERCASE-v2@email.com",
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
|
|
10
49
|
test("adding stores to customer", async () => {
|
|
11
50
|
const store1: Store = {
|
|
12
51
|
id: "d0016081-e9af-48a7-8133-1f04f340a335",
|
|
@@ -72,4 +111,17 @@ describe("Order repository", () => {
|
|
|
72
111
|
},
|
|
73
112
|
]);
|
|
74
113
|
});
|
|
114
|
+
|
|
115
|
+
test("adding customer without linked stores", async () => {
|
|
116
|
+
const result = repository.create(
|
|
117
|
+
{ projectKey: "dummy" },
|
|
118
|
+
{
|
|
119
|
+
email: "my-customer-without-stores@email.com",
|
|
120
|
+
stores: [],
|
|
121
|
+
},
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
expect(result.email).toEqual("my-customer-without-stores@email.com");
|
|
125
|
+
expect(result?.stores).toHaveLength(0);
|
|
126
|
+
});
|
|
75
127
|
});
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
validatePasswordResetToken,
|
|
21
21
|
} from "~src/lib/password";
|
|
22
22
|
import type { AbstractStorage } from "~src/storage/abstract";
|
|
23
|
-
import type { Writable } from "~src/types";
|
|
23
|
+
import type { ResourceMap, ShallowWritable, Writable } from "~src/types";
|
|
24
24
|
import {
|
|
25
25
|
AbstractResourceRepository,
|
|
26
26
|
type RepositoryContext,
|
|
@@ -37,7 +37,7 @@ export class CustomerRepository extends AbstractResourceRepository<"customer"> {
|
|
|
37
37
|
create(context: RepositoryContext, draft: CustomerDraft): Customer {
|
|
38
38
|
// Check uniqueness
|
|
39
39
|
const results = this._storage.query(context.projectKey, this.getTypeId(), {
|
|
40
|
-
where: [`
|
|
40
|
+
where: [`lowercaseEmail="${draft.email.toLowerCase()}"`],
|
|
41
41
|
});
|
|
42
42
|
if (results.count > 0) {
|
|
43
43
|
throw new CommercetoolsError<any>({
|
|
@@ -105,7 +105,7 @@ export class CustomerRepository extends AbstractResourceRepository<"customer"> {
|
|
|
105
105
|
|
|
106
106
|
let storesForCustomer: StoreKeyReference[] = [];
|
|
107
107
|
|
|
108
|
-
if (draft.stores) {
|
|
108
|
+
if (draft.stores && draft.stores.length > 0) {
|
|
109
109
|
const storeIds = draft.stores
|
|
110
110
|
.map((storeReference) => storeReference.id)
|
|
111
111
|
.filter(Boolean);
|
|
@@ -141,6 +141,7 @@ export class CustomerRepository extends AbstractResourceRepository<"customer"> {
|
|
|
141
141
|
dateOfBirth: draft.dateOfBirth,
|
|
142
142
|
companyName: draft.companyName,
|
|
143
143
|
email: draft.email.toLowerCase(),
|
|
144
|
+
lowercaseEmail: draft.email.toLowerCase(),
|
|
144
145
|
password: draft.password ? hashPassword(draft.password) : undefined,
|
|
145
146
|
isEmailVerified: draft.isEmailVerified || false,
|
|
146
147
|
addresses: addresses,
|
|
@@ -156,10 +157,25 @@ export class CustomerRepository extends AbstractResourceRepository<"customer"> {
|
|
|
156
157
|
this._storage,
|
|
157
158
|
),
|
|
158
159
|
stores: storesForCustomer,
|
|
159
|
-
};
|
|
160
|
+
} satisfies unknown as Customer;
|
|
161
|
+
|
|
160
162
|
return this.saveNew(context, resource);
|
|
161
163
|
}
|
|
162
164
|
|
|
165
|
+
saveUpdate(
|
|
166
|
+
context: RepositoryContext,
|
|
167
|
+
version: number,
|
|
168
|
+
resource: ShallowWritable<ResourceMap["customer"]>,
|
|
169
|
+
): ShallowWritable<ResourceMap["customer"]> {
|
|
170
|
+
// Also update lowercaseEmail attribute
|
|
171
|
+
const updatedResource: Customer = {
|
|
172
|
+
...resource,
|
|
173
|
+
lowercaseEmail: resource.email.toLowerCase(),
|
|
174
|
+
} satisfies unknown as Customer;
|
|
175
|
+
|
|
176
|
+
return super.saveUpdate(context, version, updatedResource);
|
|
177
|
+
}
|
|
178
|
+
|
|
163
179
|
passwordResetToken(
|
|
164
180
|
context: RepositoryContext,
|
|
165
181
|
request: CustomerCreatePasswordResetToken,
|
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
OrderSetDeliveryCustomFieldAction,
|
|
16
16
|
OrderSetLocaleAction,
|
|
17
17
|
OrderSetOrderNumberAction,
|
|
18
|
+
OrderSetParcelCustomFieldAction,
|
|
18
19
|
OrderSetPurchaseOrderNumberAction,
|
|
19
20
|
OrderSetShippingAddressAction,
|
|
20
21
|
OrderSetStoreAction,
|
|
@@ -26,7 +27,6 @@ import type {
|
|
|
26
27
|
Store,
|
|
27
28
|
SyncInfo,
|
|
28
29
|
} from "@commercetools/platform-sdk";
|
|
29
|
-
import assert from "assert";
|
|
30
30
|
import { getBaseResourceProperties } from "~src/helpers";
|
|
31
31
|
import type { Writable } from "~src/types";
|
|
32
32
|
import type { RepositoryContext, UpdateHandlerInterface } from "../abstract";
|
|
@@ -194,18 +194,14 @@ export class OrderUpdateHandler
|
|
|
194
194
|
resource: Writable<Order>,
|
|
195
195
|
{ deliveryId, name, value }: OrderSetDeliveryCustomFieldAction,
|
|
196
196
|
) {
|
|
197
|
-
|
|
197
|
+
if (!resource.shippingInfo) {
|
|
198
|
+
throw new Error("Resource has no shipping info");
|
|
199
|
+
}
|
|
198
200
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
const update = delivery.custom.fields;
|
|
204
|
-
update[name] = value;
|
|
205
|
-
Object.assign(delivery.custom.fields, update);
|
|
206
|
-
}
|
|
207
|
-
return delivery;
|
|
208
|
-
});
|
|
201
|
+
for (const delivery of resource.shippingInfo.deliveries || []) {
|
|
202
|
+
if (delivery.id === deliveryId && delivery.custom?.fields) {
|
|
203
|
+
delivery.custom.fields[name] = value;
|
|
204
|
+
}
|
|
209
205
|
}
|
|
210
206
|
}
|
|
211
207
|
|
|
@@ -225,6 +221,24 @@ export class OrderUpdateHandler
|
|
|
225
221
|
resource.orderNumber = orderNumber;
|
|
226
222
|
}
|
|
227
223
|
|
|
224
|
+
setParcelCustomField(
|
|
225
|
+
context: RepositoryContext,
|
|
226
|
+
resource: Writable<Order>,
|
|
227
|
+
{ parcelId, name, value }: OrderSetParcelCustomFieldAction,
|
|
228
|
+
) {
|
|
229
|
+
if (!resource.shippingInfo) {
|
|
230
|
+
throw new Error("Resource has no shipping info");
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
for (const delivery of resource.shippingInfo.deliveries || []) {
|
|
234
|
+
for (const parcel of delivery.parcels || []) {
|
|
235
|
+
if (parcel.id === parcelId && parcel.custom?.fields) {
|
|
236
|
+
parcel.custom.fields[name] = value;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
228
242
|
setPurchaseOrderNumber(
|
|
229
243
|
context: RepositoryContext,
|
|
230
244
|
resource: Writable<Order>,
|
|
@@ -593,6 +593,156 @@ describe("Order Update Actions", () => {
|
|
|
593
593
|
).toBe("dhl");
|
|
594
594
|
});
|
|
595
595
|
|
|
596
|
+
test("setParcelCustomField", async () => {
|
|
597
|
+
const order: Order = {
|
|
598
|
+
...getBaseResourceProperties(),
|
|
599
|
+
customLineItems: [],
|
|
600
|
+
lastMessageSequenceNumber: 0,
|
|
601
|
+
lineItems: [],
|
|
602
|
+
orderNumber: "1390",
|
|
603
|
+
orderState: "Open",
|
|
604
|
+
origin: "Customer",
|
|
605
|
+
paymentInfo: {
|
|
606
|
+
payments: [
|
|
607
|
+
{
|
|
608
|
+
typeId: "payment",
|
|
609
|
+
id: generateRandomString(10),
|
|
610
|
+
},
|
|
611
|
+
],
|
|
612
|
+
},
|
|
613
|
+
refusedGifts: [],
|
|
614
|
+
shippingInfo: {
|
|
615
|
+
shippingMethodName: "Home delivery (package)",
|
|
616
|
+
price: {
|
|
617
|
+
type: "centPrecision",
|
|
618
|
+
currencyCode: "EUR",
|
|
619
|
+
centAmount: 999,
|
|
620
|
+
fractionDigits: 2,
|
|
621
|
+
},
|
|
622
|
+
shippingRate: {
|
|
623
|
+
price: {
|
|
624
|
+
type: "centPrecision",
|
|
625
|
+
currencyCode: "EUR",
|
|
626
|
+
centAmount: 999,
|
|
627
|
+
fractionDigits: 2,
|
|
628
|
+
},
|
|
629
|
+
tiers: [
|
|
630
|
+
{
|
|
631
|
+
type: "CartScore",
|
|
632
|
+
score: 24,
|
|
633
|
+
price: {
|
|
634
|
+
type: "centPrecision",
|
|
635
|
+
currencyCode: "EUR",
|
|
636
|
+
centAmount: 1998,
|
|
637
|
+
fractionDigits: 2,
|
|
638
|
+
},
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
type: "CartScore",
|
|
642
|
+
score: 47,
|
|
643
|
+
price: {
|
|
644
|
+
type: "centPrecision",
|
|
645
|
+
currencyCode: "EUR",
|
|
646
|
+
centAmount: 2997,
|
|
647
|
+
fractionDigits: 2,
|
|
648
|
+
},
|
|
649
|
+
},
|
|
650
|
+
{
|
|
651
|
+
type: "CartScore",
|
|
652
|
+
score: 70,
|
|
653
|
+
price: {
|
|
654
|
+
type: "centPrecision",
|
|
655
|
+
currencyCode: "EUR",
|
|
656
|
+
centAmount: 3996,
|
|
657
|
+
fractionDigits: 2,
|
|
658
|
+
},
|
|
659
|
+
},
|
|
660
|
+
{
|
|
661
|
+
type: "CartScore",
|
|
662
|
+
score: 93,
|
|
663
|
+
price: {
|
|
664
|
+
type: "centPrecision",
|
|
665
|
+
currencyCode: "EUR",
|
|
666
|
+
centAmount: 4995,
|
|
667
|
+
fractionDigits: 2,
|
|
668
|
+
},
|
|
669
|
+
},
|
|
670
|
+
],
|
|
671
|
+
},
|
|
672
|
+
deliveries: [
|
|
673
|
+
{
|
|
674
|
+
id: "6a458cad-dd46-4f5f-8b73-debOede6a17d",
|
|
675
|
+
key: "CT-Z243002",
|
|
676
|
+
createdAt: "2024-07-29T13:37:48.047Z",
|
|
677
|
+
items: [
|
|
678
|
+
{
|
|
679
|
+
id: "5d209544-2892-45c9-bef0-dde4e250188e",
|
|
680
|
+
quantity: 1,
|
|
681
|
+
},
|
|
682
|
+
],
|
|
683
|
+
parcels: [
|
|
684
|
+
{
|
|
685
|
+
id: "7a458cad-dd46-4f5f-8b73-debOede6a17d",
|
|
686
|
+
createdAt: "2024-07-29T13:37:48.047Z",
|
|
687
|
+
items: [
|
|
688
|
+
{
|
|
689
|
+
id: "5d209544-2892-45c9-bef0-dde4e250188e",
|
|
690
|
+
quantity: 1,
|
|
691
|
+
},
|
|
692
|
+
],
|
|
693
|
+
custom: {
|
|
694
|
+
type: {
|
|
695
|
+
typeId: "type",
|
|
696
|
+
id: "c493b7bb-d415-450c-b421-e128a8b26569",
|
|
697
|
+
},
|
|
698
|
+
fields: {
|
|
699
|
+
status: "created",
|
|
700
|
+
},
|
|
701
|
+
},
|
|
702
|
+
},
|
|
703
|
+
],
|
|
704
|
+
},
|
|
705
|
+
],
|
|
706
|
+
shippingMethodState: "MatchesCart",
|
|
707
|
+
},
|
|
708
|
+
shipping: [],
|
|
709
|
+
shippingMode: "Single",
|
|
710
|
+
syncInfo: [],
|
|
711
|
+
totalPrice: {
|
|
712
|
+
type: "centPrecision",
|
|
713
|
+
fractionDigits: 2,
|
|
714
|
+
centAmount: 2000,
|
|
715
|
+
currencyCode: "EUR",
|
|
716
|
+
},
|
|
717
|
+
};
|
|
718
|
+
ctMock.project("dummy").add("order", order);
|
|
719
|
+
|
|
720
|
+
const response = await supertest(ctMock.app).get(
|
|
721
|
+
`/dummy/orders/order-number=${order.orderNumber}`,
|
|
722
|
+
);
|
|
723
|
+
|
|
724
|
+
// check if status is set
|
|
725
|
+
const _updateResponse = await supertest(ctMock.app)
|
|
726
|
+
.post(`/dummy/orders/${response.body.id}`)
|
|
727
|
+
.send({
|
|
728
|
+
version: 0,
|
|
729
|
+
actions: [
|
|
730
|
+
{
|
|
731
|
+
action: "setParcelCustomField",
|
|
732
|
+
parcelId: "7a458cad-dd46-4f5f-8b73-debOede6a17d",
|
|
733
|
+
name: "status",
|
|
734
|
+
value: "delayed",
|
|
735
|
+
},
|
|
736
|
+
],
|
|
737
|
+
});
|
|
738
|
+
expect(_updateResponse.status).toBe(200);
|
|
739
|
+
expect(_updateResponse.body.version).toBe(1);
|
|
740
|
+
expect(
|
|
741
|
+
_updateResponse.body.shippingInfo.deliveries[0].parcels[0].custom.fields
|
|
742
|
+
.status,
|
|
743
|
+
).toBe("delayed");
|
|
744
|
+
});
|
|
745
|
+
|
|
596
746
|
test("updateSyncInfo", async () => {
|
|
597
747
|
assert(order, "order not created");
|
|
598
748
|
|