Fixes to coupon functions (#1068)

* New Unit Tests for COUPNUM()

* COUPNUM should not return zero when settlement is in the last period

* Additional tests and fixes for COUPNCD() and COUPPCD() functions
This commit is contained in:
Mark Baker 2019-07-10 21:22:16 +02:00 committed by GitHub
parent 38e71a1210
commit 0ea97f14e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 130 additions and 47 deletions

View File

@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org).
## [Unreleased] ## [Unreleased]
### Fixed
- COUPNUM should not return zero when settlement is in the last period - [Issue #1020](https://github.com/PHPOffice/PhpSpreadsheet/issues/1020) and [PR #1021](https://github.com/PHPOffice/PhpSpreadsheet/pull/1021)
## [1.8.2] - 2019-07-08 ## [1.8.2] - 2019-07-08

View File

@ -610,7 +610,7 @@ class Financial
return Functions::VALUE(); return Functions::VALUE();
} }
if (($settlement > $maturity) || if (($settlement >= $maturity) ||
(!self::isValidFrequency($frequency)) || (!self::isValidFrequency($frequency)) ||
(($basis < 0) || ($basis > 4))) { (($basis < 0) || ($basis > 4))) {
return Functions::NAN(); return Functions::NAN();
@ -667,26 +667,22 @@ class Financial
return Functions::VALUE(); return Functions::VALUE();
} }
if (($settlement > $maturity) || if (($settlement >= $maturity) ||
(!self::isValidFrequency($frequency)) || (!self::isValidFrequency($frequency)) ||
(($basis < 0) || ($basis > 4))) { (($basis < 0) || ($basis > 4))) {
return Functions::NAN(); return Functions::NAN();
} }
$settlement = self::couponFirstPeriodDate($settlement, $maturity, $frequency, true); $daysPerYear = self::daysPerYear(DateTime::YEAR($settlement), $basis);
$daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis) * 365; $daysBetweenSettlementAndMaturity = DateTime::YEARFRAC($settlement, $maturity, $basis) * $daysPerYear;
switch ($frequency) { switch ($frequency) {
case 1: // annual payments case 1: // annual payments
return ceil($daysBetweenSettlementAndMaturity / 360);
case 2: // half-yearly case 2: // half-yearly
return ceil($daysBetweenSettlementAndMaturity / 180);
case 4: // quarterly case 4: // quarterly
return ceil($daysBetweenSettlementAndMaturity / 90);
case 6: // bimonthly case 6: // bimonthly
return ceil($daysBetweenSettlementAndMaturity / 60);
case 12: // monthly case 12: // monthly
return ceil($daysBetweenSettlementAndMaturity / 30); return ceil($daysBetweenSettlementAndMaturity / $daysPerYear * $frequency);
} }
return Functions::VALUE(); return Functions::VALUE();
@ -740,7 +736,7 @@ class Financial
return Functions::VALUE(); return Functions::VALUE();
} }
if (($settlement > $maturity) || if (($settlement >= $maturity) ||
(!self::isValidFrequency($frequency)) || (!self::isValidFrequency($frequency)) ||
(($basis < 0) || ($basis > 4))) { (($basis < 0) || ($basis > 4))) {
return Functions::NAN(); return Functions::NAN();

View File

@ -21,7 +21,7 @@ class FinancialTest extends TestCase
public function testACCRINT($expectedResult, ...$args) public function testACCRINT($expectedResult, ...$args)
{ {
$result = Financial::ACCRINT(...$args); $result = Financial::ACCRINT(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerACCRINT() public function providerACCRINT()
@ -37,7 +37,7 @@ class FinancialTest extends TestCase
public function testACCRINTM($expectedResult, ...$args) public function testACCRINTM($expectedResult, ...$args)
{ {
$result = Financial::ACCRINTM(...$args); $result = Financial::ACCRINTM(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerACCRINTM() public function providerACCRINTM()
@ -53,7 +53,7 @@ class FinancialTest extends TestCase
public function testAMORDEGRC($expectedResult, ...$args) public function testAMORDEGRC($expectedResult, ...$args)
{ {
$result = Financial::AMORDEGRC(...$args); $result = Financial::AMORDEGRC(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerAMORDEGRC() public function providerAMORDEGRC()
@ -69,7 +69,7 @@ class FinancialTest extends TestCase
public function testAMORLINC($expectedResult, ...$args) public function testAMORLINC($expectedResult, ...$args)
{ {
$result = Financial::AMORLINC(...$args); $result = Financial::AMORLINC(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerAMORLINC() public function providerAMORLINC()
@ -85,7 +85,7 @@ class FinancialTest extends TestCase
public function testCOUPDAYBS($expectedResult, ...$args) public function testCOUPDAYBS($expectedResult, ...$args)
{ {
$result = Financial::COUPDAYBS(...$args); $result = Financial::COUPDAYBS(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerCOUPDAYBS() public function providerCOUPDAYBS()
@ -101,7 +101,7 @@ class FinancialTest extends TestCase
public function testCOUPDAYS($expectedResult, ...$args) public function testCOUPDAYS($expectedResult, ...$args)
{ {
$result = Financial::COUPDAYS(...$args); $result = Financial::COUPDAYS(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerCOUPDAYS() public function providerCOUPDAYS()
@ -117,7 +117,7 @@ class FinancialTest extends TestCase
public function testCOUPDAYSNC($expectedResult, ...$args) public function testCOUPDAYSNC($expectedResult, ...$args)
{ {
$result = Financial::COUPDAYSNC(...$args); $result = Financial::COUPDAYSNC(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerCOUPDAYSNC() public function providerCOUPDAYSNC()
@ -133,7 +133,7 @@ class FinancialTest extends TestCase
public function testCOUPNCD($expectedResult, ...$args) public function testCOUPNCD($expectedResult, ...$args)
{ {
$result = Financial::COUPNCD(...$args); $result = Financial::COUPNCD(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerCOUPNCD() public function providerCOUPNCD()
@ -149,7 +149,7 @@ class FinancialTest extends TestCase
public function testCOUPNUM($expectedResult, ...$args) public function testCOUPNUM($expectedResult, ...$args)
{ {
$result = Financial::COUPNUM(...$args); $result = Financial::COUPNUM(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerCOUPNUM() public function providerCOUPNUM()
@ -165,7 +165,7 @@ class FinancialTest extends TestCase
public function testCOUPPCD($expectedResult, ...$args) public function testCOUPPCD($expectedResult, ...$args)
{ {
$result = Financial::COUPPCD(...$args); $result = Financial::COUPPCD(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerCOUPPCD() public function providerCOUPPCD()
@ -181,7 +181,7 @@ class FinancialTest extends TestCase
public function testCUMIPMT($expectedResult, ...$args) public function testCUMIPMT($expectedResult, ...$args)
{ {
$result = Financial::CUMIPMT(...$args); $result = Financial::CUMIPMT(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerCUMIPMT() public function providerCUMIPMT()
@ -197,7 +197,7 @@ class FinancialTest extends TestCase
public function testCUMPRINC($expectedResult, ...$args) public function testCUMPRINC($expectedResult, ...$args)
{ {
$result = Financial::CUMPRINC(...$args); $result = Financial::CUMPRINC(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerCUMPRINC() public function providerCUMPRINC()
@ -213,7 +213,7 @@ class FinancialTest extends TestCase
public function testDB($expectedResult, ...$args) public function testDB($expectedResult, ...$args)
{ {
$result = Financial::DB(...$args); $result = Financial::DB(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerDB() public function providerDB()
@ -229,7 +229,7 @@ class FinancialTest extends TestCase
public function testDDB($expectedResult, ...$args) public function testDDB($expectedResult, ...$args)
{ {
$result = Financial::DDB(...$args); $result = Financial::DDB(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerDDB() public function providerDDB()
@ -245,7 +245,7 @@ class FinancialTest extends TestCase
public function testDISC($expectedResult, ...$args) public function testDISC($expectedResult, ...$args)
{ {
$result = Financial::DISC(...$args); $result = Financial::DISC(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerDISC() public function providerDISC()
@ -261,7 +261,7 @@ class FinancialTest extends TestCase
public function testDOLLARDE($expectedResult, ...$args) public function testDOLLARDE($expectedResult, ...$args)
{ {
$result = Financial::DOLLARDE(...$args); $result = Financial::DOLLARDE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerDOLLARDE() public function providerDOLLARDE()
@ -277,7 +277,7 @@ class FinancialTest extends TestCase
public function testDOLLARFR($expectedResult, ...$args) public function testDOLLARFR($expectedResult, ...$args)
{ {
$result = Financial::DOLLARFR(...$args); $result = Financial::DOLLARFR(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerDOLLARFR() public function providerDOLLARFR()
@ -293,7 +293,7 @@ class FinancialTest extends TestCase
public function testEFFECT($expectedResult, ...$args) public function testEFFECT($expectedResult, ...$args)
{ {
$result = Financial::EFFECT(...$args); $result = Financial::EFFECT(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerEFFECT() public function providerEFFECT()
@ -309,7 +309,7 @@ class FinancialTest extends TestCase
public function testFV($expectedResult, ...$args) public function testFV($expectedResult, ...$args)
{ {
$result = Financial::FV(...$args); $result = Financial::FV(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerFV() public function providerFV()
@ -325,7 +325,7 @@ class FinancialTest extends TestCase
public function testFVSCHEDULE($expectedResult, ...$args) public function testFVSCHEDULE($expectedResult, ...$args)
{ {
$result = Financial::FVSCHEDULE(...$args); $result = Financial::FVSCHEDULE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerFVSCHEDULE() public function providerFVSCHEDULE()
@ -341,7 +341,7 @@ class FinancialTest extends TestCase
public function testINTRATE($expectedResult, ...$args) public function testINTRATE($expectedResult, ...$args)
{ {
$result = Financial::INTRATE(...$args); $result = Financial::INTRATE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerINTRATE() public function providerINTRATE()
@ -357,7 +357,7 @@ class FinancialTest extends TestCase
public function testIPMT($expectedResult, ...$args) public function testIPMT($expectedResult, ...$args)
{ {
$result = Financial::IPMT(...$args); $result = Financial::IPMT(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerIPMT() public function providerIPMT()
@ -373,7 +373,7 @@ class FinancialTest extends TestCase
public function testIRR($expectedResult, ...$args) public function testIRR($expectedResult, ...$args)
{ {
$result = Financial::IRR(...$args); $result = Financial::IRR(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerIRR() public function providerIRR()
@ -389,7 +389,7 @@ class FinancialTest extends TestCase
public function testISPMT($expectedResult, ...$args) public function testISPMT($expectedResult, ...$args)
{ {
$result = Financial::ISPMT(...$args); $result = Financial::ISPMT(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerISPMT() public function providerISPMT()
@ -405,7 +405,7 @@ class FinancialTest extends TestCase
public function testMIRR($expectedResult, ...$args) public function testMIRR($expectedResult, ...$args)
{ {
$result = Financial::MIRR(...$args); $result = Financial::MIRR(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerMIRR() public function providerMIRR()
@ -421,7 +421,7 @@ class FinancialTest extends TestCase
public function testNOMINAL($expectedResult, ...$args) public function testNOMINAL($expectedResult, ...$args)
{ {
$result = Financial::NOMINAL(...$args); $result = Financial::NOMINAL(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerNOMINAL() public function providerNOMINAL()
@ -437,7 +437,7 @@ class FinancialTest extends TestCase
public function testNPER($expectedResult, ...$args) public function testNPER($expectedResult, ...$args)
{ {
$result = Financial::NPER(...$args); $result = Financial::NPER(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerNPER() public function providerNPER()
@ -453,7 +453,7 @@ class FinancialTest extends TestCase
public function testNPV($expectedResult, ...$args) public function testNPV($expectedResult, ...$args)
{ {
$result = Financial::NPV(...$args); $result = Financial::NPV(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerNPV() public function providerNPV()
@ -471,7 +471,7 @@ class FinancialTest extends TestCase
$this->markTestIncomplete('TODO: This test should be fixed'); $this->markTestIncomplete('TODO: This test should be fixed');
$result = Financial::PRICE(...$args); $result = Financial::PRICE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerPRICE() public function providerPRICE()
@ -487,7 +487,7 @@ class FinancialTest extends TestCase
public function testPRICEDISC($expectedResult, array $args) public function testPRICEDISC($expectedResult, array $args)
{ {
$result = Financial::PRICEDISC(...$args); $result = Financial::PRICEDISC(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerPRICEDISC() public function providerPRICEDISC()
@ -503,7 +503,7 @@ class FinancialTest extends TestCase
public function testPV($expectedResult, array $args) public function testPV($expectedResult, array $args)
{ {
$result = Financial::PV(...$args); $result = Financial::PV(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerPV() public function providerPV()
@ -521,7 +521,7 @@ class FinancialTest extends TestCase
$this->markTestIncomplete('TODO: This test should be fixed'); $this->markTestIncomplete('TODO: This test should be fixed');
$result = Financial::RATE(...$args); $result = Financial::RATE(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerRATE() public function providerRATE()
@ -539,7 +539,7 @@ class FinancialTest extends TestCase
$this->markTestIncomplete('TODO: This test should be fixed'); $this->markTestIncomplete('TODO: This test should be fixed');
$result = Financial::XIRR(...$args); $result = Financial::XIRR(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerXIRR() public function providerXIRR()
@ -555,7 +555,7 @@ class FinancialTest extends TestCase
public function testPDURATION($expectedResult, array $args) public function testPDURATION($expectedResult, array $args)
{ {
$result = Financial::PDURATION(...$args); $result = Financial::PDURATION(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerPDURATION() public function providerPDURATION()
@ -571,7 +571,7 @@ class FinancialTest extends TestCase
public function testRRI($expectedResult, array $args) public function testRRI($expectedResult, array $args)
{ {
$result = Financial::RRI(...$args); $result = Financial::RRI(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerRRI() public function providerRRI()
@ -587,7 +587,7 @@ class FinancialTest extends TestCase
public function testSLN($expectedResult, array $args) public function testSLN($expectedResult, array $args)
{ {
$result = Financial::SLN(...$args); $result = Financial::SLN(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerSLN() public function providerSLN()
@ -603,7 +603,7 @@ class FinancialTest extends TestCase
public function testSYD($expectedResult, array $args) public function testSYD($expectedResult, array $args)
{ {
$result = Financial::SYD(...$args); $result = Financial::SYD(...$args);
self::assertEquals($expectedResult, $result, null, 1E-8); self::assertEquals($expectedResult, $result, '', 1E-8);
} }
public function providerSYD() public function providerSYD()

View File

@ -37,4 +37,32 @@ return [
3, 3,
1, 1,
], ],
[
'#NUM!',
'24-Dec-2000',
'24-Dec-2000',
4,
0,
],
[
36884,
'23-Dec-2000',
'24-Dec-2000',
4,
0,
],
[
36884,
'24-Sep-2000',
'24-Dec-2000',
4,
0,
],
[
36793,
'23-Sep-2000',
'24-Dec-2000',
4,
0,
],
]; ];

View File

@ -45,4 +45,32 @@ return [
1, 1,
1, 1,
], ],
[
'#NUM!',
'24-Dec-2000',
'24-Dec-2000',
4,
0,
],
[
1,
'23-Dec-2000',
'24-Dec-2000',
4,
0,
],
[
1,
'24-Sep-2000',
'24-Dec-2000',
4,
0,
],
[
2,
'23-Sep-2000',
'24-Dec-2000',
4,
0,
],
]; ];

View File

@ -37,4 +37,32 @@ return [
3, 3,
1, 1,
], ],
[
'#NUM!',
'24-Dec-2000',
'24-Dec-2000',
4,
0,
],
[
36793,
'23-Dec-2000',
'24-Dec-2000',
4,
0,
],
[
36793,
'24-Sep-2000',
'24-Dec-2000',
4,
0,
],
[
36701,
'23-Sep-2000',
'24-Dec-2000',
4,
0,
],
]; ];