diff --git a/src/Reference/QrPaymentReferenceGenerator.php b/src/Reference/QrPaymentReferenceGenerator.php index b875d75c..8a174c69 100644 --- a/src/Reference/QrPaymentReferenceGenerator.php +++ b/src/Reference/QrPaymentReferenceGenerator.php @@ -6,6 +6,7 @@ use Sprain\SwissQrBill\Validator\SelfValidatableInterface; use Sprain\SwissQrBill\Validator\SelfValidatableTrait; use Symfony\Component\Validator\Constraints as Assert; +use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Mapping\ClassMetadata; class QrPaymentReferenceGenerator implements SelfValidatableInterface @@ -18,10 +19,13 @@ class QrPaymentReferenceGenerator implements SelfValidatableInterface /** @var string */ private $referenceNumber; - public static function generate(string $customerIdentificationNumber, string $referenceNumber) + public static function generate(?string $customerIdentificationNumber, string $referenceNumber) { $qrPaymentReferenceGenerator = new self(); - $qrPaymentReferenceGenerator->customerIdentificationNumber = $qrPaymentReferenceGenerator->removeWhitespace($customerIdentificationNumber); + + if (null !== $customerIdentificationNumber) { + $qrPaymentReferenceGenerator->customerIdentificationNumber = $qrPaymentReferenceGenerator->removeWhitespace($customerIdentificationNumber); + } $qrPaymentReferenceGenerator->referenceNumber = $qrPaymentReferenceGenerator->removeWhitespace($referenceNumber); return $qrPaymentReferenceGenerator->doGenerate(); @@ -37,7 +41,7 @@ public function getReferenceNumber(): ?string return $this->referenceNumber; } - public function doGenerate() + private function doGenerate() { if (!$this->isValid()) { throw new InvalidQrPaymentReferenceException( @@ -45,8 +49,8 @@ public function doGenerate() ); } - $completeReferenceNumber = str_pad($this->getCustomerIdentificationNumber(), 6, '0', STR_PAD_RIGHT); - $completeReferenceNumber .= str_pad($this->getReferenceNumber(), 20, '0', STR_PAD_LEFT); + $completeReferenceNumber = $this->getCustomerIdentificationNumber(); + $completeReferenceNumber .= str_pad($this->getReferenceNumber(), 26 - strlen($completeReferenceNumber), '0', STR_PAD_LEFT); $completeReferenceNumber .= $this->modulo10($completeReferenceNumber); return $completeReferenceNumber; @@ -61,9 +65,8 @@ public static function loadValidatorMetadata(ClassMetadata $metadata): void 'match' => true ]), new Assert\Length([ - 'max' => 6 + 'max' => 11 ]), - new Assert\NotBlank() ]); $metadata->addPropertyConstraints('referenceNumber', [ @@ -72,11 +75,18 @@ public static function loadValidatorMetadata(ClassMetadata $metadata): void 'pattern' => '/^\d*$/', 'match' => true ]), - new Assert\Length([ - 'max' => 20 - ]), new Assert\NotBlank() ]); + + $metadata->addConstraint(new Assert\Callback('validateFullReference')); + } + + public function validateFullReference(ExecutionContextInterface $context, $payload) + { + if (strlen($this->customerIdentificationNumber) + strlen($this->referenceNumber) > 26) { + $context->buildViolation('The length of customer identification number + reference number may not exceed 26 characters in total.') + ->addViolation(); + } } private function removeWhitespace(string $string): string diff --git a/tests/Reference/QrPaymentReferenceGeneratorTest.php b/tests/Reference/QrPaymentReferenceGeneratorTest.php index 1cb76eeb..178b93cd 100644 --- a/tests/Reference/QrPaymentReferenceGeneratorTest.php +++ b/tests/Reference/QrPaymentReferenceGeneratorTest.php @@ -40,6 +40,11 @@ public function qrPaymentReferenceProvider() ['040329', '340 ', '040329000000000000000003406'], // https://www.lukb.ch/documents/10620/13334/LUKB-BESR-Handbuch.pdf ['247656', '3073000002311006 ', '247656000030730000023110061'], // https://hilfe.flexbuero.ch/article/1181/ ['123456', '11223344', '123456000000000000112233440'], + ['1234567890', '11223344', '123456789000000000112233444'], + ['1234', '11223344', '123400000000000000112233449'], + ['000000', '11223344', '000000000000000000112233442'], + ['', '11223344', '000000000000000000112233442'], + [null, '11223344', '000000000000000000112233442'], // Handle it as numerics as well [310014, 18310019779911119, '310014000183100197799111196'], @@ -49,13 +54,35 @@ public function qrPaymentReferenceProvider() ]; } + /** + * @dataProvider invalidQrPaymentReferenceProvider + * @expectedException Sprain\SwissQrBill\Validator\Exception\InvalidQrPaymentReferenceException + */ + public function testInvalidQrPaymentReference($customerIdentification, $referenceNumber) + { + QrPaymentReferenceGenerator::generate( + $customerIdentification, + $referenceNumber + ); + } + + public function invalidQrPaymentReferenceProvider() + { + return [ + ['1234', '12345678901234567890123'], // too long in total + ['123456', '123456789012345678901'], // too long in total + ['12345678901', '1234567890123456'], // too long in total + [null, '123456789012345678901234567'], // too long in total + ]; + } + /** * @dataProvider invalidCustomerIdentificationNumberProvider * @expectedException Sprain\SwissQrBill\Validator\Exception\InvalidQrPaymentReferenceException */ public function testInvalidCustomerIdentificationNumber($value) { - $qrReference = QrPaymentReferenceGenerator::generate( + QrPaymentReferenceGenerator::generate( $value, '18310019779911119' ); @@ -64,10 +91,9 @@ public function testInvalidCustomerIdentificationNumber($value) public function invalidCustomerIdentificationNumberProvider() { return [ - ['1234567'], // too long + ['123456789012'], // too long ['12345A'], // non-digits ['1234.5'], // non-digits - [''] ]; } @@ -77,7 +103,7 @@ public function invalidCustomerIdentificationNumberProvider() */ public function testInvalidReferenceNumber($value) { - $qrReference = QrPaymentReferenceGenerator::generate( + QrPaymentReferenceGenerator::generate( '123456', $value ); @@ -86,7 +112,6 @@ public function testInvalidReferenceNumber($value) public function invalidReferenceNumberProvider() { return [ - ['123456789012345678901'], // too long ['1234567890123456789A'], // non-digits ['123456789012345678.0'], // non-digits ['']