Skip to content

Commit

Permalink
Qr bill integration (#4)
Browse files Browse the repository at this point in the history
* Add BankCredit specializations for QR with reference and creditor reference

* Add comments

Co-authored-by: Sébastien Despont <[email protected]>
  • Loading branch information
eric-reichenbach and sdespont authored Oct 19, 2021
1 parent 24ded25 commit 4280e02
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 6 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
.php_cs
.php_cs.cache

*.phpunit.result.cache
phpunit.xml

/.idea/
composer.lock
/vendor/
/.idea
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class PaymentInformation
protected $id;

/**
* @var array
* @var CreditTransfer[]
*/
protected $transactions;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

namespace Z38\SwissPayment\TransactionInformation;

use DOMDocument;
use DOMElement;
use InvalidArgumentException;
use Z38\SwissPayment\FinancialInstitutionInterface;
use Z38\SwissPayment\IBAN;
use Z38\SwissPayment\Money;
use Z38\SwissPayment\PostalAccount;

/**
* BankCreditTransfer contains all the information about a type 3 transaction
* for a QR-Bill with Creditor Reference (SCOR)
*/
class BankCreditTransferWithCreditorReference extends BankCreditTransfer
{
/**
* @var string
*/
protected $creditorReference;

/**
* BankCreditTransferWithQRR constructor.
* @param $instructionId
* @param $endToEndId
* @param Money\Money $amount
* @param $creditorName
* @param $creditorAddress
* @param IBAN $creditorIBAN IBAN of the creditor
* @param FinancialInstitutionInterface $creditorAgent BIC or IID of the creditor's financial institution
* @param string $creditorReference QR reference number (QRR)
*/
public function __construct(
$instructionId,
$endToEndId,
Money\Money $amount,
$creditorName,
$creditorAddress,
IBAN $creditorIBAN,
FinancialInstitutionInterface $creditorAgent,
$creditorReference
) {
$cleanedCreditorReference = str_replace(' ', '', strtoupper($creditorReference));
if (!preg_match('/^RF/', $cleanedCreditorReference)) {
throw new InvalidArgumentException('The creditor reference (SCOR) must starts with RF : ISO-11649');
}
$this->creditorReference = $cleanedCreditorReference;

if (preg_match('/^CH[0-9]{2}3/', $creditorIBAN->normalize())) {
throw new InvalidArgumentException('The IBAN must not be a QR-IBAN');
}

parent::__construct($instructionId, $endToEndId, $amount, $creditorName, $creditorAddress, $creditorIBAN, $creditorAgent);
}

/**
* @param DOMDocument $doc
* @param DOMElement $transaction
*/
protected function appendRemittanceInformation(DOMDocument $doc, DOMElement $transaction)
{
$remittanceInformation = $doc->createElement('RmtInf');

$structured = $doc->createElement('Strd');
$remittanceInformation->appendChild($structured);

$creditorReferenceInformation = $doc->createElement('CdtrRefInf');
$structured->appendChild($creditorReferenceInformation);

$codeOrProperty = $doc->createElement('CdOrPrtry');
$codeOrProperty->appendChild($doc->createElement('Cd', 'SCOR'));
$type = $doc->createElement('Tp');
$type->appendChild($codeOrProperty);

$creditorReferenceInformation->appendChild($type);
$creditorReferenceInformation->appendChild($doc->createElement('Ref', $this->creditorReference));

if (!empty($this->remittanceInformation)) {
$structured->appendChild($doc->createElement('AddtlRmtInf', $this->remittanceInformation));
}

$transaction->appendChild($remittanceInformation);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

namespace Z38\SwissPayment\TransactionInformation;

use DOMDocument;
use DOMElement;
use InvalidArgumentException;
use Z38\SwissPayment\FinancialInstitutionInterface;
use Z38\SwissPayment\IBAN;
use Z38\SwissPayment\Money;
use Z38\SwissPayment\PostalAccount;

/**
* BankCreditTransfer contains all the information about a type 3 transaction
* for a QR-Bill with QR reference (QRR)
*/
class BankCreditTransferWithQRR extends BankCreditTransfer
{
/**
* @var string
*/
protected $creditorReference;

/**
* BankCreditTransferWithQRR constructor.
* @param $instructionId
* @param $endToEndId
* @param Money\Money $amount
* @param $creditorName
* @param $creditorAddress
* @param IBAN $creditorIBAN IBAN of the creditor
* @param FinancialInstitutionInterface $creditorAgent BIC or IID of the creditor's financial institution
* @param string $creditorReference QR reference number (QRR)
*/
public function __construct(
$instructionId,
$endToEndId,
Money\Money $amount,
$creditorName,
$creditorAddress,
IBAN $creditorIBAN,
FinancialInstitutionInterface $creditorAgent,
$creditorReference
) {
if (!preg_match('/^[0-9]{1,27}$/', $creditorReference) || !PostalAccount::validateCheckDigit($creditorReference)) {
throw new InvalidArgumentException('QR reference is invalid.');
}
$this->creditorReference = $creditorReference;

if (!preg_match('/^CH[0-9]{2}3/', $creditorIBAN->normalize())) {
throw new InvalidArgumentException('The IBAN must be a QR-IBAN');
}

parent::__construct($instructionId, $endToEndId, $amount, $creditorName, $creditorAddress, $creditorIBAN, $creditorAgent);
}

/**
* @param DOMDocument $doc
* @param DOMElement $transaction
*/
protected function appendRemittanceInformation(DOMDocument $doc, DOMElement $transaction)
{
$remittanceInformation = $doc->createElement('RmtInf');

$structured = $doc->createElement('Strd');
$remittanceInformation->appendChild($structured);

$creditorReferenceInformation = $doc->createElement('CdtrRefInf');
$structured->appendChild($creditorReferenceInformation);

$codeOrProperty = $doc->createElement('CdOrPrtry');
$codeOrProperty->appendChild($doc->createElement('Prtry', 'QRR'));
$type = $doc->createElement('Tp');
$type->appendChild($codeOrProperty);

$creditorReferenceInformation->appendChild($type);
$creditorReferenceInformation->appendChild($doc->createElement('Ref', $this->creditorReference));

if (!empty($this->remittanceInformation)) {
$structured->appendChild($doc->createElement('AddtlRmtInf', $this->remittanceInformation));
}

$transaction->appendChild($remittanceInformation);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
use Z38\SwissPayment\StructuredPostalAddress;
use Z38\SwissPayment\Tests\TestCase;
use Z38\SwissPayment\TransactionInformation\BankCreditTransfer;
use Z38\SwissPayment\TransactionInformation\BankCreditTransferWithCreditorReference;
use Z38\SwissPayment\TransactionInformation\BankCreditTransferWithQRR;
use Z38\SwissPayment\TransactionInformation\ForeignCreditTransfer;
use Z38\SwissPayment\TransactionInformation\IS1CreditTransfer;
use Z38\SwissPayment\TransactionInformation\IS2CreditTransfer;
Expand Down Expand Up @@ -51,6 +53,7 @@ protected function buildMessage()
new IBAN('CH51 0022 5225 9529 1301 C'),
new BIC('UBSWCHZH80A')
);
$transaction->setRemittanceInformation("Test Remittance");
$payment->addTransaction($transaction);

$transaction = new IS1CreditTransfer(
Expand All @@ -73,6 +76,7 @@ protected function buildMessage()
'Musterbank AG',
new PostalAccount('80-151-4')
);
$transaction->setRemittanceInformation("Test Remittance");
$payment->addTransaction($transaction);

$iban = new IBAN('CH51 0022 5225 9529 1301 C');
Expand All @@ -85,6 +89,7 @@ protected function buildMessage()
$iban,
IID::fromIBAN($iban)
);
$transaction->setRemittanceInformation("Test Remittance");
$transaction->setPurpose(new PurposeCode('AIRB'));
$payment->addTransaction($transaction);

Expand Down Expand Up @@ -207,6 +212,42 @@ protected function buildMessage()
new StructuredPostalAddress('Dorfstrasse', '17', '9911', 'Musterwald'),
new PostalAccount('60-9-9')
);
$transaction->setRemittanceInformation("Test Remittance");
$payment->addTransaction($transaction);

$payment = new PaymentInformation(
'payment-050',
'InnoMuster AG',
new BIC('ZKBKCHZZ80A'),
new IBAN('CH6600700110000204481')
);
$message->addPayment($payment);

$qrIban = new IBAN('CH44 3199 9123 0008 8901 2');
$transaction = new BankCreditTransferWithQRR(
'instr-050',
'e2e-050',
new Money\CHF(130000), // CHF 1300.00
'Muster Transport AG',
new StructuredPostalAddress('Wiesenweg', '14b', '8058', 'Zürich-Flughafen'),
$qrIban,
IID::fromIBAN($qrIban),
'210000000003139471430009017'
);
$transaction->setRemittanceInformation("Test Remittance");
$payment->addTransaction($transaction);

$transaction = new BankCreditTransferWithCreditorReference(
'instr-050',
'e2e-050',
new Money\CHF(130000), // CHF 1300.00
'Muster Transport AG',
new StructuredPostalAddress('Wiesenweg', '14b', '8058', 'Zürich-Flughafen'),
$iban,
IID::fromIBAN($iban),
'RF 72 0191 2301 0040 5JSH 0438'
);
$transaction->setRemittanceInformation("Test Remittance");
$payment->addTransaction($transaction);

return $message;
Expand All @@ -222,10 +263,10 @@ public function testGroupHeader()
$xpath->registerNamespace('pain001', self::SCHEMA);

$nbOfTxs = $xpath->evaluate('string(//pain001:GrpHdr/pain001:NbOfTxs)');
$this->assertEquals('12', $nbOfTxs);
$this->assertEquals('14', $nbOfTxs);

$ctrlSum = $xpath->evaluate('string(//pain001:GrpHdr/pain001:CtrlSum)');
$this->assertEquals('4210.001', $ctrlSum);
$this->assertEquals('6810.001', $ctrlSum);
}

public function testSchemaValidation()
Expand All @@ -250,6 +291,6 @@ public function testGetPaymentCount()
{
$message = $this->buildMessage();

$this->assertSame(5, $message->getPaymentCount());
$this->assertSame(6, $message->getPaymentCount());
}
}

0 comments on commit 4280e02

Please sign in to comment.