Skip to content

Commit

Permalink
Merge pull request #3 from artkonekt/feat-customer-purchases
Browse files Browse the repository at this point in the history
Added Customer Purchases
  • Loading branch information
molnarerwin authored Nov 22, 2024
2 parents a36b259 + 6c439e9 commit 4d7fb75
Show file tree
Hide file tree
Showing 10 changed files with 321 additions and 1 deletion.
5 changes: 5 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Customer Module Changelog

## Unreleased
##### 2024-XX-YY

- Added CustomerPurchases

## 3.0.0
##### 2024-04-25

Expand Down
15 changes: 15 additions & 0 deletions src/Contracts/CustomerPurchase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Konekt\Customer\Contracts;

use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo;

interface CustomerPurchase
{
public function purchasable(): MorphTo;

public function customer(): BelongsTo;
}
6 changes: 6 additions & 0 deletions src/Models/Customer.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Konekt\Address\Contracts\Address;
use Konekt\Address\Models\AddressProxy;
Expand Down Expand Up @@ -119,6 +120,11 @@ public function addresses(): MorphMany
return $this->morphMany(AddressProxy::modelClass(), 'model');
}

public function purchases(): HasMany
{
return $this->hasMany(CustomerPurchaseProxy::modelClass());
}

protected function getNameAttribute()
{
return $this->getName();
Expand Down
42 changes: 42 additions & 0 deletions src/Models/CustomerPurchase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace Konekt\Customer\Models;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Konekt\Customer\Contracts\CustomerPurchase as CustomerPurchaseContract;

/**
* @property int $id
* @property int $customer_id
* @property Carbon $purchase_date
* @property float $purchase_value
* @property string $currency
* @property int $purchasable_id
* @property string $purchasable_type
*
* @property-read Model $purchasable
* @property-read Customer $customer
*/
class CustomerPurchase extends Model implements CustomerPurchaseContract
{
protected $guarded = ['id', 'created_at', 'updated_at'];

protected $casts = [
'purchase_date' => 'date',
];

public function purchasable(): MorphTo
{
return $this->morphTo();
}

public function customer(): BelongsTo
{
return $this->belongsTo(CustomerProxy::modelClass());
}
}
11 changes: 11 additions & 0 deletions src/Models/CustomerPurchaseProxy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Konekt\Customer\Models;

use Konekt\Concord\Proxies\ModelProxy;

class CustomerPurchaseProxy extends ModelProxy
{
}
4 changes: 3 additions & 1 deletion src/Providers/ModuleServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
use Konekt\Concord\BaseModuleServiceProvider;
use Konekt\Customer\Models\Customer;
use Konekt\Customer\Models\CustomerProxy;
use Konekt\Customer\Models\CustomerPurchase;
use Konekt\Customer\Models\CustomerType;

class ModuleServiceProvider extends BaseModuleServiceProvider
{
protected $models = [
Customer::class
Customer::class,
CustomerPurchase::class,
];

protected $enums = [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class () extends Migration {
public function up(): void
{
Schema::create('customer_purchases', function (Blueprint $table) {
$table->id();
$table->integer('customer_id')->unsigned();
$table->date('purchase_date')->nullable();
$table->decimal('purchase_value', 15, 4)->nullable();
$table->char('currency', 3)->nullable();
$table->morphs('purchasable');
$table->timestamps();

$table->foreign('customer_id')
->references('id')
->on('customers')
->onDelete('cascade');
});
}

public function down(): void
{
Schema::dropIfExists('customer_purchases');
}
};
185 changes: 185 additions & 0 deletions tests/CustomerPurchaseTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
<?php

declare(strict_types=1);

use Konekt\Customer\Models\CustomerProxy;
use Konekt\Customer\Models\CustomerPurchase;
use Konekt\Customer\Models\CustomerPurchaseProxy;
use Konekt\Customer\Tests\Dummies\Order;
use Konekt\Customer\Tests\TestCase;

class CustomerPurchaseTest extends TestCase
{
/**
* @test
*/
public function customer_purchase_can_be_created_with_minimal_data(): void
{
$order = Order::create([
'number' => '70H-0WJB-2OD6'
]);

$customer = CustomerProxy::create([])->fresh();

$customerPurchase = CustomerPurchaseProxy::create([
'customer_id' => $customer->id,
'purchasable_id' => $order->id,
'purchasable_type' => Order::class,
])->fresh();

$this->assertTrue($order->is($customerPurchase->purchasable));
$this->assertTrue($customer->is($customerPurchase->customer));
}

/**
* @test
*/
public function customer_purchase_can_be_created_with_full_data(): void
{
$order = Order::create([
'number' => '70H-0WJB-2OD6'
]);

$customer = CustomerProxy::create([])->fresh();

$customerPurchase = CustomerPurchaseProxy::create([
'customer_id' => $customer->id,
'purchase_date' => '2024-11-21',
'purchase_value' => 89.62,
'currency' => 'EUR',
'purchasable_id' => $order->id,
'purchasable_type' => Order::class,
])->fresh();

$this->assertTrue($order->is($customerPurchase->purchasable));
$this->assertTrue($customer->is($customerPurchase->customer));
$this->assertEquals(89.62, $customerPurchase->purchase_value);
$this->assertEquals('EUR', $customerPurchase->currency);
$this->assertEquals('2024-11-21', $customerPurchase->purchase_date->toDateString());
}

/**
* @test
*/
public function customer_purchase_can_be_updated_with_full_data(): void
{
$order = Order::create([
'number' => '70H-0WJB-2OD6'
]);

$order2 = Order::create([
'number' => '50M3-0RD3R-NUMB3R'
]);

$customer = CustomerProxy::create([])->fresh();

$customer2 = CustomerProxy::create([])->fresh();

$customerPurchase = CustomerPurchaseProxy::create([
'customer_id' => $customer->id,
'purchase_date' => '2024-11-21',
'purchase_value' => 89.62,
'currency' => 'EUR',
'purchasable_id' => $order->id,
'purchasable_type' => Order::class,
])->fresh();

$customerPurchase->update([
'customer_id' => $customer2->id,
'purchase_date' => '2001-01-06',
'purchase_value' => 2001.06,
'currency' => 'HUF',
'purchasable_id' => $order2->id,
'purchasable_type' => Order::class,
]);

$updatedCustomerPurchase = $customerPurchase->fresh();

$this->assertFalse($order->is($updatedCustomerPurchase->purchasable));
$this->assertTrue($order2->is($updatedCustomerPurchase->purchasable));

$this->assertFalse($customer->is($updatedCustomerPurchase->customer));
$this->assertTrue($customer2->is($updatedCustomerPurchase->customer));

$this->assertEquals(2001.06, $updatedCustomerPurchase->purchase_value);
$this->assertEquals('HUF', $updatedCustomerPurchase->currency);
$this->assertEquals('2001-01-06', $updatedCustomerPurchase->purchase_date->toDateString());
}

/**
* @test
*/
public function customer_purchase_can_be_deleted(): void
{
$order = Order::create([
'number' => '50M3-0RD3R-NUMB3R'
]);

$customer = CustomerProxy::create([])->fresh();

$customerPurchase = CustomerPurchaseProxy::create([
'customer_id' => $customer->id,
'purchase_date' => '2024-11-21',
'purchase_value' => 89.62,
'currency' => 'EUR',
'purchasable_id' => $order->id,
'purchasable_type' => Order::class,
])->fresh();

$customerPurchaseId = $customerPurchase->id;

$customerPurchase->delete();

$this->assertNull(CustomerPurchaseProxy::find($customerPurchaseId));
}

/**
* @test
*/
public function purchases_of_a_customer_can_be_retrieved(): void
{
$order = Order::create([
'number' => '50M3-0RD3R-NUMB3R'
]);

$order2 = Order::create([
'number' => 'WH47-H4V3-Y0U-B0U6H7'
]);

$customer = CustomerProxy::create([])->fresh();

$customerPurchase1 = CustomerPurchaseProxy::create([
'customer_id' => $customer->id,
'purchase_date' => '2024-11-21',
'purchase_value' => 89.62,
'currency' => 'EUR',
'purchasable_id' => $order->id,
'purchasable_type' => Order::class,
])->fresh();

$customerPurchase2 = CustomerPurchaseProxy::create([
'customer_id' => $customer->id,
'purchase_date' => '2023-12-09',
'purchase_value' => 10000000.94,
'currency' => 'HUF',
'purchasable_id' => $order2->id,
'purchasable_type' => Order::class,
])->fresh();

$this->assertEquals(2, $customer->purchases->count());

$this->assertTrue($customer->purchases->every(function ($purchase) {
return $purchase instanceof CustomerPurchase;
}));

$this->assertTrue($customer->purchases->map->purchasable->every(function ($order) {
return $order instanceof Order;
}));

$this->assertTrue($customer->purchases->pluck('purchase_value')->contains(89.62));
$this->assertTrue($customer->purchases->pluck('purchase_value')->contains(10000000.94));

$this->assertTrue($customer->purchases->map->purchasable->pluck('number')->contains('50M3-0RD3R-NUMB3R'));
$this->assertTrue($customer->purchases->map->purchasable->pluck('number')->contains('WH47-H4V3-Y0U-B0U6H7'));
}
}
12 changes: 12 additions & 0 deletions tests/Dummies/Order.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Konekt\Customer\Tests\Dummies;

use Illuminate\Database\Eloquent\Model;

class Order extends Model
{
protected $guarded = ['id', 'created_at', 'updated_at'];
}
10 changes: 10 additions & 0 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

namespace Konekt\Customer\Tests;

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Konekt\Address\Providers\ModuleServiceProvider as AddressModule;
use Konekt\Concord\ConcordServiceProvider;
use Konekt\Concord\Contracts\Concord;
Expand Down Expand Up @@ -83,6 +85,14 @@ protected function setUpDatabase($app)
$this->artisan('migrate:reset');
$this->loadLaravelMigrations();
$this->artisan('migrate', ['--force' => true]);

if (!Schema::hasTable('orders')) {
$app['db']->connection()->getSchemaBuilder()->create('orders', function (Blueprint $table) {
$table->increments('id');
$table->string('number', 32);
$table->timestamps();
});
}
}

/**
Expand Down

0 comments on commit 4d7fb75

Please sign in to comment.