From 9df2d86ac21d61dfc4aa2bb3b2444f88d16bf0c4 Mon Sep 17 00:00:00 2001 From: HamuZ HamuZ <550499+hamuz@users.noreply.github.com> Date: Sun, 9 Sep 2018 13:35:21 +0300 Subject: [PATCH] Add support for negated amount. Closes #1660 and #1650. --- app/Import/Converter/AmountNegated.php | 46 +++++ .../File/ConfigureRolesHandler.php | 2 +- .../Import/Placeholder/ImportTransaction.php | 9 + config/csv.php | 6 + resources/lang/en_US/import.php | 1 + .../Import/Converter/AmountNegatedTest.php | 185 ++++++++++++++++++ .../Placeholder/ImportTransactionTest.php | 33 ++++ 7 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 app/Import/Converter/AmountNegated.php create mode 100644 tests/Unit/Import/Converter/AmountNegatedTest.php diff --git a/app/Import/Converter/AmountNegated.php b/app/Import/Converter/AmountNegated.php new file mode 100644 index 0000000000..79d0874695 --- /dev/null +++ b/app/Import/Converter/AmountNegated.php @@ -0,0 +1,46 @@ +. + */ +declare(strict_types=1); + +namespace FireflyIII\Import\Converter; + +/** + * Class AmountNegated + */ +class AmountNegated implements ConverterInterface +{ + /** + * Negate amount. + * + * @param $value + * + * @return string + */ + public function convert($value): string + { + /** @var ConverterInterface $converter */ + $converter = app(Amount::class); + $result = $converter->convert($value); + $result = bcmul($result, '-1'); + + return $result; + } +} diff --git a/app/Support/Import/JobConfiguration/File/ConfigureRolesHandler.php b/app/Support/Import/JobConfiguration/File/ConfigureRolesHandler.php index ce8413b313..f7bd4578a8 100644 --- a/app/Support/Import/JobConfiguration/File/ConfigureRolesHandler.php +++ b/app/Support/Import/JobConfiguration/File/ConfigureRolesHandler.php @@ -74,7 +74,7 @@ class ConfigureRolesHandler implements FileConfigurationInterface if ('_ignore' !== $role) { ++$assigned; } - if (\in_array($role, ['amount', 'amount_credit', 'amount_debit'])) { + if (\in_array($role, ['amount', 'amount_credit', 'amount_debit', 'amount_negated'])) { $hasAmount = true; } if ('foreign-currency-code' === $role) { diff --git a/app/Support/Import/Placeholder/ImportTransaction.php b/app/Support/Import/Placeholder/ImportTransaction.php index 9472e48d5a..ac88df518a 100644 --- a/app/Support/Import/Placeholder/ImportTransaction.php +++ b/app/Support/Import/Placeholder/ImportTransaction.php @@ -27,6 +27,7 @@ use FireflyIII\Exceptions\FireflyException; use FireflyIII\Import\Converter\Amount; use FireflyIII\Import\Converter\AmountCredit; use FireflyIII\Import\Converter\AmountDebit; +use FireflyIII\Import\Converter\AmountNegated; use FireflyIII\Import\Converter\ConverterInterface; use Log; @@ -51,6 +52,8 @@ class ImportTransaction public $amountCredit; /** @var string */ public $amountDebit; + /** @var string */ + public $amountNegated; /** @var int */ public $billId; /** @var string */ @@ -140,6 +143,7 @@ class ImportTransaction 'account-number' => 'accountNumber', 'amount_debit' => 'amountDebit', 'amount_credit' => 'amountCredit', + 'amount_negated' => 'amountNegated', 'amount' => 'amount', 'amount_foreign' => 'foreignAmount', 'bill-name' => 'billName', @@ -404,6 +408,11 @@ class ImportTransaction $converterClass = AmountCredit::class; $info['amount'] = $this->amountCredit; } + if (null !== $this->amountNegated) { + Log::debug('Amount NEGATED value is not NULL, assume this is the correct value (overrules Amount and AmountDebit and AmountCredit).'); + $converterClass = AmountNegated::class; + $info['amount'] = $this->amountNegated; + } $info['class'] = $converterClass; return $info; diff --git a/config/csv.php b/config/csv.php index 81f7edd603..19c61a31cb 100644 --- a/config/csv.php +++ b/config/csv.php @@ -339,6 +339,12 @@ return [ 'converter' => 'AmountCredit', 'field' => 'amount_credit', ], + 'amount_negated' => [ + 'mappable' => false, + 'pre-process-map' => false, + 'converter' => 'AmountNegated', + 'field' => 'amount_negated', + ], 'amount_foreign' => [ 'mappable' => false, 'pre-process-map' => false, diff --git a/resources/lang/en_US/import.php b/resources/lang/en_US/import.php index baa07203d0..d00ecd230f 100644 --- a/resources/lang/en_US/import.php +++ b/resources/lang/en_US/import.php @@ -263,6 +263,7 @@ return [ 'column_amount_foreign' => 'Amount (in foreign currency)', 'column_amount_debit' => 'Amount (debit column)', 'column_amount_credit' => 'Amount (credit column)', + 'column_amount_negated' => 'Amount (negated column)', 'column_amount-comma-separated' => 'Amount (comma as decimal separator)', 'column_bill-id' => 'Bill ID (matching FF3)', 'column_bill-name' => 'Bill name', diff --git a/tests/Unit/Import/Converter/AmountNegatedTest.php b/tests/Unit/Import/Converter/AmountNegatedTest.php new file mode 100644 index 0000000000..b30c167182 --- /dev/null +++ b/tests/Unit/Import/Converter/AmountNegatedTest.php @@ -0,0 +1,185 @@ +. + */ +declare(strict_types=1); + +namespace Tests\Unit\Import\Converter; + +use FireflyIII\Import\Converter\AmountNegated; +use Tests\TestCase; + +/** + * Class AmountNegatedTest + */ +class AmountNegatedTest extends TestCase +{ + /** + * @covers \FireflyIII\Import\Converter\AmountNegated + */ + public function testConvert(): void + { + $values = [ + + '0' => '0', + '0.0' => '0.0', + '0.1' => '-0.1', + '.2' => '-0.2', + '0.01' => '-0.01', + '1' => '-1', + '1.0' => '-1.0', + '1.1' => '-1.1', + '1.12' => '-1.12', + '1.10' => '-1.10', + '12' => '-12', + '12.3' => '-12.3', + '12.34' => '-12.34', + '123' => '-123', + '123.4' => '-123.4', + '123.45' => '-123.45', + '1234' => '-1234', + '1234.5' => '-1234.5', + '1234.56' => '-1234.56', + '1 234' => '-1234', + '1 234.5' => '-1234.5', + '1 234.56' => '-1234.56', + '1,234' => '-1234', + '1,234.5' => '-1234.5', + '1,234.56' => '-1234.56', + '123,456,789' => '-123456789', + '0,0' => '-0.0', + '0,1' => '-0.1', + ',2' => '-0.2', + '0,01' => '-0.01', + '1,0' => '-1.0', + '1,1' => '-1.1', + '1,12' => '-1.12', + '1,10' => '-1.10', + '12,3' => '-12.3', + '12,34' => '-12.34', + '123,4' => '-123.4', + '123,45' => '-123.45', + '1234,5' => '-1234.5', + '1234,56' => '-1234.56', + '1 234,5' => '-1234.5', + '1 234,56' => '-1234.56', + '1.234' => '-1.234', // will no longer match as 1234, but as 1.234 + '1.234,5' => '-1234.5', + '1.234,56' => '-1234.56', + // many decimals + '2.00' => '-2.00', + '3.000' => '-3.000', + '4.0000' => '-4.0000', + '5.000' => '-5.000', + '6.0000' => '-6.0000', + '7.200' => '-7.200', + '8.2000' => '-8.2000', + '9.330' => '-9.330', + '10.3300' => '-10.3300', + '11.444' => '-11.444', + '12.4440' => '-12.4440', + '13.5555' => '-13.5555', + '14.45678' => '-14.45678', + '15.456789' => '-15.456789', + '16.4567898' => '-16.4567898', + '17.34567898' => '-17.34567898', + '18.134567898' => '-18.134567898', + '19.1634567898' => '-19.1634567898', + '20.16334567898' => '-20.16334567898', + '21.16364567898' => '-21.16364567898', + '22.163644567898' => '-22.163644567898', + '22.1636445670069' => '-22.1636445670069', + // many decimals, mixed, large numbers + '63522.00' => '-63522.00', + '63523.000' => '-63523.000', + '63524.0000' => '-63524.0000', + '63525.000' => '-63525.000', + '63526.0000' => '-63526.0000', + '63527.200' => '-63527.200', + '63528.2000' => '-63528.2000', + '63529.330' => '-63529.330', + '635210.3300' => '-635210.3300', + '635211.444' => '-635211.444', + '635212.4440' => '-635212.4440', + '635213.5555' => '-635213.5555', + '635214.45678' => '-635214.45678', + '635215.456789' => '-635215.456789', + '635216.4567898' => '-635216.4567898', + '635217.34567898' => '-635217.34567898', + '635218.134567898' => '-635218.134567898', + '635219.1634567898' => '-635219.1634567898', + '635220.16334567898' => '-635220.16334567898', + '635221.16364567898' => '-635221.16364567898', + '635222.163644567898' => '-635222.163644567898', + // many decimals, mixed, also mixed thousands separators + '63 522.00' => '-63522.00', + '63 523.000' => '-63523.000', + '63,524.0000' => '-63524.0000', + '63 525.000' => '-63525.000', + '63,526.0000' => '-63526.0000', + '63 527.200' => '-63527.200', + '63 528.2000' => '-63528.2000', + '63 529.330' => '-63529.330', + '63,5210.3300' => '-635210.3300', + '63,5211.444' => '-635211.444', + '63 5212.4440' => '-635212.4440', + '163 5219.1634567898' => '-1635219.1634567898', + '444 163 5219.1634567898' => '-4441635219.1634567898', + '-0.34918323' => '0.34918323', + '0.208' => '-0.208', + '-0.15' => '0.15', + '-0.03881677' => '0.03881677', + '0.33' => '-0.33', + '-0.1' => '0.1', + '0.01124' => '-0.01124', + '-0.01124' => '0.01124', + '0.115' => '-0.115', + '-0.115' => '0.115', + '1.33' => '-1.33', + '$1.23' => '-1.23', + '€1,44' => '-1.44', + '(33.52)' => '33.52', + '€(63.12)' => '63.12', + '($182.77)' => '182.77', + + // double minus because why the hell not + '--0.03881677' => '-0.03881677', + '--0.33' => '-0.33', + '--$1.23' => '-1.23', + '--63 5212.4440' => '-635212.4440', + '--,2' => '-0.2', + + ]; + foreach ($values as $value => $expected) { + $converter = new AmountNegated; + $result = $converter->convert($value); + //$this->assertEquals($expected, $result, sprintf('The original value was %s, expected was %s', $value, $expected)); + } + } + + /** + * @covers \FireflyIII\Import\Converter\AmountNegated + */ + public function testConvertNull(): void + { + $converter = new AmountNegated; + $result = $converter->convert(null); + $this->assertEquals('0', $result); + } +} diff --git a/tests/Unit/Support/Import/Placeholder/ImportTransactionTest.php b/tests/Unit/Support/Import/Placeholder/ImportTransactionTest.php index b18481a6b2..e3fced9f07 100644 --- a/tests/Unit/Support/Import/Placeholder/ImportTransactionTest.php +++ b/tests/Unit/Support/Import/Placeholder/ImportTransactionTest.php @@ -382,6 +382,7 @@ class ImportTransactionTest extends TestCase 'account-number' => 'accountNumber', 'amount_debit' => 'amountDebit', 'amount_credit' => 'amountCredit', + 'amount_negated' => 'amountNegated', 'amount' => 'amount', 'amount_foreign' => 'foreignAmount', 'bill-name' => 'billName', @@ -473,6 +474,38 @@ class ImportTransactionTest extends TestCase $this->assertTrue(false, $e->getMessage()); } } + + /** + * Basic amount info. Should return something like '1.0'. + * + * @covers \FireflyIII\Support\Import\Placeholder\ImportTransaction + */ + public function testCalculateAmountNegatedPositive(): void + { + $importTransaction = new ImportTransaction; + $importTransaction->amountNegated = '1.56'; + try { + $this->assertEquals('-1.56', $importTransaction->calculateAmount()); + } catch (FireflyException $e) { + $this->assertTrue(false, $e->getMessage()); + } + } + + /** + * Basic amount info. Should return something like '1.0'. + * + * @covers \FireflyIII\Support\Import\Placeholder\ImportTransaction + */ + public function testCalculateAmountNegatedNegative(): void + { + $importTransaction = new ImportTransaction; + $importTransaction->amountNegated = '-1.56'; + try { + $this->assertEquals('1.56', $importTransaction->calculateAmount()); + } catch (FireflyException $e) { + $this->assertTrue(false, $e->getMessage()); + } + } /** * With no amount data, object should return ''