From 6c72deb6133e4db0713096d23f1bebd5da093a04 Mon Sep 17 00:00:00 2001 From: Attila Fulop <1162360+fulopattila122@users.noreply.github.com> Date: Wed, 18 Oct 2023 18:22:58 +0300 Subject: [PATCH] Added the `default_billing_address_id` & `default_shipping_address_id` fields to the customer table --- Changelog.md | 10 ++- src/Contracts/Customer.php | 13 ++++ src/Models/Customer.php | 47 ++++++++++++- ...t_address_fields_to_the_customer_table.php | 31 +++++++++ tests/AddressDefaultsTest.php | 66 +++++++++++++++++++ 5 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 src/resources/database/migrations/2023_10_18_173544_add_default_address_fields_to_the_customer_table.php create mode 100644 tests/AddressDefaultsTest.php diff --git a/Changelog.md b/Changelog.md index c46633a..32eb51b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,11 +4,19 @@ ##### 2023-XX-YY - BC: Changed the `CustomerType` interface so that it now extends the `EnumInterface` -- BC: Added the `addresses()` method to the Customer interface +- BC: Added the following methods to the Customer interface: + - `addresses()` + - `hasDefaultBillingAddress()` + - `hasDefaultShippingAddress()` + - `defaultBillingAddress()` + - `defaultShippingAddress()` + - `setDefaultShippingAddress()` + - `setDefaultBillingAddress()` - BC: Changed the `Address::addresses()` method from `BelongsToMany` to `MorphToMany` - the two are very compatible, but aren't the same - Dropped the `customer_addresses` table in favor of the Address module's `model()` polymorphic properties (migration included) - Dropped Laravel 9 support - Dropped PHP 8.0 support +- Added the `default_billing_address_id` and the `default_shipping_address_id` fields to the customer table/model - Added the registration of `customer` to the relation morph map - Changed minimum version requirements to: - Enum v4.1 diff --git a/src/Contracts/Customer.php b/src/Contracts/Customer.php index 5bff9b6..efc29dc 100644 --- a/src/Contracts/Customer.php +++ b/src/Contracts/Customer.php @@ -14,6 +14,7 @@ namespace Konekt\Customer\Contracts; use Illuminate\Database\Eloquent\Relations\MorphMany; +use Konekt\Address\Contracts\Address; interface Customer { @@ -23,4 +24,16 @@ interface Customer public function getName(): string; public function addresses(): MorphMany; + + public function hasDefaultBillingAddress(): bool; + + public function hasDefaultShippingAddress(): bool; + + public function defaultBillingAddress(): ?Address; + + public function defaultShippingAddress(): ?Address; + + public function setDefaultShippingAddress(Address|int|null $address): void; + + public function setDefaultBillingAddress(Address|int|null $address): void; } diff --git a/src/Models/Customer.php b/src/Models/Customer.php index d468738..8d9883f 100644 --- a/src/Models/Customer.php +++ b/src/Models/Customer.php @@ -14,8 +14,10 @@ namespace Konekt\Customer\Models; use Carbon\Carbon; +use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\MorphMany; +use Konekt\Address\Contracts\Address; use Konekt\Address\Models\AddressProxy; use Konekt\Customer\Contracts\Customer as CustomerContract; use Konekt\Customer\Events\CustomerTypeWasChanged; @@ -39,6 +41,12 @@ * @property bool $is_active * @property float $ltv * @property Carbon|null $last_purchase_at + * @property int|null $default_billing_address_id + * @property int|null $default_shipping_address_id + * + * @property-read Collection|Address[] $addresses + * @property-read Address|null $default_billing_address + * @property-read Address|null $default_shipping_address * * @method static Customer create(array $attributes) */ @@ -74,6 +82,38 @@ public function getName(): string return sprintf('%s %s', $this->firstname, $this->lastname); } + public function hasDefaultBillingAddress(): bool + { + return null !== $this->default_billing_address_id; + } + + public function hasDefaultShippingAddress(): bool + { + return null !== $this->default_shipping_address_id; + } + + public function defaultBillingAddress(): ?Address + { + return $this->default_billing_address; + } + + public function defaultShippingAddress(): ?Address + { + return $this->default_shipping_address; + } + + public function setDefaultShippingAddress(Address|int|null $address): void + { + $value = $address instanceof Address ? $address->id : $address; + $this->update(['default_shipping_address_id' => $value]); + } + + public function setDefaultBillingAddress(Address|int|null $address): void + { + $value = $address instanceof Address ? $address->id : $address; + $this->update(['default_billing_address_id' => $value]); + } + public function addresses(): MorphMany { return $this->morphMany(AddressProxy::modelClass(), 'model'); @@ -88,12 +128,15 @@ protected static function boot() { parent::boot(); + static::resolveRelationUsing('default_shipping_address', fn($model) => $model->belongsTo(AddressProxy::modelClass(), 'default_shipping_address_id')); + static::resolveRelationUsing('default_billing_address', fn($model) => $model->belongsTo(AddressProxy::modelClass(), 'default_billing_address_id')); + static::updated(function ($customer) { - if ($customer->original['type'] != $customer->type) { + if ($customer->original['type'] ?? null !== $customer->type) { event( new CustomerTypeWasChanged( $customer, - CustomerTypeProxy::create($customer->original['type']), + CustomerTypeProxy::create($customer->original['type'] ?? null), $customer->original ) ); diff --git a/src/resources/database/migrations/2023_10_18_173544_add_default_address_fields_to_the_customer_table.php b/src/resources/database/migrations/2023_10_18_173544_add_default_address_fields_to_the_customer_table.php new file mode 100644 index 0000000..97328c8 --- /dev/null +++ b/src/resources/database/migrations/2023_10_18_173544_add_default_address_fields_to_the_customer_table.php @@ -0,0 +1,31 @@ +unsignedBigInteger('default_billing_address_id')->nullable(); + $table->unsignedBigInteger('default_shipping_address_id')->nullable(); + + $table->foreign('default_billing_address_id')->references('id')->on('addresses')->nullOnDelete(); + $table->foreign('default_shipping_address_id')->references('id')->on('addresses')->nullOnDelete(); + }); + } + + public function down(): void + { + Schema::table('customers', function (Blueprint $table) { + $table->dropForeign('customers_default_billing_address_id_foreign'); + $table->dropForeign('customers_default_shipping_address_id_foreign'); + + $table->dropColumn('default_billing_address_id'); + $table->dropColumn('default_shipping_address_id'); + }); + } +}; diff --git a/tests/AddressDefaultsTest.php b/tests/AddressDefaultsTest.php new file mode 100644 index 0000000..c2b134b --- /dev/null +++ b/tests/AddressDefaultsTest.php @@ -0,0 +1,66 @@ +assertFalse($customer->hasDefaultBillingAddress()); + $this->assertFalse($customer->hasDefaultShippingAddress()); + + $this->assertNull($customer->defaultBillingAddress()); + $this->assertNull($customer->defaultShippingAddress()); + + $this->assertNull($customer->default_billing_address_id); + $this->assertNull($customer->default_shipping_address_id); + + $this->assertNull($customer->default_billing_address); + $this->assertNull($customer->default_shipping_address); + } + + /** @test */ + public function default_shipping_address_can_be_set() + { + $customer = Customer::create([])->fresh(); + $address = Address::create(['name' => 'Xyz', 'country_id' => 'UK', 'address' => 'asdqwe']); + $customer->setDefaultShippingAddress($address); + + $this->assertTrue($customer->hasDefaultShippingAddress()); + $this->assertInstanceOf(Address::class, $customer->defaultShippingAddress()); + $this->assertEquals($address->id, $customer->default_shipping_address_id); + $this->assertInstanceOf(Address::class, $customer->default_shipping_address); + } + + /** @test */ + public function default_billing_address_can_be_set() + { + $customer = Customer::create([])->fresh(); + $address = Address::create(['name' => 'Xyz', 'country_id' => 'UK', 'address' => 'asdqwe']); + $customer->setDefaultBillingAddress($address); + + $this->assertTrue($customer->hasDefaultBillingAddress()); + $this->assertInstanceOf(Address::class, $customer->defaultBillingAddress()); + $this->assertEquals($address->id, $customer->default_billing_address_id); + $this->assertInstanceOf(Address::class, $customer->default_billing_address); + } +}