['number_format' => $format]]); $repository = $this->createMock(InvoiceRepository::class); $repository ->expects($this->any()) ->method('getCounterForCustomerAllTime') ->willReturn($counter); $repository ->expects($this->any()) ->method('getCounterForUserAllTime') ->willReturn($counter); $repository ->expects($this->any()) ->method('getCounterForYear') ->willReturn($counter); $repository ->expects($this->any()) ->method('getCounterForMonth') ->willReturn($counter); $repository ->expects($this->any()) ->method('getCounterForDay') ->willReturn($counter); return new ConfigurableNumberGenerator($repository, $config); } /** * @return array> */ public static function getTestData(): array { $invoiceDate = new \DateTime(); $invoiceDateFixed = new \DateTime('2021-03-07'); $invoiceDateFixed1 = new \DateTime('2021-03-27'); return [ // simple tests for single calls ['my-{date} is+cool,really', 'my-' . $invoiceDate->format('ymd') . ' is+cool,really', $invoiceDate], ['{date}', $invoiceDate->format('ymd'), $invoiceDate], ['{Y}', $invoiceDate->format('Y'), $invoiceDate], ['{y}', $invoiceDate->format('y'), $invoiceDate], ['{M}', $invoiceDate->format('m'), $invoiceDate], ['{m}', $invoiceDate->format('n'), $invoiceDate], ['{D}', $invoiceDate->format('d'), $invoiceDate], ['{d}', $invoiceDate->format('j'), $invoiceDate], ['{c}', '2', $invoiceDate], ['{cy}', '2', $invoiceDate], ['{cm}', '2', $invoiceDate], ['{cd}', '2', $invoiceDate], // customer ['{cc}', '2', $invoiceDate], ['{ccy}', '2', $invoiceDate], ['{ccm}', '2', $invoiceDate], ['{ccd}', '2', $invoiceDate], ['{cname}', 'Acme company', $invoiceDate], ['{cnumber}', '0815', $invoiceDate], // user ['{cu}', '2', $invoiceDate], ['{cuy}', '2', $invoiceDate], ['{cum}', '2', $invoiceDate], ['{cud}', '2', $invoiceDate], ['{ustaff}', '0815', $invoiceDate], ['{uid}', '13', $invoiceDate], // number formatting (not testing the lower case versions, as the tests might break depending on the date) ['{date,10}', '0000' . $invoiceDate->format('ymd'), $invoiceDate], ['{Y,6}', '00' . $invoiceDate->format('Y'), $invoiceDate], ['{M,3}', '0' . $invoiceDate->format('m'), $invoiceDate], ['{D,3}', '0' . $invoiceDate->format('d'), $invoiceDate], // counter across all invoices ['{c,2}', '02', $invoiceDate], ['{cy,2}', '02', $invoiceDate], ['{cm,2}', '02', $invoiceDate], ['{cd,2}', '02', $invoiceDate], // customer specific ['{cc,2}', '02', $invoiceDate], ['{ccy,2}', '02', $invoiceDate], ['{ccm,2}', '02', $invoiceDate], ['{ccd,2}', '02', $invoiceDate], // with incrementing counter ['{c+13,3}', '014', $invoiceDate], ['{c+13,2}', '14', $invoiceDate], ['{c+13}', '14', $invoiceDate], ['{c-20}', '0', $invoiceDate], ['{cd+111}', '112', $invoiceDate], ['{cd+111,5}', '00112', $invoiceDate], ['{cd+111,2}', '113', $invoiceDate, 2], ['{cm+0,2}', '03', $invoiceDate, 2], // zero is not allowed and set to 1 ['{cm+0}', '2', $invoiceDate], // zero is not allowed and set to 1 ['{cy+2}', '3', $invoiceDate], ['{cc+4}', '5', $invoiceDate], ['{ccy+2,2}', '03', $invoiceDate], ['{ccm+2,2}', '03', $invoiceDate], ['{ccd+2,2}', '03', $invoiceDate], // mixing identifiers ['{Y}{cy}', $invoiceDate->format('Y') . '2', $invoiceDate], ['{Y}{cy}{m}', $invoiceDate->format('Y') . '2' . $invoiceDate->format('n'), $invoiceDate], ['{Y}-{cy}/{m}', $invoiceDate->format('Y') . '-2/' . $invoiceDate->format('n'), $invoiceDate], ['{Y}-{cy}/{m}', $invoiceDate->format('Y') . '-2/' . $invoiceDate->format('n'), $invoiceDate], ['{ustaff}|{cuy}_{Y}-{cy}/{m}', '0815|2_' . $invoiceDate->format('Y') . '-2/' . $invoiceDate->format('n'), $invoiceDate], ['{Y,5}/{cy,5}', '0' . $invoiceDate->format('Y') . '/00002', $invoiceDate], // with decrementing counter ['{c-1,2}', '00', $invoiceDate], ['{c-2,2}', '00', $invoiceDate], // with incrementing and decrementing counter ['{c-5+13,1}', '9', $invoiceDate], ['{c+13-5,2}', '09', $invoiceDate], // undefined behaviour - can change at any time ['{cm+-1,2}', '00', $invoiceDate], ['{cm+-1}', '0', $invoiceDate], ['{cm-+1,2}', '02', $invoiceDate], ['{cm-+1}', '2', $invoiceDate], ['{a-+1+-1+++2}', '{a-+1+-1+++2}', $invoiceDate], ['{date+2+2+2}', $invoiceDate->format('ymd'), $invoiceDate], ['{cm+22+2+2-1-13-4}', '9', $invoiceDate], ['{cm+22+2-2-22}', '6', $invoiceDate, 5], ['{cm-21+22+2-2}', '6', $invoiceDate, 5], // increment dates ['{YY}', '2022', $invoiceDateFixed], ['{YY+1}', '2022', $invoiceDateFixed], ['{YY+2}', '2023', $invoiceDateFixed], ['{YY+3}', '2024', $invoiceDateFixed], ['{YY-1}', '2020', $invoiceDateFixed], ['{YY-2}', '2019', $invoiceDateFixed], ['{YY-3}', '2018', $invoiceDateFixed], ['{yy}', '22', $invoiceDateFixed], ['{yy+1}', '22', $invoiceDateFixed], ['{yy+2}', '23', $invoiceDateFixed], ['{yy+3}', '24', $invoiceDateFixed], ['{yy-1}', '20', $invoiceDateFixed], ['{yy-2}', '19', $invoiceDateFixed], ['{yy-3}', '18', $invoiceDateFixed], ['{MM}', '4', $invoiceDateFixed], // cast to int removes leading zero ['{MM+1}', '4', $invoiceDateFixed], // cast to int removes leading zero ['{MM+2}', '5', $invoiceDateFixed], // cast to int removes leading zero ['{MM+3}', '6', $invoiceDateFixed], // cast to int removes leading zero ['{MM-1}', '2', $invoiceDateFixed], // cast to int removes leading zero ['{MM-2}', '1', $invoiceDateFixed], // cast to int removes leading zero ['{MM-3}', '0', $invoiceDateFixed], // cast to int removes leading zero ['{MM-4}', '0', $invoiceDateFixed], // cast to int removes leading zero ['{DD}', '8', $invoiceDateFixed], // cast to int removes leading zero ['{DD+1}', '8', $invoiceDateFixed], // cast to int removes leading zero ['{DD+2}', '9', $invoiceDateFixed], // cast to int removes leading zero ['{DD+3}', '10', $invoiceDateFixed], // cast to int removes leading zero ['{DD-1}', '6', $invoiceDateFixed], // cast to int removes leading zero ['{DD-2}', '5', $invoiceDateFixed], // cast to int removes leading zero ['{DD-3}', '4', $invoiceDateFixed], // cast to int removes leading zero ['{DD}', '28', $invoiceDateFixed1], // cast to int removes leading zero ['{DD+1}', '28', $invoiceDateFixed1], // cast to int removes leading zero ['{DD+2}', '29', $invoiceDateFixed1], // cast to int removes leading zero ['{DD+3}', '30', $invoiceDateFixed1], // cast to int removes leading zero ['{DD-1}', '26', $invoiceDateFixed1], // cast to int removes leading zero ['{DD-2}', '25', $invoiceDateFixed1], // cast to int removes leading zero ['{DD-3}', '24', $invoiceDateFixed1], // cast to int removes leading zero ]; } #[DataProvider('getTestData')] public function testGetInvoiceNumber(string $format, string $expectedInvoiceNumber, \DateTime $invoiceDate, int $counter = 1): void { $customer = new Customer('Acme company'); $customer->setNumber('0815'); $user = $this->createMock(User::class); $user->method('getId')->willReturn(13); $user->method('getAccountNumber')->willReturn('0815'); $sut = $this->getSut($format, $counter); $model = (new InvoiceModelFactoryFactory($this))->create()->createModel(new DebugFormatter(), $customer, new InvoiceTemplate(), new InvoiceQuery()); $model->setInvoiceDate($invoiceDate); $model->setUser($user); $sut->setModel($model); self::assertEquals($expectedInvoiceNumber, $sut->getInvoiceNumber()); self::assertEquals('default', $sut->getId()); } /** * @return array> */ public static function getInvalidTestData(): array { $invoiceDate = new \DateTime(); return [ ['{cm-}', $invoiceDate, 'decrement'], ['{cm+}', $invoiceDate, 'increment'], ['{cm+-}', $invoiceDate, 'decrement'], ['{cm-+}', $invoiceDate, 'increment'], ['{cy,}', $invoiceDate, 'format length'], ['{date,a}', $invoiceDate, 'format length'], ['{M,#}', $invoiceDate, 'format length'], ['{,a}', $invoiceDate, 'format length'], ['{Y,!}/{cy,o}', $invoiceDate, 'format length'], ['{cm,}', $invoiceDate, 'format length'], ['{cd+111,050}', $invoiceDate, 'format length'], ['{-+}', $invoiceDate, 'increment'], ['{+}', $invoiceDate, 'increment'], ['{+-}', $invoiceDate, 'decrement'], ]; } #[DataProvider('getInvalidTestData')] public function testInvalidGetInvoiceNumber(string $format, \DateTime $invoiceDate, string $brokenPart): void { $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage(\sprintf('Unknown %s found', $brokenPart)); $sut = $this->getSut($format); $model = (new InvoiceModelFactoryFactory($this))->create()->createModel(new DebugFormatter(), new Customer('foo'), new InvoiceTemplate(), new InvoiceQuery()); $model->setInvoiceDate($invoiceDate); $sut->setModel($model); $sut->getInvoiceNumber(); } /** * @return array> */ public static function getMissingFieldTestData(): array { return [ ['{Y}/{cnumber}_{ccy,3}', 'Customer has no number, replacer {cnumber} failed evaluation'], ['{Y}/{cname}_{ccy,3}', 'Customer has no name, replacer {cname} failed evaluation'], ]; } #[DataProvider('getMissingFieldTestData')] public function testCustomerHasMissingField(string $format, string $message): void { $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage($message); $user = $this->createMock(User::class); $user->method('getId')->willReturn(13); $user->method('getAccountNumber')->willReturn('0815'); $customer = new Customer(''); $customer->setName(null); $sut = $this->getSut($format); $model = (new InvoiceModelFactoryFactory($this))->create()->createModel(new DebugFormatter(), $customer, new InvoiceTemplate(), new InvoiceQuery()); $model->setInvoiceDate(new \DateTime()); $model->setUser($user); $sut->setModel($model); $sut->getInvoiceNumber(); } }