From 8c6cc82c5d851d18a68bcfa4b3579de96ee7d909 Mon Sep 17 00:00:00 2001 From: Sebastian Rindom Date: Fri, 26 Jan 2024 16:35:23 +0100 Subject: [PATCH] feat(customer): add customer addresses (#6224) **What** - adds methods to create update list customer addresses - removes default_shipping_id and billing id from customer record and moves them to address (better normalization) --- .../services/customer-module/index.spec.ts | 355 ++++++++++++++++++ .../migrations/.snapshot-medusa-customer.json | 111 +++--- .../src/migrations/Migration20240124154000.ts | 30 +- packages/customer/src/models/address.ts | 22 ++ packages/customer/src/models/customer.ts | 22 -- .../customer/src/services/customer-module.ts | 116 ++++++ packages/types/src/customer/common.ts | 50 ++- packages/types/src/customer/mutations.ts | 38 ++ packages/types/src/customer/service.ts | 40 +- 9 files changed, 672 insertions(+), 112 deletions(-) diff --git a/packages/customer/integration-tests/__tests__/services/customer-module/index.spec.ts b/packages/customer/integration-tests/__tests__/services/customer-module/index.spec.ts index 3b55fb9047..09769a8e59 100644 --- a/packages/customer/integration-tests/__tests__/services/customer-module/index.spec.ts +++ b/packages/customer/integration-tests/__tests__/services/customer-module/index.spec.ts @@ -59,6 +59,51 @@ describe("Customer Module Service", () => { ) }) + it("should create address", async () => { + const customerData = { + company_name: "Acme Corp", + first_name: "John", + last_name: "Doe", + addresses: [ + { + address_1: "Testvej 1", + address_2: "Testvej 2", + city: "Testby", + country_code: "DK", + province: "Test", + postal_code: "8000", + phone: "123456789", + metadata: { membership: "gold" }, + is_default_shipping: true, + }, + ], + } + const customer = await service.create(customerData) + + expect(customer).toEqual( + expect.objectContaining({ + id: expect.any(String), + company_name: "Acme Corp", + first_name: "John", + last_name: "Doe", + addresses: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(String), + address_1: "Testvej 1", + address_2: "Testvej 2", + city: "Testby", + country_code: "DK", + province: "Test", + postal_code: "8000", + phone: "123456789", + metadata: expect.objectContaining({ membership: "gold" }), + is_default_shipping: true, + }), + ]), + }) + ) + }) + it("should create multiple customers", async () => { const customersData = [ { @@ -419,6 +464,34 @@ describe("Customer Module Service", () => { expect(remainingCustomers.length).toBe(0) }) + it("should cascade address relationship when deleting customer", async () => { + // Creating a customer and an address + const customer = await service.create({ + first_name: "John", + last_name: "Doe", + }) + await service.addAddresses({ + customer_id: customer.id, + first_name: "John", + last_name: "Doe", + postal_code: "10001", + country_code: "US", + }) + + // verify that the address was added + const customerWithAddress = await service.retrieve(customer.id, { + relations: ["addresses"], + }) + expect(customerWithAddress.addresses?.length).toBe(1) + + await service.delete(customer.id) + + const res = await service.listAddresses({ + customer_id: customer.id, + }) + expect(res.length).toBe(0) + }) + it("should cascade relationship when deleting customer", async () => { // Creating a customer and a group const customer = await service.create({ @@ -505,6 +578,288 @@ describe("Customer Module Service", () => { }) }) + describe("addAddresses", () => { + it("should add a single address to a customer", async () => { + const customer = await service.create({ + first_name: "John", + last_name: "Doe", + }) + const address = await service.addAddresses({ + customer_id: customer.id, + first_name: "John", + last_name: "Doe", + postal_code: "10001", + country_code: "US", + }) + const [customerWithAddress] = await service.list( + { id: customer.id }, + { relations: ["addresses"] } + ) + + expect(customerWithAddress.addresses).toEqual([ + expect.objectContaining({ id: address.id }), + ]) + }) + + it("should add multiple addresses to a customer", async () => { + const customer = await service.create({ + first_name: "John", + last_name: "Doe", + }) + const addresses = await service.addAddresses([ + { + customer_id: customer.id, + first_name: "John", + last_name: "Doe", + postal_code: "10001", + country_code: "US", + }, + { + customer_id: customer.id, + first_name: "John", + last_name: "Doe", + postal_code: "10002", + country_code: "US", + }, + ]) + const [customerWithAddresses] = await service.list( + { id: customer.id }, + { relations: ["addresses"] } + ) + + expect(customerWithAddresses.addresses).toEqual( + expect.arrayContaining([ + expect.objectContaining({ id: addresses[0].id }), + expect.objectContaining({ id: addresses[1].id }), + ]) + ) + }) + + it("should only be possible to add one default shipping address per customer", async () => { + const customer = await service.create({ + first_name: "John", + last_name: "Doe", + }) + await service.addAddresses({ + customer_id: customer.id, + first_name: "John", + last_name: "Doe", + postal_code: "10001", + country_code: "US", + is_default_shipping: true, + }) + await service.addAddresses({ + customer_id: customer.id, + first_name: "John", + last_name: "Doe", + postal_code: "10001", + country_code: "US", + is_default_shipping: false, + }) + + await expect( + service.addAddresses({ + customer_id: customer.id, + first_name: "John", + last_name: "Doe", + postal_code: "10002", + country_code: "US", + is_default_shipping: true, + }) + ).rejects.toThrow() + }) + + it("should only be possible to add one default billing address per customer", async () => { + const customer = await service.create({ + first_name: "John", + last_name: "Doe", + }) + await service.addAddresses({ + customer_id: customer.id, + first_name: "John", + last_name: "Doe", + postal_code: "10001", + country_code: "US", + is_default_billing: true, + }) + await service.addAddresses({ + customer_id: customer.id, + first_name: "John", + last_name: "Doe", + postal_code: "10001", + country_code: "US", + is_default_billing: false, + }) + + await expect( + service.addAddresses({ + customer_id: customer.id, + first_name: "John", + last_name: "Doe", + postal_code: "10002", + country_code: "US", + is_default_billing: true, + }) + ).rejects.toThrow() + }) + }) + + describe("updateAddresses", () => { + it("should update a single address", async () => { + const customer = await service.create({ + first_name: "John", + last_name: "Doe", + }) + const address = await service.addAddresses({ + customer_id: customer.id, + address_name: "Home", + address_1: "123 Main St", + }) + + await service.updateAddress(address.id, { + address_name: "Work", + address_1: "456 Main St", + }) + + const updatedCustomer = await service.retrieve(customer.id, { + select: ["id"], + relations: ["addresses"], + }) + + expect(updatedCustomer.addresses).toEqual([ + expect.objectContaining({ + id: address.id, + address_name: "Work", + address_1: "456 Main St", + }), + ]) + }) + + it("should update multiple addresses", async () => { + const customer = await service.create({ + first_name: "John", + last_name: "Doe", + }) + const address1 = await service.addAddresses({ + customer_id: customer.id, + address_name: "Home", + address_1: "123 Main St", + }) + const address2 = await service.addAddresses({ + customer_id: customer.id, + address_name: "Work", + address_1: "456 Main St", + }) + + await service.updateAddress( + { customer_id: customer.id }, + { + address_name: "Under Construction", + } + ) + + const updatedCustomer = await service.retrieve(customer.id, { + select: ["id"], + relations: ["addresses"], + }) + + expect(updatedCustomer.addresses).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: address1.id, + address_name: "Under Construction", + }), + expect.objectContaining({ + id: address2.id, + address_name: "Under Construction", + }), + ]) + ) + }) + + it("should update multiple addresses with ids", async () => { + const customer = await service.create({ + first_name: "John", + last_name: "Doe", + }) + const [address1, address2] = await service.addAddresses([ + { + customer_id: customer.id, + address_name: "Home", + address_1: "123 Main St", + }, + { + customer_id: customer.id, + address_name: "Work", + address_1: "456 Main St", + }, + ]) + + await service.updateAddress([address1.id, address2.id], { + address_name: "Under Construction", + }) + + const updatedCustomer = await service.retrieve(customer.id, { + select: ["id"], + relations: ["addresses"], + }) + + expect(updatedCustomer.addresses).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: address1.id, + address_name: "Under Construction", + }), + expect.objectContaining({ + id: address2.id, + address_name: "Under Construction", + }), + ]) + ) + }) + }) + + describe("listAddresses", () => { + it("should list all addresses for a customer", async () => { + const customer = await service.create({ + first_name: "John", + last_name: "Doe", + }) + const [address1, address2] = await service.addAddresses([ + { + customer_id: customer.id, + address_name: "Home", + address_1: "123 Main St", + }, + { + customer_id: customer.id, + address_name: "Work", + + address_1: "456 Main St", + }, + ]) + + const addresses = await service.listAddresses({ + customer_id: customer.id, + }) + + expect(addresses).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: address1.id, + address_name: "Home", + address_1: "123 Main St", + }), + expect.objectContaining({ + id: address2.id, + address_name: "Work", + address_1: "456 Main St", + }), + ]) + ) + }) + }) + describe("removeCustomerFromGroup", () => { it("should remove a single customer from a group", async () => { // Creating a customer and a group diff --git a/packages/customer/src/migrations/.snapshot-medusa-customer.json b/packages/customer/src/migrations/.snapshot-medusa-customer.json index b39fc7ed7d..7274b8fa9c 100644 --- a/packages/customer/src/migrations/.snapshot-medusa-customer.json +++ b/packages/customer/src/migrations/.snapshot-medusa-customer.json @@ -70,24 +70,6 @@ "default": "false", "mappedType": "boolean" }, - "default_shipping_address_id": { - "name": "default_shipping_address_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "mappedType": "text" - }, - "default_billing_address_id": { - "name": "default_billing_address_id", - "type": "text", - "unsigned": false, - "autoincrement": false, - "primary": false, - "nullable": true, - "mappedType": "text" - }, "metadata": { "name": "metadata", "type": "jsonb", @@ -142,24 +124,6 @@ "name": "customer", "schema": "public", "indexes": [ - { - "columnNames": [ - "default_shipping_address_id" - ], - "composite": false, - "keyName": "IDX_customer_default_shipping_address_id", - "primary": false, - "unique": false - }, - { - "columnNames": [ - "default_billing_address_id" - ], - "composite": false, - "keyName": "IDX_customer_default_billing_address_id", - "primary": false, - "unique": false - }, { "keyName": "customer_pkey", "columnNames": [ @@ -171,34 +135,7 @@ } ], "checks": [], - "foreignKeys": { - "customer_default_shipping_address_id_foreign": { - "constraintName": "customer_default_shipping_address_id_foreign", - "columnNames": [ - "default_shipping_address_id" - ], - "localTableName": "public.customer", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.customer_address", - "deleteRule": "set null", - "updateRule": "cascade" - }, - "customer_default_billing_address_id_foreign": { - "constraintName": "customer_default_billing_address_id_foreign", - "columnNames": [ - "default_billing_address_id" - ], - "localTableName": "public.customer", - "referencedColumnNames": [ - "id" - ], - "referencedTableName": "public.customer_address", - "deleteRule": "set null", - "updateRule": "cascade" - } - } + "foreignKeys": {} }, { "columns": { @@ -211,6 +148,35 @@ "nullable": false, "mappedType": "text" }, + "address_name": { + "name": "address_name", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": true, + "mappedType": "text" + }, + "is_default_shipping": { + "name": "is_default_shipping", + "type": "boolean", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "default": "false", + "mappedType": "boolean" + }, + "is_default_billing": { + "name": "is_default_billing", + "type": "boolean", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "default": "false", + "mappedType": "boolean" + }, "customer_id": { "name": "customer_id", "type": "text", @@ -354,6 +320,22 @@ "primary": false, "unique": false }, + { + "keyName": "IDX_customer_address_unqiue_customer_billing", + "columnNames": [], + "composite": false, + "primary": false, + "unique": false, + "expression": "create unique index \"IDX_customer_address_unqiue_customer_billing\" on \"customer_address\" (\"customer_id\") where \"is_default_billing\" = true" + }, + { + "keyName": "IDX_customer_address_unqiue_customer_shipping", + "columnNames": [], + "composite": false, + "primary": false, + "unique": false, + "expression": "create unique index \"IDX_customer_address_unique_customer_shipping\" on \"customer_address\" (\"customer_id\") where \"is_default_shipping\" = true" + }, { "keyName": "customer_address_pkey", "columnNames": [ @@ -376,6 +358,7 @@ "id" ], "referencedTableName": "public.customer", + "deleteRule": "cascade", "updateRule": "cascade" } } diff --git a/packages/customer/src/migrations/Migration20240124154000.ts b/packages/customer/src/migrations/Migration20240124154000.ts index 53680c9c8f..443d06f80d 100644 --- a/packages/customer/src/migrations/Migration20240124154000.ts +++ b/packages/customer/src/migrations/Migration20240124154000.ts @@ -4,35 +4,29 @@ export class Migration20240124154000 extends Migration { async up(): Promise { // Customer table modifications this.addSql( - 'create table if not exists "customer" ("id" text not null, "company_name" text null, "first_name" text null, "last_name" text null, "email" text null, "phone" text null, "has_account" boolean not null default false, "default_shipping_address_id" text null, "default_billing_address_id" text null, "metadata" jsonb null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, "created_by" text null, constraint "customer_pkey" primary key ("id"));' + 'create table if not exists "customer" ("id" text not null, "company_name" text null, "first_name" text null, "last_name" text null, "email" text null, "phone" text null, "has_account" boolean not null default false, "metadata" jsonb null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), "deleted_at" timestamptz null, "created_by" text null, constraint "customer_pkey" primary key ("id"));' ) this.addSql( 'alter table "customer" add column if not exists "company_name" text null;' ) - this.addSql( - 'alter table "customer" add column if not exists "default_shipping_address_id" text null;' - ) - this.addSql( - 'alter table "customer" add column if not exists "default_billing_address_id" text null;' - ) this.addSql( 'alter table "customer" add column if not exists "created_by" text null;' ) this.addSql('drop index if exists "IDX_8abe81b9aac151ae60bf507ad1";') - this.addSql( - 'create index if not exists "IDX_customer_default_shipping_address_id" on "customer" ("default_shipping_address_id");' - ) - this.addSql( - 'create index if not exists "IDX_customer_default_billing_address_id" on "customer" ("default_billing_address_id");' - ) // Customer Address table this.addSql( - 'create table if not exists "customer_address" ("id" text not null, "customer_id" text not null, "company" text null, "first_name" text null, "last_name" text null, "address_1" text null, "address_2" text null, "city" text null, "country_code" text null, "province" text null, "postal_code" text null, "phone" text null, "metadata" jsonb null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), constraint "customer_address_pkey" primary key ("id"));' + 'create table if not exists "customer_address" ("id" text not null, "customer_id" text not null, "address_name" text null, "is_default_shipping" boolean not null default false, "is_default_billing" boolean not null default false, "company" text null, "first_name" text null, "last_name" text null, "address_1" text null, "address_2" text null, "city" text null, "country_code" text null, "province" text null, "postal_code" text null, "phone" text null, "metadata" jsonb null, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), constraint "customer_address_pkey" primary key ("id"));' ) this.addSql( 'create index if not exists "IDX_customer_address_customer_id" on "customer_address" ("customer_id");' ) + this.addSql( + 'create unique index "IDX_customer_address_unqiue_customer_billing" on "customer_address" ("customer_id") where "is_default_billing" = true;' + ) + this.addSql( + 'create unique index "IDX_customer_address_unique_customer_shipping" on "customer_address" ("customer_id") where "is_default_shipping" = true;' + ) // Customer Group table modifications this.addSql( @@ -62,13 +56,7 @@ export class Migration20240124154000 extends Migration { 'alter table "customer" drop constraint if exists "FK_8abe81b9aac151ae60bf507ad15";' ) this.addSql( - 'alter table "customer" add constraint "customer_default_shipping_address_id_foreign" foreign key ("default_shipping_address_id") references "customer_address" ("id") on update cascade on delete set null;' - ) - this.addSql( - 'alter table "customer" add constraint "customer_default_billing_address_id_foreign" foreign key ("default_billing_address_id") references "customer_address" ("id") on update cascade on delete set null;' - ) - this.addSql( - 'alter table "customer_address" add constraint "customer_address_customer_id_foreign" foreign key ("customer_id") references "customer" ("id") on update cascade;' + 'alter table "customer_address" add constraint "customer_address_customer_id_foreign" foreign key ("customer_id") references "customer" ("id") on update cascade on delete cascade;' ) this.addSql( 'alter table "customer_group_customer" add constraint "customer_group_customer_customer_group_id_foreign" foreign key ("customer_group_id") references "customer_group" ("id") on delete cascade;' diff --git a/packages/customer/src/models/address.ts b/packages/customer/src/models/address.ts index 2ed08e3f92..13aacd7c00 100644 --- a/packages/customer/src/models/address.ts +++ b/packages/customer/src/models/address.ts @@ -8,24 +8,46 @@ import { PrimaryKey, Property, ManyToOne, + Cascade, + Index, } from "@mikro-orm/core" import Customer from "./customer" type OptionalAddressProps = DAL.EntityDateColumns // TODO: To be revisited when more clear @Entity({ tableName: "customer_address" }) +@Index({ + name: "IDX_customer_address_unique_customer_shipping", + expression: + 'create unique index "IDX_customer_address_unique_customer_shipping" on "customer_address" ("customer_id") where "is_default_shipping" = true', +}) +@Index({ + name: "IDX_customer_address_unique_customer_billing", + expression: + 'create unique index "IDX_customer_address_unique_customer_billing" on "customer_address" ("customer_id") where "is_default_billing" = true', +}) export default class Address { [OptionalProps]: OptionalAddressProps @PrimaryKey({ columnType: "text" }) id!: string + @Property({ columnType: "text", nullable: true }) + address_name: string | null = null + + @Property({ columnType: "boolean", default: false }) + is_default_shipping: boolean = false + + @Property({ columnType: "boolean", default: false }) + is_default_billing: boolean = false + @Property({ columnType: "text" }) customer_id: string @ManyToOne(() => Customer, { fieldName: "customer_id", index: "IDX_customer_address_customer_id", + cascade: [Cascade.REMOVE, Cascade.PERSIST], }) customer: Customer diff --git a/packages/customer/src/models/customer.ts b/packages/customer/src/models/customer.ts index 0313c771dc..8c1e0a0cfe 100644 --- a/packages/customer/src/models/customer.ts +++ b/packages/customer/src/models/customer.ts @@ -22,8 +22,6 @@ import Address from "./address" type OptionalCustomerProps = | "groups" | "addresses" - | "default_shipping_address" - | "default_billing_address" | DAL.SoftDeletableEntityDateColumns @Entity({ tableName: "customer" }) @@ -52,26 +50,6 @@ export default class Customer { @Property({ columnType: "boolean", default: false }) has_account: boolean = false - @Index({ name: "IDX_customer_default_shipping_address_id" }) - @Property({ columnType: "text", nullable: true }) - default_shipping_address_id: string | null = null - - @ManyToOne(() => Address, { - fieldName: "default_shipping_address_id", - nullable: true, - }) - default_shipping_address: Address | null - - @Index({ name: "IDX_customer_default_billing_address_id" }) - @Property({ columnType: "text", nullable: true }) - default_billing_address_id: string | null = null - - @ManyToOne(() => Address, { - fieldName: "default_billing_address_id", - nullable: true, - }) - default_billing_address: Address | null - @Property({ columnType: "jsonb", nullable: true }) metadata: Record | null = null diff --git a/packages/customer/src/services/customer-module.ts b/packages/customer/src/services/customer-module.ts index d9d399de91..40c682e08a 100644 --- a/packages/customer/src/services/customer-module.ts +++ b/packages/customer/src/services/customer-module.ts @@ -415,6 +415,122 @@ export default class CustomerModuleService implements ICustomerModuleService { return { id: groupCustomers[0].id } } + async addAddresses( + addresses: CustomerTypes.CreateCustomerAddressDTO[], + sharedContext?: Context + ): Promise + async addAddresses( + address: CustomerTypes.CreateCustomerAddressDTO, + sharedContext?: Context + ): Promise + + @InjectTransactionManager("baseRepository_") + async addAddresses( + data: + | CustomerTypes.CreateCustomerAddressDTO + | CustomerTypes.CreateCustomerAddressDTO[], + @MedusaContext() sharedContext: Context = {} + ): Promise< + CustomerTypes.CustomerAddressDTO | CustomerTypes.CustomerAddressDTO[] + > { + const addresses = await this.addressService_.create( + Array.isArray(data) ? data : [data], + sharedContext + ) + + const serialized = await this.baseRepository_.serialize< + CustomerTypes.CustomerAddressDTO[] + >(addresses, { populate: true }) + + if (Array.isArray(data)) { + return serialized + } + + return serialized[0] + } + + async updateAddress( + addressId: string, + data: CustomerTypes.UpdateCustomerAddressDTO, + sharedContext?: Context + ): Promise + async updateAddress( + addressIds: string[], + data: CustomerTypes.UpdateCustomerAddressDTO, + sharedContext?: Context + ): Promise + async updateAddress( + selector: CustomerTypes.FilterableCustomerAddressProps, + data: CustomerTypes.UpdateCustomerAddressDTO, + sharedContext?: Context + ): Promise + + @InjectTransactionManager("baseRepository_") + async updateAddress( + addressIdOrSelector: + | string + | string[] + | CustomerTypes.FilterableCustomerAddressProps, + data: CustomerTypes.UpdateCustomerAddressDTO, + @MedusaContext() sharedContext: Context = {} + ) { + let updateData: CustomerTypes.UpdateCustomerAddressDTO[] = [] + if (isString(addressIdOrSelector)) { + updateData = [ + { + id: addressIdOrSelector, + ...data, + }, + ] + } else if (Array.isArray(addressIdOrSelector)) { + updateData = addressIdOrSelector.map((id) => ({ + id, + ...data, + })) + } else { + const ids = await this.addressService_.list( + addressIdOrSelector, + { select: ["id"] }, + sharedContext + ) + updateData = ids.map(({ id }) => ({ + id, + ...data, + })) + } + + const addresses = await this.addressService_.update( + updateData, + sharedContext + ) + const serialized = await this.baseRepository_.serialize< + CustomerTypes.CustomerAddressDTO[] + >(addresses, { populate: true }) + + if (isString(addressIdOrSelector)) { + return serialized[0] + } + + return serialized + } + + @InjectManager("baseRepository_") + async listAddresses( + filters?: CustomerTypes.FilterableCustomerAddressProps, + config?: FindConfig, + @MedusaContext() sharedContext: Context = {} + ): Promise { + const addresses = await this.addressService_.list( + filters, + config, + sharedContext + ) + + return await this.baseRepository_.serialize< + CustomerTypes.CustomerAddressDTO[] + >(addresses, { populate: true }) + } + async removeCustomerFromGroup( groupCustomerPair: CustomerTypes.GroupCustomerPair, sharedContext?: Context diff --git a/packages/types/src/customer/common.ts b/packages/types/src/customer/common.ts index a4ebbb69c4..0240c7e4c0 100644 --- a/packages/types/src/customer/common.ts +++ b/packages/types/src/customer/common.ts @@ -1,6 +1,50 @@ +import { AddressDTO } from "../address" import { BaseFilterable } from "../dal" import { OperatorMap } from "../dal/utils" -import { AddressDTO } from "../address" + +export interface CustomerAddressDTO { + id: string + address_name?: string + is_default_shipping: boolean + is_default_billing: boolean + customer_id: string + company?: string + first_name?: string + last_name?: string + address_1?: string + address_2?: string + city?: string + country_code?: string + province?: string + postal_code?: string + phone?: string + metadata?: Record + created_at: string + updated_at: string +} + +export interface FilterableCustomerAddressProps + extends BaseFilterable { + id?: string | string[] + address_name?: string | OperatorMap + is_default_shipping?: boolean | OperatorMap + is_default_billing?: boolean | OperatorMap + customer_id?: string | string[] + customer?: FilterableCustomerProps | string | string[] + company?: string | OperatorMap + first_name?: string | OperatorMap + last_name?: string | OperatorMap + address_1?: string | OperatorMap + address_2?: string | OperatorMap + city?: string | OperatorMap + country_code?: string | OperatorMap + province?: string | OperatorMap + postal_code?: string | OperatorMap + phone?: string | OperatorMap + metadata?: Record | OperatorMap> + created_at?: OperatorMap + updated_at?: OperatorMap +} export interface FilterableCustomerGroupProps extends BaseFilterable { @@ -69,9 +113,7 @@ export interface CustomerDTO { company_name?: string | null first_name?: string | null last_name?: string | null - default_billing_address?: AddressDTO - default_shipping_address?: AddressDTO - addresses?: AddressDTO[] + addresses?: CustomerAddressDTO[] phone?: string | null groups?: { id: string }[] metadata?: Record diff --git a/packages/types/src/customer/mutations.ts b/packages/types/src/customer/mutations.ts index 929b4f8734..a2275be9a2 100644 --- a/packages/types/src/customer/mutations.ts +++ b/packages/types/src/customer/mutations.ts @@ -1,3 +1,40 @@ +export interface CreateCustomerAddressDTO { + address_name?: string + is_default_shipping?: boolean + is_default_billing?: boolean + customer_id: string + company?: string + first_name?: string + last_name?: string + address_1?: string + address_2?: string + city?: string + country_code?: string + province?: string + postal_code?: string + phone?: string + metadata?: Record +} + +export interface UpdateCustomerAddressDTO { + id?: string + address_name?: string + is_default_shipping?: boolean + is_default_billing?: boolean + customer_id?: string + company?: string + first_name?: string + last_name?: string + address_1?: string + address_2?: string + city?: string + country_code?: string + province?: string + postal_code?: string + phone?: string + metadata?: Record +} + export interface CreateCustomerDTO { company_name?: string first_name?: string @@ -5,6 +42,7 @@ export interface CreateCustomerDTO { email?: string phone?: string created_by?: string + addresses?: Omit[] metadata?: Record } diff --git a/packages/types/src/customer/service.ts b/packages/types/src/customer/service.ts index cbbb873dcd..bd45ec1dcd 100644 --- a/packages/types/src/customer/service.ts +++ b/packages/types/src/customer/service.ts @@ -10,8 +10,15 @@ import { FilterableCustomerProps, FilterableCustomerGroupProps, GroupCustomerPair, + FilterableCustomerAddressProps, + CustomerAddressDTO, } from "./common" -import { CreateCustomerDTO, CreateCustomerGroupDTO } from "./mutations" +import { + CreateCustomerAddressDTO, + CreateCustomerDTO, + CreateCustomerGroupDTO, + UpdateCustomerAddressDTO, +} from "./mutations" export interface ICustomerModuleService extends IModuleService { retrieve( @@ -110,6 +117,37 @@ export interface ICustomerModuleService extends IModuleService { sharedContext?: Context ): Promise + addAddresses( + addresses: CreateCustomerAddressDTO[], + sharedContext?: Context + ): Promise + addAddresses( + address: CreateCustomerAddressDTO, + sharedContext?: Context + ): Promise + + updateAddress( + addressId: string, + data: UpdateCustomerAddressDTO, + sharedContext?: Context + ): Promise + updateAddress( + addressIds: string[], + data: UpdateCustomerAddressDTO, + sharedContext?: Context + ): Promise + updateAddress( + selector: FilterableCustomerAddressProps, + data: UpdateCustomerAddressDTO, + sharedContext?: Context + ): Promise + + listAddresses( + filters?: FilterableCustomerAddressProps, + config?: FindConfig, + sharedContext?: Context + ): Promise + listCustomerGroupRelations( filters?: FilterableCustomerGroupCustomerProps, config?: FindConfig,