Skip to content

Commit

Permalink
Merge pull request #10 from juliomotol/fix/model-with-money-and-relat…
Browse files Browse the repository at this point in the history
…ed-currency

[Bug] Saving a record where currency is in related model
  • Loading branch information
andriichuk authored Oct 17, 2020
2 parents c7ef435 + 89ecf55 commit 15302fb
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 4 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ class Transaction extends Model implements HasMoneyWithCurrencyInterface
}
}
```
> If the currency is in a related model, just return an empty string (`''`) in `getCurrencyColumnFor()`.
#### Money to Currencies columns mapping

Expand Down
8 changes: 4 additions & 4 deletions src/Casts/MoneyCast.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function set($model, $key, $value, $attributes)
? $value
: Laracash::factory()->make($value, $this->resolveCurrencyColumn($model, $key, $attributes));

if ($this->hasCurrencyColumn($model)) {
if ($this->hasCurrencyColumn($model, $key)) {
return [
$key => $money->getAmount(),
$model->getCurrencyColumnFor($key) => $money->getCurrency()->getCode(),
Expand All @@ -62,7 +62,7 @@ public function set($model, $key, $value, $attributes)

private function resolveCurrencyColumn(Model $model, string $key, $attributes): ?Currency
{
if (!$this->hasCurrencyColumn($model)) {
if (!$this->hasCurrencyColumn($model, $key)) {
return null;
}

Expand All @@ -75,8 +75,8 @@ private function resolveCurrencyColumn(Model $model, string $key, $attributes):
);
}

private function hasCurrencyColumn(Model $model): bool
private function hasCurrencyColumn(Model $model, $key): bool
{
return $model instanceof HasMoneyWithCurrencyInterface;
return $model instanceof HasMoneyWithCurrencyInterface && $model->getCurrencyColumnFor($key);
}
}
84 changes: 84 additions & 0 deletions tests/Feature/ModelWithMoneyAndRelationCurrencyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

declare(strict_types=1);

namespace Andriichuk\Laracash\Tests\Feature;

use Andriichuk\Laracash\Tests\BaseTestCase;
use Andriichuk\Laracash\Tests\Models\Order;
use Illuminate\Database\Schema\Blueprint;
use Money\Money;

/**
* Class ModelWithOneMoneyToOneCurrencyColumnTest
*
* @author Serhii Andriichuk <andriichuk29@gmail.com>
*/
class ModelWithMoneyAndRelationCurrencyTest extends BaseTestCase
{
protected function setUp(): void
{
parent::setUp();

$this->createOrdersTable();
$this->createOrderItemsTable();
}

/**
* @dataProvider moneyCasesProvider
*
* @param mixed $price
*/
public function testMoneyCasts(array $options, Money $expected): void
{
$orderModel = Order::create([
'total_price' => $options['price'],
'currency' => $options['currency'],
]);

$orderModel->items()->create([
'unit_price' => $options['price']
]);

$this->assertEquals($expected, $orderModel->total_price);
$this->assertEquals($expected, $orderModel->items()->first()->unit_price);
}

public function moneyCasesProvider(): array
{
return [
'from scalar' => [
[
'price' => 1000,
'currency' => 'USD',
],
Money::USD(1000),
],
'from native Money object' => [
[
'price' => Money::USD(1000),
'currency' => 'UAH',
],
Money::USD(1000),
]
];
}

public function createOrdersTable(): void
{
$this->app['db']->connection()->getSchemaBuilder()->create('orders', function (Blueprint $table) {
$table->increments('id');
$table->string('total_price');
$table->char('currency', 3);
});
}

public function createOrderItemsTable(): void
{
$this->app['db']->connection()->getSchemaBuilder()->create('order_items', function (Blueprint $table) {
$table->increments('id');
$table->foreignId('order_id')->constrained();
$table->string('unit_price');
});
}
}
33 changes: 33 additions & 0 deletions tests/Models/Order.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Andriichuk\Laracash\Tests\Models;

use Andriichuk\Laracash\Casts\CurrencyCast;
use Andriichuk\Laracash\Casts\MoneyCast;
use Andriichuk\Laracash\Model\HasCurrency;
use Andriichuk\Laracash\Model\HasCurrencyInterface;
use Andriichuk\Laracash\Model\HasMoneyWithCurrency;
use Andriichuk\Laracash\Model\HasMoneyWithCurrencyInterface;
use Illuminate\Database\Eloquent\Model;

class Order extends Model implements HasMoneyWithCurrencyInterface, HasCurrencyInterface
{
use HasMoneyWithCurrency;
use HasCurrency;

protected $table = 'orders';

public $timestamps = false;

protected $fillable = ['total_price', 'currency'];

protected $casts = [
'total_price' => MoneyCast::class,
'currency' => CurrencyCast::class
];

public function items()
{
return $this->hasMany(OrderItem::class);
}
}
42 changes: 42 additions & 0 deletions tests/Models/OrderItem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace Andriichuk\Laracash\Tests\Models;

use Andriichuk\Laracash\Casts\MoneyCast;
use Andriichuk\Laracash\Model\HasCurrency;
use Andriichuk\Laracash\Model\HasCurrencyInterface;
use Andriichuk\Laracash\Model\HasMoneyWithCurrency;
use Andriichuk\Laracash\Model\HasMoneyWithCurrencyInterface;
use Illuminate\Database\Eloquent\Model;
use Money\Currency;

class OrderItem extends Model implements HasMoneyWithCurrencyInterface, HasCurrencyInterface
{
use HasMoneyWithCurrency;
use HasCurrency;

protected $table = 'order_items';

public $timestamps = false;

protected $fillable = ['unit_price'];

protected $casts = [
'unit_price' => MoneyCast::class,
];

public function order()
{
return $this->belongsTo(Order::class);
}

public function getDefaultCurrencyFor(string $field): Currency
{
return $this->order->currency;
}

public function getCurrencyColumnFor(string $field): string
{
return '';
}
}

0 comments on commit 15302fb

Please sign in to comment.