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); } /** * Covers Nice() and getValue() */ public function testToCurrency() { $USD = new DBMoney(); $USD->setValue([ 'Currency' => 'USD', 'Amount' => 53292.18, ]); $USD->setLocale('en_US'); $this->assertSame('53292.18 USD', $USD->getValue()); $this->assertSame('$53,292.18', $USD->Nice()); // USD in de locale $USD->setLocale('de_DE'); $this->assertSame($this->clean('53.292,18 $'), $this->clean($USD->Nice())); } public function testGetSymbol() { // Swedish kroner $SKR = new DBMoney(); $SKR->setValue([ 'Currency' => 'SEK', 'Amount' => 3.44 ]); $SKR->setLocale('sv'); $this->assertSame('kr', $SKR->getSymbol()); // EU currency $EUR = new DBMoney(); $EUR->setValue([ 'Currency' => 'EUR', 'Amount' => 3.44 ]); $EUR->setLocale('de_DE'); $this->assertSame('€', $EUR->getSymbol()); // Where locale doesn't match currency $USD = new DBMoney(); $USD->setValue([ 'Currency' => 'USD', 'Amount' => 3.44, ]); $USD->setLocale('de_DE'); $this->assertSame('$', $USD->getSymbol()); } public function testSetValueAsArray() { $m = new DBMoney(); $m->setValue([ 'Currency' => 'EUR', 'Amount' => 3.44 ]); $this->assertEquals( $m->getCurrency(), 'EUR' ); $this->assertEquals( $m->getAmount(), 3.44 ); } public function testSetValueAsMoney() { $m1 = new DBMoney(); $m1->setValue([ 'Currency' => 'EUR', 'Amount' => 3.44 ]); $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(); $m2->setValue([ 'Currency' => 'EUR', 'Amount' => 3.44 ]); $this->assertTrue($m2->exists()); $m3 = new DBMoney(); $m3->setValue([ 'Currency' => 'EUR', 'Amount' => 0 ]); $this->assertTrue($m3->exists()); $m4 = new DBMoney(); $m4->setValue([ 'Currency' => 'EUR', 'Amount' => null, ]); $this->assertFalse($m4->exists()); } public function testLoadIntoDataObject() { $obj = new DBMoneyTest\TestObject(); $this->assertInstanceOf(DBMoney::class, $obj->obj('MyMoney')); $m = new DBMoney(); $m->setValue([ 'Currency' => 'EUR', 'Amount' => 1.23 ]); $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(); $m->setValue([ 'Currency' => 'EUR', 'Amount' => 1.23 ]); $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; $m->setValue(['Amount' => 1]); $this->assertTrue($obj->MyMoney->hasAmount()); $m->setValue(['Amount' => 1.00]); $this->assertTrue($obj->MyMoney->hasAmount()); $m->setValue(['Amount' => 1.01]); $this->assertTrue($obj->MyMoney->hasAmount()); $m->setValue(['Amount' => 0.99]); $this->assertTrue($obj->MyMoney->hasAmount()); $m->setValue(['Amount' => 0.01]); $this->assertTrue($obj->MyMoney->hasAmount()); $m->setValue(['Amount' => 0]); $this->assertFalse($obj->MyMoney->hasAmount()); $m->setValue(['Amount' => 0.0]); $this->assertFalse($obj->MyMoney->hasAmount()); $m->setValue(['Amount' => 0.00]); $this->assertFalse($obj->MyMoney->hasAmount()); } /** * 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(' ', 0, 'UTF-8'); return str_replace(' ', $nbsp ?? '', trim($input ?? '')); } }