2009-05-05 10:10:51 +02:00
|
|
|
<?php
|
2015-08-30 07:02:55 +02:00
|
|
|
|
2016-10-14 03:30:05 +02:00
|
|
|
namespace SilverStripe\ORM\Tests;
|
2016-06-15 06:03:16 +02:00
|
|
|
|
|
|
|
use SilverStripe\ORM\FieldType\DBMoney;
|
|
|
|
use SilverStripe\ORM\DataObject;
|
|
|
|
use SilverStripe\ORM\DB;
|
2016-08-19 00:51:35 +02:00
|
|
|
use SilverStripe\Dev\SapphireTest;
|
|
|
|
use SilverStripe\i18n\i18n;
|
2017-01-26 05:20:08 +01:00
|
|
|
|
2016-12-16 05:34:21 +01:00
|
|
|
class DBMoneyTest extends SapphireTest
|
|
|
|
{
|
|
|
|
|
|
|
|
protected static $fixture_file = 'DBMoneyTest.yml';
|
|
|
|
|
2020-04-20 19:58:09 +02:00
|
|
|
protected static $extra_dataobjects = [
|
2016-12-16 05:34:21 +01:00
|
|
|
DBMoneyTest\TestObject::class,
|
|
|
|
DBMoneyTest\TestObjectSubclass::class,
|
2020-04-20 19:58:09 +02:00
|
|
|
];
|
2016-12-16 05:34:21 +01:00
|
|
|
|
|
|
|
public function testMoneyFieldsReturnedAsObjects()
|
|
|
|
{
|
|
|
|
$obj = $this->objFromFixture(DBMoneyTest\TestObject::class, 'test1');
|
|
|
|
$this->assertInstanceOf(DBMoney::class, $obj->MyMoney);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testLoadFromFixture()
|
|
|
|
{
|
|
|
|
$obj = $this->objFromFixture(DBMoneyTest\TestObject::class, 'test1');
|
|
|
|
|
|
|
|
$this->assertInstanceOf(DBMoney::class, $obj->MyMoney);
|
|
|
|
$this->assertEquals($obj->MyMoney->getCurrency(), 'EUR');
|
|
|
|
$this->assertEquals($obj->MyMoney->getAmount(), 1.23);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testDataObjectChangedFields()
|
|
|
|
{
|
|
|
|
$obj = $this->objFromFixture(DBMoneyTest\TestObject::class, 'test1');
|
|
|
|
|
|
|
|
// Without changes
|
|
|
|
$curr = $obj->obj('MyMoney');
|
|
|
|
$changed = $obj->getChangedFields();
|
|
|
|
$this->assertNotContains('MyMoney', array_keys($changed));
|
|
|
|
|
|
|
|
// With changes
|
|
|
|
$this->assertInstanceOf(DBMoney::class, $obj->MyMoney);
|
|
|
|
$obj->MyMoney->setAmount(99);
|
|
|
|
$changed = $obj->getChangedFields();
|
|
|
|
$this->assertContains('MyMoney', array_keys($changed), 'Field is detected as changed');
|
|
|
|
$this->assertEquals(2, $changed['MyMoney']['level'], 'Correct change level');
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testCanOverwriteSettersWithNull()
|
|
|
|
{
|
|
|
|
$obj = new DBMoneyTest\TestObject();
|
|
|
|
|
|
|
|
$m1 = new DBMoney();
|
|
|
|
$m1->setAmount(987.65);
|
|
|
|
$m1->setCurrency('USD');
|
|
|
|
$obj->MyMoney = $m1;
|
|
|
|
$obj->write();
|
|
|
|
|
|
|
|
$m2 = new DBMoney();
|
|
|
|
$m2->setAmount(null);
|
|
|
|
$m2->setCurrency(null);
|
|
|
|
$obj->MyMoney = $m2;
|
|
|
|
$obj->write();
|
|
|
|
|
|
|
|
$moneyTest = DataObject::get_by_id(DBMoneyTest\TestObject::class, $obj->ID);
|
|
|
|
$this->assertTrue($moneyTest instanceof DBMoneyTest\TestObject);
|
|
|
|
$this->assertEquals('', $moneyTest->MyMoneyCurrency);
|
|
|
|
$this->assertEquals(0.0000, $moneyTest->MyMoneyAmount);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testIsChanged()
|
|
|
|
{
|
|
|
|
$obj1 = $this->objFromFixture(DBMoneyTest\TestObject::class, 'test1');
|
|
|
|
$this->assertFalse($obj1->isChanged());
|
|
|
|
$this->assertFalse($obj1->isChanged('MyMoney'));
|
|
|
|
|
|
|
|
// modify non-db field
|
|
|
|
$m1 = new DBMoney();
|
|
|
|
$m1->setAmount(500);
|
|
|
|
$m1->setCurrency('NZD');
|
|
|
|
$obj1->NonDBMoneyField = $m1;
|
|
|
|
$this->assertFalse($obj1->isChanged()); // Because only detects DB fields
|
|
|
|
$this->assertTrue($obj1->isChanged('NonDBMoneyField')); // Allow change detection to non-db fields explicitly named
|
|
|
|
|
|
|
|
// Modify db field
|
|
|
|
$obj2 = $this->objFromFixture(DBMoneyTest\TestObject::class, 'test2');
|
|
|
|
$m2 = new DBMoney();
|
|
|
|
$m2->setAmount(500);
|
|
|
|
$m2->setCurrency('NZD');
|
|
|
|
$obj2->MyMoney = $m2;
|
|
|
|
$this->assertTrue($obj2->isChanged()); // Detects change to DB field
|
|
|
|
$this->assertTrue($obj2->ischanged('MyMoney'));
|
|
|
|
|
|
|
|
// Modify sub-fields
|
|
|
|
$obj3 = $this->objFromFixture(DBMoneyTest\TestObject::class, 'test3');
|
|
|
|
$obj3->MyMoneyCurrency = 'USD';
|
|
|
|
$this->assertTrue($obj3->isChanged()); // Detects change to DB field
|
|
|
|
$this->assertTrue($obj3->ischanged('MyMoneyCurrency'));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Write a Money object to the database, then re-read it to ensure it
|
|
|
|
* is re-read properly.
|
|
|
|
*/
|
|
|
|
public function testGettingWrittenDataObject()
|
|
|
|
{
|
|
|
|
$local = i18n::get_locale();
|
|
|
|
//make sure that the $ amount is not prefixed by US$, as it would be in non-US locale
|
|
|
|
i18n::set_locale('en_US');
|
|
|
|
|
|
|
|
$obj = new DBMoneyTest\TestObject();
|
|
|
|
|
|
|
|
$m = new DBMoney();
|
|
|
|
$m->setAmount(987.65);
|
|
|
|
$m->setCurrency('USD');
|
|
|
|
$obj->MyMoney = $m;
|
|
|
|
$this->assertEquals(
|
|
|
|
"$987.65",
|
|
|
|
$obj->MyMoney->Nice(),
|
|
|
|
"Money field not added to data object properly when read prior to first writing the record."
|
|
|
|
);
|
|
|
|
|
|
|
|
$objID = $obj->write();
|
|
|
|
|
|
|
|
$moneyTest = DataObject::get_by_id(DBMoneyTest\TestObject::class, $objID);
|
|
|
|
$this->assertTrue($moneyTest instanceof DBMoneyTest\TestObject);
|
|
|
|
$this->assertEquals('USD', $moneyTest->MyMoneyCurrency);
|
|
|
|
$this->assertEquals(987.65, $moneyTest->MyMoneyAmount);
|
|
|
|
$this->assertEquals(
|
|
|
|
"$987.65",
|
|
|
|
$moneyTest->MyMoney->Nice(),
|
|
|
|
"Money field not added to data object properly when read."
|
|
|
|
);
|
|
|
|
|
|
|
|
i18n::set_locale($local);
|
|
|
|
}
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
/**
|
|
|
|
* Covers Nice() and getValue()
|
|
|
|
*/
|
2016-12-16 05:34:21 +01:00
|
|
|
public function testToCurrency()
|
|
|
|
{
|
|
|
|
$USD = new DBMoney();
|
2017-01-26 05:20:08 +01:00
|
|
|
$USD->setValue([
|
|
|
|
'Currency' => 'USD',
|
|
|
|
'Amount' => 53292.18,
|
|
|
|
]);
|
2016-12-16 05:34:21 +01:00
|
|
|
$USD->setLocale('en_US');
|
2017-01-26 05:20:08 +01:00
|
|
|
$this->assertSame('53292.18 USD', $USD->getValue());
|
2016-12-16 05:34:21 +01:00
|
|
|
$this->assertSame('$53,292.18', $USD->Nice());
|
2017-01-26 05:20:08 +01:00
|
|
|
|
|
|
|
// USD in de locale
|
|
|
|
$USD->setLocale('de_DE');
|
|
|
|
$this->assertSame($this->clean('53.292,18 $'), $this->clean($USD->Nice()));
|
2016-12-16 05:34:21 +01:00
|
|
|
}
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
public function testGetSymbol()
|
2016-12-16 05:34:21 +01:00
|
|
|
{
|
2017-01-26 05:20:08 +01:00
|
|
|
// Swedish kroner
|
2016-12-16 05:34:21 +01:00
|
|
|
$SKR = new DBMoney();
|
2017-01-26 05:20:08 +01:00
|
|
|
$SKR->setValue([
|
|
|
|
'Currency' => 'SEK',
|
2016-12-16 05:34:21 +01:00
|
|
|
'Amount' => 3.44
|
2017-01-26 05:20:08 +01:00
|
|
|
]);
|
|
|
|
$SKR->setLocale('sv');
|
|
|
|
$this->assertSame('kr', $SKR->getSymbol());
|
2016-12-16 05:34:21 +01:00
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
// EU currency
|
2016-12-16 05:34:21 +01:00
|
|
|
$EUR = new DBMoney();
|
2017-01-26 05:20:08 +01:00
|
|
|
$EUR->setValue([
|
2016-12-16 05:34:21 +01:00
|
|
|
'Currency' => 'EUR',
|
|
|
|
'Amount' => 3.44
|
2017-01-26 05:20:08 +01:00
|
|
|
]);
|
2016-12-16 05:34:21 +01:00
|
|
|
$EUR->setLocale('de_DE');
|
|
|
|
$this->assertSame('€', $EUR->getSymbol());
|
|
|
|
|
2017-01-26 05:20:08 +01:00
|
|
|
// Where locale doesn't match currency
|
|
|
|
$USD = new DBMoney();
|
|
|
|
$USD->setValue([
|
|
|
|
'Currency' => 'USD',
|
|
|
|
'Amount' => 3.44,
|
|
|
|
]);
|
|
|
|
$USD->setLocale('de_DE');
|
|
|
|
$this->assertSame('$', $USD->getSymbol());
|
2016-12-16 05:34:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testSetValueAsArray()
|
|
|
|
{
|
|
|
|
$m = new DBMoney();
|
2017-01-26 05:20:08 +01:00
|
|
|
$m->setValue([
|
2016-12-16 05:34:21 +01:00
|
|
|
'Currency' => 'EUR',
|
|
|
|
'Amount' => 3.44
|
2017-01-26 05:20:08 +01:00
|
|
|
]);
|
2016-12-16 05:34:21 +01:00
|
|
|
$this->assertEquals(
|
|
|
|
$m->getCurrency(),
|
|
|
|
'EUR'
|
|
|
|
);
|
|
|
|
$this->assertEquals(
|
|
|
|
$m->getAmount(),
|
|
|
|
3.44
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testSetValueAsMoney()
|
|
|
|
{
|
|
|
|
$m1 = new DBMoney();
|
2017-01-26 05:20:08 +01:00
|
|
|
$m1->setValue([
|
2016-12-16 05:34:21 +01:00
|
|
|
'Currency' => 'EUR',
|
|
|
|
'Amount' => 3.44
|
2017-01-26 05:20:08 +01:00
|
|
|
]);
|
2016-12-16 05:34:21 +01:00
|
|
|
$m2 = new DBMoney();
|
|
|
|
$m2->setValue($m1);
|
|
|
|
$this->assertEquals(
|
|
|
|
$m2->getCurrency(),
|
|
|
|
'EUR'
|
|
|
|
);
|
|
|
|
$this->assertEquals(
|
|
|
|
$m2->getAmount(),
|
|
|
|
3.44
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testExists()
|
|
|
|
{
|
|
|
|
$m1 = new DBMoney();
|
|
|
|
$this->assertFalse($m1->exists());
|
|
|
|
|
|
|
|
$m2 = new DBMoney();
|
2017-01-26 05:20:08 +01:00
|
|
|
$m2->setValue([
|
2016-12-16 05:34:21 +01:00
|
|
|
'Currency' => 'EUR',
|
|
|
|
'Amount' => 3.44
|
2017-01-26 05:20:08 +01:00
|
|
|
]);
|
2016-12-16 05:34:21 +01:00
|
|
|
$this->assertTrue($m2->exists());
|
|
|
|
|
|
|
|
$m3 = new DBMoney();
|
2017-01-26 05:20:08 +01:00
|
|
|
$m3->setValue([
|
2016-12-16 05:34:21 +01:00
|
|
|
'Currency' => 'EUR',
|
|
|
|
'Amount' => 0
|
2017-01-26 05:20:08 +01:00
|
|
|
]);
|
2016-12-16 05:34:21 +01:00
|
|
|
$this->assertTrue($m3->exists());
|
2017-01-26 05:20:08 +01:00
|
|
|
|
|
|
|
$m4 = new DBMoney();
|
|
|
|
$m4->setValue([
|
|
|
|
'Currency' => 'EUR',
|
|
|
|
'Amount' => null,
|
|
|
|
]);
|
|
|
|
$this->assertFalse($m4->exists());
|
2016-12-16 05:34:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function testLoadIntoDataObject()
|
|
|
|
{
|
|
|
|
$obj = new DBMoneyTest\TestObject();
|
|
|
|
|
|
|
|
$this->assertInstanceOf(DBMoney::class, $obj->obj('MyMoney'));
|
|
|
|
|
|
|
|
$m = new DBMoney();
|
2017-01-26 05:20:08 +01:00
|
|
|
$m->setValue([
|
2016-12-16 05:34:21 +01:00
|
|
|
'Currency' => 'EUR',
|
|
|
|
'Amount' => 1.23
|
2017-01-26 05:20:08 +01:00
|
|
|
]);
|
2016-12-16 05:34:21 +01:00
|
|
|
$obj->MyMoney = $m;
|
|
|
|
|
|
|
|
$this->assertEquals($obj->MyMoney->getCurrency(), 'EUR');
|
|
|
|
$this->assertEquals($obj->MyMoney->getAmount(), 1.23);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testWriteToDataObject()
|
|
|
|
{
|
|
|
|
$obj = new DBMoneyTest\TestObject();
|
|
|
|
$m = new DBMoney();
|
2017-01-26 05:20:08 +01:00
|
|
|
$m->setValue([
|
2016-12-16 05:34:21 +01:00
|
|
|
'Currency' => 'EUR',
|
|
|
|
'Amount' => 1.23
|
2017-01-26 05:20:08 +01:00
|
|
|
]);
|
2016-12-16 05:34:21 +01:00
|
|
|
$obj->MyMoney = $m;
|
|
|
|
$obj->write();
|
|
|
|
|
|
|
|
$this->assertEquals(
|
|
|
|
'EUR',
|
|
|
|
DB::query(
|
|
|
|
sprintf(
|
|
|
|
'SELECT "MyMoneyCurrency" FROM "MoneyTest_DataObject" WHERE "ID" = %d',
|
|
|
|
$obj->ID
|
|
|
|
)
|
|
|
|
)->value()
|
|
|
|
);
|
|
|
|
$this->assertEquals(
|
|
|
|
'1.23',
|
|
|
|
DB::query(
|
|
|
|
sprintf(
|
|
|
|
'SELECT "MyMoneyAmount" FROM "MoneyTest_DataObject" WHERE "ID" = %d',
|
|
|
|
$obj->ID
|
|
|
|
)
|
|
|
|
)->value()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testMoneyLazyLoading()
|
|
|
|
{
|
|
|
|
// Get the object, ensuring that MyOtherMoney will be lazy loaded
|
|
|
|
$id = $this->idFromFixture(DBMoneyTest\TestObjectSubclass::class, 'test2');
|
|
|
|
$obj = DBMoneyTest\TestObject::get()->byID($id);
|
|
|
|
|
|
|
|
$this->assertEquals('£2.46', $obj->obj('MyOtherMoney')->Nice());
|
|
|
|
}
|
|
|
|
|
|
|
|
public function testHasAmount()
|
|
|
|
{
|
|
|
|
$obj = new DBMoneyTest\TestObject();
|
|
|
|
$m = new DBMoney();
|
|
|
|
$obj->MyMoney = $m;
|
|
|
|
|
2020-04-20 19:58:09 +02:00
|
|
|
$m->setValue(['Amount' => 1]);
|
2016-12-16 05:34:21 +01:00
|
|
|
$this->assertTrue($obj->MyMoney->hasAmount());
|
|
|
|
|
2020-04-20 19:58:09 +02:00
|
|
|
$m->setValue(['Amount' => 1.00]);
|
2016-12-16 05:34:21 +01:00
|
|
|
$this->assertTrue($obj->MyMoney->hasAmount());
|
|
|
|
|
2020-04-20 19:58:09 +02:00
|
|
|
$m->setValue(['Amount' => 1.01]);
|
2016-12-16 05:34:21 +01:00
|
|
|
$this->assertTrue($obj->MyMoney->hasAmount());
|
|
|
|
|
2020-04-20 19:58:09 +02:00
|
|
|
$m->setValue(['Amount' => 0.99]);
|
2016-12-16 05:34:21 +01:00
|
|
|
$this->assertTrue($obj->MyMoney->hasAmount());
|
|
|
|
|
2020-04-20 19:58:09 +02:00
|
|
|
$m->setValue(['Amount' => 0.01]);
|
2016-12-16 05:34:21 +01:00
|
|
|
$this->assertTrue($obj->MyMoney->hasAmount());
|
|
|
|
|
2020-04-20 19:58:09 +02:00
|
|
|
$m->setValue(['Amount' => 0]);
|
2016-12-16 05:34:21 +01:00
|
|
|
$this->assertFalse($obj->MyMoney->hasAmount());
|
|
|
|
|
2020-04-20 19:58:09 +02:00
|
|
|
$m->setValue(['Amount' => 0.0]);
|
2016-12-16 05:34:21 +01:00
|
|
|
$this->assertFalse($obj->MyMoney->hasAmount());
|
|
|
|
|
2020-04-20 19:58:09 +02:00
|
|
|
$m->setValue(['Amount' => 0.00]);
|
2016-12-16 05:34:21 +01:00
|
|
|
$this->assertFalse($obj->MyMoney->hasAmount());
|
|
|
|
}
|
2017-01-26 05:20:08 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* In some cases and locales, validation expects non-breaking spaces.
|
|
|
|
*
|
|
|
|
* Duplicates non-public NumericField::clean method
|
|
|
|
*
|
|
|
|
* @param string $input
|
|
|
|
* @return string The input value, with all spaces replaced with non-breaking spaces
|
|
|
|
*/
|
|
|
|
protected function clean($input)
|
|
|
|
{
|
|
|
|
$nbsp = html_entity_decode(' ', null, 'UTF-8');
|
|
|
|
return str_replace(' ', $nbsp, trim($input));
|
|
|
|
}
|
2009-05-05 10:10:51 +02:00
|
|
|
}
|