From f0659c9218434a21dbfc55597313a4cfe2f182b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Pillevesse?= Date: Tue, 15 Oct 2024 15:59:08 +0200 Subject: [PATCH] Remove useless code (#51) --- .../AdditionalSupportingDocument.php | 89 - src/BusinessTermsGroup/Buyer.php | 150 - src/BusinessTermsGroup/BuyerContact.php | 73 - src/BusinessTermsGroup/BuyerPostalAddress.php | 145 - src/BusinessTermsGroup/CreditTransfer.php | 71 - src/BusinessTermsGroup/DeliverToAddress.php | 146 - .../DeliveryInformation.php | 114 - src/BusinessTermsGroup/DirectDebit.php | 78 - .../DocumentLevelAllowance.php | 170 -- .../DocumentLevelCharge.php | 171 -- src/BusinessTermsGroup/DocumentTotals.php | 170 -- src/BusinessTermsGroup/InvoiceLine.php | 294 -- .../InvoiceLineAllowance.php | 100 - src/BusinessTermsGroup/InvoiceLineCharge.php | 101 - src/BusinessTermsGroup/InvoiceLinePeriod.php | 52 - src/BusinessTermsGroup/InvoiceNote.php | 50 - src/BusinessTermsGroup/InvoicingPeriod.php | 52 - src/BusinessTermsGroup/ItemAttribute.php | 40 - src/BusinessTermsGroup/ItemInformation.php | 187 -- src/BusinessTermsGroup/LineVatInformation.php | 89 - src/BusinessTermsGroup/Payee.php | 69 - .../PaymentCardInformation.php | 51 - .../PaymentInstructions.php | 155 - src/BusinessTermsGroup/PrecedingInvoice.php | 49 - src/BusinessTermsGroup/PriceDetails.php | 123 - src/BusinessTermsGroup/ProcessControl.php | 51 - src/BusinessTermsGroup/Seller.php | 206 -- src/BusinessTermsGroup/SellerContact.php | 73 - .../SellerPostalAddress.php | 145 - .../SellerTaxRepresentativeParty.php | 57 - .../SellerTaxRepresentativePostalAddress.php | 145 - src/BusinessTermsGroup/VatBreakdown.php | 165 -- src/Invoice.php | 1633 ----------- tests/BusinessRulesConditionsTest.php | 2527 ----------------- .../BusinessRulesIntegrityConstraintsTest.php | 1475 ---------- tests/BusinessRulesVatRulesBRAETest.php | 1908 ------------- tests/BusinessRulesVatRulesBRETest.php | 1170 -------- tests/BusinessRulesVatRulesBRGTest.php | 1067 ------- tests/BusinessRulesVatRulesBRICTest.php | 1347 --------- tests/BusinessRulesVatRulesBRIGTest.php | 1221 -------- tests/BusinessRulesVatRulesBRIPTest.php | 1221 -------- tests/BusinessRulesVatRulesBROTest.php | 1327 --------- tests/BusinessRulesVatRulesBRSTest.php | 1444 ---------- tests/BusinessRulesVatRulesBRZTest.php | 1170 -------- 44 files changed, 21141 deletions(-) delete mode 100644 src/BusinessTermsGroup/AdditionalSupportingDocument.php delete mode 100644 src/BusinessTermsGroup/Buyer.php delete mode 100644 src/BusinessTermsGroup/BuyerContact.php delete mode 100644 src/BusinessTermsGroup/BuyerPostalAddress.php delete mode 100644 src/BusinessTermsGroup/CreditTransfer.php delete mode 100644 src/BusinessTermsGroup/DeliverToAddress.php delete mode 100644 src/BusinessTermsGroup/DeliveryInformation.php delete mode 100644 src/BusinessTermsGroup/DirectDebit.php delete mode 100644 src/BusinessTermsGroup/DocumentLevelAllowance.php delete mode 100644 src/BusinessTermsGroup/DocumentLevelCharge.php delete mode 100644 src/BusinessTermsGroup/DocumentTotals.php delete mode 100644 src/BusinessTermsGroup/InvoiceLine.php delete mode 100644 src/BusinessTermsGroup/InvoiceLineAllowance.php delete mode 100644 src/BusinessTermsGroup/InvoiceLineCharge.php delete mode 100644 src/BusinessTermsGroup/InvoiceLinePeriod.php delete mode 100644 src/BusinessTermsGroup/InvoiceNote.php delete mode 100644 src/BusinessTermsGroup/InvoicingPeriod.php delete mode 100644 src/BusinessTermsGroup/ItemAttribute.php delete mode 100644 src/BusinessTermsGroup/ItemInformation.php delete mode 100644 src/BusinessTermsGroup/LineVatInformation.php delete mode 100644 src/BusinessTermsGroup/Payee.php delete mode 100644 src/BusinessTermsGroup/PaymentCardInformation.php delete mode 100644 src/BusinessTermsGroup/PaymentInstructions.php delete mode 100644 src/BusinessTermsGroup/PrecedingInvoice.php delete mode 100644 src/BusinessTermsGroup/PriceDetails.php delete mode 100644 src/BusinessTermsGroup/ProcessControl.php delete mode 100644 src/BusinessTermsGroup/Seller.php delete mode 100644 src/BusinessTermsGroup/SellerContact.php delete mode 100644 src/BusinessTermsGroup/SellerPostalAddress.php delete mode 100644 src/BusinessTermsGroup/SellerTaxRepresentativeParty.php delete mode 100644 src/BusinessTermsGroup/SellerTaxRepresentativePostalAddress.php delete mode 100644 src/BusinessTermsGroup/VatBreakdown.php delete mode 100644 src/Invoice.php delete mode 100644 tests/BusinessRulesConditionsTest.php delete mode 100644 tests/BusinessRulesIntegrityConstraintsTest.php delete mode 100644 tests/BusinessRulesVatRulesBRAETest.php delete mode 100644 tests/BusinessRulesVatRulesBRETest.php delete mode 100644 tests/BusinessRulesVatRulesBRGTest.php delete mode 100644 tests/BusinessRulesVatRulesBRICTest.php delete mode 100644 tests/BusinessRulesVatRulesBRIGTest.php delete mode 100644 tests/BusinessRulesVatRulesBRIPTest.php delete mode 100644 tests/BusinessRulesVatRulesBROTest.php delete mode 100644 tests/BusinessRulesVatRulesBRSTest.php delete mode 100644 tests/BusinessRulesVatRulesBRZTest.php diff --git a/src/BusinessTermsGroup/AdditionalSupportingDocument.php b/src/BusinessTermsGroup/AdditionalSupportingDocument.php deleted file mode 100644 index 8ddc609..0000000 --- a/src/BusinessTermsGroup/AdditionalSupportingDocument.php +++ /dev/null @@ -1,89 +0,0 @@ -reference = $reference; - $this->description = null; - $this->externalDocumentLocation = null; - $this->attachedDocument = null; - } - - public function getReference(): SupportingDocumentReference - { - return $this->reference; - } - - public function getDescription(): ?string - { - return $this->description; - } - - public function setDescription(?string $description): self - { - $this->description = $description; - - return $this; - } - - public function getExternalDocumentLocation(): ?string - { - return $this->externalDocumentLocation; - } - - public function setExternalDocumentLocation(?string $externalDocumentLocation): self - { - $this->externalDocumentLocation = $externalDocumentLocation; - - return $this; - } - - public function getAttachedDocument(): ?BinaryObject - { - return $this->attachedDocument; - } - - public function setAttachedDocument(?BinaryObject $attachedDocument): self - { - $this->attachedDocument = $attachedDocument; - - return $this; - } -} diff --git a/src/BusinessTermsGroup/Buyer.php b/src/BusinessTermsGroup/Buyer.php deleted file mode 100644 index 9ea2f51..0000000 --- a/src/BusinessTermsGroup/Buyer.php +++ /dev/null @@ -1,150 +0,0 @@ -name = $name; - $this->address = $address; - $this->vatIdentifier = $vatIdentifier; - $this->legalRegistrationIdentifier = $legalRegistrationIdentifier; - $this->tradingName = null; - $this->identifier = null; - $this->electronicAddress = null; - $this->contact = null; - } - - public function getName(): string - { - return $this->name; - } - - public function getTradingName(): ?string - { - return $this->tradingName; - } - - public function setTradingName(?string $tradingName): self - { - $this->tradingName = $tradingName; - - return $this; - } - - public function getIdentifier(): ?BuyerIdentifier - { - return $this->identifier; - } - - public function setIdentifier(?BuyerIdentifier $identifier): self - { - $this->identifier = $identifier; - - return $this; - } - - public function getLegalRegistrationIdentifier(): ?LegalRegistrationIdentifier - { - return $this->legalRegistrationIdentifier; - } - - public function getVatIdentifier(): ?VatIdentifier - { - return $this->vatIdentifier; - } - - public function getElectronicAddress(): ?ElectronicAddressIdentifier - { - return $this->electronicAddress; - } - - public function setElectronicAddress(?ElectronicAddressIdentifier $electronicAddress): self - { - $this->electronicAddress = $electronicAddress; - - return $this; - } - - public function getAddress(): BuyerPostalAddress - { - return $this->address; - } - - public function getContact(): ?BuyerContact - { - return $this->contact; - } - - public function setContact(?BuyerContact $contact): self - { - $this->contact = $contact; - - return $this; - } -} diff --git a/src/BusinessTermsGroup/BuyerContact.php b/src/BusinessTermsGroup/BuyerContact.php deleted file mode 100644 index d77d5c0..0000000 --- a/src/BusinessTermsGroup/BuyerContact.php +++ /dev/null @@ -1,73 +0,0 @@ -point = null; - $this->phoneNumber = null; - $this->email = null; - } - - public function getPoint(): ?string - { - return $this->point; - } - - public function setPoint(?string $point): self - { - $this->point = $point; - - return $this; - } - - public function getPhoneNumber(): ?string - { - return $this->phoneNumber; - } - - public function setPhoneNumber(?string $phoneNumber): self - { - $this->phoneNumber = $phoneNumber; - - return $this; - } - - public function getEmail(): ?string - { - return $this->email; - } - - public function setEmail(?string $email): self - { - $this->email = $email; - - return $this; - } -} diff --git a/src/BusinessTermsGroup/BuyerPostalAddress.php b/src/BusinessTermsGroup/BuyerPostalAddress.php deleted file mode 100644 index b710a97..0000000 --- a/src/BusinessTermsGroup/BuyerPostalAddress.php +++ /dev/null @@ -1,145 +0,0 @@ -countryCode = $countryCode; - $this->line1 = null; - $this->line2 = null; - $this->line3 = null; - $this->city = null; - $this->postCode = null; - $this->countrySubdivision = null; - } - - public function getLine1(): ?string - { - return $this->line1; - } - - public function setLine1(?string $line1): self - { - $this->line1 = $line1; - - return $this; - } - - public function getLine2(): ?string - { - return $this->line2; - } - - public function setLine2(?string $line2): self - { - $this->line2 = $line2; - - return $this; - } - - public function getLine3(): ?string - { - return $this->line3; - } - - public function setLine3(?string $line3): self - { - $this->line3 = $line3; - - return $this; - } - - public function getCity(): ?string - { - return $this->city; - } - - public function setCity(?string $city): self - { - $this->city = $city; - - return $this; - } - - public function getPostCode(): ?string - { - return $this->postCode; - } - - public function setPostCode(?string $postCode): self - { - $this->postCode = $postCode; - - return $this; - } - - public function getCountrySubdivision(): ?string - { - return $this->countrySubdivision; - } - - public function setCountrySubdivision(?string $countrySubdivision): self - { - $this->countrySubdivision = $countrySubdivision; - - return $this; - } - - public function getCountryCode(): CountryAlpha2Code - { - return $this->countryCode; - } -} diff --git a/src/BusinessTermsGroup/CreditTransfer.php b/src/BusinessTermsGroup/CreditTransfer.php deleted file mode 100644 index 66c6609..0000000 --- a/src/BusinessTermsGroup/CreditTransfer.php +++ /dev/null @@ -1,71 +0,0 @@ -paymentAccountIdentifier = $paymentAccountIdentifier; - $this->paymentAccountName = null; - $this->paymentServiceProviderIdentifier = null; - } - - public function getPaymentAccountIdentifier(): PaymentAccountIdentifier - { - return $this->paymentAccountIdentifier; - } - - public function getPaymentAccountName(): ?string - { - return $this->paymentAccountName; - } - - public function setPaymentAccountName(?string $paymentAccountName): self - { - $this->paymentAccountName = $paymentAccountName; - - return $this; - } - - public function getPaymentServiceProviderIdentifier(): ?PaymentServiceProviderIdentifier - { - return $this->paymentServiceProviderIdentifier; - } - - public function setPaymentServiceProviderIdentifier( - ?PaymentServiceProviderIdentifier $paymentServiceProviderIdentifier - ): self { - $this->paymentServiceProviderIdentifier = $paymentServiceProviderIdentifier; - - return $this; - } -} diff --git a/src/BusinessTermsGroup/DeliverToAddress.php b/src/BusinessTermsGroup/DeliverToAddress.php deleted file mode 100644 index 56cc5fc..0000000 --- a/src/BusinessTermsGroup/DeliverToAddress.php +++ /dev/null @@ -1,146 +0,0 @@ -countryCode = $countryCode; - $this->line1 = null; - $this->line2 = null; - $this->line3 = null; - $this->city = null; - $this->postCode = null; - $this->countrySubdivision = null; - } - - public function getLine1(): ?string - { - return $this->line1; - } - - public function setLine1(?string $line1): self - { - $this->line1 = $line1; - - return $this; - } - - public function getLine2(): ?string - { - return $this->line2; - } - - public function setLine2(?string $line2): self - { - $this->line2 = $line2; - - return $this; - } - - public function getLine3(): ?string - { - return $this->line3; - } - - public function setLine3(?string $line3): self - { - $this->line3 = $line3; - - return $this; - } - - public function getCity(): ?string - { - return $this->city; - } - - public function setCity(?string $city): self - { - $this->city = $city; - - return $this; - } - - public function getPostCode(): ?string - { - return $this->postCode; - } - - public function setPostCode(?string $postCode): self - { - $this->postCode = $postCode; - - return $this; - } - - public function getCountrySubdivision(): ?string - { - return $this->countrySubdivision; - } - - public function setCountrySubdivision(?string $countrySubdivision): self - { - $this->countrySubdivision = $countrySubdivision; - - return $this; - } - - public function getCountryCode(): CountryAlpha2Code - { - return $this->countryCode; - } -} diff --git a/src/BusinessTermsGroup/DeliveryInformation.php b/src/BusinessTermsGroup/DeliveryInformation.php deleted file mode 100644 index 0eb5b23..0000000 --- a/src/BusinessTermsGroup/DeliveryInformation.php +++ /dev/null @@ -1,114 +0,0 @@ -deliverToPartyName = null; - $this->locationIdentifier = null; - $this->actualDeliveryDate = null; - $this->invoicingPeriod = null; - $this->deliverToAddress = null; - } - - public function getDeliverToPartyName(): ?string - { - return $this->deliverToPartyName; - } - - public function setDeliverToPartyName(?string $deliverToPartyName): self - { - $this->deliverToPartyName = $deliverToPartyName; - - return $this; - } - - public function getLocationIdentifier(): ?LocationIdentifier - { - return $this->locationIdentifier; - } - - public function setLocationIdentifier(?LocationIdentifier $locationIdentifier): self - { - $this->locationIdentifier = $locationIdentifier; - - return $this; - } - - public function getActualDeliveryDate(): ?\DateTimeInterface - { - return $this->actualDeliveryDate; - } - - public function setActualDeliveryDate(?\DateTimeInterface $actualDeliveryDate): self - { - $this->actualDeliveryDate = $actualDeliveryDate; - - return $this; - } - - public function getInvoicingPeriod(): ?InvoicingPeriod - { - return $this->invoicingPeriod; - } - - public function setInvoicingPeriod(?InvoicingPeriod $invoicingPeriod): self - { - $this->invoicingPeriod = $invoicingPeriod; - - return $this; - } - - public function getDeliverToAddress(): ?DeliverToAddress - { - return $this->deliverToAddress; - } - - public function setDeliverToAddress(?DeliverToAddress $deliverToAddress): self - { - $this->deliverToAddress = $deliverToAddress; - - return $this; - } -} diff --git a/src/BusinessTermsGroup/DirectDebit.php b/src/BusinessTermsGroup/DirectDebit.php deleted file mode 100644 index a001c40..0000000 --- a/src/BusinessTermsGroup/DirectDebit.php +++ /dev/null @@ -1,78 +0,0 @@ -mandateReferenceIdentifier = null; - $this->bankAssignedCreditorIdentifier = null; - $this->debitedAccountIdentifier = null; - } - - public function getMandateReferenceIdentifier(): ?MandateReferenceIdentifier - { - return $this->mandateReferenceIdentifier; - } - - public function setMandateReferenceIdentifier(?MandateReferenceIdentifier $mandateReferenceIdentifier): DirectDebit - { - $this->mandateReferenceIdentifier = $mandateReferenceIdentifier; - - return $this; - } - - public function getBankAssignedCreditorIdentifier(): ?BankAssignedCreditorIdentifier - { - return $this->bankAssignedCreditorIdentifier; - } - - public function setBankAssignedCreditorIdentifier( - ?BankAssignedCreditorIdentifier $bankAssignedCreditorIdentifier - ): DirectDebit { - $this->bankAssignedCreditorIdentifier = $bankAssignedCreditorIdentifier; - - return $this; - } - - public function getDebitedAccountIdentifier(): ?DebitedAccountIdentifier - { - return $this->debitedAccountIdentifier; - } - - public function setDebitedAccountIdentifier(?DebitedAccountIdentifier $debitedAccountIdentifier): DirectDebit - { - $this->debitedAccountIdentifier = $debitedAccountIdentifier; - - return $this; - } -} diff --git a/src/BusinessTermsGroup/DocumentLevelAllowance.php b/src/BusinessTermsGroup/DocumentLevelAllowance.php deleted file mode 100644 index 0fa6640..0000000 --- a/src/BusinessTermsGroup/DocumentLevelAllowance.php +++ /dev/null @@ -1,170 +0,0 @@ -vatRate = is_float($vatRate) ? new Percentage($vatRate) : $vatRate; - $this->amount = new Amount($amount); - $this->baseAmount = null; - $this->percentage = null; - $this->vatCategoryCode = $vatCategoryCode; - $this->reason = $reason; - $this->reasonCode = $reasonCode; - } - - public function getAmount(): Amount - { - return $this->amount; - } - - public function getBaseAmount(): ?Amount - { - return $this->baseAmount; - } - - public function setBaseAmount(?float $baseAmount): self - { - $this->baseAmount = \is_float($baseAmount) ? new Amount($baseAmount) : null; - - return $this; - } - - public function getPercentage(): ?Percentage - { - return $this->percentage; - } - - public function setPercentage(?float $percentage): self - { - $this->percentage = \is_float($percentage) ? new Percentage($percentage) : null; - - return $this; - } - - public function getVatCategoryCode(): VatCategory - { - return $this->vatCategoryCode; - } - - public function getVatRate(): ?Percentage - { - return $this->vatRate; - } - - public function getReason(): ?string - { - return $this->reason; - } - - public function getReasonCode(): ?AllowanceReasonCodeUNTDID5189 - { - return $this->reasonCode; - } -} diff --git a/src/BusinessTermsGroup/DocumentLevelCharge.php b/src/BusinessTermsGroup/DocumentLevelCharge.php deleted file mode 100644 index 047ae5b..0000000 --- a/src/BusinessTermsGroup/DocumentLevelCharge.php +++ /dev/null @@ -1,171 +0,0 @@ -vatRate = is_float($vatRate) ? new Percentage($vatRate) : $vatRate; - $this->amount = new Amount($amount); - $this->baseAmount = null; - $this->percentage = null; - $this->vatCategoryCode = $vatCategoryCode; - $this->reason = $reason; - $this->reasonCode = $reasonCode; - } - - public function getAmount(): Amount - { - return $this->amount; - } - - public function getBaseAmount(): ?Amount - { - return $this->baseAmount; - } - - public function setBaseAmount(?float $baseAmount): self - { - $this->baseAmount = \is_float($baseAmount) ? new Amount($baseAmount) : null; - - return $this; - } - - public function getPercentage(): ?Percentage - { - return $this->percentage; - } - - public function setPercentage(?float $percentage): self - { - $this->percentage = \is_float($percentage) ? new Percentage($percentage) : null; - - return $this; - } - - public function getVatCategoryCode(): VatCategory - { - return $this->vatCategoryCode; - } - - public function getVatRate(): ?Percentage - { - return $this->vatRate; - } - - public function getReason(): ?string - { - return $this->reason; - } - - public function getReasonCode(): ?ChargeReasonCode - { - return $this->reasonCode; - } -} diff --git a/src/BusinessTermsGroup/DocumentTotals.php b/src/BusinessTermsGroup/DocumentTotals.php deleted file mode 100644 index 99f71ac..0000000 --- a/src/BusinessTermsGroup/DocumentTotals.php +++ /dev/null @@ -1,170 +0,0 @@ -sumOfInvoiceLineNetAmount = new Amount($sumOfInvoiceLineNetAmount); - $this->invoiceTotalAmountWithoutVat = new Amount($invoiceTotalAmountWithoutVat); - $this->invoiceTotalAmountWithVat = new Amount($invoiceTotalAmountWithVat); - $this->amountDueForPayment = new Amount($amountDueForPayment); - - $this->invoiceTotalVatAmountInAccountingCurrency = $invoiceTotalVatAmountInAccountingCurrency !== null ? - new Amount($invoiceTotalVatAmountInAccountingCurrency) : $invoiceTotalVatAmountInAccountingCurrency; - $this->invoiceTotalVatAmount = $invoiceTotalVatAmount !== null ? - new Amount($invoiceTotalVatAmount) : $invoiceTotalVatAmount; - $this->paidAmount = $paidAmount !== null ? new Amount($paidAmount) : $paidAmount; - $this->roundingAmount = $roundingAmount !== null ? new Amount($roundingAmount) : $roundingAmount; - $this->sumOfAllowancesOnDocumentLevel = $sumOfAllowancesOnDocumentLevel !== null ? - new Amount($sumOfAllowancesOnDocumentLevel) : $sumOfAllowancesOnDocumentLevel; - $this->sumOfChargesOnDocumentLevel = $sumOfChargesOnDocumentLevel !== null ? - new Amount($sumOfChargesOnDocumentLevel) : $sumOfChargesOnDocumentLevel; - - $BT109_plus_BT110 = $this->invoiceTotalAmountWithoutVat - ->add($this->invoiceTotalVatAmount ?? new Amount(0.00), Amount::DECIMALS); - - if ($this->invoiceTotalAmountWithVat->getValueRounded() !== $BT109_plus_BT110) { - throw new \Exception('@todo : BR-CO-15'); - } - - $BT112_minus_BT113 = $this->invoiceTotalAmountWithVat - ->subtract($this->paidAmount ?? new Amount(0.00)); - $BT112_BT113_plus_BT114 = (new DecimalNumber($BT112_minus_BT113)) - ->add($this->roundingAmount ?? new Amount(0.00), Amount::DECIMALS); - - if ($this->amountDueForPayment->getValueRounded() !== $BT112_BT113_plus_BT114) { - throw new \Exception('@todo : BR-CO-16'); - } - } - - public function getSumOfInvoiceLineNetAmount(): Amount - { - return $this->sumOfInvoiceLineNetAmount; - } - - public function getSumOfAllowancesOnDocumentLevel(): ?Amount - { - return $this->sumOfAllowancesOnDocumentLevel; - } - - public function getSumOfChargesOnDocumentLevel(): ?Amount - { - return $this->sumOfChargesOnDocumentLevel; - } - - public function getInvoiceTotalAmountWithoutVat(): Amount - { - return $this->invoiceTotalAmountWithoutVat; - } - - public function getInvoiceTotalVatAmount(): ?Amount - { - return $this->invoiceTotalVatAmount; - } - - public function getInvoiceTotalVatAmountInAccountingCurrency(): ?Amount - { - return $this->invoiceTotalVatAmountInAccountingCurrency; - } - - public function getInvoiceTotalAmountWithVat(): Amount - { - return $this->invoiceTotalAmountWithVat; - } - - public function getPaidAmount(): ?Amount - { - return $this->paidAmount; - } - - public function getRoundingAmount(): ?Amount - { - return $this->roundingAmount; - } - - public function getAmountDueForPayment(): Amount - { - return $this->amountDueForPayment; - } -} diff --git a/src/BusinessTermsGroup/InvoiceLine.php b/src/BusinessTermsGroup/InvoiceLine.php deleted file mode 100644 index fc4ecc4..0000000 --- a/src/BusinessTermsGroup/InvoiceLine.php +++ /dev/null @@ -1,294 +0,0 @@ - - */ - private array $allowances; - - /** - * BG-28 - * A group of business terms providing information about charges and taxes other than VAT applicable to - * the individual Invoice line. - * - * @var array - */ - private array $charges; - - /** - * BG-29 - * A group of business terms providing information about the price applied for - * the goods and services invoiced on the Invoice line. - */ - private PriceDetails $priceDetails; - - /** - * BG-30 - * A group of business terms providing information about the VAT applicable for - * the goods and services invoiced on the Invoice line. - */ - private LineVatInformation $lineVatInformation; - - /** - * BG-31 - * A group of business terms providing information about the goods and services invoiced. - */ - private ItemInformation $itemInformation; - - - - public function __construct( - InvoiceLineIdentifier $identifier, - float $invoicedQuantity, - UnitOfMeasurement $invoicedQuantityUnitOfMeasureCode, - float $netAmount, - PriceDetails $priceDetails, - LineVatInformation $lineVatInformation, - ItemInformation $itemInformation, - ) { - $this->identifier = $identifier; - $this->invoicedQuantity = new Quantity($invoicedQuantity); - $this->invoicedQuantityUnitOfMeasureCode = $invoicedQuantityUnitOfMeasureCode; - $this->netAmount = new Amount($netAmount); - $this->priceDetails = $priceDetails; - $this->lineVatInformation = $lineVatInformation; - $this->itemInformation = $itemInformation; - $this->allowances = []; - $this->charges = []; - $this->note = null; - $this->objectIdentifier = null; - $this->referencedPurchaseOrderLineReference = null; - $this->buyerAccountingReference = null; - $this->period = null; - } - - public function getIdentifier(): InvoiceLineIdentifier - { - return $this->identifier; - } - - public function getNote(): ?string - { - return $this->note; - } - - public function setNote(?string $note): self - { - $this->note = $note; - - return $this; - } - - public function getObjectIdentifier(): ?ObjectIdentifier - { - return $this->objectIdentifier; - } - - public function setObjectIdentifier(?ObjectIdentifier $objectIdentifier): self - { - $this->objectIdentifier = $objectIdentifier; - - return $this; - } - - public function getInvoicedQuantity(): Quantity - { - return $this->invoicedQuantity; - } - - public function getInvoicedQuantityUnitOfMeasureCode(): UnitOfMeasurement - { - return $this->invoicedQuantityUnitOfMeasureCode; - } - - public function getNetAmount(): Amount - { - return $this->netAmount; - } - - public function getReferencedPurchaseOrderLineReference(): ?PurchaseOrderLineReference - { - return $this->referencedPurchaseOrderLineReference; - } - - public function setReferencedPurchaseOrderLineReference( - ?PurchaseOrderLineReference $referencedPurchaseOrderLineReference - ): self { - $this->referencedPurchaseOrderLineReference = $referencedPurchaseOrderLineReference; - - return $this; - } - - public function getBuyerAccountingReference(): ?string - { - return $this->buyerAccountingReference; - } - - public function setBuyerAccountingReference(?string $buyerAccountingReference): self - { - $this->buyerAccountingReference = $buyerAccountingReference; - - return $this; - } - - public function getPeriod(): ?InvoiceLinePeriod - { - return $this->period; - } - - public function setPeriod(?InvoiceLinePeriod $period): self - { - $this->period = $period; - - return $this; - } - - /** - * @return array - */ - public function getAllowances(): array - { - return $this->allowances; - } - - /** - * @param array $allowances - */ - public function setAllowances(array $allowances): self - { - $this->allowances = $allowances; - - return $this; - } - - /** - * @return array - */ - public function getCharges(): array - { - return $this->charges; - } - - /** - * @param array $charges - */ - public function setCharges(array $charges): self - { - $this->charges = $charges; - - return $this; - } - - public function getPriceDetails(): PriceDetails - { - return $this->priceDetails; - } - - public function getLineVatInformation(): LineVatInformation - { - return $this->lineVatInformation; - } - - public function getItemInformation(): ItemInformation - { - return $this->itemInformation; - } -} diff --git a/src/BusinessTermsGroup/InvoiceLineAllowance.php b/src/BusinessTermsGroup/InvoiceLineAllowance.php deleted file mode 100644 index efcbad1..0000000 --- a/src/BusinessTermsGroup/InvoiceLineAllowance.php +++ /dev/null @@ -1,100 +0,0 @@ -amount = new Amount($amount); - $this->baseAmount = null; - $this->percentage = null; - $this->reason = $reason; - $this->reasonCode = $reasonCode; - } - - public function getAmount(): Amount - { - return $this->amount; - } - - public function getBaseAmount(): ?Amount - { - return $this->baseAmount; - } - - public function setBaseAmount(?float $baseAmount): self - { - $this->baseAmount = \is_float($baseAmount) ? new Amount($baseAmount) : null; - - return $this; - } - - public function getPercentage(): ?Percentage - { - return $this->percentage; - } - - public function setPercentage(?float $percentage): self - { - $this->percentage = \is_float($percentage) ? new Percentage($percentage) : null; - - return $this; - } - - public function getReason(): ?string - { - return $this->reason; - } - - public function getReasonCode(): ?AllowanceReasonCodeUNTDID5189 - { - return $this->reasonCode; - } -} diff --git a/src/BusinessTermsGroup/InvoiceLineCharge.php b/src/BusinessTermsGroup/InvoiceLineCharge.php deleted file mode 100644 index 4caf37e..0000000 --- a/src/BusinessTermsGroup/InvoiceLineCharge.php +++ /dev/null @@ -1,101 +0,0 @@ -amount = new Amount($amount); - $this->baseAmount = null; - $this->percentage = null; - $this->reason = $reason; - $this->reasonCode = $reasonCode; - } - - public function getAmount(): Amount - { - return $this->amount; - } - - public function getBaseAmount(): ?Amount - { - return $this->baseAmount; - } - - public function setBaseAmount(?float $baseAmount): self - { - $this->baseAmount = \is_float($baseAmount) ? new Amount($baseAmount) : null; - - return $this; - } - - public function getPercentage(): ?Percentage - { - return $this->percentage; - } - - public function setPercentage(?float $percentage): self - { - $this->percentage = \is_float($percentage) ? new Percentage($percentage) : null; - - return $this; - } - - public function getReason(): ?string - { - return $this->reason; - } - - public function getReasonCode(): ?ChargeReasonCode - { - return $this->reasonCode; - } -} diff --git a/src/BusinessTermsGroup/InvoiceLinePeriod.php b/src/BusinessTermsGroup/InvoiceLinePeriod.php deleted file mode 100644 index 6ebe1ed..0000000 --- a/src/BusinessTermsGroup/InvoiceLinePeriod.php +++ /dev/null @@ -1,52 +0,0 @@ - $endDate - ) { - throw new \Exception('@todo'); - } - - if (null === $startDate && null === $endDate) { - throw new \Exception('@todo : BR-CO-20'); - } - - $this->startDate = $startDate; - $this->endDate = $endDate; - } - - public function getStartDate(): ?\DateTimeInterface - { - return $this->startDate; - } - - public function getEndDate(): ?\DateTimeInterface - { - return $this->endDate; - } -} diff --git a/src/BusinessTermsGroup/InvoiceNote.php b/src/BusinessTermsGroup/InvoiceNote.php deleted file mode 100644 index a916743..0000000 --- a/src/BusinessTermsGroup/InvoiceNote.php +++ /dev/null @@ -1,50 +0,0 @@ -note = $note; - $this->subjectCode = null; - } - - public function getSubjectCode(): ?InvoiceNoteCode - { - return $this->subjectCode; - } - - public function setSubjectCode(?InvoiceNoteCode $subjectCode): self - { - $this->subjectCode = $subjectCode; - - return $this; - } - - public function getNote(): string - { - return $this->note; - } -} diff --git a/src/BusinessTermsGroup/InvoicingPeriod.php b/src/BusinessTermsGroup/InvoicingPeriod.php deleted file mode 100644 index 249a90e..0000000 --- a/src/BusinessTermsGroup/InvoicingPeriod.php +++ /dev/null @@ -1,52 +0,0 @@ - $endDate - ) { - throw new \Exception('@todo'); - } - - if (null === $startDate && null === $endDate) { - throw new \Exception('@todo : BR-CO-19'); - } - - $this->startDate = $startDate; - $this->endDate = $endDate; - } - - public function getStartDate(): ?\DateTimeInterface - { - return $this->startDate; - } - - public function getEndDate(): ?\DateTimeInterface - { - return $this->endDate; - } -} diff --git a/src/BusinessTermsGroup/ItemAttribute.php b/src/BusinessTermsGroup/ItemAttribute.php deleted file mode 100644 index b181057..0000000 --- a/src/BusinessTermsGroup/ItemAttribute.php +++ /dev/null @@ -1,40 +0,0 @@ -name = $name; - $this->value = $value; - } - - public function getName(): string - { - return $this->name; - } - - public function getValue(): string - { - return $this->value; - } -} diff --git a/src/BusinessTermsGroup/ItemInformation.php b/src/BusinessTermsGroup/ItemInformation.php deleted file mode 100644 index 1ca3027..0000000 --- a/src/BusinessTermsGroup/ItemInformation.php +++ /dev/null @@ -1,187 +0,0 @@ - - */ - private array $classificationIdentifiers; - - /** - * BT-159 - * Item country of origin. - * - * Code identifiant le pays d'où provient l'article. - */ - private ?CountryAlpha2Code $itemCountryOfOrigin; - - /** - * BG-32 - * A group of business terms providing information about properties of the goods and services invoiced. - * - * @var array - */ - private array $itemAttributes; - - public function __construct(string $name) - { - $this->name = $name; - $this->itemAttributes = []; - $this->classificationIdentifiers = []; - $this->description = null; - $this->sellerIdentifier = null; - $this->buyerIdentifier = null; - $this->standardIdentifier = null; - $this->itemCountryOfOrigin = null; - } - - public function getName(): string - { - return $this->name; - } - - public function getDescription(): ?string - { - return $this->description; - } - - public function setDescription(?string $description): self - { - $this->description = $description; - - return $this; - } - - public function getSellerIdentifier(): ?SellerItemIdentifier - { - return $this->sellerIdentifier; - } - - public function setSellerIdentifier(?SellerItemIdentifier $sellerIdentifier): self - { - $this->sellerIdentifier = $sellerIdentifier; - - return $this; - } - - public function getBuyerIdentifier(): ?BuyerItemIdentifier - { - return $this->buyerIdentifier; - } - - public function setBuyerIdentifier(?BuyerItemIdentifier $buyerIdentifier): self - { - $this->buyerIdentifier = $buyerIdentifier; - - return $this; - } - - public function getStandardIdentifier(): ?StandardItemIdentifier - { - return $this->standardIdentifier; - } - - public function setStandardIdentifier(?StandardItemIdentifier $standardIdentifier): self - { - $this->standardIdentifier = $standardIdentifier; - - return $this; - } - - /** - * @return array - */ - public function getClassificationIdentifiers(): array - { - return $this->classificationIdentifiers; - } - - /** - * @param array $classificationIdentifiers - */ - public function setClassificationIdentifiers(array $classificationIdentifiers): self - { - $this->classificationIdentifiers = $classificationIdentifiers; - - return $this; - } - - public function getItemCountryOfOrigin(): ?CountryAlpha2Code - { - return $this->itemCountryOfOrigin; - } - - public function setItemCountryOfOrigin(?CountryAlpha2Code $itemCountryOfOrigin): self - { - $this->itemCountryOfOrigin = $itemCountryOfOrigin; - - return $this; - } - - /** - * @return array - */ - public function getItemAttributes(): array - { - return $this->itemAttributes; - } - - /** - * @param array $itemAttributes - */ - public function setItemAttributes(array $itemAttributes): self - { - $this->itemAttributes = $itemAttributes; - - return $this; - } -} diff --git a/src/BusinessTermsGroup/LineVatInformation.php b/src/BusinessTermsGroup/LineVatInformation.php deleted file mode 100644 index 10ea7e3..0000000 --- a/src/BusinessTermsGroup/LineVatInformation.php +++ /dev/null @@ -1,89 +0,0 @@ -invoicedItemVatCategoryCode = $invoicedItemVatCategoryCode; - $this->invoicedItemVatRate = is_float($invoicedItemVatRate) ? - new Percentage($invoicedItemVatRate) : $invoicedItemVatRate; - } - - public function getInvoicedItemVatCategoryCode(): VatCategory - { - return $this->invoicedItemVatCategoryCode; - } - - public function getInvoicedItemVatRate(): ?Percentage - { - return $this->invoicedItemVatRate; - } -} diff --git a/src/BusinessTermsGroup/Payee.php b/src/BusinessTermsGroup/Payee.php deleted file mode 100644 index 1f68dc3..0000000 --- a/src/BusinessTermsGroup/Payee.php +++ /dev/null @@ -1,69 +0,0 @@ -name = $name; - $this->identifier = null; - $this->legalRegistrationIdentifier = null; - } - - public function getName(): string - { - return $this->name; - } - - public function getIdentifier(): ?PayeeIdentifier - { - return $this->identifier; - } - - public function setIdentifier(?PayeeIdentifier $identifier): self - { - $this->identifier = $identifier; - - return $this; - } - - public function getLegalRegistrationIdentifier(): ?LegalRegistrationIdentifier - { - return $this->legalRegistrationIdentifier; - } - - public function setLegalRegistrationIdentifier(?LegalRegistrationIdentifier $legalRegistrationIdentifier): self - { - $this->legalRegistrationIdentifier = $legalRegistrationIdentifier; - - return $this; - } -} diff --git a/src/BusinessTermsGroup/PaymentCardInformation.php b/src/BusinessTermsGroup/PaymentCardInformation.php deleted file mode 100644 index b2ba917..0000000 --- a/src/BusinessTermsGroup/PaymentCardInformation.php +++ /dev/null @@ -1,51 +0,0 @@ -primaryAccountNumber = $primaryAccountNumber; - $this->holderName = null; - } - - public function getPrimaryAccountNumber(): string - { - return $this->primaryAccountNumber; - } - - public function getHolderName(): ?string - { - return $this->holderName; - } - - public function setHolderName(?string $holderName): self - { - $this->holderName = $holderName; - - return $this; - } -} diff --git a/src/BusinessTermsGroup/PaymentInstructions.php b/src/BusinessTermsGroup/PaymentInstructions.php deleted file mode 100644 index 964c122..0000000 --- a/src/BusinessTermsGroup/PaymentInstructions.php +++ /dev/null @@ -1,155 +0,0 @@ - - */ - private array $creditTransfers; - - /** - * BG-18 - * A group of business terms providing information about card used for payment contemporaneous with invoice - * issuance. - */ - private ?PaymentCardInformation $paymentCardInformation; - - /** - * BG-19 - * A group of business terms to specify a direct debit. - */ - private ?DirectDebit $directDebit; - - /** - * @param array $creditTransfers - */ - public function __construct(PaymentMeansCode $paymentMeansTypeCode, array $creditTransfers = []) - { - $this->paymentMeansTypeCode = $paymentMeansTypeCode; - $this->setCreditTransfers($creditTransfers); - $this->paymentMeansText = null; - $this->remittanceInformation = null; - $this->paymentCardInformation = null; - $this->directDebit = null; - } - - public function getPaymentMeansTypeCode(): PaymentMeansCode - { - return $this->paymentMeansTypeCode; - } - - public function getPaymentMeansText(): ?string - { - return $this->paymentMeansText; - } - - public function setPaymentMeansText(?string $paymentMeansText): self - { - $this->paymentMeansText = $paymentMeansText; - - return $this; - } - - public function getRemittanceInformation(): ?string - { - return $this->remittanceInformation; - } - - public function setRemittanceInformation(?string $remittanceInformation): self - { - $this->remittanceInformation = $remittanceInformation; - - return $this; - } - - /** - * @return array - */ - public function getCreditTransfers(): array - { - return $this->creditTransfers; - } - - /** - * @param array $creditTransfers - */ - public function setCreditTransfers(array $creditTransfers): self - { - if ( - \count($creditTransfers) === 0 - && \in_array($this->paymentMeansTypeCode, self::CREDIT_TRANSFER_CODES, true) - ) { - throw new \Exception('@todo'); - } - - $this->creditTransfers = []; - - foreach ($creditTransfers as $creditTransfer) { - $this->addCreditTransfer($creditTransfer); - } - - return $this; - } - - private function addCreditTransfer(CreditTransfer $creditTransfer): void - { - $this->creditTransfers[] = $creditTransfer; - } - - public function getPaymentCardInformation(): ?PaymentCardInformation - { - return $this->paymentCardInformation; - } - - public function setPaymentCardInformation(?PaymentCardInformation $paymentCardInformation): self - { - $this->paymentCardInformation = $paymentCardInformation; - - return $this; - } - - public function getDirectDebit(): ?DirectDebit - { - return $this->directDebit; - } - - public function setDirectDebit(?DirectDebit $directDebit): self - { - $this->directDebit = $directDebit; - - return $this; - } -} diff --git a/src/BusinessTermsGroup/PrecedingInvoice.php b/src/BusinessTermsGroup/PrecedingInvoice.php deleted file mode 100644 index 9121d07..0000000 --- a/src/BusinessTermsGroup/PrecedingInvoice.php +++ /dev/null @@ -1,49 +0,0 @@ -reference = $reference; - $this->issueDate = null; - } - - public function getReference(): PrecedingInvoiceReference - { - return $this->reference; - } - - public function getIssueDate(): ?\DateTimeInterface - { - return $this->issueDate; - } - - public function setIssueDate(?\DateTimeInterface $issueDate): self - { - $this->issueDate = $issueDate; - - return $this; - } -} diff --git a/src/BusinessTermsGroup/PriceDetails.php b/src/BusinessTermsGroup/PriceDetails.php deleted file mode 100644 index 5698473..0000000 --- a/src/BusinessTermsGroup/PriceDetails.php +++ /dev/null @@ -1,123 +0,0 @@ -itemNetPrice = new UnitPriceAmount($itemNetPrice); - $this->itemPriceDiscount = null; - $this->itemGrossPrice = null; - $this->itemPriceBaseQuantity = null; - $this->itemPriceBaseQuantityUnitOfMeasureCode = null; - } - - public function getItemNetPrice(): UnitPriceAmount - { - return $this->itemNetPrice; - } - - public function getItemPriceDiscount(): ?UnitPriceAmount - { - return $this->itemPriceDiscount; - } - - public function setItemPriceDiscount(?float $itemPriceDiscount): self - { - $this->itemPriceDiscount = \is_float($itemPriceDiscount) ? new UnitPriceAmount($itemPriceDiscount) : null; - - return $this; - } - - public function getItemGrossPrice(): ?UnitPriceAmount - { - return $this->itemGrossPrice; - } - - public function setItemGrossPrice(?float $itemGrossPrice): self - { - if ($itemGrossPrice < 0) { - throw new \Exception('@todo'); - } - - $this->itemGrossPrice = \is_float($itemGrossPrice) ? new UnitPriceAmount($itemGrossPrice) : null; - - return $this; - } - - public function getItemPriceBaseQuantity(): ?Quantity - { - return $this->itemPriceBaseQuantity; - } - - public function setItemPriceBaseQuantity(?float $itemPriceBaseQuantity): self - { - $this->itemPriceBaseQuantity = \is_float($itemPriceBaseQuantity) ? new Quantity($itemPriceBaseQuantity) : null; - - return $this; - } - - public function getItemPriceBaseQuantityUnitOfMeasureCode(): ?UnitOfMeasurement - { - return $this->itemPriceBaseQuantityUnitOfMeasureCode; - } - - public function setItemPriceBaseQuantityUnitOfMeasureCode( - ?UnitOfMeasurement $itemPriceBaseQuantityUnitOfMeasureCode - ): self { - $this->itemPriceBaseQuantityUnitOfMeasureCode = $itemPriceBaseQuantityUnitOfMeasureCode; - - return $this; - } -} diff --git a/src/BusinessTermsGroup/ProcessControl.php b/src/BusinessTermsGroup/ProcessControl.php deleted file mode 100644 index 95df4de..0000000 --- a/src/BusinessTermsGroup/ProcessControl.php +++ /dev/null @@ -1,51 +0,0 @@ -specificationIdentifier = $specificationIdentifier; - $this->businessProcessType = null; - } - - public function getBusinessProcessType(): ?string - { - return $this->businessProcessType; - } - - public function setBusinessProcessType(?string $businessProcessType): self - { - $this->businessProcessType = $businessProcessType; - - return $this; - } - - public function getSpecificationIdentifier(): Specificationidentifier - { - return $this->specificationIdentifier; - } -} diff --git a/src/BusinessTermsGroup/Seller.php b/src/BusinessTermsGroup/Seller.php deleted file mode 100644 index 3abde07..0000000 --- a/src/BusinessTermsGroup/Seller.php +++ /dev/null @@ -1,206 +0,0 @@ - - */ - private array $identifiers; - - /** - * BT-30 - * An identifier issued by an official registrar that identifies the seller as a legal entity or person. - */ - private ?LegalRegistrationIdentifier $legalRegistrationIdentifier; - - /** - * BT-31 - * The Seller's VAT identifier (also known as Seller VAT identification number) - */ - private ?VatIdentifier $vatIdentifier; - - /** - * BT-32 - * The local identification (defined by the Seller’s address) of the Seller for tax purposes - * or a reference that enables the Seller to state his registered tax status. - */ - private ?TaxRegistrationIdentifier $taxRegistrationIdentifier; - - /** - * BT-33 - * Additional legal information relevant for the Seller. - */ - private ?string $additionalLegalInformation; - - /** - * BT-34 - * Identifies the seller's electronic address to which the application level response to - * the invoice may be delivered. - */ - private ?ElectronicAddressIdentifier $electronicAddress; - - /** - * BG-5 - * A group of business terms providing information about the address of the Seller. - */ - private SellerPostalAddress $address; - - /** - * BG-6 - * A group of business terms providing contact information about the Seller. - */ - private ?SellerContact $contact; - - /** - * @param array $identifiers - */ - public function __construct( - string $name, - SellerPostalAddress $address, - array $identifiers, - ?LegalRegistrationIdentifier $legalRegistrationIdentifier, - ?VatIdentifier $vatIdentifier, - ?TaxRegistrationIdentifier $taxRegistrationIdentifier = null - ) { - $this->name = $name; - $this->address = $address; - $this->legalRegistrationIdentifier = $legalRegistrationIdentifier; - $this->vatIdentifier = $vatIdentifier; - - $this->identifiers = []; - foreach ($identifiers as $identifier) { - if (!$identifier instanceof SellerIdentifier) { - throw new \TypeError(); - } - - $this->identifiers[] = $identifier; - } - - if ( - count($this->identifiers) === 0 - && !$legalRegistrationIdentifier instanceof LegalRegistrationIdentifier - && !$vatIdentifier instanceof VatIdentifier - ) { - throw new \Exception('@todo'); - } - - $this->taxRegistrationIdentifier = $taxRegistrationIdentifier; - $this->tradingName = null; - $this->additionalLegalInformation = null; - $this->electronicAddress = null; - $this->contact = null; - } - - public function getName(): string - { - return $this->name; - } - - public function getAddress(): SellerPostalAddress - { - return $this->address; - } - - public function getTradingName(): ?string - { - return $this->tradingName; - } - - public function setTradingName(?string $tradingName): self - { - $this->tradingName = $tradingName; - - return $this; - } - - /** - * @return array - */ - public function getIdentifiers(): array - { - return $this->identifiers; - } - - public function getLegalRegistrationIdentifier(): ?LegalRegistrationIdentifier - { - return $this->legalRegistrationIdentifier; - } - - public function getVatIdentifier(): ?VatIdentifier - { - return $this->vatIdentifier; - } - - public function getTaxRegistrationIdentifier(): ?TaxRegistrationIdentifier - { - return $this->taxRegistrationIdentifier; - } - - public function getAdditionalLegalInformation(): ?string - { - return $this->additionalLegalInformation; - } - - public function setAdditionalLegalInformation(?string $additionalLegalInformation): self - { - $this->additionalLegalInformation = $additionalLegalInformation; - - return $this; - } - - public function getElectronicAddress(): ?ElectronicAddressIdentifier - { - return $this->electronicAddress; - } - - public function setElectronicAddress(?ElectronicAddressIdentifier $electronicAddress): self - { - $this->electronicAddress = $electronicAddress; - - return $this; - } - - public function getContact(): ?SellerContact - { - return $this->contact; - } - - public function setContact(?SellerContact $contact): self - { - $this->contact = $contact; - - return $this; - } -} diff --git a/src/BusinessTermsGroup/SellerContact.php b/src/BusinessTermsGroup/SellerContact.php deleted file mode 100644 index f0f3079..0000000 --- a/src/BusinessTermsGroup/SellerContact.php +++ /dev/null @@ -1,73 +0,0 @@ -point = null; - $this->phoneNumber = null; - $this->email = null; - } - - public function getPoint(): ?string - { - return $this->point; - } - - public function setPoint(?string $point): self - { - $this->point = $point; - - return $this; - } - - public function getPhoneNumber(): ?string - { - return $this->phoneNumber; - } - - public function setPhoneNumber(?string $phoneNumber): self - { - $this->phoneNumber = $phoneNumber; - - return $this; - } - - public function getEmail(): ?string - { - return $this->email; - } - - public function setEmail(?string $email): self - { - $this->email = $email; - - return $this; - } -} diff --git a/src/BusinessTermsGroup/SellerPostalAddress.php b/src/BusinessTermsGroup/SellerPostalAddress.php deleted file mode 100644 index eb73a5f..0000000 --- a/src/BusinessTermsGroup/SellerPostalAddress.php +++ /dev/null @@ -1,145 +0,0 @@ -countryCode = $countryCode; - $this->line1 = null; - $this->line2 = null; - $this->line3 = null; - $this->city = null; - $this->postCode = null; - $this->countrySubdivision = null; - } - - public function getLine1(): ?string - { - return $this->line1; - } - - public function setLine1(?string $line1): self - { - $this->line1 = $line1; - - return $this; - } - - public function getLine2(): ?string - { - return $this->line2; - } - - public function setLine2(?string $line2): self - { - $this->line2 = $line2; - - return $this; - } - - public function getLine3(): ?string - { - return $this->line3; - } - - public function setLine3(?string $line3): self - { - $this->line3 = $line3; - - return $this; - } - - public function getCity(): ?string - { - return $this->city; - } - - public function setCity(?string $city): self - { - $this->city = $city; - - return $this; - } - - public function getPostCode(): ?string - { - return $this->postCode; - } - - public function setPostCode(?string $postCode): self - { - $this->postCode = $postCode; - - return $this; - } - - public function getCountrySubdivision(): ?string - { - return $this->countrySubdivision; - } - - public function setCountrySubdivision(?string $countrySubdivision): self - { - $this->countrySubdivision = $countrySubdivision; - - return $this; - } - - public function getCountryCode(): CountryAlpha2Code - { - return $this->countryCode; - } -} diff --git a/src/BusinessTermsGroup/SellerTaxRepresentativeParty.php b/src/BusinessTermsGroup/SellerTaxRepresentativeParty.php deleted file mode 100644 index b1a004c..0000000 --- a/src/BusinessTermsGroup/SellerTaxRepresentativeParty.php +++ /dev/null @@ -1,57 +0,0 @@ -name = $name; - $this->vatIdentifier = $vatIdentifier; - $this->address = $address; - } - - public function getName(): string - { - return $this->name; - } - - public function getVatIdentifier(): VatIdentifier - { - return $this->vatIdentifier; - } - - public function getAddress(): SellerTaxRepresentativePostalAddress - { - return $this->address; - } -} diff --git a/src/BusinessTermsGroup/SellerTaxRepresentativePostalAddress.php b/src/BusinessTermsGroup/SellerTaxRepresentativePostalAddress.php deleted file mode 100644 index d0f07a2..0000000 --- a/src/BusinessTermsGroup/SellerTaxRepresentativePostalAddress.php +++ /dev/null @@ -1,145 +0,0 @@ -countryCode = $countryCode; - $this->line1 = null; - $this->line2 = null; - $this->line3 = null; - $this->city = null; - $this->postCode = null; - $this->countrySubdivision = null; - } - - public function getLine1(): ?string - { - return $this->line1; - } - - public function setLine1(?string $line1): self - { - $this->line1 = $line1; - - return $this; - } - - public function getLine2(): ?string - { - return $this->line2; - } - - public function setLine2(?string $line2): self - { - $this->line2 = $line2; - - return $this; - } - - public function getLine3(): ?string - { - return $this->line3; - } - - public function setLine3(?string $line3): self - { - $this->line3 = $line3; - - return $this; - } - - public function getCity(): ?string - { - return $this->city; - } - - public function setCity(?string $city): self - { - $this->city = $city; - - return $this; - } - - public function getPostCode(): ?string - { - return $this->postCode; - } - - public function setPostCode(?string $postCode): self - { - $this->postCode = $postCode; - - return $this; - } - - public function getCountrySubdivision(): ?string - { - return $this->countrySubdivision; - } - - public function setCountrySubdivision(?string $countrySubdivision): self - { - $this->countrySubdivision = $countrySubdivision; - - return $this; - } - - public function getCountryCode(): CountryAlpha2Code - { - return $this->countryCode; - } -} diff --git a/src/BusinessTermsGroup/VatBreakdown.php b/src/BusinessTermsGroup/VatBreakdown.php deleted file mode 100644 index 5d1c3b8..0000000 --- a/src/BusinessTermsGroup/VatBreakdown.php +++ /dev/null @@ -1,165 +0,0 @@ -vatCategoryTaxableAmount = new Amount($vatCategoryTaxableAmount); - $this->vatCategoryTaxAmount = new Amount($vatCategoryTaxAmount); - $this->vatCategoryCode = $vatCategoryCode; - $this->vatCategoryRate = is_float($vatCategoryRate) ? new Percentage($vatCategoryRate) : $vatCategoryRate; - $this->vatExemptionReasonText = $vatExemptionReasonText; - $this->vatExemptionReasonCode = $vatExemptionReasonCode; - - $BT119_divided_100 = ($this->vatCategoryRate ?? new Percentage(0.00))->divide(new IntegerNumber(100)); - $BT119_100_multiply_BT117 = $this->vatCategoryTaxableAmount - ->multiply(new DecimalNumber($BT119_divided_100), Amount::DECIMALS); - - if ($this->vatCategoryTaxAmount->getValueRounded() !== $BT119_100_multiply_BT117) { - throw new \Exception('@todo : BR-CO-17'); - } - - $this->checkExemptionReason(); - } - - public function getVatCategoryTaxableAmount(): Amount - { - return $this->vatCategoryTaxableAmount; - } - - public function getVatCategoryTaxAmount(): Amount - { - return $this->vatCategoryTaxAmount; - } - - public function getVatCategoryCode(): VatCategory - { - return $this->vatCategoryCode; - } - - public function getVatCategoryRate(): ?Percentage - { - return $this->vatCategoryRate; - } - - public function getVatExemptionReasonText(): ?string - { - return $this->vatExemptionReasonText; - } - - public function getVatExemptionReasonCode(): ?VatExemptionReasonCode - { - return $this->vatExemptionReasonCode; - } - - private function checkExemptionReason(): void - { - $noExemptionCategories = [ - VatCategory::STANDARD_RATE, - VatCategory::ZERO_RATED_GOODS, - VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, - VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA - ]; - - $shallHaveExemptionReason = !in_array($this->vatCategoryCode, $noExemptionCategories); - $hasExemptionReason = is_string($this->vatExemptionReasonText) - || $this->vatExemptionReasonCode instanceof VatExemptionReasonCode; - - if ($shallHaveExemptionReason !== $hasExemptionReason) { - throw new \Exception('@todo BR-genericVAT-10'); - } - } -} diff --git a/src/Invoice.php b/src/Invoice.php deleted file mode 100644 index 91b4ba9..0000000 --- a/src/Invoice.php +++ /dev/null @@ -1,1633 +0,0 @@ - - */ - private array $invoiceNote; - - /** - * BG-2 - * A group of business terms providing information on the business process and rules applicable to the Invoice - * document. - */ - private ProcessControl $processControl; - - /** - * BG-3 - * A group of business terms providing information on one or more preceding Invoices. - * - * @var array - */ - private array $precedingInvoices; - - /** - * BG-4 - * A group of business terms providing information about the Seller. - */ - private Seller $seller; - - /** - * BG-7 - * A group of business terms providing information about the Buyer. - */ - private Buyer $buyer; - - /** - * BG-10 - * A group of business terms providing information about the Payee, i.e. the role that receives the payment. - */ - private ?Payee $payee; - - /** - * BG-11 - * A group of business terms providing information about the Seller's tax representative. - */ - private ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty; - - /** - * BG-13 - * A group of business terms providing information about where and when the goods and services invoiced are - * delivered. - */ - private ?DeliveryInformation $deliveryInformation; - - /** - * BG-16 - * A group of business terms providing information about the payment. - */ - private ?PaymentInstructions $paymentInstructions; - - /** - * BG-20 - * A group of business terms providing information about allowances applicable to the Invoice as a whole. - * - * @var array - */ - private array $documentLevelAllowances; - - /** - * BG-21 - * A group of business terms providing information about charges and taxes other than VAT, - * applicable to the Invoice as a whole. - * - * @var array - */ - private array $documentLevelCharges; - - /** - * BG-22 - * A group of business terms providing the monetary totals for the Invoice. - */ - private DocumentTotals $documentTotals; - - /** - * BG-23 - * A group of business terms providing information about VAT breakdown by different - * categories, rates and exemption reasons. - * - * @var array - */ - private array $vatBreakdowns; - - /** - * BG-24 - * A group of business terms providing information about additional supporting documents substantiating - * the claims made in the Invoice. - * - * @var array - */ - private array $additionalSupportingDocuments; - - /** - * BG-25 - * A group of business terms providing information on individual Invoice lines. - * - * @var array - */ - private array $invoiceLines; - - /** - * @param array $vatBreakdowns - * @param array $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - */ - public function __construct( - InvoiceIdentifier $number, - \DateTimeInterface $issueDate, - InvoiceTypeCode $typeCode, - CurrencyCode $currencyCode, - ProcessControl $processControl, - Seller $seller, - Buyer $buyer, - ?CurrencyCode $vatAccountingCurrencyCode, - DocumentTotals $documentTotals, - array $vatBreakdowns, - array $invoiceLines, - ?\DateTimeInterface $valueAddedTaxPointDate, - ?DateCode2005 $valueAddedTaxPointDateCode, - ?\DateTimeInterface $paymentDueDate, - ?string $paymentTerms, - array $documentLevelAllowances, - array $documentLevelCharges, - ?DeliveryInformation $deliveryInformation = null, - ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty = null - ) { - /** BR-S-1 */ - $hasBT151orBT95orBT102VatCategoryStandard = false; - $hasBT118VatCategoryStandard = false; - - /** BR-Z-1 */ - $hasBT151orBT95orBT102VatCategoryZeroRatedGoods = false; - $countBT118VatCategoryZeroRatedGoods = 0; - - /** BR-E-1 */ - $hasBT151orBT95orBT102VatCategoryExemptFromTax = false; - $countBT118VatCategoryExemptFromTax = 0; - - /** BR-AE-1 */ - $hasBT151orBT95orBT102VatCategoryReverseCharge = false; - $countBT118VatCategoryReverseCharge = 0; - - /** BR-IC-1 */ - $hasBT151orBT95orBT102VatCategoryIntraCommunitySupply = false; - $countBT118VatCategoryIntraCommunitySupply = 0; - - /** BR-G-1 */ - $hasBT151orBT95orBT102VatCategoryExportOutsideEU = false; - $countBT118VatCategoryExportOutsideEU = 0; - - /** BR-O-1 */ - $hasBT151orBT95orBT102VatCategoryNotSubjectToVat = false; - $countBT118VatCategoryNotSubjectToVat = 0; - - /** BR-IG-1 */ - $hasBT151orBT95orBT102VatCategoryCanaryIslands = false; - $hasBT118VatCategoryCanaryIslands = false; - - /** BR-IP-1 */ - $hasBT151orBT95orBT102VatCategoryCeutaMelilla = false; - $hasBT118VatCategoryCeutaMelilla = false; - - /** BR-S-2 */ - $hasBT151VatCategoryStandard = false; - - /** BR-Z-2 */ - $hasBT151VatCategoryZeroRatedGoods = false; - - /** BR-E-2 */ - $hasBT151VatCategoryExemptFromTax = false; - - /** BR-AE-2 */ - $hasBT151VatCategoryReverseCharge = false; - - /** BR-IC-2 */ - $hasBT151VatCategoryIntraCommunitySupply = false; - - /** BR-G-2 */ - $hasBT151VatCategoryExportOutsideEU = false; - - /** BR-O-2 */ - $hasBT151VatCategoryNotSubjectToVat = false; - - /** BR-IG-2 */ - $hasBT151VatCategoryCanaryIslands = false; - - /** BR-IP-2 */ - $hasBT151VatCategoryCeutaMelilla = false; - - /** BR-S-3 */ - $hasBT95VatCategoryStandard = false; - - /** BR-Z-3 */ - $hasBT95VatCategoryZeroRatedGoods = false; - - /** BR-E-3 */ - $hasBT95VatCategoryExemptFromTax = false; - - /** BR-AE-3 */ - $hasBT95VatCategoryReverseCharge = false; - - /** BR-IC-3 */ - $hasBT95VatCategoryIntraCommunitySupply = false; - - /** BR-G-3 */ - $hasBT95VatCategoryExportOutsideEU = false; - - /** BR-O-3 */ - $hasBT95VatCategoryNotSubjectToVat = false; - - /** BR-IG-3 */ - $hasBT95VatCategoryCanaryIslands = false; - - /** BR-IP-3 */ - $hasBT95VatCategoryCeutaMelilla = false; - - $this->vatBreakdowns = []; - $totalVatCategoryTaxAmountVatBreakdowns = new DecimalNumber(0); - foreach ($vatBreakdowns as $vatBreakdown) { - if (!$vatBreakdown instanceof VatBreakdown) { - throw new \TypeError(); - } - - $this->vatBreakdowns[] = $vatBreakdown; - - $totalVatCategoryTaxAmountVatBreakdowns = new DecimalNumber( - $totalVatCategoryTaxAmountVatBreakdowns - ->add($vatBreakdown->getVatCategoryTaxAmount()) - ); - - /** BR-S-1 */ - if (!$hasBT118VatCategoryStandard && $vatBreakdown->getVatCategoryCode() === VatCategory::STANDARD_RATE) { - $hasBT118VatCategoryStandard = true; - } - - /** BR-Z-1 */ - if ($vatBreakdown->getVatCategoryCode() === VatCategory::ZERO_RATED_GOODS) { - $countBT118VatCategoryZeroRatedGoods++; - } - - /** BR-E-1 */ - if ($vatBreakdown->getVatCategoryCode() === VatCategory::EXEMPT_FROM_TAX) { - $countBT118VatCategoryExemptFromTax++; - } - - /** BR-AE-1 */ - if ($vatBreakdown->getVatCategoryCode() === VatCategory::VAT_REVERSE_CHARGE) { - $countBT118VatCategoryReverseCharge++; - } - - /** BR-IC-1 */ - if ( - $vatBreakdown->getVatCategoryCode() - === VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES - ) { - $countBT118VatCategoryIntraCommunitySupply++; - } - - /** BR-G-1 */ - if ($vatBreakdown->getVatCategoryCode() === VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED) { - $countBT118VatCategoryExportOutsideEU++; - } - - /** BR-O-1 */ - if ($vatBreakdown->getVatCategoryCode() === VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX) { - $countBT118VatCategoryNotSubjectToVat++; - } - - /** BR-IG-1 */ - if ( - !$hasBT118VatCategoryCanaryIslands - && $vatBreakdown->getVatCategoryCode() === VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX - ) { - $hasBT118VatCategoryCanaryIslands = true; - } - - /** BR-IP-1 */ - if ( - !$hasBT118VatCategoryCeutaMelilla - && $vatBreakdown->getVatCategoryCode() - === VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA - ) { - $hasBT118VatCategoryCeutaMelilla = true; - } - } - - $totalVatCategoryTaxAmountVatBreakdowns = round( - $totalVatCategoryTaxAmountVatBreakdowns->getValue(), - Amount::DECIMALS - ); - - if ( - count($this->vatBreakdowns) > 0 - && $totalVatCategoryTaxAmountVatBreakdowns - !== ( - $documentTotals->getInvoiceTotalVatAmount()?->getValueRounded() ?? - (new Amount(0.00))->getValueRounded() - ) - ) { - throw new \Exception('@todo : BR-CO-14'); - } - - if (empty($this->vatBreakdowns)) { - throw new \Exception('@todo'); - } - - $this->invoiceLines = []; - $totalNetAmountInvoiceLines = new DecimalNumber(0); - foreach ($invoiceLines as $invoiceLine) { - if (!$invoiceLine instanceof InvoiceLine) { - throw new \TypeError(); - } - - $this->invoiceLines[] = $invoiceLine; - - $totalNetAmountInvoiceLines = new DecimalNumber( - $totalNetAmountInvoiceLines->add($invoiceLine->getNetAmount()) - ); - - $invoiceLineVatCategoryCode = $invoiceLine->getLineVatInformation()->getInvoicedItemVatCategoryCode(); - - if ($invoiceLineVatCategoryCode === VatCategory::STANDARD_RATE) { - /** BR-S-1 */ - if (!$hasBT151orBT95orBT102VatCategoryStandard) { - $hasBT151orBT95orBT102VatCategoryStandard = true; - } - - /** BR-S-2 */ - if (!$hasBT151VatCategoryStandard) { - $hasBT151VatCategoryStandard = true; - } - } - - if ($invoiceLineVatCategoryCode === VatCategory::ZERO_RATED_GOODS) { - /** BR-Z-1 */ - if (!$hasBT151orBT95orBT102VatCategoryZeroRatedGoods) { - $hasBT151orBT95orBT102VatCategoryZeroRatedGoods = true; - } - - /** BR-Z-2 */ - if (!$hasBT151VatCategoryZeroRatedGoods) { - $hasBT151VatCategoryZeroRatedGoods = true; - } - } - - if ($invoiceLineVatCategoryCode === VatCategory::EXEMPT_FROM_TAX) { - /** BR-E-1 */ - if (!$hasBT151orBT95orBT102VatCategoryExemptFromTax) { - $hasBT151orBT95orBT102VatCategoryExemptFromTax = true; - } - - /** BR-E-2 */ - if (!$hasBT151VatCategoryExemptFromTax) { - $hasBT151VatCategoryExemptFromTax = true; - } - } - - if ($invoiceLineVatCategoryCode === VatCategory::VAT_REVERSE_CHARGE) { - /** BR-AE-1 */ - if (!$hasBT151orBT95orBT102VatCategoryReverseCharge) { - $hasBT151orBT95orBT102VatCategoryReverseCharge = true; - } - - /** BR-AE-2 */ - if (!$hasBT151VatCategoryReverseCharge) { - $hasBT151VatCategoryReverseCharge = true; - } - } - - if ( - $invoiceLineVatCategoryCode - === VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES - ) { - /** BR-IC-1 */ - if (!$hasBT151orBT95orBT102VatCategoryIntraCommunitySupply) { - $hasBT151orBT95orBT102VatCategoryIntraCommunitySupply = true; - } - - /** BR-IC-2 */ - if (!$hasBT151VatCategoryIntraCommunitySupply) { - $hasBT151VatCategoryIntraCommunitySupply = true; - } - } - - if ($invoiceLineVatCategoryCode === VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED) { - /** BR-G-1 */ - if (!$hasBT151orBT95orBT102VatCategoryExportOutsideEU) { - $hasBT151orBT95orBT102VatCategoryExportOutsideEU = true; - } - - /** BR-G-2 */ - if (!$hasBT151VatCategoryExportOutsideEU) { - $hasBT151VatCategoryExportOutsideEU = true; - } - } - - if ($invoiceLineVatCategoryCode === VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX) { - /** BR-O-1 */ - if (!$hasBT151orBT95orBT102VatCategoryNotSubjectToVat) { - $hasBT151orBT95orBT102VatCategoryNotSubjectToVat = true; - } - - /** BR-O-2 */ - if (!$hasBT151VatCategoryNotSubjectToVat) { - $hasBT151VatCategoryNotSubjectToVat = true; - } - } - - if ($invoiceLineVatCategoryCode === VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX) { - /** BR-IG-1 */ - if (!$hasBT151orBT95orBT102VatCategoryCanaryIslands) { - $hasBT151orBT95orBT102VatCategoryCanaryIslands = true; - } - - /** BR-IG-2 */ - if (!$hasBT151VatCategoryCanaryIslands) { - $hasBT151VatCategoryCanaryIslands = true; - } - } - - if ( - $invoiceLineVatCategoryCode - === VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA - ) { - /** BR-IP-1 */ - if (!$hasBT151orBT95orBT102VatCategoryCeutaMelilla) { - $hasBT151orBT95orBT102VatCategoryCeutaMelilla = true; - } - - /** BR-IP-2 */ - if (!$hasBT151VatCategoryCeutaMelilla) { - $hasBT151VatCategoryCeutaMelilla = true; - } - } - } - - if (empty($this->invoiceLines)) { - throw new \Exception('@todo'); - } - - /** BR-[S/Z/E/IG/IP]-2 */ - if ( - ( - $hasBT151VatCategoryStandard - || $hasBT151VatCategoryZeroRatedGoods - || $hasBT151VatCategoryExemptFromTax - || $hasBT151VatCategoryCanaryIslands - || $hasBT151VatCategoryCeutaMelilla - ) - && !$seller->getVatIdentifier() - && !$seller->getTaxRegistrationIdentifier() - && !$sellerTaxRepresentativeParty?->getVatIdentifier() - ) { - throw new \Exception('@todo : BR-[S/Z/E/IG/IP]-2'); - } - - /** BR-AE-2 */ - if ( - $hasBT151VatCategoryReverseCharge - && ( - ( - !$seller->getVatIdentifier() - && !$seller->getTaxRegistrationIdentifier() - && !$sellerTaxRepresentativeParty?->getVatIdentifier() - ) - || (!$buyer->getLegalRegistrationIdentifier() && !$buyer->getVatIdentifier()) - ) - ) { - throw new \Exception('@todo : BR-AE-2'); - } - - /** BR-IC-2 */ - if ( - $hasBT151VatCategoryIntraCommunitySupply - && !( - ($seller->getVatIdentifier() xor $sellerTaxRepresentativeParty?->getVatIdentifier()) - && $buyer->getVatIdentifier() - ) - ) { - throw new \Exception('@todo : BR-IC-2'); - } - - /** BR-G-2 */ - if ( - $hasBT151VatCategoryExportOutsideEU - && !($seller->getVatIdentifier() xor $sellerTaxRepresentativeParty?->getVatIdentifier()) - ) { - throw new \Exception('@todo : BR-G-2'); - } - - /** BR-O-2 */ - if ( - $hasBT151VatCategoryNotSubjectToVat - && $seller->getVatIdentifier() - && $sellerTaxRepresentativeParty?->getVatIdentifier() - && $buyer->getVatIdentifier() - ) { - throw new \Exception('@todo : BR-O-2'); - } - - - if ( - $documentTotals->getSumOfInvoiceLineNetAmount()->getValueRounded() - !== $totalNetAmountInvoiceLines->getValueRounded() - ) { - throw new \Exception('@todo : BR-CO-10'); - } - - $totalBT131_minus_BT107 = $totalNetAmountInvoiceLines->subtract( - $documentTotals->getSumOfAllowancesOnDocumentLevel() ?? new Amount(0.00) - ); - - $documentTotalsSumOfChargesOnDocumentLevel = $documentTotals->getSumOfChargesOnDocumentLevel() - ?? new Amount(0.00); - $totalBT131_BT107_plus_BT108 = (new DecimalNumber($totalBT131_minus_BT107)) - ->add($documentTotalsSumOfChargesOnDocumentLevel); - - if ($documentTotals->getInvoiceTotalAmountWithoutVat()->getValueRounded() !== $totalBT131_BT107_plus_BT108) { - throw new \Exception('@todo : BR-CO-13'); - } - - if ( - $vatAccountingCurrencyCode instanceof CurrencyCode - xor is_float($documentTotals->getInvoiceTotalVatAmountInAccountingCurrency()?->getValueRounded()) - ) { - throw new \Exception('@todo'); - } - - if ( - $valueAddedTaxPointDate instanceof \DateTimeInterface - && $valueAddedTaxPointDateCode instanceof DateCode2005 - ) { - throw new \Exception('@todo : BR-CO-3'); - } - - if ( - $documentTotals->getAmountDueForPayment()->getValueRounded() > 0 - && null === $paymentDueDate && empty($paymentTerms) - ) { - throw new \Exception('@todo : BR-CO-25'); - } - - $totalAmountDocumentLevelAllowances = new DecimalNumber(0); - $this->documentLevelAllowances = []; - foreach ($documentLevelAllowances as $documentLevelAllowance) { - if ($documentLevelAllowance instanceof DocumentLevelAllowance) { - $this->documentLevelAllowances[] = $documentLevelAllowance; - - $totalAmountDocumentLevelAllowances = new DecimalNumber( - $totalAmountDocumentLevelAllowances->add($documentLevelAllowance->getAmount()) - ); - - $documentLevelAllowanceVatCategoryCode = $documentLevelAllowance->getVatCategoryCode(); - - if ($documentLevelAllowanceVatCategoryCode === VatCategory::STANDARD_RATE) { - /** BR-S-1 */ - if (!$hasBT151orBT95orBT102VatCategoryStandard) { - $hasBT151orBT95orBT102VatCategoryStandard = true; - } - - /** BR-S-3 */ - if (!$hasBT95VatCategoryStandard) { - $hasBT95VatCategoryStandard = true; - } - } - - if ($documentLevelAllowanceVatCategoryCode === VatCategory::ZERO_RATED_GOODS) { - /** BR-Z-1 */ - if (!$hasBT151orBT95orBT102VatCategoryZeroRatedGoods) { - $hasBT151orBT95orBT102VatCategoryZeroRatedGoods = true; - } - - /** BR-Z-3 */ - if (!$hasBT95VatCategoryZeroRatedGoods) { - $hasBT95VatCategoryZeroRatedGoods = true; - } - } - - if ($documentLevelAllowanceVatCategoryCode === VatCategory::EXEMPT_FROM_TAX) { - /** BR-E-1 */ - if (!$hasBT151orBT95orBT102VatCategoryExemptFromTax) { - $hasBT151orBT95orBT102VatCategoryExemptFromTax = true; - } - - /** BR-E-3 */ - if (!$hasBT95VatCategoryExemptFromTax) { - $hasBT95VatCategoryExemptFromTax = true; - } - } - - if ($documentLevelAllowanceVatCategoryCode === VatCategory::VAT_REVERSE_CHARGE) { - /** BR-AE-1 */ - if (!$hasBT151orBT95orBT102VatCategoryReverseCharge) { - $hasBT151orBT95orBT102VatCategoryReverseCharge = true; - } - - /** BR-AE-3 */ - if (!$hasBT95VatCategoryReverseCharge) { - $hasBT95VatCategoryReverseCharge = true; - } - } - - if ( - $documentLevelAllowanceVatCategoryCode - === VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES - ) { - /** BR-IC-1 */ - if (!$hasBT151orBT95orBT102VatCategoryIntraCommunitySupply) { - $hasBT151orBT95orBT102VatCategoryIntraCommunitySupply = true; - } - - /** BR-IC-3 */ - if (!$hasBT95VatCategoryIntraCommunitySupply) { - $hasBT95VatCategoryIntraCommunitySupply = true; - } - } - - if ($documentLevelAllowanceVatCategoryCode === VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED) { - /** BR-G-1 */ - if (!$hasBT151orBT95orBT102VatCategoryExportOutsideEU) { - $hasBT151orBT95orBT102VatCategoryExportOutsideEU = true; - } - - /** BR-G-3 */ - if (!$hasBT95VatCategoryExportOutsideEU) { - $hasBT95VatCategoryExportOutsideEU = true; - } - } - - if ($documentLevelAllowanceVatCategoryCode === VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX) { - /** BR-O-1 */ - if (!$hasBT151orBT95orBT102VatCategoryNotSubjectToVat) { - $hasBT151orBT95orBT102VatCategoryNotSubjectToVat = true; - } - - /** BR-O-3 */ - if (!$hasBT95VatCategoryNotSubjectToVat) { - $hasBT95VatCategoryNotSubjectToVat = true; - } - } - - if ($documentLevelAllowanceVatCategoryCode === VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX) { - /** BR-IG-1 */ - if (!$hasBT151orBT95orBT102VatCategoryCanaryIslands) { - $hasBT151orBT95orBT102VatCategoryCanaryIslands = true; - } - - /** BR-IG-3 */ - if (!$hasBT95VatCategoryCanaryIslands) { - $hasBT95VatCategoryCanaryIslands = true; - } - } - - if ( - $documentLevelAllowanceVatCategoryCode - === VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA - ) { - /** BR-IP-1 */ - if (!$hasBT151orBT95orBT102VatCategoryCeutaMelilla) { - $hasBT151orBT95orBT102VatCategoryCeutaMelilla = true; - } - - /** BR-IP-3 */ - if (!$hasBT95VatCategoryCeutaMelilla) { - $hasBT95VatCategoryCeutaMelilla = true; - } - } - } - } - - /** BR-[S/Z/E/IG/IP]-3 */ - if ( - ( - $hasBT95VatCategoryStandard - || $hasBT95VatCategoryZeroRatedGoods - || $hasBT95VatCategoryExemptFromTax - || $hasBT95VatCategoryCanaryIslands - || $hasBT95VatCategoryCeutaMelilla - ) - && !$seller->getVatIdentifier() - && !$seller->getTaxRegistrationIdentifier() - && !$sellerTaxRepresentativeParty?->getVatIdentifier() - ) { - throw new \Exception('@todo : BR-[S/Z/E/IG/IP]-3'); - } - - /** BR-AE-3 */ - if ( - $hasBT95VatCategoryReverseCharge - && ( - ( - !$seller->getVatIdentifier() - && !$seller->getTaxRegistrationIdentifier() - && !$sellerTaxRepresentativeParty?->getVatIdentifier() - ) - || (!$buyer->getLegalRegistrationIdentifier() && !$buyer->getVatIdentifier()) - ) - ) { - throw new \Exception('@todo : BR-AE-3'); - } - - /** BR-IC-3 */ - if ( - $hasBT95VatCategoryIntraCommunitySupply - && !( - ($seller->getVatIdentifier() xor $sellerTaxRepresentativeParty?->getVatIdentifier()) - && $buyer->getVatIdentifier() - ) - ) { - throw new \Exception('@todo : BR-IC-3'); - } - - /** BR-G-3 */ - if ( - $hasBT95VatCategoryExportOutsideEU - && !($seller->getVatIdentifier() xor $sellerTaxRepresentativeParty?->getVatIdentifier()) - ) { - throw new \Exception('@todo : BR-G-3'); - } - - /** BR-O-3 */ - if ( - $hasBT95VatCategoryNotSubjectToVat - && $seller->getVatIdentifier() - && $sellerTaxRepresentativeParty?->getVatIdentifier() - && $buyer->getVatIdentifier() - ) { - throw new \Exception('@todo : BR-O-3'); - } - - $totalAmountDocumentLevelAllowances = round($totalAmountDocumentLevelAllowances->getValue(), Amount::DECIMALS); - if ( - count($this->documentLevelAllowances) > 0 - && $totalAmountDocumentLevelAllowances - !== ( - $documentTotals->getSumOfAllowancesOnDocumentLevel()?->getValueRounded() - ?? (new Amount(0.00))->getValueRounded() - ) - ) { - throw new \Exception('@todo : BR-CO-11'); - } - - $totalDocumentLevelCharges = new DecimalNumber(0); - $this->documentLevelCharges = []; - foreach ($documentLevelCharges as $documentLevelCharge) { - if ($documentLevelCharge instanceof DocumentLevelCharge) { - $this->documentLevelCharges[] = $documentLevelCharge; - - $totalDocumentLevelCharges = new DecimalNumber( - $totalDocumentLevelCharges->add($documentLevelCharge->getAmount()) - ); - - /** BR-S-1 */ - if ( - !$hasBT151orBT95orBT102VatCategoryStandard - && $documentLevelCharge->getVatCategoryCode() === VatCategory::STANDARD_RATE - ) { - $hasBT151orBT95orBT102VatCategoryStandard = true; - } - - /** BR-Z-1 */ - if ( - !$hasBT151orBT95orBT102VatCategoryZeroRatedGoods - && $documentLevelCharge->getVatCategoryCode() === VatCategory::ZERO_RATED_GOODS - ) { - $hasBT151orBT95orBT102VatCategoryZeroRatedGoods = true; - } - - /** BR-E-1 */ - if ( - !$hasBT151orBT95orBT102VatCategoryExemptFromTax - && $documentLevelCharge->getVatCategoryCode() === VatCategory::EXEMPT_FROM_TAX - ) { - $hasBT151orBT95orBT102VatCategoryExemptFromTax = true; - } - - /** BR-AE-1 */ - if ( - !$hasBT151orBT95orBT102VatCategoryReverseCharge - && $documentLevelCharge->getVatCategoryCode() === VatCategory::VAT_REVERSE_CHARGE - ) { - $hasBT151orBT95orBT102VatCategoryReverseCharge = true; - } - - /** BR-IC-1 */ - if ( - !$hasBT151orBT95orBT102VatCategoryIntraCommunitySupply - && $documentLevelCharge->getVatCategoryCode() - === VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES - ) { - $hasBT151orBT95orBT102VatCategoryIntraCommunitySupply = true; - } - - /** BR-G-1 */ - if ( - !$hasBT151orBT95orBT102VatCategoryExportOutsideEU - && $documentLevelCharge->getVatCategoryCode() === VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED - ) { - $hasBT151orBT95orBT102VatCategoryExportOutsideEU = true; - } - - /** BR-O-1 */ - if ( - !$hasBT151orBT95orBT102VatCategoryNotSubjectToVat - && $documentLevelCharge->getVatCategoryCode() === VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX - ) { - $hasBT151orBT95orBT102VatCategoryNotSubjectToVat = true; - } - - /** BR-IG-1 */ - if ( - !$hasBT151orBT95orBT102VatCategoryCanaryIslands - && $documentLevelCharge->getVatCategoryCode() === VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX - ) { - $hasBT151orBT95orBT102VatCategoryCanaryIslands = true; - } - - /** BR-IP-1 */ - if ( - !$hasBT151orBT95orBT102VatCategoryCeutaMelilla - && $documentLevelCharge->getVatCategoryCode() - === VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA - ) { - $hasBT151orBT95orBT102VatCategoryCeutaMelilla = true; - } - } - } - - $totalDocumentLevelCharges = round($totalDocumentLevelCharges->getValue(), Amount::DECIMALS); - if ( - count($this->documentLevelCharges) > 0 - && $totalDocumentLevelCharges - !== ( - $documentTotals->getSumOfChargesOnDocumentLevel()?->getValueRounded() - ?? (new Amount(0.00))->getValueRounded() - ) - ) { - throw new \Exception('@todo : BR-CO-12'); - } - - if ($hasBT151orBT95orBT102VatCategoryStandard && !$hasBT118VatCategoryStandard) { - throw new \Exception('@todo : BR-S-1'); - } - - if ($hasBT151orBT95orBT102VatCategoryZeroRatedGoods && $countBT118VatCategoryZeroRatedGoods !== 1) { - throw new \Exception('@todo : BR-Z-1'); - } - - if ($hasBT151orBT95orBT102VatCategoryExemptFromTax && $countBT118VatCategoryExemptFromTax !== 1) { - throw new \Exception('@todo : BR-E-1'); - } - - if ($hasBT151orBT95orBT102VatCategoryReverseCharge && $countBT118VatCategoryReverseCharge !== 1) { - throw new \Exception('@todo : BR-AE-1'); - } - - if ($hasBT151orBT95orBT102VatCategoryIntraCommunitySupply && $countBT118VatCategoryIntraCommunitySupply !== 1) { - throw new \Exception('@todo : BR-IC-1'); - } - - if ($hasBT151orBT95orBT102VatCategoryExportOutsideEU && $countBT118VatCategoryExportOutsideEU !== 1) { - throw new \Exception('@todo : BR-G-1'); - } - - if ($hasBT151orBT95orBT102VatCategoryNotSubjectToVat && $countBT118VatCategoryNotSubjectToVat !== 1) { - throw new \Exception('@todo : BR-O-1'); - } - - if ($hasBT151orBT95orBT102VatCategoryCanaryIslands && !$hasBT118VatCategoryCanaryIslands) { - throw new \Exception('@todo : BR-IG-1'); - } - - if ($hasBT151orBT95orBT102VatCategoryCeutaMelilla && !$hasBT118VatCategoryCeutaMelilla) { - throw new \Exception('@todo : BR-IP-1'); - } - - $this->number = $number; - $this->issueDate = $issueDate; - $this->typeCode = $typeCode; - $this->invoiceNote = []; - $this->currencyCode = $currencyCode; - $this->vatAccountingCurrencyCode = $vatAccountingCurrencyCode; - $this->valueAddedTaxPointDate = $valueAddedTaxPointDate; - $this->valueAddedTaxPointDateCode = $valueAddedTaxPointDateCode; - $this->processControl = $processControl; - $this->seller = $seller; - $this->buyer = $buyer; - $this->documentTotals = $documentTotals; - $this->paymentDueDate = $paymentDueDate; - $this->paymentTerms = $paymentTerms; - $this->deliveryInformation = $deliveryInformation; - - $this->buyerReference = null; - $this->projectReference = null; - $this->contractReference = null; - $this->purchaseOrderReference = null; - $this->salesOrderReference = null; - $this->receivingAdviceReference = null; - $this->despatchAdviceReference = null; - $this->tenderOrLotReference = null; - $this->objectIdentifier = null; - $this->buyerAccountingReference = null; - $this->precedingInvoices = []; - $this->payee = null; - $this->paymentInstructions = null; - $this->additionalSupportingDocuments = []; - $this->sellerTaxRepresentativeParty = $sellerTaxRepresentativeParty; - - $this->checkChargesVatCategoryCodeConsistencyWithPartyIdentifiers(); - - $this->checkNotSubjectToVatBreakdown(); - - foreach ($this->vatBreakdowns as $vatBreakdown) { - $this->checkVatBreakdownTaxableAmountCoherence($vatBreakdown); - $this->checkNeedsDeliveryInformation($vatBreakdown); - } - } - - public function getNumber(): InvoiceIdentifier - { - return $this->number; - } - - public function getIssueDate(): \DateTimeInterface - { - return $this->issueDate; - } - - public function getTypeCode(): InvoiceTypeCode - { - return $this->typeCode; - } - - public function getCurrencyCode(): CurrencyCode - { - return $this->currencyCode; - } - - public function getVatAccountingCurrencyCode(): ?CurrencyCode - { - return $this->vatAccountingCurrencyCode; - } - - public function getValueAddedTaxPointDate(): ?\DateTimeInterface - { - return $this->valueAddedTaxPointDate; - } - - public function getValueAddedTaxPointDateCode(): ?DateCode2005 - { - return $this->valueAddedTaxPointDateCode; - } - - public function getPaymentDueDate(): ?\DateTimeInterface - { - return $this->paymentDueDate; - } - - public function getBuyerReference(): ?string - { - return $this->buyerReference; - } - - public function getProjectReference(): ?ProjectReference - { - return $this->projectReference; - } - - public function setProjectReference(?ProjectReference $projectReference): self - { - $this->projectReference = $projectReference; - - return $this; - } - - public function getContractReference(): ?ContractReference - { - return $this->contractReference; - } - - public function setContractReference(?ContractReference $contractReference): self - { - $this->contractReference = $contractReference; - - return $this; - } - - public function getPurchaseOrderReference(): ?PurchaseOrderReference - { - return $this->purchaseOrderReference; - } - - public function setPurchaseOrderReference(?PurchaseOrderReference $purchaseOrderReference): self - { - $this->purchaseOrderReference = $purchaseOrderReference; - - return $this; - } - - public function getSalesOrderReference(): ?SalesOrderReference - { - return $this->salesOrderReference; - } - - public function setSalesOrderReference(?SalesOrderReference $salesOrderReference): self - { - $this->salesOrderReference = $salesOrderReference; - - return $this; - } - - public function getReceivingAdviceReference(): ?ReceivingAdviceReference - { - return $this->receivingAdviceReference; - } - - public function setReceivingAdviceReference(?ReceivingAdviceReference $receivingAdviceReference): self - { - $this->receivingAdviceReference = $receivingAdviceReference; - - return $this; - } - - public function getDespatchAdviceReference(): ?DespatchAdviceReference - { - return $this->despatchAdviceReference; - } - - public function setDespatchAdviceReference(?DespatchAdviceReference $despatchAdviceReference): self - { - $this->despatchAdviceReference = $despatchAdviceReference; - - return $this; - } - - public function getTenderOrLotReference(): ?TenderOrLotReference - { - return $this->tenderOrLotReference; - } - - public function setTenderOrLotReference(?TenderOrLotReference $tenderOrLotReference): self - { - $this->tenderOrLotReference = $tenderOrLotReference; - - return $this; - } - - public function getObjectIdentifier(): ?ObjectIdentifier - { - return $this->objectIdentifier; - } - - public function setObjectIdentifier(?ObjectIdentifier $objectIdentifier): self - { - $this->objectIdentifier = $objectIdentifier; - - return $this; - } - - public function getBuyerAccountingReference(): ?string - { - return $this->buyerAccountingReference; - } - - public function setBuyerAccountingReference(?string $buyerAccountingReference): self - { - $this->buyerAccountingReference = $buyerAccountingReference; - - return $this; - } - - public function getPaymentTerms(): ?string - { - return $this->paymentTerms; - } - - /** - * @return array - */ - public function getInvoiceNote(): array - { - return $this->invoiceNote; - } - - public function getProcessControl(): ProcessControl - { - return $this->processControl; - } - - /** - * @return array - */ - public function getPrecedingInvoices(): array - { - return $this->precedingInvoices; - } - - /** - * @param array $precedingInvoices - */ - public function setPrecedingInvoices(array $precedingInvoices): self - { - $this->precedingInvoices = $precedingInvoices; - - return $this; - } - - public function getSeller(): Seller - { - return $this->seller; - } - - public function getBuyer(): Buyer - { - return $this->buyer; - } - - public function getPayee(): ?Payee - { - return $this->payee; - } - - public function setPayee(?Payee $payee): self - { - $this->payee = $payee; - - return $this; - } - - public function getSellerTaxRepresentativeParty(): ?SellerTaxRepresentativeParty - { - return $this->sellerTaxRepresentativeParty; - } - - public function getDeliveryInformation(): ?DeliveryInformation - { - return $this->deliveryInformation; - } - - public function getPaymentInstructions(): ?PaymentInstructions - { - return $this->paymentInstructions; - } - - public function setPaymentInstructions(?PaymentInstructions $paymentInstructions): self - { - $this->paymentInstructions = $paymentInstructions; - - return $this; - } - - /** - * @return array - */ - public function getDocumentLevelAllowances(): array - { - return $this->documentLevelAllowances; - } - - /** - * @return array - */ - public function getDocumentLevelCharges(): array - { - return $this->documentLevelCharges; - } - - public function getDocumentTotals(): DocumentTotals - { - return $this->documentTotals; - } - - /** - * @return array - */ - public function getVatBreakdowns(): array - { - return $this->vatBreakdowns; - } - - /** - * @return array - */ - public function getAdditionalSupportingDocuments(): array - { - return $this->additionalSupportingDocuments; - } - - /** - * @return array - */ - public function getInvoiceLines(): array - { - return $this->invoiceLines; - } - - public function setBuyerReference(?string $buyerReference): self - { - $this->buyerReference = $buyerReference; - - return $this; - } - - public function addIncludedNote(InvoiceNote ...$notes): self - { - foreach ($notes as $note) { - $this->invoiceNote[] = $note; - } - - return $this; - } - - /** - * @throws \Exception - */ - private function checkVatBreakdownTaxableAmountCoherence(VatBreakdown $vatBreakdown): void - { - $vatCategoryCode = $vatBreakdown->getVatCategoryCode(); - $positiveRateCategories = [ - VatCategory::STANDARD_RATE, - VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, - VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA - ]; - - $vatRate = new Percentage(0); - - if (in_array($vatCategoryCode, $positiveRateCategories)) { - $vatRate = $vatBreakdown->getVatCategoryRate(); - } - - if ($vatCategoryCode === VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX) { - $vatRate = null; - } - - $invoiceLinesNetSum = $this->getInvoiceLinesNetSumPerVatCategory($vatCategoryCode, $vatRate); - $chargesSum = $this->getDocumentLevelChargesSumPerVatCategory($vatCategoryCode, $vatRate); - $allowancesSum = $this->getDocumentLevelAllowancesSumPerVatCategory($vatCategoryCode, $vatRate); - - $computedSum = new Amount((new DecimalNumber($invoiceLinesNetSum->add($chargesSum)))->subtract($allowancesSum)); - - if ($computedSum->getValueRounded() !== $vatBreakdown->getVatCategoryTaxableAmount()->getValueRounded()) { - throw new \Exception('@todo BR-genericVAT-8'); - } - } - - /** - * @throws \Exception - */ - private function getInvoiceLinesNetSumPerVatCategory( - VatCategory $vatCategoryCode, - ?Percentage $vatRate = null - ): DecimalNumber { - $sum = new DecimalNumber(0); - - foreach ($this->invoiceLines as $invoiceLine) { - $vatInformation = $invoiceLine->getLineVatInformation(); - - if ( - $vatInformation->getInvoicedItemVatCategoryCode() === $vatCategoryCode - && $vatInformation->getInvoicedItemVatRate()?->getValueRounded() === $vatRate?->getValueRounded() - ) { - $sum = new DecimalNumber($sum->add($invoiceLine->getNetAmount())); - } - } - - return $sum; - } - - /** - * @throws \Exception - */ - private function getDocumentLevelChargesSumPerVatCategory( - VatCategory $vatCategoryCode, - ?Percentage $vatRate = null - ): DecimalNumber { - $sum = new DecimalNumber(0); - - foreach ($this->documentLevelCharges as $charge) { - if ( - $charge->getVatCategoryCode() === $vatCategoryCode - && $charge->getVatRate()?->getValueRounded() === $vatRate?->getValueRounded() - ) { - $sum = new DecimalNumber($sum->add($charge->getAmount())); - } - } - - return $sum; - } - - /** - * @throws \Exception - */ - private function getDocumentLevelAllowancesSumPerVatCategory( - VatCategory $vatCategoryCode, - ?Percentage $vatRate = null - ): DecimalNumber { - $sum = new DecimalNumber(0); - - foreach ($this->documentLevelAllowances as $allowance) { - if ( - $allowance->getVatCategoryCode() === $vatCategoryCode - && $allowance->getVatRate()?->getValueRounded() === $vatRate?->getValueRounded() - ) { - $sum = new DecimalNumber($sum->add($allowance->getAmount())); - } - } - - return $sum; - } - - private function checkNeedsDeliveryInformation(VatBreakdown $vatBreakdown): void - { - $vatCategory = $vatBreakdown->getVatCategoryCode(); - - if ($vatCategory !== VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES) { - return; - } - - if (false === $this->deliveryInformation instanceof DeliveryInformation) { - throw new \Exception('@todo: BR-IC-11'); - } - - if ( - false === $this->deliveryInformation->getActualDeliveryDate() instanceof \DateTimeInterface - && false === $this->deliveryInformation->getInvoicingPeriod() instanceof InvoicingPeriod - ) { - throw new \Exception('@todo: BR-IC-11'); - } - - if (false === $this->deliveryInformation->getDeliverToAddress() instanceof DeliverToAddress) { - throw new \Exception('@todo: BR-IC-12'); - } - } - - /** - * @throws \Exception - */ - private function checkNotSubjectToVatBreakdown(): void - { - $notSubjectToVatBreakdowns = array_filter($this->vatBreakdowns, function (VatBreakdown $vatBreakdown) { - return $vatBreakdown->getVatCategoryCode() === VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX; - }); - - if (0 === count($notSubjectToVatBreakdowns)) { - return; - } - - if (1 < count($notSubjectToVatBreakdowns) || 1 < count($this->vatBreakdowns)) { - throw new \Exception('@todo: BR-0-11'); - } - - $this->checkNotSubjectToVatInvoiceLines(); - $this->checkNotSubjectToVatAllowances(); - $this->checkNotSubjectToVatCharges(); - } - - private function checkNotSubjectToVatInvoiceLines(): void - { - foreach ($this->invoiceLines as $invoiceLine) { - $invoiceLineVatCategoryCode = $invoiceLine->getLineVatInformation()->getInvoicedItemVatCategoryCode(); - - if ($invoiceLineVatCategoryCode !== VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX) { - throw new \Exception('@todo: BR-O-12'); - } - } - } - - private function checkNotSubjectToVatAllowances(): void - { - foreach ($this->documentLevelAllowances as $documentLevelAllowance) { - if ($documentLevelAllowance->getVatCategoryCode() !== VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX) { - throw new \Exception('@todo: BR-O-13'); - } - } - } - - private function checkNotSubjectToVatCharges(): void - { - foreach ($this->documentLevelCharges as $documentLevelCharge) { - if ($documentLevelCharge->getVatCategoryCode() !== VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX) { - throw new \Exception('@todo: BR-O-14'); - } - } - } - - private function checkChargesVatCategoryCodeConsistencyWithPartyIdentifiers(): void - { - $categoriesRequiringASellerIdentifier = [ - VatCategory::STANDARD_RATE, - VatCategory::ZERO_RATED_GOODS, - VatCategory::EXEMPT_FROM_TAX, - VatCategory::VAT_REVERSE_CHARGE, - VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, - VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, - ]; - - $hasSellerVatIdentifier = $this->seller->getVatIdentifier() instanceof VatIdentifier; - - $hasSellerTaxRegistrationIdentifier = - $this->seller->getTaxRegistrationIdentifier() instanceof TaxRegistrationIdentifier; - - $hasSellerRepresentativeIdentifier = - $this->sellerTaxRepresentativeParty?->getVatIdentifier() instanceof VatIdentifier; - - $hasBuyerVatIdentifier = $this->buyer->getVatIdentifier() instanceof VatIdentifier; - $hasBuyerLegalRegistrationIdentifier = - $this->buyer->getLegalRegistrationIdentifier() instanceof LegalRegistrationIdentifier; - - foreach ($this->documentLevelCharges as $charge) { - $vatCategoryCode = $charge->getVatCategoryCode(); - - if ( - in_array($vatCategoryCode, $categoriesRequiringASellerIdentifier) - && !( - $hasSellerVatIdentifier - || $hasSellerTaxRegistrationIdentifier - || $hasSellerRepresentativeIdentifier - ) - ) { - throw new \Exception('@todo: BR-[S/Z/E/AE/IG/IP]-4'); - } - - if ( - $vatCategoryCode === VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX - && ( - $hasSellerVatIdentifier - || $hasSellerTaxRegistrationIdentifier - || $hasSellerRepresentativeIdentifier - ) - ) { - throw new \Exception('@todo: BR-O-4'); - } - - if ( - in_array($vatCategoryCode, [ - VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, - VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED - ]) && !($hasSellerVatIdentifier || $hasSellerRepresentativeIdentifier) - ) { - throw new \Exception('@todo: BR-[K/G]-4'); - } - - if ( - $vatCategoryCode === VatCategory::VAT_REVERSE_CHARGE - && !($hasBuyerVatIdentifier || $hasBuyerLegalRegistrationIdentifier) - ) { - throw new \Exception('@todo: BR-AE-4'); - } - - if ( - $vatCategoryCode === VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES - && !$hasBuyerVatIdentifier - ) { - throw new \Exception('@todo: BR-K-4'); - } - } - } -} diff --git a/tests/BusinessRulesConditionsTest.php b/tests/BusinessRulesConditionsTest.php deleted file mode 100644 index 9e1489b..0000000 --- a/tests/BusinessRulesConditionsTest.php +++ /dev/null @@ -1,2527 +0,0 @@ -setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 12, - 12, - 14.4, - 14.4, - invoiceTotalVatAmount: 2.4 - ), - [new VatBreakdown(12, 2.4, VatCategory::STANDARD_RATE, 20.00)], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 12, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - )], - null, - null, - new \DateTimeImmutable(), - null, - [], - [] - )); - - $this->assertInstanceOf(Invoice::class, $invoice); - $this->assertNull($invoice->getVatAccountingCurrencyCode()); - $this->assertNull($invoice->getValueAddedTaxPointDate()); - } - - /** - * @test - * @testdox BR-CO-3 : Value added tax point date (BT-7) and Value added tax point date code (BT-8) are mutually exclusive. - */ - public function brCo3_bt7_is_set_and_bt8_null(): void - { - $invoice = (new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 12, - 12, - 14.4, - 14.4, - invoiceTotalVatAmount: 2.4 - ), - [new VatBreakdown(12, 2.4, VatCategory::STANDARD_RATE, 20.00)], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 12, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - )], - new \DateTimeImmutable(), - null, - new \DateTimeImmutable(), - null, - [], - [] - )); - - $this->assertInstanceOf(Invoice::class, $invoice); - $this->assertNotNull($invoice->getValueAddedTaxPointDate()); - $this->assertNull($invoice->getValueAddedTaxPointDateCode()); - } - - /** - * @test - * @testdox BR-CO-3 : Value added tax point date (BT-7) and Value added tax point date code (BT-8) are mutually exclusive. - */ - public function brCo3_bt7_null_and_bt8_is_set(): void - { - $invoice = (new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 12, - 12, - 14.4, - 14.4, - invoiceTotalVatAmount: 2.4 - ), - [new VatBreakdown(12, 2.4, VatCategory::STANDARD_RATE, 20.00)], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 12, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - )], - null, - DateCode2005::DELIVERY_DATE, - new \DateTimeImmutable(), - null, - [], - [] - )); - - $this->assertInstanceOf(Invoice::class, $invoice); - $this->assertNull($invoice->getValueAddedTaxPointDate()); - $this->assertNotNull($invoice->getValueAddedTaxPointDateCode()); - } - - /** - * @test - * @testdox BR-CO-3 : Value added tax point date (BT-7) and Value added tax point date code (BT-8) are mutually exclusive. - */ - public function brCo3_bt7_is_set_and_bt8_is_set(): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - CurrencyCode::CANADIAN_DOLLAR, - new DocumentTotals( - 0, - 0, - 20, - 20, - invoiceTotalVatAmount: 20 - ), - [new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20.00)], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - )], - new \DateTimeImmutable(), - DateCode2005::DELIVERY_DATE, - new \DateTimeImmutable(), - null, - [], - [] - ); - } - - /** - * @test - * @testdox BR-CO-4 : Each Invoice line (BG-25) shall be categorized with an Invoiced item VAT category code (BT-151). - */ - public function brCo4(): void - { - $invoiceLine = new InvoiceLine( - new InvoiceLineIdentifier('value'), - 1, - UnitOfMeasurement::CENTILITRE_REC20, - 10, - new PriceDetails(10), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation('item') - ); - - $this->assertNotNull($invoiceLine->getLineVatInformation()->getInvoicedItemVatCategoryCode()); - $this->assertInstanceOf(VatCategory::class, $invoiceLine->getLineVatInformation()->getInvoicedItemVatCategoryCode()); - } - - /** - * @test - * @testdox BR-CO-5 : Document level allowance reason code (BT-98) and Document level allowance reason (BT-97) shall indicate the same type of allowance. - */ - public function brCo5(): void - { - $this->markTestSkipped('@todo'); - } - - /** - * @test - * @testdox BR-CO-6 : Document level charge reason code (BT-105) and Document level charge reason (BT-104) shall indicate the same type of charge. - */ - public function brCo6(): void - { - $this->markTestSkipped('@todo'); - } - - /** - * @test - * @testdox BR-CO-7 : Invoice line allowance reason code (BT-140) and Invoice line allowance reason (BT-139) shall indicate the same type of allowance reason. - */ - public function brCo7(): void - { - $this->markTestSkipped('@todo'); - } - - /** - * @test - * @testdox BR-CO-8 : Invoice line charge reason code (BT-145) and Invoice line charge reason (BT144) shall indicate the same type of charge reason. - */ - public function brCo8(): void - { - $this->markTestSkipped('@todo'); - } - - /** - * @test - * @testdox BR-CO-9 : The Seller VAT identifier (BT-31), the Seller tax representative VAT identifier (BT-63) and the Buyer VAT identifier (BT-48) shall have a prefix in accordance with ISO code ISO 3166-1 alpha-2 by which the country of issue may be identified. Nevertheless, Greece may use the prefix ‘EL’. - * @dataProvider provideBrCo9Success - */ - public function brCo9_success(string $value): void - { - $vatIdentifier = new VatIdentifier($value); - - $this->assertInstanceOf(VatIdentifier::class, $vatIdentifier); - $this->assertSame($value, $vatIdentifier->getValue()); - } - - public static function provideBrCo9Success(): \Generator - { - yield 'BR-CO-9 Success #1' => [ - 'value' => 'IT123456789', - ]; - yield 'BR-CO-9 Success #2' => [ - 'value' => 'EL987654321', - ]; - yield 'BR-CO-9 Success #3' => [ - 'value' => 'NL-967611265', - ]; - } - - /** - * @test - * @testdox BR-CO-9 : The Seller VAT identifier (BT-31), the Seller tax representative VAT identifier (BT-63) and the Buyer VAT identifier (BT-48) shall have a prefix in accordance with ISO code ISO 3166-1 alpha-2 by which the country of issue may be identified. Nevertheless, Greece may use the prefix ‘EL’. - * @dataProvider provideBrCo9Error - */ - public function brCo9_error(string $value): void - { - $this->expectException(\Exception::class); - - new VatIdentifier($value); - } - - public static function provideBrCo9Error(): \Generator - { - yield 'BR-CO-9 Error #1' => [ - 'value' => 'A123456789', - ]; - yield 'BR-CO-9 Error #2' => [ - 'value' => '987654321', - ]; - yield 'BR-CO-9 Error #3' => [ - 'value' => '967611265', - ]; - } - - /** - * @test - * @testdox BR-CO-10 : Sum of Invoice line net amount (BT-106) = ∑ Invoice line net amount (BT-131). - * @dataProvider provideBrCo10Success - * @param array $vatBreakdowns - * @param array $invoiceLines - */ - public function brCo10_success(DocumentTotals $documentTotals, array $vatBreakdowns, array $invoiceLines): void - { - $invoice = (new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR989465454') - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotals, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - [], - [] - )); - - $invoiceLinesFromObject = $invoice->getInvoiceLines(); - $invoiceLinesTotal = 0.00; - foreach ($invoiceLinesFromObject as $invoiceLineFromObject) { - $invoiceLinesTotal += $invoiceLineFromObject->getNetAmount()->multiply($invoiceLineFromObject->getInvoicedQuantity()); - } - - $this->assertEquals($invoice->getDocumentTotals()->getSumOfInvoiceLineNetAmount()->getValueRounded(), round($invoiceLinesTotal * 100) / 100); - } - - public static function provideBrCo10Success(): \Generator - { - yield 'One invoice line with positive amount' => [ - 'documentTotals' => new DocumentTotals( - 100, - 100, - 100, - 100, - ), - 'vatBreakdowns' => [new VatBreakdown(100, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, vatExemptionReasonText: 'Hoobastank')], - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100.00, - new PriceDetails(100), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ] - ]; - yield 'One invoice line with negative amount' => [ - 'documentTotals' => new DocumentTotals( - -100, - -100, - -120, - -120, - invoiceTotalVatAmount: -20 - ), - 'vatBreakdowns' => [new VatBreakdown(-100, -20, VatCategory::STANDARD_RATE, 20.0)], - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - -100.00, - new PriceDetails(100), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ] - ]; - yield 'One invoice line with amount equal to 0 (float)' => [ - 'documentTotals' => new DocumentTotals( - 0, - 0, - 0, - 0 - ), - 'vatBreakdowns' => [new VatBreakdown(0, 0, VatCategory::STANDARD_RATE, 20.0)], - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0.00, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ] - ]; - yield 'One invoice line with amount equal to 0 (int)' => [ - 'documentTotals' => new DocumentTotals( - 0, - 0, - 0, - 0 - ), - 'vatBreakdowns' => [new VatBreakdown(0, 0, VatCategory::STANDARD_RATE, 20.0)], - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(100), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ] - ]; - yield 'Two invoice lines with two positives numbers and positive total' => [ - 'documentTotals' => new DocumentTotals( - 200, - 200, - 240, - 240, - invoiceTotalVatAmount: 40 - ), - 'vatBreakdowns' => [new VatBreakdown(200, 40, VatCategory::STANDARD_RATE, 20.0)], - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 110.00, - new PriceDetails(110), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 90.00, - new PriceDetails(90), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ] - ]; - yield 'Two invoice lines with one positive number / one negative number and positive total' => [ - 'documentTotals' => new DocumentTotals( - 20, - 20, - 24, - 24, - invoiceTotalVatAmount: 4 - ), - 'vatBreakdowns' => [new VatBreakdown(20, 4, VatCategory::STANDARD_RATE, 20)], - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 110.00, - new PriceDetails(110), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - -90.00, - new PriceDetails(90), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ] - ]; - yield 'Two invoice lines with one positive number / one negative number and negative total' => [ - 'documentTotals' => new DocumentTotals( - -20, - -20, - -24, - -24, - invoiceTotalVatAmount:-4 - ), - 'vatBreakdowns' => [new VatBreakdown(-20, -4, VatCategory::STANDARD_RATE, 20)], - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - -110.00, - new PriceDetails(110), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 90.00, - new PriceDetails(90), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ] - ]; - } - - /** - * @test - * @testdox BR-CO-10 : Sum of Invoice line net amount (BT-106) = ∑ Invoice line net amount (BT-131). - * @dataProvider provideBrCo10Error - * @param array $invoiceLines - */ - public function brCo10_error(DocumentTotals $documentTotals, array $invoiceLines): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotals, - [new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20.00)], - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - [], - [] - ); - } - - public static function provideBrCo10Error(): \Generator - { - yield 'Error with two invoice lines' => [ - 'documentTotals' => new DocumentTotals( - 200.01, - 0, - 20, - 20, - invoiceTotalVatAmount: 20 - ), - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 110.00, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 90.00, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ] - ]; - yield 'Error with one invoice lines' => [ - 'documentTotals' => new DocumentTotals( - -91, - 0, - 20, - 20, - invoiceTotalVatAmount: 20 - ), - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - -90.00, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ] - ]; - } - - /** - * @test - * @testdox BR-CO-11 : Sum of allowances on document level (BT-107) = ∑ Document level allowance amount (BT-92). - * @dataProvider provideBrCo11Success - * @param array $vatBreakdowns - * @param array $invoiceLines - * @param array $documentLevelAllowances - */ - public function brCo11_success(DocumentTotals $documentTotals, array $vatBreakdowns, array $invoiceLines, array $documentLevelAllowances): void - { - $invoice = (new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR95645545') - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotals, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - [] - )); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrCo11Success(): \Generator - { - yield 'BR-CO-11 Success #1' => [ - 'documentTotals' => - new DocumentTotals( - 100, - 0, - 0, - 0, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(0, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, vatExemptionReasonText: 'Hoobastank') - ], - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(12), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ], - 'documentLevelAllowances' => [ - new DocumentLevelAllowance(100, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, reasonCode: AllowanceReasonCodeUNTDID5189::STANDARD) - ] - ]; - yield 'BR-CO-11 Success #2' => [ - 'documentTotals' => - new DocumentTotals( - 100, - 100, - 100, - 100, - sumOfAllowancesOnDocumentLevel: 0 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, vatExemptionReasonText: 'Hoobastank') - ], - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(12), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ], - 'documentLevelAllowances' => [ - new DocumentLevelAllowance(0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, reasonCode: AllowanceReasonCodeUNTDID5189::STANDARD) - ] - ]; - yield 'BR-CO-11 Success #3' => [ - 'documentTotals' => - new DocumentTotals( - 2000, - 1000, - 1200, - 1200, - invoiceTotalVatAmount: 200, - sumOfAllowancesOnDocumentLevel: 1000.00 - ), - 'vatBreakdowns' => [ - new VatBreakdown(1000, 200, VatCategory::STANDARD_RATE, 20) - ], - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 2000, - new PriceDetails(2000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ], - 'documentLevelAllowances' => [ - new DocumentLevelAllowance(100, VatCategory::STANDARD_RATE, reasonCode: AllowanceReasonCodeUNTDID5189::STANDARD, vatRate: 20), - new DocumentLevelAllowance(900.0, VatCategory::STANDARD_RATE, reasonCode: AllowanceReasonCodeUNTDID5189::STANDARD, vatRate: 20) - ] - ]; - } - - /** - * @test - * @testdox BR-CO-11 : Sum of allowances on document level (BT-107) = ∑ Document level allowance amount (BT-92). - * @dataProvider provideBrCo11Error - * @param array $documentLevelAllowances - */ - public function brCo11_error(DocumentTotals $documentTotals, array $documentLevelAllowances): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotals, - [new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20.00)], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(12), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - )], - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - [] - ); - } - - public static function provideBrCo11Error(): \Generator - { - yield 'BR-CO-11 Error #1' => [ - 'documentTotals' => - new DocumentTotals( - 0, - 0, - 20, - 20, - invoiceTotalVatAmount: 20, - sumOfAllowancesOnDocumentLevel: 1000.00 - ), - 'documentLevelAllowances' => [ - new DocumentLevelAllowance(0.0, VatCategory::STANDARD_RATE, reasonCode: AllowanceReasonCodeUNTDID5189::STANDARD, vatRate: 20) - ] - ]; - yield 'BR-CO-11 Error #2' => [ - 'documentTotals' => - new DocumentTotals( - 0, - 0, - 20, - 20, - invoiceTotalVatAmount: 20, - sumOfAllowancesOnDocumentLevel: 1000.00 - ), - 'documentLevelAllowances' => [ - new DocumentLevelAllowance(100, VatCategory::STANDARD_RATE, reasonCode: AllowanceReasonCodeUNTDID5189::STANDARD, vatRate: 20), - new DocumentLevelAllowance(1000.0, VatCategory::STANDARD_RATE, reasonCode: AllowanceReasonCodeUNTDID5189::STANDARD, vatRate: 20) - ] - ]; - } - - /** - * @test - * @testdox BR-CO-12 : Sum of charges on document level (BT-108) = ∑ Document level charge amount (BT-99). - * @dataProvider provideBrCo12Success - * @param array $vatBreakdowns - * @param array $documentLevelCharges - */ - public function brCo12_success(DocumentTotals $documentTotals, array $vatBreakdowns, array $documentLevelCharges): void - { - $invoice = (new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('AZE') - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotals, - $vatBreakdowns, - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(12), - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, 0), - new ItemInformation("A thing"), - )], - null, - null, - new \DateTimeImmutable(), - null, - [], - $documentLevelCharges - )); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrCo12Success(): \Generator - { - yield 'BR-CO-12 Success #1' => [ - 'documentTotals' => - new DocumentTotals( - 100, - 200, - 220, - 220, - invoiceTotalVatAmount: 20, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank'), - new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20.00), - ], - 'documentLevelCharges' => [ - new DocumentLevelCharge(100, VatCategory::STANDARD_RATE, reasonCode: ChargeReasonCode::ADVERTISING, vatRate: 20) - ] - ]; - yield 'BR-CO-12 Success #2' => [ - 'documentTotals' => - new DocumentTotals( - 100, - 100, - 100, - 100, - invoiceTotalVatAmount: 0, - sumOfChargesOnDocumentLevel: 0 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank'), - new VatBreakdown(0, 0, VatCategory::STANDARD_RATE, 20.00), - ], - 'documentLevelCharges' => [ - new DocumentLevelCharge(0, VatCategory::STANDARD_RATE, reasonCode: ChargeReasonCode::ADVERTISING, vatRate: 20), - ] - ]; - yield 'BR-CO-12 Success #3' => [ - 'documentTotals' => - new DocumentTotals( - 100, - 160, - 172, - 172, - invoiceTotalVatAmount: 12, - sumOfChargesOnDocumentLevel: 60 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank'), - new VatBreakdown(60, 12, VatCategory::STANDARD_RATE, 20.00), - ], - 'documentLevelCharges' => [ - new DocumentLevelCharge(10, VatCategory::STANDARD_RATE, reasonCode: ChargeReasonCode::ADVERTISING, vatRate: 20), - new DocumentLevelCharge(50, VatCategory::STANDARD_RATE, reasonCode: ChargeReasonCode::ADVERTISING, vatRate: 20), - ] - ]; - } - - /** - * @test - * @testdox BR-CO-12 : Sum of charges on document level (BT-108) = ∑ Document level charge amount (BT-99). - * @dataProvider provideBrCo12Error - * @param array $documentLevelCharges - */ - public function brCo12_error(DocumentTotals $documentTotals, array $documentLevelCharges): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotals, - [new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20.00)], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(12), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - )], - null, - null, - new \DateTimeImmutable(), - null, - [], - $documentLevelCharges - ); - } - - public static function provideBrCo12Error(): \Generator - { - yield 'BR-CO-12 Error #1' => [ - 'documentTotals' => - new DocumentTotals( - 0, - 0, - 20, - 20, - invoiceTotalVatAmount: 20, - sumOfChargesOnDocumentLevel: 1000 - ), - 'documentLevelCharges' => [ - new DocumentLevelCharge(0, VatCategory::STANDARD_RATE, reasonCode: ChargeReasonCode::ADVERTISING, vatRate: 20) - ] - ]; - yield 'BR-CO-12 Error #2' => [ - 'documentTotals' => - new DocumentTotals( - 0, - 0, - 20, - 20, - invoiceTotalVatAmount: 20, - sumOfChargesOnDocumentLevel: 1000 - ), - 'documentLevelCharges' => [ - new DocumentLevelCharge(100, VatCategory::STANDARD_RATE, reasonCode: ChargeReasonCode::ADVERTISING, vatRate: 20), - new DocumentLevelCharge(1000, VatCategory::STANDARD_RATE, reasonCode: ChargeReasonCode::ADVERTISING, vatRate: 20) - ] - ]; - } - - /** - * @test - * @testdox BR-CO-13 : Invoice total amount without VAT (BT-109) = ∑ Invoice line net amount (BT-131) - Sum of allowances on document level (BT-107) + Sum of charges on document level (BT-108). - * @dataProvider provideBrCo13Success - * @param array $vatBreakdowns - * @param array $invoiceLines - */ - public function brCo13_success(DocumentTotals $documentTotals, array $vatBreakdowns, array $invoiceLines): void - { - // TODO : error cases - - $invoice = (new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR95645545') - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotals, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - [], - [] - )); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrCo13Success(): \Generator - { - yield 'BR-CO-13 Success #1' => [ - 'documentTotals' => - new DocumentTotals( - 1000, - 1000, - 1000, - 1000 - ), - 'vatBreakdown' => [ - new VatBreakdown( - 1000, - 0, - VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, - vatExemptionReasonText: 'Hoobastank' - ) - ], - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(12), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ] - ]; - yield 'BR-CO-13 Success #2' => [ - 'documentTotals' => - new DocumentTotals( - 1500, - 1500, - 1500, - 1500 - ), - 'vatBreakdown' => [ - new VatBreakdown( - 1500, - 0, - VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, - vatExemptionReasonText: 'Hoobastank' - ) - ], - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(12), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 500, - new PriceDetails(12), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ] - ]; - yield 'BR-CO-13 Success #3' => [ - 'documentTotals' => - new DocumentTotals( - 2000, - 1000, - 2000, - 2000, - invoiceTotalVatAmount: 1000, - sumOfAllowancesOnDocumentLevel: 1000 - ), - 'vatBreakdown' => [ - new VatBreakdown( - 2000, - 1000, - VatCategory::STANDARD_RATE, - vatCategoryRate: 50 - ) - ], - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 50.0), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 50.0), - new ItemInformation("A thing"), - ) - ] - ]; - } - - /** - * @test - * @testdox BR-CO-14 : Invoice total VAT amount (BT-110) = ∑ VAT category tax amount (BT-117). - * @dataProvider provideBrCo14Success - * @param array $vatBreakdowns - * @param array $invoiceLines - */ - public function brCo14_success(DocumentTotals $documentTotals, array $vatBreakdowns, array $invoiceLines): void - { - $invoice = (new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotals, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - [], - [] - )); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrCo14Success(): \Generator - { - yield 'BR-CO-14 Success #1' => [ - 'documentTotals' => - new DocumentTotals( - 1000, - 1000, - 1250, - 1250, - invoiceTotalVatAmount: 250 - ), - 'vatBreakdowns' => [ - new VatBreakdown(1000, 250, VatCategory::STANDARD_RATE, 25) - ], - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 25), - new ItemInformation("A thing"), - ) - ], - ]; - yield 'BR-CO-14 Success #2' => [ - 'documentTotals' => - new DocumentTotals( - 1600, - 1600, - 1970, - 1970, - invoiceTotalVatAmount: 370 - ), - 'vatBreakdowns' => [ - new VatBreakdown(1000, 250, VatCategory::STANDARD_RATE, 25), - new VatBreakdown(600, 120, VatCategory::STANDARD_RATE, 20) - ], - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 25), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 600, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ], - ]; - yield 'BR-CO-14 Success #3' => [ - 'documentTotals' => - new DocumentTotals( - 1000, - 1000, - 1250, - 1250, - invoiceTotalVatAmount: 250.0 - ), - 'vatBreakdowns' => [ - new VatBreakdown(1000, 250, VatCategory::STANDARD_RATE, 25), - new VatBreakdown(0, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank') - ], - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 25), - new ItemInformation("A thing"), - ) - ], - ]; - yield 'BR-CO-14 Success #4' => [ - 'documentTotals' => - new DocumentTotals( - 0, - 0, - 0, - 0, - invoiceTotalVatAmount: 00 - ), - 'vatBreakdowns' => [ - new VatBreakdown(0, 0, VatCategory::STANDARD_RATE, 20), - ], - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ], - ]; - } - - /** - * @test - * @testdox BR-CO-14 : Invoice total VAT amount (BT-110) = ∑ VAT category tax amount (BT-117). - * @dataProvider provideBrCo14Error - * @param array $vatBreakdowns - */ - public function brCo14_error(DocumentTotals $documentTotals, array $vatBreakdowns): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotals, - $vatBreakdowns, - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(12), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - )], - null, - null, - new \DateTimeImmutable(), - null, - [], - [] - ); - } - - public static function provideBrCo14Error(): \Generator - { - yield 'BR-CO-14 Error #1' => [ - 'documentTotals' => - new DocumentTotals( - 0, - 0, - 250, - 250, - invoiceTotalVatAmount: 250 - ), - 'vatBreakdowns' => [ - new VatBreakdown(600, 300, VatCategory::STANDARD_RATE, 50) - ] - ]; - yield 'BR-CO-14 Error #2' => [ - 'documentTotals' => - new DocumentTotals( - 0, - 0, - 300, - 300, - invoiceTotalVatAmount: 300 - ), - 'vatBreakdowns' => [ - new VatBreakdown(1000, 250, VatCategory::STANDARD_RATE, 25), - new VatBreakdown(600, 150, VatCategory::STANDARD_RATE, 25) - ] - ]; - yield 'BR-CO-14 Error #3' => [ - 'documentTotals' => - new DocumentTotals( - 0, - 0, - 1, - 1, - invoiceTotalVatAmount: 1 - ), - 'vatBreakdowns' => [ - new VatBreakdown(0, 0, VatCategory::STANDARD_RATE, 0), - new VatBreakdown(0, 0, VatCategory::STANDARD_RATE, 0) - ] - ]; - } - - /** - * @test - * @testdox BR-CO-15 : Invoice total amount with VAT (BT-112) = Invoice total amount without VAT (BT-109) + Invoice total VAT amount (BT-110). - * @dataProvider provideBrCo15_success - */ - public function brCo15_success( - float $invoiceTotalAmountWithoutVat, - ?float $invoiceTotalVatAmount, - float $invoiceTotalAmountWithVat, - float $amountDueForPayment - ): void - { - $documentTotals = new DocumentTotals( - 0, - $invoiceTotalAmountWithoutVat, - $invoiceTotalAmountWithVat, - $amountDueForPayment, - invoiceTotalVatAmount: $invoiceTotalVatAmount - ); - - $this->assertInstanceOf(DocumentTotals::class, $documentTotals); - $this->assertEquals( - $documentTotals->getInvoiceTotalAmountWithVat()->getValueRounded(), - $documentTotals->getInvoiceTotalAmountWithoutVat() - ->add($documentTotals->getInvoiceTotalVatAmount() ?? new Amount(0.00)) - ); - } - - public static function provideBrCo15_success(): \Generator - { - // BT-109, BT-110, BT-112, BT-115 - yield 'Standard calculation' => [ - 'invoiceTotalAmountWithoutVat' => 1000, - 'invoiceTotalVatAmount' => 300, - 'invoiceTotalAmountWithVat' => 1300, - 'amountDueForPayment' => 1300 - ]; - yield 'Standard calculation with VAT to null' => [ - 'invoiceTotalAmountWithoutVat' => 1300, - 'invoiceTotalVatAmount' => null, - 'invoiceTotalAmountWithVat' => 1300, - 'amountDueForPayment' => 1300 - ]; - yield 'Standard calculation with VAT to 0' => [ - 'invoiceTotalAmountWithoutVat' => 1300, - 'invoiceTotalVatAmount' => 0, - 'invoiceTotalAmountWithVat' => 1300, - 'amountDueForPayment' => 1300 - ]; - yield 'Calculation with Invoice Total Amount Without VAT < 0' => [ - 'invoiceTotalAmountWithoutVat' => -100, - 'invoiceTotalVatAmount' => 300, - 'invoiceTotalAmountWithVat' => 200, - 'amountDueForPayment' => 200 - ]; - yield 'Calculation with Invoice Total Amount Without VAT < 0 and Invoice Total Amount With VAT = 0' => [ - 'invoiceTotalAmountWithoutVat' => -100, - 'invoiceTotalVatAmount' => 100, - 'invoiceTotalAmountWithVat' => 0.0, - 'amountDueForPayment' => 0.0 - ]; - yield 'Calculation with all data = 0' => [ - 'invoiceTotalAmountWithoutVat' => 0.00, - 'invoiceTotalVatAmount' => 0, - 'invoiceTotalAmountWithVat' => 0.0, - 'amountDueForPayment' => 0.0 - ]; - } - - /** - * @test - * @testdox BR-CO-15 : Invoice total amount with VAT (BT-112) = Invoice total amount without VAT (BT-109) + Invoice total VAT amount (BT-110). - * @dataProvider provideBrCo15_error - */ - public function brCo15_error(float $invoiceTotalAmountWithVat, float $invoiceTotalAmountWithoutVat, ?float $invoiceTotalVatAmount): void - { - $this->expectException(\Exception::class); - - new DocumentTotals( - 0, - $invoiceTotalAmountWithoutVat, - $invoiceTotalAmountWithVat, - 0, - invoiceTotalVatAmount: $invoiceTotalVatAmount - ); - } - - public static function provideBrCo15_error(): \Generator - { - yield 'Invoice total amount with VAT != Invoice total amount without VAT + Invoice total VAT amount #1' => [ - 1250.00, 1000.00, 0 - ]; - yield 'Invoice total amount with VAT != Invoice total amount without VAT + Invoice total VAT amount #2' => [ - 0.01, -100, 100 - ]; - yield 'Invoice total amount with VAT != Invoice total amount without VAT + Invoice total VAT amount #3' => [ - 12, 10, null - ]; - } - - /** - * @test - * @testdox BR-CO-16 : Amount due for payment (BT-115) = Invoice total amount with VAT (BT-112) - Paid amount (BT-113) + Rounding amount (BT-114). - * @dataProvider provideBrCo16_success - */ - public function brCo16_success( - float $invoiceTotalAmountWithoutVat, - ?float $invoiceTotalVatAmount, - float $invoiceTotalAmountWithVat, - ?float $paidAmount, - ?float $roundingAmount, - float $amountDueForPayment - ): void - { - $documentTotals = new DocumentTotals( - 0, - $invoiceTotalAmountWithoutVat, - $invoiceTotalAmountWithVat, - $amountDueForPayment, - invoiceTotalVatAmount: $invoiceTotalVatAmount, - paidAmount: $paidAmount, - roundingAmount: $roundingAmount - ); - - $this->assertInstanceOf(DocumentTotals::class, $documentTotals); - } - - public static function provideBrCo16_success(): \Generator - { - yield 'BR-CO-16 Success #1' => [ - 'invoiceTotalAmountWithoutVat' => 1200, - 'invoiceTotalVatAmount' => 0, - 'invoiceTotalAmountWithVat' => 1200, - 'paidAmount' => 1000, - 'roundingAmount' => null, - 'amountDueForPayment' => 200.00 - ]; - yield 'BR-CO-16 Success #2' => [ - 'invoiceTotalAmountWithoutVat' => 8250.00, - 'invoiceTotalVatAmount' => 0, - 'invoiceTotalAmountWithVat' => 8250.00, - 'paidAmount' => null, - 'roundingAmount' => null, - 'amountDueForPayment' => 8250.0 - ]; - yield 'BR-CO-16 Success #3' => [ - 'invoiceTotalAmountWithoutVat' => 1200.00, - 'invoiceTotalVatAmount' => 0, - 'invoiceTotalAmountWithVat' => 1200.00, - 'paidAmount' => 0, - 'roundingAmount' => null, - 'amountDueForPayment' => 1200.00 - ]; - yield 'BR-CO-16 Success #4' => [ - 'invoiceTotalAmountWithoutVat' => 1200.00, - 'invoiceTotalVatAmount' => 0, - 'invoiceTotalAmountWithVat' => 1200.00, - 'paidAmount' => 1200, - 'roundingAmount' => null, - 'amountDueForPayment' => 0.0 - ]; - yield 'BR-CO-16 Success #5' => [ - 'invoiceTotalAmountWithoutVat' => 1200.78, - 'invoiceTotalVatAmount' => 0, - 'invoiceTotalAmountWithVat' => 1200.78, - 'paidAmount' => 1000.0, - 'roundingAmount' => 0.22, - 'amountDueForPayment' => 201 - ]; - yield 'BR-CO-16 Success #6' => [ - 'invoiceTotalAmountWithoutVat' => 1200.78, - 'invoiceTotalVatAmount' => 0, - 'invoiceTotalAmountWithVat' => 1200.78, - 'paidAmount' => null, - 'roundingAmount' => 0.22, - 'amountDueForPayment' => 1201 - ]; - yield 'BR-CO-16 Success #7' => [ - 'invoiceTotalAmountWithoutVat' => 1200.22, - 'invoiceTotalVatAmount' => 0, - 'invoiceTotalAmountWithVat' => 1200.22, - 'paidAmount' => null, - 'roundingAmount' => -0.22, - 'amountDueForPayment' => 1200.0 - ]; - } - - /** - * @test - * @testdox BR-CO-16 : Amount due for payment (BT-115) = Invoice total amount with VAT (BT-112) - Paid amount (BT-113) + Rounding amount (BT-114). - * @dataProvider provideBrCo16_error - */ - public function brCo16_error( - float $invoiceTotalAmountWithoutVat, - ?float $invoiceTotalVatAmount, - float $invoiceTotalAmountWithVat, - ?float $paidAmount, - ?float $roundingAmount, - float $amountDueForPayment - ): void - { - $this->expectException(\Exception::class); - - $documentTotals = new DocumentTotals( - 0, - $invoiceTotalAmountWithoutVat, - $invoiceTotalAmountWithVat, - $amountDueForPayment, - invoiceTotalVatAmount: $invoiceTotalVatAmount, - paidAmount: $paidAmount, - roundingAmount: $roundingAmount - ); - - $this->assertInstanceOf(DocumentTotals::class, $documentTotals); - } - - public static function provideBrCo16_error(): \Generator - { - yield 'BR-CO-16 Error #1' => [ - 'invoiceTotalAmountWithoutVat' => 1200, - 'invoiceTotalVatAmount' => 0, - 'invoiceTotalAmountWithVat' => 1200, // x - 'paidAmount' => 100, // x - 'roundingAmount' => null, - 'amountDueForPayment' => 1200 // x - ]; - yield 'BR-CO-16 Error #2' => [ - 'invoiceTotalAmountWithoutVat' => 1200, - 'invoiceTotalVatAmount' => 0, - 'invoiceTotalAmountWithVat' => 1200.78, - 'paidAmount' => 100, - 'roundingAmount' => 0.22, - 'amountDueForPayment' => 1100.78 - ]; - yield 'BR-CO-16 Error #3' => [ - 'invoiceTotalAmountWithoutVat' => 1200, - 'invoiceTotalVatAmount' => 0, - 'invoiceTotalAmountWithVat' => 1200, - 'paidAmount' => null, - 'roundingAmount' => null, - 'amountDueForPayment' => 1100 - ]; - } - - /** - * @test - * @testdox BR-CO-17 : VAT category tax amount (BT-117) = VAT category taxable amount (BT-116) x (VAT category rate (BT-119) / 100), rounded to two decimals. - * @dataProvider provideBrCo17_success - */ - public function brCo17_success( - float $vatCategoryTaxableAmount, - float $vatCategoryTaxAmount, - VatCategory $vatCategoryCode, - ?float $vatCategoryRate, - ?string $vatExemptionReasonText = null - ): void - { - $vatBreakdown = new VatBreakdown( - $vatCategoryTaxableAmount, - $vatCategoryTaxAmount, - $vatCategoryCode, - $vatCategoryRate, - vatExemptionReasonText: $vatExemptionReasonText - ); - - $this->assertInstanceOf(VatBreakdown::class, $vatBreakdown); - $this->assertSame($vatCategoryTaxableAmount, $vatBreakdown->getVatCategoryTaxableAmount()->getValueRounded()); - $this->assertSame($vatCategoryTaxAmount, $vatBreakdown->getVatCategoryTaxAmount()->getValueRounded()); - $this->assertSame($vatCategoryCode, $vatBreakdown->getVatCategoryCode()); - $this->assertSame($vatCategoryRate, $vatBreakdown->getVatCategoryRate()?->getValueRounded()); - $this->assertSame($vatExemptionReasonText, $vatBreakdown->getVatExemptionReasonText()); - } - - public static function provideBrCo17_success(): \Generator - { - yield 'BR-CO-17 Success #1' => [ - 'vatCategoryTaxableAmount' => 1000, - 'vatCategoryTaxAmount' => 250, - 'vatCategoryCode' => VatCategory::STANDARD_RATE, - 'vatCategoryRate' => 25 - ]; - yield 'BR-CO-17 Success #2' => [ - 'vatCategoryTaxableAmount' => -6491.34, - 'vatCategoryTaxAmount' => -1622.84, - 'vatCategoryCode' => VatCategory::STANDARD_RATE, - 'vatCategoryRate' => 25 - ]; - yield 'BR-CO-17 Success #3' => [ - 'vatCategoryTaxableAmount' => 2141.05, - 'vatCategoryTaxAmount' => 299.75, - 'vatCategoryCode' => VatCategory::STANDARD_RATE, - 'vatCategoryRate' => 14 - ]; - yield 'BR-CO-17 Success #4' => [ - 'vatCategoryTaxableAmount' => 2141.05, - 'vatCategoryTaxAmount' => .00, - 'vatCategoryCode' => VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, - 'vatCategoryRate' => null, - 'vatExemptionReasonText' => 'Hoobastank' - ]; - yield 'BR-CO-17 Success #5' => [ - 'vatCategoryTaxableAmount' => 2141.19, - 'vatCategoryTaxAmount' => 44.96, - 'vatCategoryCode' => VatCategory::STANDARD_RATE, - 'vatCategoryRate' => 2.1 - ]; - yield 'BR-CO-17 Success #6' => [ - 'vatCategoryTaxableAmount' => 2141.19, - 'vatCategoryTaxAmount' => 0.0, - 'vatCategoryCode' => VatCategory::STANDARD_RATE, - 'vatCategoryRate' => 0 - ]; - yield 'BR-CO-17 Success #7' => [ - 'vatCategoryTaxableAmount' => -2141.19, - 'vatCategoryTaxAmount' => -117.77, - 'vatCategoryCode' => VatCategory::STANDARD_RATE, - 'vatCategoryRate' => 5.5 - ]; - yield 'BR-CO-17 Success #8' => [ - 'vatCategoryTaxableAmount' => -25.00, - 'vatCategoryTaxAmount' => 0.00, - 'vatCategoryCode' => VatCategory::STANDARD_RATE, - 'vatCategoryRate' => 0 - ]; - yield 'BR-CO-17 Success #9' => [ - 'vatCategoryTaxableAmount' => -2141.19, - 'vatCategoryTaxAmount' => -117.77, - 'vatCategoryCode' => VatCategory::STANDARD_RATE, - 'vatCategoryRate' => 5.5 - ]; - yield 'BR-CO-17 Success #10' => [ - 'vatCategoryTaxableAmount' => 6491.34, - 'vatCategoryTaxAmount' => 1622.84, - 'vatCategoryCode' => VatCategory::STANDARD_RATE, - 'vatCategoryRate' => 25 - ]; - } - - /** - * @test - * @testdox BR-CO-17 : VAT category tax amount (BT-117) = VAT category taxable amount (BT-116) x (VAT category rate (BT-119) / 100), rounded to two decimals. - * @dataProvider provideBrCo17_error - */ - public function brCo17_error( - float $vatCategoryTaxableAmount, - float $vatCategoryTaxAmount, - VatCategory $vatCategoryCode, - ?float $vatCategoryRate - ): void - { - $this->expectException(\Exception::class); - - new VatBreakdown( - $vatCategoryTaxableAmount, - $vatCategoryTaxAmount, - $vatCategoryCode, - $vatCategoryRate - ); - } - - public static function provideBrCo17_error(): \Generator - { - yield 'BR-CO-17 Error #1' => [ - 'vatCategoryTaxableAmount' => 1000, - 'vatCategoryTaxAmount' => 251, - 'vatCategoryCode' => VatCategory::STANDARD_RATE, - 'vatCategoryRate' => 25 - ]; - yield 'BR-CO-17 Error #2' => [ - 'vatCategoryTaxableAmount' => 2141.19, - 'vatCategoryTaxAmount' => 43.91, - 'vatCategoryCode' => VatCategory::STANDARD_RATE, - 'vatCategoryRate' => 2.1 - ]; - yield 'BR-CO-17 Error #3' => [ - 'vatCategoryTaxableAmount' => 2141.194, - 'vatCategoryTaxAmount' => 43.91, - 'vatCategoryCode' => VatCategory::STANDARD_RATE, - 'vatCategoryRate' => 2.1 - ]; - yield 'BR-CO-17 Error #4' => [ - 'vatCategoryTaxableAmount' => 2141.19, - 'vatCategoryTaxAmount' => 43.919, - 'vatCategoryCode' => VatCategory::STANDARD_RATE, - 'vatCategoryRate' => 2.1 - ]; - } - - /** - * @test - * @testdox : BR-CO-18 : An Invoice shall at least have one VAT breakdown group (BG-23). - */ - public function brCo18_success(): void - { - $invoice = (new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 100, - 100, - 120, - 120, - invoiceTotalVatAmount: 20 - ), - [new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20.00)], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - )], - null, - null, - new \DateTimeImmutable(), - null, - [], - [] - )); - - $this->assertEquals(1, count($invoice->getVatBreakdowns())); - } - - /** - * @test - * @testdox : BR-CO-18 : An Invoice shall at least have one VAT breakdown group (BG-23). - */ - public function brCo18_error(): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals(0, 0, 0, 0), - [], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - )], - null, - null, - null, - null, - [], - [] - ); - } - - /** - * @test - * @testdox BR-CO-19 : If Invoicing period (BG-14) is used, the Invoicing period start date (BT-73) or the Invoicing period end date (BT-74) shall be filled, or both. - * @dataProvider provideBrCo19_success - */ - public function brCo19_success(?\DateTimeInterface $startDate, ?\DateTimeInterface $endDate): void - { - $invoicingPeriod = new InvoicingPeriod($startDate, $endDate); - - $this->assertInstanceOf(InvoicingPeriod::class, $invoicingPeriod); - $this->assertEquals($startDate, $invoicingPeriod->getStartDate()); - $this->assertEquals($endDate, $invoicingPeriod->getEndDate()); - } - - public static function provideBrCo19_success(): \Generator - { - yield 'Invoicing period start date (BT-73) is present' => [ - 'startDate' => new \DateTimeImmutable('2021-01-02'), - 'endDate' => null - ]; - yield 'Invoicing period end date (BT-74) is present' => [ - 'startDate' => null, - 'endDate' => new \DateTimeImmutable('2021-01-03') - ]; - yield 'Invoicing period start date (BT-73) and Invoicing period end date (BT-74) are present' => [ - 'startDate' => new \DateTimeImmutable('2021-01-02'), - 'endDate' => new \DateTimeImmutable('2021-01-03') - ]; - } - - - /** - * @test - * @testdox BR-CO-19 : If Invoicing period (BG-14) is used, the Invoicing period start date (BT-73) or the Invoicing period end date (BT-74) shall be filled, or both. - */ - public function brCo19_error(): void - { - $this->expectException(\Exception::class); - - new InvoiceLinePeriod(null, null); - } - - /** - * @test - * @testdox BR-CO-20 : If Invoice line period (BG-26) is used, the Invoice line period start date (BT-134) or the Invoice line period end date (BT-135) shall be filled, or both. - * @dataProvider provideBrCo20_success - */ - public function brCo20_success(?\DateTimeInterface $startDate, ?\DateTimeInterface $endDate): void - { - $invoiceLinePeriod = new InvoiceLinePeriod($startDate, $endDate); - - $this->assertInstanceOf(InvoiceLinePeriod::class, $invoiceLinePeriod); - $this->assertEquals($startDate, $invoiceLinePeriod->getStartDate()); - $this->assertEquals($endDate, $invoiceLinePeriod->getEndDate()); - } - - public static function provideBrCo20_success(): \Generator - { - yield 'Invoice line period start date (BT-134) is present' => [ - 'startDate' => new \DateTimeImmutable('2021-01-02'), - 'endDate' => null - ]; - yield 'Invoice line period end date (BT-135) is present' => [ - 'startDate' => null, - 'endDate' => new \DateTimeImmutable('2021-01-03') - ]; - yield 'Invoice line period start date (BT-134) and Invoice line period end date (BT-135) are present' => [ - 'startDate' => new \DateTimeImmutable('2021-01-02'), - 'endDate' => new \DateTimeImmutable('2021-01-03') - ]; - } - - /** - * @test - * @testdox BR-CO-20 : If Invoice line period (BG-26) is used, the Invoice line period start date (BT-134) or the Invoice line period end date (BT-135) shall be filled, or both. - */ - public function brCo20_error(): void - { - $this->expectException(\Exception::class); - - new InvoiceLinePeriod(null, null); - } - - /** - * @test - * @testdox BR-CO-21 : Each Document level allowance (BG-20) shall contain a Document level allowance reason (BT-97) or a Document level allowance reason code (BT-98), or both. - * @dataProvider provideBrCo21_success - */ - public function brCo21_success(?string $reason, ?AllowanceReasonCodeUNTDID5189 $reasonCode): void - { - $documentLevelAllowance = new DocumentLevelAllowance(14, VatCategory::STANDARD_RATE, $reason, $reasonCode, vatRate: 20); - - $this->assertInstanceOf(DocumentLevelAllowance::class, $documentLevelAllowance); - $this->assertEquals($reason, $documentLevelAllowance->getReason()); - $this->assertEquals($reasonCode, $documentLevelAllowance->getReasonCode()); - } - - public static function provideBrCo21_success(): \Generator - { - yield 'Document level allowance reason (BT-97) is present' => [ - 'reason' => 'Reason', - 'reasonCode' => null - ]; - yield 'Document level allowance reason code (BT-98) is present' => [ - 'reason' => null, - 'reasonCode' => AllowanceReasonCodeUNTDID5189::STANDARD - ]; - yield 'Document level allowance reason (BT-97) and Document level allowance reason code (BT-98) are present' => [ - 'reason' => 'Reason', - 'reasonCode' => AllowanceReasonCodeUNTDID5189::STANDARD - ]; - } - - /** - * @test - * @testdox BR-CO-21 : Each Document level allowance (BG-20) shall contain a Document level allowance reason (BT-97) or a Document level allowance reason code (BT-98), or both. - * @dataProvider provideBrCo21_error - */ - public function brCo21_error(?string $reason, ?AllowanceReasonCodeUNTDID5189 $reasonCode): void - { - $this->expectException(\Exception::class); - - new DocumentLevelAllowance(14, VatCategory::STANDARD_RATE, $reason, $reasonCode, vatRate: 20); - } - - public static function provideBrCo21_error(): \Generator - { - yield 'Document level allowance reason (BT-97) as an empty string' => [ - 'reason' => '', - 'reasonCode' => null - ]; - yield 'Document level allowance reason (BT-97) and Document level allowance reason code (BT-98) are null' => [ - 'reason' => null, - 'reasonCode' => null - ]; - } - - /** - * @test - * @testdox BR-CO-22 : Each Document level charge (BG-21) shall contain a Document level charge reason (BT-104) or a Document level charge reason code (BT-105), or both. - * @dataProvider provideBrCo22_success - */ - public function brCo22_success(?string $reason, ?ChargeReasonCode $reasonCode): void - { - $documentLevelCharge = new DocumentLevelCharge(14, VatCategory::STANDARD_RATE, $reason, $reasonCode, vatRate: 20); - - $this->assertInstanceOf(DocumentLevelCharge::class, $documentLevelCharge); - $this->assertEquals($reason, $documentLevelCharge->getReason()); - $this->assertEquals($reasonCode, $documentLevelCharge->getReasonCode()); - } - - public static function provideBrCo22_success(): \Generator - { - yield 'Document level charge reason (BT-104) is present' => [ - 'reason' => 'Reason', - 'reasonCode' => null - ]; - yield 'Document level charge reason code (BT-105) is present' => [ - 'reason' => null, - 'reasonCode' => ChargeReasonCode::ADVERTISING - ]; - yield 'Document level charge reason (BT-104) and Document level charge reason code (BT-105) are present' => [ - 'reason' => 'Reason', - 'reasonCode' => ChargeReasonCode::ADVERTISING - ]; - } - - /** - * @test - * @testdox BR-CO-22 : Each Document level charge (BG-21) shall contain a Document level charge reason (BT-104) or a Document level charge reason code (BT-105), or both. - * @dataProvider provideBrCo22_error - */ - public function brCo22_error(?string $reason, ?ChargeReasonCode $reasonCode): void - { - $this->expectException(\Exception::class); - - new DocumentLevelCharge(14, VatCategory::STANDARD_RATE, $reason, $reasonCode); - } - - public static function provideBrCo22_error(): \Generator - { - yield 'Document level charge reason (BT-104) as an empty string' => [ - 'reason' => '', - 'reasonCode' => null - ]; - yield 'Document level charge reason (BT-104) and Document level charge reason code (BT-105) are null' => [ - 'reason' => null, - 'reasonCode' => null - ]; - } - - /** - * @test - * @testdox BR-CO-23 : Each Invoice line allowance (BG-27) shall contain an Invoice line allowance reason (BT-139) or an Invoice line allowance reason code (BT-140), or both. - * @dataProvider provideBrCo23_success - */ - public function brCo23_success(?string $reason, ?AllowanceReasonCodeUNTDID5189 $reasonCode): void - { - $invoiceLineAllowance = new InvoiceLineAllowance(14, $reason, $reasonCode); - - $this->assertInstanceOf(InvoiceLineAllowance::class, $invoiceLineAllowance); - $this->assertEquals($reason, $invoiceLineAllowance->getReason()); - $this->assertEquals($reasonCode, $invoiceLineAllowance->getReasonCode()); - } - - public static function provideBrCo23_success(): \Generator - { - yield 'Invoice line allowance reason (BT-139) is present' => [ - 'reason' => 'Reason', - 'reasonCode' => null - ]; - yield 'Invoice line allowance reason code (BT-140) is present' => [ - 'reason' => null, - 'reasonCode' => AllowanceReasonCodeUNTDID5189::STANDARD - ]; - yield 'Invoice line allowance reason (BT-139) and Invoice line allowance reason code (BT-140) are present' => [ - 'reason' => 'Reason', - 'reasonCode' => AllowanceReasonCodeUNTDID5189::STANDARD - ]; - } - - /** - * @test - * @testdox BR-CO-23 : Each Invoice line allowance (BG-27) shall contain an Invoice line allowance reason (BT-139) or an Invoice line allowance reason code (BT-140), or both. - * @dataProvider provideBrCo23_error - */ - public function brCo23_error(?string $reason, ?AllowanceReasonCodeUNTDID5189 $reasonCode): void - { - $this->expectException(\Exception::class); - - new InvoiceLineAllowance(14, $reason, $reasonCode); - } - - public static function provideBrCo23_error(): \Generator - { - yield 'Invoice line allowance reason (BT-139) as an empty string' => [ - 'reason' => '', - 'reasonCode' => null - ]; - yield 'Invoice line allowance reason (BT-139) and Invoice line allowance reason code (BT-140) are null' => [ - 'reason' => null, - 'reasonCode' => null - ]; - } - - /** - * @test - * @testdox BR-CO-24 : Each Invoice line charge (BG-28) shall contain an Invoice line charge reason (BT-144) or an Invoice line charge reason code (BT-145), or both. - * @dataProvider provideBrCo24_success - */ - public function brCo24_success(?string $reason, ?ChargeReasonCode $reasonCode): void - { - $invoiceLineCharge = new InvoiceLineCharge(10, $reason, $reasonCode); - - $this->assertInstanceOf(InvoiceLineCharge::class, $invoiceLineCharge); - $this->assertEquals($reason, $invoiceLineCharge->getReason()); - $this->assertEquals($reasonCode, $invoiceLineCharge->getReasonCode()); - } - - public static function provideBrCo24_success(): \Generator - { - yield 'Invoice line charge reason (BT-144) is present' => [ - 'reason' => 'Reason', - 'reasonCode' => null - ]; - yield 'Invoice line charge reason code (BT-145) is present' => [ - 'reason' => null, - 'reasonCode' => ChargeReasonCode::ADVERTISING - ]; - yield 'Invoice line charge reason (BT-144) and Invoice line charge reason code (BT-145) are present' => [ - 'reason' => 'Reason', - 'reasonCode' => ChargeReasonCode::ADVERTISING - ]; - } - - /** - * @test - * @testdox BR-CO-24 : Each Invoice line charge (BG-28) shall contain an Invoice line charge reason (BT-144) or an Invoice line charge reason code (BT-145), or both. - * @dataProvider provideBrCo24_error - */ - public function brCo24_error(?string $reason, ?ChargeReasonCode $reasonCode): void - { - $this->expectException(\Exception::class); - - new InvoiceLineCharge(10, $reason, $reasonCode); - } - - public static function provideBrCo24_error(): \Generator - { - yield 'Invoice line charge reason (BT-144) as an empty string' => [ - 'reason' => '', - 'reasonCode' => null - ]; - yield 'Invoice line charge reason (BT-144) and Invoice line charge reason code (BT-145) are null' => [ - 'reason' => null, - 'reasonCode' => null - ]; - } - - /** - * @test - * @testdox BR-CO-25 : In case the Amount due for payment (BT-115) is positive, either the Payment due date (BT-9) or the Payment terms (BT-20) shall be present. - * @dataProvider provideBrCo25_success - */ - public function brCo25_success(float $amountDueForPayment, ?\DateTimeInterface $paymentDueDate, ?string $paymentTerms): void - { - $invoice = (new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 100, - 100, - 120, - $amountDueForPayment, - invoiceTotalVatAmount: 20 - ), - [new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20.00)], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - )], - null, - null, - $paymentDueDate, - $paymentTerms, - [], - [] - )); - - if ($invoice->getDocumentTotals()->getAmountDueForPayment()->getValueRounded() > 0) { - $this->assertTrue($paymentDueDate || $paymentTerms); - } else { - $this->assertTrue(true); - } - } - - public static function provideBrCo25_success(): \Generator - { - yield 'Amount due for payment (BT-115) is positive and the Payment due date (BT-9) is present' => [ - 'amountDueForPayment' => 120, - 'paymentDueDate' => new \DateTimeImmutable('2021-01-02'), - 'paymentTerms' => null - ]; - - yield 'Amount due for payment (BT-115) is positive and the Payment terms (BT-20) is present' => [ - 'amountDueForPayment' => 120, - 'paymentDueDate' => null, - 'paymentTerms' => '30 JOURS NETS' - ]; - - yield 'Amount due for payment (BT-115) is positive, the Payment due date (BT-9) and the Payment terms (BT-20) are present' => [ - 'amountDueForPayment' => 120, - 'paymentDueDate' => new \DateTimeImmutable('2021-01-02'), - 'paymentTerms' => '30 JOURS NETS' - ]; - } - - /** - * @test - * @testdox BR-CO-25 : In case the Amount due for payment (BT-115) is positive, either the Payment due date (BT-9) or the Payment terms (BT-20) shall be present. - * @dataProvider provideBrCo25_error - */ - public function brCo25_error(float $amountDueForPayment, ?\DateTimeInterface $paymentDueDate, ?string $paymentTerms): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals(0, 0, 0, $amountDueForPayment), - [new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20.00)], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - )], - null, - null, - $paymentDueDate, - $paymentTerms, - [], - [] - ); - } - - public static function provideBrCo25_error(): \Generator - { - yield 'Amount due for payment (BT-115) is positive, the Payment due date (BT-9) and the Payment terms (BT-20) are not present' => [ - 'amountDueForPayment' => 12.2, - 'paymentDueDate' => null, - 'paymentTerms' => null - ]; - } - - /** - * @test - * @testdox BR-CO-26 : In order for the buyer to automatically identify a supplier, the Seller identifier (BT-29), the Seller legal registration identifier (BT-30) and/or the Seller VAT identifier (BT-31) shall be present. - * @dataProvider provideBrCo26_success - * @param array $identifiers - */ - public function brCo26_success( - array $identifiers, - ?LegalRegistrationIdentifier $legalRegistrationIdentifier, - ?VatIdentifier $vatIdentifier - ): void - { - $invoice = (new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - $identifiers, - $legalRegistrationIdentifier, - $vatIdentifier - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 100, - 100, - 120, - 120, - invoiceTotalVatAmount: 20 - ), - [new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20.00)], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - )], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - sellerTaxRepresentativeParty: new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - )); - - $seller = $invoice->getSeller(); - $this->assertTrue(!empty($seller->getIdentifiers()) || null !== $seller->getLegalRegistrationIdentifier() || null !== $seller->getVatIdentifier()); - } - - public static function provideBrCo26_success(): \Generator - { - yield 'Seller identifier (BT-29)' => [ - 'identifiers' => [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - 'legalRegistrationIdentifier' => null, - 'vatIdentifier' => null - ]; - yield 'Seller legal registration identifier (BT-30)' => [ - 'identifiers' => [], - 'legalRegistrationIdentifier' => new LegalRegistrationIdentifier('100000009', InternationalCodeDesignator::SYSTEM_INFORMATION_ET_REPERTOIRE_DES_ENTREPRISE_ET_DES_ETABLISSEMENTS_SIRENE), - 'vatIdentifier' => null - ]; - yield 'Seller VAT identifier (BT-31)' => [ - 'identifiers' => [], - 'legalRegistrationIdentifier' => null, - 'vatIdentifier' => new VatIdentifier('FR88100000009') - ]; - yield 'Seller identifier (BT-29) and Seller legal registration identifier (BT-30)' => [ - 'identifiers' => [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - 'legalRegistrationIdentifier' => new LegalRegistrationIdentifier('100000009', InternationalCodeDesignator::SYSTEM_INFORMATION_ET_REPERTOIRE_DES_ENTREPRISE_ET_DES_ETABLISSEMENTS_SIRENE), - 'vatIdentifier' => null - ]; - yield 'Seller identifier (BT-29) and Seller VAT identifier (BT-31)' => [ - 'identifiers' => [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - 'legalRegistrationIdentifier' => null, - 'vatIdentifier' => new VatIdentifier('FR88100000009') - ]; - yield 'Seller legal registration identifier (BT-30) and Seller VAT identifier (BT-31)' => [ - 'identifiers' => [], - 'legalRegistrationIdentifier' => new LegalRegistrationIdentifier('100000009', InternationalCodeDesignator::SYSTEM_INFORMATION_ET_REPERTOIRE_DES_ENTREPRISE_ET_DES_ETABLISSEMENTS_SIRENE), - 'vatIdentifier' => new VatIdentifier('FR88100000009') - ]; - yield 'Seller identifier (BT-29) and Seller legal registration identifier (BT-30) and Seller VAT identifier (BT-31)' => [ - 'identifiers' => [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - 'legalRegistrationIdentifier' => new LegalRegistrationIdentifier('100000009', InternationalCodeDesignator::SYSTEM_INFORMATION_ET_REPERTOIRE_DES_ENTREPRISE_ET_DES_ETABLISSEMENTS_SIRENE), - 'vatIdentifier' => new VatIdentifier('FR88100000009') - ]; - } - - /** - * @test - * @testdox BR-CO-26 : In order for the buyer to automatically identify a supplier, the Seller identifier (BT-29), the Seller legal registration identifier (BT-30) and/or the Seller VAT identifier (BT-31) shall be present. - * @dataProvider provideBrCo26_error - * @param array $identifiers - */ - public function brCo26_error( - array $identifiers, - ?LegalRegistrationIdentifier $legalRegistrationIdentifier, - ?VatIdentifier $vatIdentifier - ): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - $identifiers, - $legalRegistrationIdentifier, - $vatIdentifier - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals(0, 0, 0, 0), - [new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20.00)], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - )], - null, - null, - null, - null, - [], - [] - ); - } - - public static function provideBrCo26_error(): \Generator - { - yield 'No field are filled in' => [ - 'identifiers' => [], - 'legalRegistrationIdentifier' => null, - 'vatIdentifier' => null - ]; - } -} diff --git a/tests/BusinessRulesIntegrityConstraintsTest.php b/tests/BusinessRulesIntegrityConstraintsTest.php deleted file mode 100644 index fa224ee..0000000 --- a/tests/BusinessRulesIntegrityConstraintsTest.php +++ /dev/null @@ -1,1475 +0,0 @@ -invoice = (new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 100, - 100, - 120, - 120, - invoiceTotalVatAmount: 20 - ), - [new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20.00)], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::STANDARD_RATE, 20.00), - new ItemInformation("A thing"), - )], - null, - null, - new \DateTimeImmutable(), - null, - [], - [] - )) - ->setBuyerReference("SERVEXEC") - ->addIncludedNote( - new InvoiceNote("Lorem Ipsum"), - new InvoiceNote("Lorem Ipsum"), - ); - } - - - /** - * @test - * @testdox BR-1 : An invoice shall have a specification identifier - */ - public function br1MandatorySpecificationIdentifier(): void - { - $specificationIdentifier = $this->invoice->getProcessControl()->getSpecificationIdentifier(); - - $this->assertInstanceOf(SpecificationIdentifier::class, $specificationIdentifier); - $this->assertSame($specificationIdentifier->value, SpecificationIdentifier::BASIC); - } - - /** - * @test - * @testdox BR-2 : An invoice shall have an invoice number - */ - public function br2MandatoryInvoiceNumber(): void - { - $invoiceNumber = $this->invoice->getNumber(); - - $this->assertInstanceOf(InvoiceIdentifier::class, $invoiceNumber); - $this->assertSame($invoiceNumber->value, '34'); - } - - /** - * @test - * @testdox BR-3 : An invoice shall have an invoice issue date - */ - public function br3MandatoryIssueDate(): void - { - $this->assertInstanceOf(\DateTimeInterface::class, $this->invoice->getIssueDate()); - } - - /** - * @test - * @testdox BR-4 : An invoice shall have an invoice type code - */ - public function br4MandatoryTypeCode(): void - { - $this->assertInstanceOf(InvoiceTypeCode::class, $this->invoice->getTypeCode()); - $this->assertSame(InvoiceTypeCode::COMMERCIAL_INVOICE, $this->invoice->getTypeCode()); - } - - /** - * @test - * @testdox BR-5 : An invoice shall have an invoice currency code - */ - public function br5MandatoryCurrencyCode(): void - { - $this->assertInstanceOf(CurrencyCode::class, $this->invoice->getCurrencyCode()); - $this->assertSame(CurrencyCode::EURO, $this->invoice->getCurrencyCode()); - } - - /** - * @test - * @testdox BR-6 : An invoice shall contain the seller name - */ - public function br6MandatorySellerName(): void - { - $this->assertSame('John Doe', $this->invoice->getSeller()->getName()); - } - - /** - * @test - * @testdox BR-7 : An invoice shall contain the buyer name - */ - public function br7MandatoryBuyerName(): void - { - $this->assertSame('Richard Roe', $this->invoice->getBuyer()->getName()); - } - - /** - * @test - * @testdox BR-8 : An invoice shall contain the seller postal address - */ - public function br8MandatorySellerPostalAddress(): void - { - $this->assertInstanceOf(SellerPostalAddress::class, $this->invoice->getSeller()->getAddress()); - } - - /** - * @test - * @testdox BR-9 : The seller postal address shall contain a seller country code - */ - public function br9MandatorySellerCountryCode(): void - { - $sellerPostalAddress = new SellerPostalAddress(CountryAlpha2Code::FRANCE); - - $this->assertInstanceOf(CountryAlpha2Code::class, $sellerPostalAddress->getCountryCode()); - $this->assertSame(CountryAlpha2Code::FRANCE, $sellerPostalAddress->getCountryCode()); - } - - /** - * @test - * @testdox BR-10 : An invoice shall contain the buyer postal address - */ - public function br10MandatoryBuyerPostalAddress(): void - { - $this->assertInstanceOf(BuyerPostalAddress::class, $this->invoice->getBuyer()->getAddress()); - } - - /** - * @test - * @testdox BR-11 : The buyer postal address shall contain a buyer country code - */ - public function br11MandatoryBuyerCountryCode(): void - { - $buyerPostalAddress = new BuyerPostalAddress(CountryAlpha2Code::FRANCE); - - $this->assertInstanceOf(CountryAlpha2Code::class, $buyerPostalAddress->getCountryCode()); - $this->assertSame(CountryAlpha2Code::FRANCE, $buyerPostalAddress->getCountryCode()); - } - - /** - * @test - * @testdox BR-12 : An invoice shall have the sum of invoice line net amount - */ - public function br12MandatoryInvoiceLineNetAmount(): void - { - $this->assertIsFloat($this->invoice->getDocumentTotals()->getSumOfInvoiceLineNetAmount()->getValueRounded()); - $this->assertEquals(100, $this->invoice->getDocumentTotals()->getSumOfInvoiceLineNetAmount()->getValueRounded()); - } - - /** - * @test - * @testdox BR-13 : An invoice shall have the invoice total amount without VAT - */ - public function br13MandatoryTotalAmountWithoutVat(): void - { - $this->assertIsFloat($this->invoice->getDocumentTotals()->getInvoiceTotalAmountWithoutVat()->getValueRounded()); - $this->assertEquals(100, $this->invoice->getDocumentTotals()->getInvoiceTotalAmountWithoutVat()->getValueRounded()); - } - - /** - * @test - * @testdox BR-14 : An invoice shall have the invoice total amount with VAT - */ - public function br14MandatoryTotalAmountWithVat(): void - { - $this->assertIsFloat($this->invoice->getDocumentTotals()->getInvoiceTotalAmountWithVat()->getValueRounded()); - $this->assertEquals(120, $this->invoice->getDocumentTotals()->getInvoiceTotalAmountWithVat()->getValueRounded()); - } - - /** - * @test - * @testdox BR-15 : An invoice shall have the amount due for payment - */ - public function br15MandatoryAmountDueForPayment(): void - { - $this->assertEquals(120, $this->invoice->getDocumentTotals()->getAmountDueForPayment()->getValueRounded()); - } - - /** - * @test - * @testdox BR-16 [case without lines] : An invoice shall have at least one invoice line - */ - public function br16CaseWithoutLines(): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::MINIMUM)), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals(0, 0, 0, 0), - [new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20.00)], - [], - null, - null, - null, - null, - [], - [] - ); - } - - /** - * @test - * @testdox BR-16 [case with lines] : An invoice shall have at least one invoice line - * @dataProvider provideBR16InvoiceLines - * @param array $lines - */ - public function br16CaseWithLines(DocumentTotals $documentTotals, array $lines): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::MINIMUM)), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotals, - [new VatBreakdown(10, 2, VatCategory::STANDARD_RATE, 20.00)], - $lines, - null, - null, - new \DateTimeImmutable(), - null, - [], - [] - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - $this->assertTrue(count($invoice->getInvoiceLines()) > 0); - - foreach ($invoice->getInvoiceLines() as $line) { - $this->assertInstanceOf(InvoiceLine::class, $line); - } - } - - /** - * @return array|DocumentTotals>> - */ - public static function provideBR16InvoiceLines(): array - { - return [ - 'single line' => [ - 'documentTotals' => - new DocumentTotals( - 10, - 10, - 12, - 12, - invoiceTotalVatAmount: 2 - ), - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier('value'), - 1, - UnitOfMeasurement::CENTILITRE_REC20, - 10, - new PriceDetails(10), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation('item') - ) - ] - ], - 'multiple lines' => [ - 'documentTotals' => - new DocumentTotals( - 10, - 10, - 12, - 12, - invoiceTotalVatAmount: 2 - ), - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier('value'), - 1, - UnitOfMeasurement::CENTILITRE_REC20, - 5, - new PriceDetails(10), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation('item') - ), - new InvoiceLine( - new InvoiceLineIdentifier('value2'), - 1, - UnitOfMeasurement::CENTILITRE_REC20, - 5, - new PriceDetails(10), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation('item2') - ) - ] - ] - ]; - } - - /** - * @test - * @testdox BR-17 : The payee name shall be provided in the invoice if the payee is different from the seller - */ - public function br17MandatoryPayeeNameInPayee(): void - { - $this->invoice->setPayee(new Payee('Jane Doe')); - - $this->assertInstanceOf(Payee::class, $this->invoice->getPayee()); - $this->assertSame('Jane Doe', $this->invoice->getPayee()->getName()); - } - - /** - * @test - * @testdox BR-18 : The seller tax representative name shall be provided in the invoice if the seller has a seller tax representative party - */ - public function br18MandatorySellerTaxRepresentativeName(): void - { - $sellerTaxRepresentativeParty = new SellerTaxRepresentativeParty( - 'Freddie Hines', - new VatIdentifier('FR'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ); - - $this->assertSame('Freddie Hines', $sellerTaxRepresentativeParty->getName()); - } - - /** - * @test - * @testdox BR-19 : The seller tax representative postal address shall be provided in the invoice if the seller has a seller tax representative party - */ - public function br19MandatorySellerTaxRepresentativePostalAddress(): void - { - $sellerTaxRepresentativeParty = new SellerTaxRepresentativeParty( - 'Freddie Hines', - new VatIdentifier('FR'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ); - - $this->assertInstanceOf( - SellerTaxRepresentativePostalAddress::class, - $sellerTaxRepresentativeParty->getAddress() - ); - } - - /** - * @test - * @testdox BR-20 : The seller tax representative postal address shall contain a tax representative country code if the seller has a seller tax representative party - */ - public function br20MandatoryCountryCodeInSellerTaxRepresentativePostalAddress(): void - { - $address = new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE); - - $this->assertInstanceOf( - CountryAlpha2Code::class, - $address->getCountryCode() - ); - - $this->assertSame( - CountryAlpha2Code::FRANCE, - $address->getCountryCode() - ); - } - - /** - * @test - * @testdox BR-21 : Each invoice line shall have an invoice line identifier - */ - public function br21MandatoryInvoiceLineIdentifier(): void - { - $invoiceLine = new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ); - - $this->assertInstanceOf(InvoiceLineIdentifier::class, $invoiceLine->getIdentifier()); - $this->assertSame('1', $invoiceLine->getIdentifier()->value); - } - - /** - * @test - * @testdox BR-22 : Each invoice line shall have an invoiced quantity - */ - public function br22MandatoryInvoicedQuantity(): void - { - $invoiceLine = new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ); - - $this->assertIsFloat($invoiceLine->getInvoicedQuantity()->getValueRounded()); - $this->assertEquals(1, $invoiceLine->getInvoicedQuantity()->getValueRounded()); - } - - /** - * @test - * @testdox BR-23 : An invoice line shall have an invoiced quantity unit of measure code - */ - public function br23MandatoryInvoicedQuantityUnitOfMeasureCode(): void - { - $invoiceLine = new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ); - - $this->assertInstanceOf(UnitOfMeasurement::class, $invoiceLine->getInvoicedQuantityUnitOfMeasureCode()); - } - - /** - * @test - * @testdox BR-24 : Each invoice line shall have an invoice line net amount - */ - public function br24MandatoryInvoiceLineNetAmount(): void - { - $invoiceLine = new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ); - - $this->assertEquals(0, $invoiceLine->getNetAmount()->getValueRounded()); - } - - /** - * @test - * @testdox BR-25 : Each invoice line shall contain the item name - */ - public function br25MandatoryItemName(): void - { - $invoiceLine = new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ); - - $this->assertSame('A thing', $invoiceLine->getItemInformation()->getName()); - } - - /** - * @test - * @testdox BR-26 : Each invoice line shall contain the item net price - */ - public function br26MandatoryItemNetPrice(): void - { - $invoiceLine = new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ); - - $this->assertEquals(12, $invoiceLine->getPriceDetails()->getItemNetPrice()->getValueRounded()); - } - - /** - * @test - * @testdox BR-27 [case with negative price] : The item net price shall not be negative - */ - public function br27WithNegativePrice(): void - { - $this->expectException(\Exception::class); - - new PriceDetails(-1); - } - - /** - * @test - * @testdox BR-27 [case with positive price] : The item net price shall not be negative - * @dataProvider provideBR27NetPrices - */ - public function br27WithPositivePrice(float $netPrice): void - { - $priceDetails = new PriceDetails($netPrice); - - $this->assertSame($netPrice, $priceDetails->getItemNetPrice()->getValueRounded()); - } - - /** - * @return array> - */ - public static function provideBR27NetPrices(): array - { - return [ - 'strictly positive' => [1.0], - 'zero' => [0.0] - ]; - } - - /** - * @test - * @testdox BR-28 [case with negative price] : The item gross price shall not be negative - */ - public function br28WithNegativePrice(): void - { - $priceDetails = new PriceDetails(1); - - $this->expectException(\Exception::class); - - $priceDetails->setItemGrossPrice(-1); - } - - /** - * @test - * @testdox BR-28 [case with positive price] : The item gross price shall not be negative - * @dataProvider provideBR28GrossPrices - */ - public function br28WithPositivePrice(float $price): void - { - $priceDetails = new PriceDetails(1); - $priceDetails->setItemGrossPrice($price); - - $this->assertSame($price, $priceDetails->getItemGrossPrice()?->getValueRounded()); - } - - /** - * @return array> - */ - public static function provideBR28GrossPrices(): array - { - return [ - 'strictly positive' => [1.0], - 'zero' => [0.0] - ]; - } - - /** - * @test - * @testdox BR-29 [case with start date later than end date] : If both invoicing period start date and invoicing period end date are given then the invoicing period end date shall be later or equal to the invoicing period start date - */ - public function br29CaseWithStartDateLaterThanEndDate(): void - { - $this->expectException(\Exception::class); - - new InvoicingPeriod(new \DateTimeImmutable('2021-01-02'), new \DateTimeImmutable('2021-01-01')); - } - - - /** - * @test - * @testdox BR-29 [case with start date earlier or equal to end date]: If both invoicing period start date and invoicing period end date are given then the invoicing period end date shall be later or equal to the invoicing period start date - * @dataProvider provideBR29Dates - */ - public function br29CaseWithStartDateEarlierOrEqualToEndDate(\DateTimeImmutable $startDate, \DateTimeImmutable $endDate): void - { - $period = new InvoicingPeriod($startDate, $endDate); - - $this->assertEquals($startDate, $period->getStartDate()); - $this->assertEquals($endDate, $period->getEndDate()); - } - - /** - * @return array> - */ - public static function provideBR29Dates(): array - { - return [ - 'start earlier than end' => [new \DateTimeImmutable('2021-01-01'), new \DateTimeImmutable('2021-01-02')], - 'start equal to end' => [new \DateTimeImmutable('2021-01-01'), new \DateTimeImmutable('2021-01-01')] - ]; - } - - /** - * @test BR-30 - * @testdox BR-30 [case with start date later than end date] : If both invoice line period start date and invoice line period end date are given then the invoice line period end date shall be later or equal to the invoice line period start date - */ - public function br30CaseWithStartDateLaterThanEndDate(): void - { - $this->expectException(\Exception::class); - - new InvoiceLinePeriod(new \DateTimeImmutable('2021-01-02'), new \DateTimeImmutable('2021-01-01')); - } - - - /** - * @test BR-30 - * @testdox BR-30 [case with start date earlier or equal to end date] : If both invoice line period start date and invoice line period end date are given then the invoice line period end date shall be later or equal to the invoice line period start date - * @dataProvider provideBR30Dates - */ - public function br30CaseWithStartDateEarlierOrEqualToEndDate(\DateTimeImmutable $startDate, \DateTimeImmutable $endDate): void - { - $period = new InvoiceLinePeriod($startDate, $endDate); - - $this->assertEquals($startDate, $period->getStartDate()); - $this->assertEquals($endDate, $period->getEndDate()); - } - - /** - * @return array> - */ - public static function provideBR30Dates(): array - { - return [ - 'start earlier than end' => [new \DateTimeImmutable('2021-01-01'), new \DateTimeImmutable('2021-01-02')], - 'start equal to end' => [new \DateTimeImmutable('2021-01-01'), new \DateTimeImmutable('2021-01-01')] - ]; - } - - /** - * @test - * @testdox BR-31 : Each document level allowance shall have a document level allowance amount - */ - public function br31MandatoryDocumentLevelAllowanceAmount(): void - { - $allowance = new DocumentLevelAllowance(1, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20); - - $this->assertEquals(1, $allowance->getAmount()->getValueRounded()); - } - - /** - * @test - * @testdox BR-32 : Each document level allowance shall have a document level allowance vat category code - */ - public function br32MandatoryDocumentLevelAllowanceVatCategoryCode(): void - { - $allowance = new DocumentLevelAllowance(1, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20); - - $this->assertSame(VatCategory::STANDARD_RATE, $allowance->getVatCategoryCode()); - } - - /** - * @test - * @testdox BR-33 [case without reason or code] : Each document level allowance shall have a document level allowance reason or a document level allowance reason code - */ - public function br33CaseWithoutReasonOrCode(): void - { - $this->expectException(\Exception::class); - - new DocumentLevelAllowance(1, VatCategory::STANDARD_RATE, vatRate: 20); - } - - /** - * @test - * @testdox BR-33 [cases with at least a reason or code] : Each document level allowance shall have a document level allowance reason or a document level allowance reason code - * @dataProvider provideBR33ReasonAndCodeCombinations - */ - public function br33CasesWithReasonAndCodeCombinations(?string $reason, ?AllowanceReasonCodeUNTDID5189 $reasonCode): void - { - $allowance = new DocumentLevelAllowance(1, VatCategory::STANDARD_RATE, $reason, $reasonCode, vatRate: 20); - - $this->assertSame($reason, $allowance->getReason()); - $this->assertSame($reasonCode, $allowance->getReasonCode()); - } - - /** - * @return array - */ - public static function provideBR33ReasonAndCodeCombinations(): array - { - return [ - 'with reason, without code' => [ - 'reason' => 'Hoobastank', - 'reasonCode' => null - ], - 'with reason, with code' => [ - 'reason' => 'Hoobastank', - 'reasonCode' => AllowanceReasonCodeUNTDID5189::STANDARD - ], - 'without reason, with code' => [ - 'reason' => null, - 'reasonCode' => AllowanceReasonCodeUNTDID5189::STANDARD - ], - ]; - } - - /** - * @test - * @testdox BR-36 : Each document level charge shall have a document level charge amount - */ - public function br36MandatoryDocumentLevelChargeAmount(): void - { - $charge = new DocumentLevelCharge(1, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20); - - $this->assertEquals(1, $charge->getAmount()->getValueRounded()); - } - - /** - * @test - * @testdox BR-37 : Each document level charge shall have a document level charge vat category code - */ - public function br37MandatoryDocumentLevelChargeVatCategoryCode(): void - { - $charge = new DocumentLevelCharge(1, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20); - - $this->assertSame(VatCategory::STANDARD_RATE, $charge->getVatCategoryCode()); - } - - /** - * @test - * @testdox BR-38 [case without reason or code] : Each document level charge shall have a document level charge reason or a document level charge reason code - */ - public function br38CaseWithoutReasonOrCode(): void - { - $this->expectException(\Exception::class); - - new DocumentLevelCharge(1, VatCategory::STANDARD_RATE, vatRate: 20); - } - - /** - * @test - * @testdox BR-38 [cases with at least a reason or code] : Each document level charge shall have a document level charge reason or a document level charge reason code - * @dataProvider provideBR38ReasonAndCodeCombinations - */ - public function br38CasesWithReasonAndCodeCombinations(?string $reason, ?ChargeReasonCode $reasonCode): void - { - $charge = new DocumentLevelCharge(1, VatCategory::STANDARD_RATE, $reason, $reasonCode, vatRate: 20); - - $this->assertSame($reason, $charge->getReason()); - $this->assertSame($reasonCode, $charge->getReasonCode()); - } - - /** - * @return array - */ - public static function provideBR38ReasonAndCodeCombinations(): array - { - return [ - 'with reason, without code' => [ - 'reason' => 'Hoobastank', - 'reasonCode' => null - ], - 'with reason, with code' => [ - 'reason' => 'Hoobastank', - 'reasonCode' => ChargeReasonCode::TESTING - ], - 'without reason, with code' => [ - 'reason' => null, - 'reasonCode' => ChargeReasonCode::TESTING - ], - ]; - } - - /** - * @test - * @testdox BR-41 : Each invoice line allowance shall have an invoice line allowance amount - */ - public function br41MandatoryInvoiceLineAllowanceAmount(): void - { - $allowance = new InvoiceLineAllowance(1, 'Hoobastank'); - - $this->assertEquals(1, $allowance->getAmount()->getValueRounded()); - } - - /** - * @test - * @testdox BR-42 [case without reason or code] : Each invoice line allowance shall have an invoice line allowance reason or an invoice line allowance reason code - */ - public function br42CaseWithoutReasonOrCode(): void - { - $this->expectException(\Exception::class); - - new InvoiceLineAllowance(1); - } - - - /** - * @test - * @testdox BR-42 [cases with at least a reason or code] : Each invoice line allowance shall have an invoice line allowance reason or an invoice line allowance reason code - * @dataProvider provideBR42ReasonAndCodeCombinations - */ - public function br42CasesWithReasonAndCodeCombinations(?string $reason, ?AllowanceReasonCodeUNTDID5189 $reasonCode): void - { - $allowance = new InvoiceLineAllowance(1, $reason, $reasonCode); - - $this->assertSame($reason, $allowance->getReason()); - $this->assertSame($reasonCode, $allowance->getReasonCode()); - } - - /** - * @return array - */ - public static function provideBR42ReasonAndCodeCombinations(): array - { - return [ - 'with reason, without code' => [ - 'reason' => 'Hoobastank', - 'reasonCode' => null - ], - 'with reason, with code' => [ - 'reason' => 'Hoobastank', - 'reasonCode' => AllowanceReasonCodeUNTDID5189::STANDARD - ], - 'without reason, with code' => [ - 'reason' => null, - 'reasonCode' => AllowanceReasonCodeUNTDID5189::STANDARD - ], - ]; - } - - /** - * @test - * @testdox BR-43 : Each invoice line charge shall have an invoice line charge amount - */ - public function br43MandatoryInvoiceLineChargeAmount(): void - { - $charge = new InvoiceLineCharge(1, 'Hoobastank'); - - $this->assertEquals(1, $charge->getAmount()->getValueRounded()); - } - - /** - * @test - * @testdox BR-44 [case without reason or code] : Each invoice line charge shall have an invoice line charge reason or an invoice line charge reason code - */ - public function br44CaseWithoutReasonOrCode(): void - { - $this->expectException(\Exception::class); - - new InvoiceLineCharge(1); - } - - /** - * @test - * @testdox BR-44 [case with at least a reason or code] : Each invoice line charge shall have an invoice line charge reason or an invoice line charge reason code - * @dataProvider provideBR44ReasonAndCodeCombinations - */ - public function br44CasesWithReasonAndCodeCombinations(?string $reason, ?ChargeReasonCode $reasonCode): void - { - $charge = new InvoiceLineCharge(1, $reason, $reasonCode); - - $this->assertSame($reason, $charge->getReason()); - $this->assertSame($reasonCode, $charge->getReasonCode()); - } - - /** - * @return array - */ - public static function provideBR44ReasonAndCodeCombinations(): array - { - return [ - 'with reason, without code' => [ - 'reason' => 'Hoobastank', - 'reasonCode' => null - ], - 'with reason, with code' => [ - 'reason' => 'Hoobastank', - 'reasonCode' => ChargeReasonCode::TESTING - ], - 'without reason, with code' => [ - 'reason' => null, - 'reasonCode' => ChargeReasonCode::TESTING - ], - ]; - } - - /** - * @test - * @testdox BR-45 : Each vat breakdown shall have a vat category taxable amount - */ - public function br45MandatoryVatCategoryTaxableAmount(): void - { - $vatBreakdown = new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20.00); - - $this->assertEquals(100, $vatBreakdown->getVatCategoryTaxableAmount()->getValueRounded()); - } - - /** - * @test - * @testdox BR-46 : Each vat breakdown shall have a vat category tax amount - */ - public function br46MandatoryVatCategoryTaxAmount(): void - { - $vatBreakdown = new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20.00); - - $this->assertEquals(20, $vatBreakdown->getVatCategoryTaxAmount()->getValueRounded()); - } - - /** - * @test - * @testdox BR-47 : Each vat breakdown shall be defined through a vat category code - */ - public function br47MandatoryVatCategoryCode(): void - { - $vatBreakdown = new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20.00); - - $this->assertInstanceOf(VatCategory::class, $vatBreakdown->getVatCategoryCode()); - $this->assertSame(VatCategory::STANDARD_RATE, $vatBreakdown->getVatCategoryCode()); - } - - /** - * @test - * @testdox BR-48 [case with coherent vat category & rate] : Each vat breakdown shall have a vat category rate except if the invoice is not subject to vat - * @dataProvider provideBR48SuccessfulCases - */ - public function br48SuccessfulCases( - float $vatCategoryTaxableAmount, - float $vatCategoryTaxAmount, - VatCategory $vatCategory, - ?float $vatRate, - ?string $vatExemptionReasonText = null, - ): void { - $vatBreakdown = new VatBreakdown( - $vatCategoryTaxableAmount, - $vatCategoryTaxAmount, - $vatCategory, - $vatRate, - vatExemptionReasonText: $vatExemptionReasonText - ); - - $this->assertSame($vatCategoryTaxableAmount, $vatBreakdown->getVatCategoryTaxableAmount()->getValueRounded()); - $this->assertSame($vatCategoryTaxAmount, $vatBreakdown->getVatCategoryTaxAmount()->getValueRounded()); - $this->assertSame($vatCategory, $vatBreakdown->getVatCategoryCode()); - $this->assertSame($vatRate, $vatBreakdown->getVatCategoryRate()?->getValueRounded()); - $this->assertSame($vatExemptionReasonText, $vatBreakdown->getVatExemptionReasonText()); - } - - /** - * @return array - */ - public static function provideBR48SuccessfulCases(): array - { - return [ - 'subject to vat with rate' => [ - 'vatCategoryTaxableAmount' => 100.00, - 'vatCategoryTaxAmount' => 20.00, - 'vatCategory' => VatCategory::STANDARD_RATE, - 'vatRate' => 20.00, - ], - 'not subject to vat without rate' => [ - 'vatCategoryTaxableAmount' => 0.00, - 'vatCategoryTaxAmount' => 0.00, - 'vatCategory' => VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, - 'vatRate' => null, - 'vatExemptionReasonText' => 'Hoobastank', - ], - ]; - } - - /** - * @test - * @testdox BR-48 [cases with non-coherent vat category & rate] : Each vat breakdown shall have a vat category rate except if the invoice is not subject to vat - * @dataProvider provideBR48FailingCases - */ - public function br48FailingCases(VatCategory $vatCategory, ?float $vatRate): void - { - $this->expectException(\Exception::class); - - new VatBreakdown(100, 20, $vatCategory, $vatRate); - } - - /** - * @return array - */ - public static function provideBR48FailingCases(): array - { - return [ - 'subject to vat without rate' => [ - 'vatCategory' => VatCategory::STANDARD_RATE, - 'vatRate' => null, - ], - 'not subject to vat with rate' => [ - 'vatCategory' => VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, - 'vatRate' => 0.2, - ], - ]; - } - - /** - * @test - * @testdox BR-49 : A payment instruction shall specify the payment means type code - */ - public function br49MandatoryPaymentMeansTypeCode(): void - { - $paymentInstructions = new PaymentInstructions(PaymentMeansCode::DEBIT_TRANSFER); - - $this->assertSame(PaymentMeansCode::DEBIT_TRANSFER, $paymentInstructions->getPaymentMeansTypeCode()); - } - - /** - * @test - * @testdox BR-50 : A payment account identifier shall be present if credit transfer information is provided in the invoice - */ - public function br50MandatoryPaymentAccountIdentifier(): void - { - $creditTransfer = new CreditTransfer(new PaymentAccountIdentifier('123')); - - $this->assertInstanceOf(PaymentAccountIdentifier::class, $creditTransfer->getPaymentAccountIdentifier()); - $this->assertSame('123', $creditTransfer->getPaymentAccountIdentifier()->value); - } - - /** - * @test - * @testdox BR-51 [with valid numbers] : (Only) The last 4 to 6 digits of the payment card primary account number shall be present if payment card information is provided in the invoice - * @dataProvider provideBR51ValidNumbers - */ - public function br51CasesWithValidNumbers(string $validNumber): void - { - $invalidNumbers = [ - '', - 'invalid', - '123', - '1234567', - '123*****1234', - ]; - - $paymentCardInformation = new PaymentCardInformation($validNumber); - - $this->assertSame($validNumber, $paymentCardInformation->getPrimaryAccountNumber()); - } - - /** - * @return array> - */ - public static function provideBR51ValidNumbers(): array - { - return [ - ['1234'], - ['12345'], - ['123456'], - ['****1234'], - ['****12345'], - ['****123456'], - ]; - } - - /** - * @test - * @testdox BR-51 [with invalid numbers] : (Only) The last 4 to 6 digits of the payment card primary account number shall be present if payment card information is provided in the invoice - * @dataProvider provideBR51InvalidNumbers - */ - public function br51CasesWithInvalidNumbers(string $invalidNumber): void - { - $this->expectException(\Exception::class); - - new PaymentCardInformation($invalidNumber); - } - - /** - * @return array> - */ - public static function provideBR51InvalidNumbers(): array - { - return [ - [''], - ['invalid'], - ['123'], - ['1234567'], - ['123*****1234'], - ]; - } - - /** - * @test - * @testdox BR-52 : Each additional supporting document shall contain a supporting document reference - */ - public function br52MandatorySupportingDocumentReference(): void - { - $supportingDocument = new AdditionalSupportingDocument(new SupportingDocumentReference('ref')); - - $this->assertInstanceOf(SupportingDocumentReference::class, $supportingDocument->getReference()); - $this->assertSame('ref', $supportingDocument->getReference()->value); - } - - /** - * @test - * @testdox BR-53 [cases with coherent currency and amount] : If the vat accounting currency code is present then the invoice total vat amount in accounting currency shall be provided - * @dataProvider provideBR53SuccessfulCases - */ - public function br53SuccessfulCases(?CurrencyCode $currencyCode, ?float $vatAmount): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - $currencyCode, - new DocumentTotals( - 100, - 100, - 120, - 120, - $vatAmount, - invoiceTotalVatAmount: 20 - ), - [new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20.00)], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - )], - null, - null, - new \DateTimeImmutable(), - null, - [], - [] - ); - - $this->assertSame($currencyCode, $invoice->getVatAccountingCurrencyCode()); - $this->assertSame($vatAmount, $invoice->getDocumentTotals()->getInvoiceTotalVatAmountInAccountingCurrency()?->getValueRounded()); - } - - /** - * @return array - */ - public static function provideBR53SuccessfulCases(): array - { - return [ - 'case with accounting currency code and with total vat amount in accounting currency' => [ - 'currencyCode' => CurrencyCode::CANADIAN_DOLLAR, - 'vatAmount' => 1.0, - ], - 'case without accounting currency code and without total vat amount in accounting currency' => [ - 'currencyCode' => null, - 'vatAmount' => null, - ], - ]; - } - - /** - * @test - * @testdox BR-53 [cases with non-coherent currency and amount] : If the vat accounting currency code is present then the invoice total vat amount in accounting currency shall be provided - * @dataProvider provideBR53FailingCases - */ - public function br53FailingCases(?CurrencyCode $currencyCode, ?float $vatAmount): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - $currencyCode, - new DocumentTotals(0, 0, 0, 0, $vatAmount), - [new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20.00)], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(12), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - )], - null, - null, - null, - null, - [], - [] - ); - } - - - /** - * @return array - */ - public static function provideBR53FailingCases(): array - { - return [ - 'case with accounting currency code and without total vat amount in accounting currency' => [ - 'currencyCode' => CurrencyCode::CANADIAN_DOLLAR, - 'vatAmount' => null, - ], - 'case without accounting currency code and with total vat amount in accounting currency' => [ - 'currencyCode' => null, - 'vatAmount' => 1.0, - ], - ]; - } - - /** - * @test - * @testdox BR-54 : Each item attribute shall contain an item attribute name and an item attribute value - */ - public function br54MandatoryItemAttributeNameAndValue(): void - { - $itemAttribute = new ItemAttribute('name', 'value'); - - $this->assertSame('name', $itemAttribute->getName()); - $this->assertSame('value', $itemAttribute->getValue()); - } - - /** - * @test - * @testdox BR-55 : Each preceding invoice reference shall contain a preceding invoice reference - */ - public function br55MandatoryPrecedingInvoiceReference(): void - { - $precedingInvoice = new PrecedingInvoice(new PrecedingInvoiceReference('ref')); - - $this->assertInstanceOf(PrecedingInvoiceReference::class, $precedingInvoice->getReference()); - $this->assertSame('ref', $precedingInvoice->getReference()->value); - } - - /** - * @test - * @testdox BR-56 : Each seller tax representative party shall have a seller tax representative vat identifier - */ - public function br56MandatorySellerTaxRepresentativePartyVatIdentifier(): void - { - $sellerTaxRepresentativeParty = new SellerTaxRepresentativeParty( - 'name', - new VatIdentifier('FR'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ); - - $this->assertInstanceOf(VatIdentifier::class, $sellerTaxRepresentativeParty->getVatIdentifier()); - $this->assertSame('FR', $sellerTaxRepresentativeParty->getVatIdentifier()->getValue()); - } - - /** - * @test - * @testdox BR-57 : Each deliver to address shall contain a deliver to country code - */ - public function br57MandatoryDeliverToAddressCountryCode(): void - { - $deliverToAdress = new DeliverToAddress(CountryAlpha2Code::FRANCE); - - $this->assertSame(CountryAlpha2Code::FRANCE, $deliverToAdress->getCountryCode()); - } - - /** - * @test BR-61 - * @testdox BR-61 [cases with coherent code and credit transfers] : If the payment means type code means SEPA credit transfer local credit transfer or non SEPA international credit transfer the payment account identifier shall be present - * @dataProvider provideBR61SuccessfulCases - * - * @param array $creditTransfers - */ - public function br61SuccessfulCases(PaymentMeansCode $code, array $creditTransfers): void - { - $paymentInstructions = new PaymentInstructions( - $code, - $creditTransfers - ); - - $this->assertSame($code, $paymentInstructions->getPaymentMeansTypeCode()); - - foreach ($paymentInstructions->getCreditTransfers() as $creditTransfer) { - $this->assertInstanceOf(PaymentAccountIdentifier::class, $creditTransfer->getPaymentAccountIdentifier()); - } - } - - /** - * @return array}> - */ - public static function provideBR61SuccessfulCases(): array - { - return [ - 'with code credit transfer and with account identifier' => [ - 'code' => PaymentMeansCode::CREDIT_TRANSFER, - 'creditTransfers' => [new CreditTransfer(new PaymentAccountIdentifier('id'))], - ], - 'with code SEPA credit transfer and with account identifier' => [ - 'code' => PaymentMeansCode::SEPA_CREDIT_TRANSFER, - 'creditTransfers' => [new CreditTransfer(new PaymentAccountIdentifier('id'))], - ], - 'with other code and with account identifier' => [ // shall this case throw an exception ? - 'code' => PaymentMeansCode::ACCEPTED_BILL_OF_EXCHANGE, - 'creditTransfers' => [new CreditTransfer(new PaymentAccountIdentifier('id'))], - ], - 'with other code and without account identifier' => [ - 'code' => PaymentMeansCode::ACCEPTED_BILL_OF_EXCHANGE, - 'creditTransfers' => [], - ], - ]; - } - - /** - * @test BR-61 - * @testdox BR-61 [cases with coherent code and credit transfers] : If the payment means type code means SEPA credit transfer local credit transfer or non SEPA international credit transfer the payment account identifier shall be present - * @dataProvider provideBR61FailingCases - * - * @param array $creditTransfers - */ - public function br61FailingCases(PaymentMeansCode $code, array $creditTransfers): void - { - $this->expectException(\Exception::class); - - new PaymentInstructions( - $code, - $creditTransfers - ); - } - - /** - * @return array}> - */ - public static function provideBR61FailingCases(): array - { - return [ - 'with code credit transfer and without account identifier' => [ - 'code' => PaymentMeansCode::CREDIT_TRANSFER, - 'creditTransfers' => [], - ], - 'with code SEPA credit transfer and without account identifier' => [ - 'code' => PaymentMeansCode::SEPA_CREDIT_TRANSFER, - 'creditTransfers' => [], - ], - ]; - } - - /** - * @test - * @testdox BR-62 & BR-63 : The seller and buyer electronic addresses shall have a scheme identifier - */ - public function br62br63MandatoryElectronicAddressIdentifierScheme(): void - { - $electronicAddressIdentifier = new ElectronicAddressIdentifier('value', ElectronicAddressScheme::SIRET_CODE); - - $this->assertSame(ElectronicAddressScheme::SIRET_CODE, $electronicAddressIdentifier->scheme); - } - - /** - * @test - * @testdox BR-64 : The item standard identifier shall have a scheme identifier - */ - public function br64MandatoryStandardItemIdentifierScheme(): void - { - $standardItemIdentifier = new StandardItemIdentifier('value', InternationalCodeDesignator::COMMON_LANGUAGE); - - $this->assertSame(InternationalCodeDesignator::COMMON_LANGUAGE, $standardItemIdentifier->scheme); - } - - /** - * @test - * @testdox BR-65 : The item classification identifier shall have a scheme identifier - */ - public function br65MandatoryItemClassificationIdentifierScheme(): void - { - $itemClassificationIdentifier = new ItemClassificationIdentifier('value', ItemTypeCode::BUYER_ITEM_NUMBER, 'v1'); - - $this->assertSame(ItemTypeCode::BUYER_ITEM_NUMBER, $itemClassificationIdentifier->scheme); - } -} diff --git a/tests/BusinessRulesVatRulesBRAETest.php b/tests/BusinessRulesVatRulesBRAETest.php deleted file mode 100644 index eb4270f..0000000 --- a/tests/BusinessRulesVatRulesBRAETest.php +++ /dev/null @@ -1,1908 +0,0 @@ - $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brAE1_success(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE), new VatIdentifier('FR966666')), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrAE1Success(): \Generator - { - yield 'BR-AE-1 Success #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, 0), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(1000, 200, VatCategory::STANDARD_RATE, 20), - new VatBreakdown(1000, 0, VatCategory::VAT_REVERSE_CHARGE, 0, vatExemptionReasonText: 'Hoobastank') - ], - 'documentTotals' => new DocumentTotals( - 2000, - 2000, - 2200, - 2200, - invoiceTotalVatAmount: 200, - ) - ]; - } - - /** - * @test - * @testdox BR-AE-1 : An Invoice that contains an Invoice line (BG-25), a Document level allowance (BG-20) or a - * Document level charge (BG-21) where the VAT category code (BT-151, BT-95 or BT102) is “Reverse charge” shall - * contain in the VAT breakdown (BG-23) exactly one VAT category code (BT-118) equal with "VAT reverse charge". - * @dataProvider provideBrAE1Error - * @param array $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brAE1_error(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges - ); - } - - public static function provideBrAE1Error(): \Generator - { - yield 'BR-AE-1 Error #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, 0), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(2000, 400, VatCategory::STANDARD_RATE, 20) - ], - 'documentTotals' => new DocumentTotals( - 2000, - 2000, - 2400, - 2400, - invoiceTotalVatAmount: 400, - ) - ]; - } - - /** - * @test - * @testdox BR-AE-2 : An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code - * (BT-151) is “Reverse charge” shall contain the Seller VAT Identifier (BT-31), the Seller Tax registration - * identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63) and the Buyer VAT identifier - * (BT-48) and/or the Buyer legal registration identifier (BT-47). - * @dataProvider provideBrAE2Success - */ - public function brAE2_success(Buyer $buyer, Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - $buyer, - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::VAT_REVERSE_CHARGE, 0, vatExemptionReasonText: 'Hoobastank') - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, 0), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrAE2Success(): \Generator - { - yield 'BR-AE-2 - (Buyer) LegalRegistrationIdentifier and (Seller) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-2 - (Buyer) LegalRegistrationIdentifier and (Seller) TaxRegistrationIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-2 - (Buyer) LegalRegistrationIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-2 - (Buyer) VatIdentifier and (Seller) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645') - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-2 - (Buyer) VatIdentifier and (Seller) TaxRegistrationIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645') - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-2 - (Buyer) VatIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645') - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-2 - (Buyer) LegalRegistrationIdentifier and (Seller) VatIdentifier and (Seller) TaxRegistrationIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-2 - (Buyer) LegalRegistrationIdentifier and (Seller) VatIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-2 - (Buyer) LegalRegistrationIdentifier and (Seller) TaxRegistrationIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-2 - (Buyer) VatIdentifier and (Seller) VatIdentifier and (Seller) TaxRegistrationIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645') - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-2 - (Buyer) VatIdentifier and (Seller) VatIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645') - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-2 - (Buyer) VatIdentifier and (Seller) TaxRegistrationIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645') - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-2 - (Buyer) LegalRegistrationIdentifier and (Seller) VatIdentifier and (Seller) TaxRegistrationIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-2 - (Buyer) VatIdentifier and (Seller) VatIdentifier and (Seller) TaxRegistrationIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645') - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-2 - (Buyer) VatIdentifier and (Buyer) LegalRegistrationIdentifier and (Seller) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645'), - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-2 - (Buyer) VatIdentifier and (Buyer) LegalRegistrationIdentifier and (Seller) TaxRegistrationIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645'), - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-2 - (Buyer) VatIdentifier and (Buyer) LegalRegistrationIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645'), - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-2 - (Buyer) VatIdentifier and (Buyer) LegalRegistrationIdentifier and (Seller) VatIdentifier and (Seller) TaxRegistrationIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645'), - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-2 - (Buyer) VatIdentifier and (Buyer) LegalRegistrationIdentifier and (Seller) VatIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645'), - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-2 - (Buyer) VatIdentifier and (Buyer) LegalRegistrationIdentifier and (Seller) TaxRegistrationIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645'), - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-2 - (Buyer) VatIdentifier and (Buyer) LegalRegistrationIdentifier and (Seller) VatIdentifier and (Seller) TaxRegistrationIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645'), - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-AE-2 : An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code - * (BT-151) is “Reverse charge” shall contain the Seller VAT Identifier (BT-31), the Seller Tax registration - * identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63) and the Buyer VAT identifier - * (BT-48) and/or the Buyer legal registration identifier (BT-47). - * @dataProvider provideBrAE2Error - */ - public function brAE2_error(Buyer $buyer, Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - $buyer, - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::VAT_REVERSE_CHARGE, 0, vatExemptionReasonText: 'Hoobastank') - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, 0), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - } - - public static function provideBrAE2Error(): \Generator - { - yield 'BR-AE-2 - No field' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-2 - Only (Seller) VatIdentifier field' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-2 - Only (Seller) TaxRegistrationIdentifier field' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-2 - Only (TaxRepresentativeParty) VatIdentifier field' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-2 - Only (Buyer) LegalRegistrationIdentifier field' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-2 - Only (Buyer) VatIdentifier field' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR986416485'), - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => null - ]; - } - - /** - * @test - * @testdox BR-AE-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “Reverse charge” shall contain the Seller VAT Identifier (BT-31), the Seller tax - * registration identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63) and the Buyer VAT - * identifier (BT-48) and/or the Buyer legal registration identifier (BT-47). - * @dataProvider provideBrAE3Success - */ - public function brAE3_success(Buyer $buyer, Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - $buyer, - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::VAT_REVERSE_CHARGE, 0, vatExemptionReasonText: 'Hoobastank') - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, 0), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [ - new DocumentLevelAllowance(0, VatCategory::VAT_REVERSE_CHARGE, 'Hoobastank', vatRate: 0), - ], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrAE3Success(): \Generator - { - yield 'BR-AE-3 - (Buyer) LegalRegistrationIdentifier and (Seller) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-3 - (Buyer) LegalRegistrationIdentifier and (Seller) TaxRegistrationIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-3 - (Buyer) LegalRegistrationIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-3 - (Buyer) VatIdentifier and (Seller) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645') - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-3 - (Buyer) VatIdentifier and (Seller) TaxRegistrationIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645') - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-3 - (Buyer) VatIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645') - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-3 - (Buyer) LegalRegistrationIdentifier and (Seller) VatIdentifier and (Seller) TaxRegistrationIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-3 - (Buyer) LegalRegistrationIdentifier and (Seller) VatIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-3 - (Buyer) LegalRegistrationIdentifier and (Seller) TaxRegistrationIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-3 - (Buyer) VatIdentifier and (Seller) VatIdentifier and (Seller) TaxRegistrationIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645') - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-3 - (Buyer) VatIdentifier and (Seller) VatIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645') - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-3 - (Buyer) VatIdentifier and (Seller) TaxRegistrationIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645') - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-3 - (Buyer) LegalRegistrationIdentifier and (Seller) VatIdentifier and (Seller) TaxRegistrationIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null, - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-3 - (Buyer) VatIdentifier and (Seller) VatIdentifier and (Seller) TaxRegistrationIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645') - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-3 - (Buyer) VatIdentifier and (Buyer) LegalRegistrationIdentifier and (Seller) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645'), - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-3 - (Buyer) VatIdentifier and (Buyer) LegalRegistrationIdentifier and (Seller) TaxRegistrationIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645'), - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-3 - (Buyer) VatIdentifier and (Buyer) LegalRegistrationIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645'), - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-3 - (Buyer) VatIdentifier and (Buyer) LegalRegistrationIdentifier and (Seller) VatIdentifier and (Seller) TaxRegistrationIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645'), - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-AE-3 - (Buyer) VatIdentifier and (Buyer) LegalRegistrationIdentifier and (Seller) VatIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645'), - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-3 - (Buyer) VatIdentifier and (Buyer) LegalRegistrationIdentifier and (Seller) TaxRegistrationIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645'), - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-AE-3 - (Buyer) VatIdentifier and (Buyer) LegalRegistrationIdentifier and (Seller) VatIdentifier and (Seller) TaxRegistrationIdentifier and (TaxRepresentativeParty) VatIdentifier fields' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956415645'), - new LegalRegistrationIdentifier('FR9956959', InternationalCodeDesignator::ADVANCED_TELECOMMUNICATIONS_MODULES_LIMITED_CORPORATE_NETWORK) - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-AE-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “Reverse charge” shall contain the Seller VAT Identifier (BT-31), the Seller tax - * registration identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63) and the Buyer VAT - * identifier (BT-48) and/or the Buyer legal registration identifier (BT-47). - */ - public function brAE3_error(): void - { - $this->markTestSkipped('Same error case as BR-AE-2 that\'s why BR-AE-2 exception is thrown before BR-AE-3 exception'); - } - - /** - * @test - * @testdox BR-AE-5 : In an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151) is - * "Reverse charge" the Invoiced item VAT rate (BT-152) shall be 0 (zero). - * @dataProvider provideBrAE5Success - */ - public function brAE5_success(?float $invoicedItemVatRate): void - { - $lineVatInformation = new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, $invoicedItemVatRate); - - $this->assertInstanceOf(LineVatInformation::class, $lineVatInformation); - } - - public static function provideBrAE5Success(): \Generator - { - yield 'BR-AE-5 Success #1' => [ - 'invoicedItemVatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-AE-5 : In an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151) is - * "Reverse charge" the Invoiced item VAT rate (BT-152) shall be 0 (zero). - * @dataProvider provideBrAE5Error - */ - public function brAE5_error(?float $invoicedItemVatRate): void - { - $this->expectException(\Exception::class); - - new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, $invoicedItemVatRate); - } - - public static function provideBrAE5Error(): \Generator - { - yield 'BR-AE-5 Error #1' => [ - 'invoicedItemVatRate' => 10, - ]; - yield 'BR-AE-5 Error #2' => [ - 'invoicedItemVatRate' => -10, - ]; - yield 'BR-AE-5 Error #3' => [ - 'invoicedItemVatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-AE-6 : In a Document level allowance (BG-20) where the Document level allowance VAT category code - * (BT-95) is "Reverse charge" the Document level allowance VAT rate (BT96) shall be 0 (zero). - * @dataProvider provideBrAE6Success - */ - public function brAE6_success(?float $vatRate): void - { - $documentLevelAllowance = new DocumentLevelAllowance(1, VatCategory::VAT_REVERSE_CHARGE, 'Hoobastank', vatRate: $vatRate); - - $this->assertInstanceOf(DocumentLevelAllowance::class, $documentLevelAllowance); - } - - public static function provideBrAE6Success(): \Generator - { - yield 'BR-AE-6 Success #1' => [ - 'vatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-AE-6 : In a Document level allowance (BG-20) where the Document level allowance VAT category code - * (BT-95) is "Reverse charge" the Document level allowance VAT rate (BT96) shall be 0 (zero). - * @dataProvider provideBrAE6Error - */ - public function brAE6_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelAllowance(1, VatCategory::VAT_REVERSE_CHARGE, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrAE6Error(): \Generator - { - yield 'BR-AE-6 Error #1' => [ - 'vatRate' => 10, - ]; - yield 'BR-AE-6 Error #2' => [ - 'vatRate' => -10, - ]; - yield 'BR-AE-6 Error #3' => [ - 'vatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-AE-7 : In a Document level charge (BG-21) where the Document level charge VAT category code (BT-102) - * is "Reverse charge" the Document level charge VAT rate (BT-103) shall be 0 (zero). - * @dataProvider provideBrAE7Success - */ - public function brAE7_success(?float $vatRate): void - { - $documentLevelCharge = new DocumentLevelCharge(1, VatCategory::VAT_REVERSE_CHARGE, 'Hoobastank', vatRate: $vatRate); - - $this->assertInstanceOf(DocumentLevelCharge::class, $documentLevelCharge); - } - - public static function provideBrAE7Success(): \Generator - { - yield 'BR-AE-7 Success #1' => [ - 'vatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-AE-7 : In a Document level charge (BG-21) where the Document level charge VAT category code (BT-102) - * is "Reverse charge" the Document level charge VAT rate (BT-103) shall be 0 (zero). - * @dataProvider provideBrAE7Error - */ - public function brAE7_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelCharge(1, VatCategory::VAT_REVERSE_CHARGE, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrAE7Error(): \Generator - { - yield 'BR-AE-7 Error #1' => [ - 'vatRate' => 10, - ]; - yield 'BR-AE-7 Error #2' => [ - 'vatRate' => -10, - ]; - yield 'BR-AE-7 Error #3' => [ - 'vatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-AE-8 : In a VAT breakdown (BG-23) where the VAT category code (BT-118) is "Reverse charge" - * the VAT category taxable amount (BT-116) shall equal the sum of Invoice line net amounts (BT-131) minus the sum - * of Document level allowance amounts (BT-92) plus the sum of Document level charge amounts (BT-99) where the VAT - * category codes (BT151, BT-95, BT-102) are “Reverse charge". - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrAE8Success - */ - public function brAE8_success( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void - { - $invoice = new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE), new VatIdentifier('FR9666666')), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrAE8Success(): \Generator - { - yield "single invoice line" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::VAT_REVERSE_CHARGE, 0, vatExemptionReasonText: 'Hoobastank') - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "multiple invoice lines" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::VAT_REVERSE_CHARGE, 0, vatExemptionReasonText: 'Hoobastank') - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, 0), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "single allowance" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -100, - -100, - invoiceTotalVatAmount: 0, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, 0, VatCategory::VAT_REVERSE_CHARGE, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::VAT_REVERSE_CHARGE, 'Hoobastank', vatRate: 0) - ], - 'charges' => [], - ]; - - yield "multiple allowances" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -100, - -100, - invoiceTotalVatAmount: 0, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, 0, VatCategory::VAT_REVERSE_CHARGE, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::VAT_REVERSE_CHARGE, 'Hoobastank', vatRate: 0), - new DocumentLevelAllowance(60, VatCategory::VAT_REVERSE_CHARGE, 'Hoobastank', vatRate: 0) - ], - 'charges' => [], - ]; - - yield "single charge" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 100, - 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::VAT_REVERSE_CHARGE, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::VAT_REVERSE_CHARGE, 'Hoobastank', vatRate: 0), - ], - ]; - - yield "multiple charges" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 100, - 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::VAT_REVERSE_CHARGE, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::VAT_REVERSE_CHARGE, 'Hoobastank', vatRate: 0), - new DocumentLevelCharge(60, VatCategory::VAT_REVERSE_CHARGE, 'Hoobastank', vatRate: 0), - ], - ]; - - yield "lines, allowances and charges" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::VAT_REVERSE_CHARGE, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, 0), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::VAT_REVERSE_CHARGE, 'Hoobastank', vatRate: 0), - new DocumentLevelAllowance(60, VatCategory::VAT_REVERSE_CHARGE, 'Hoobastank', vatRate: 0) - ], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::VAT_REVERSE_CHARGE, 'Hoobastank', vatRate: 0), - new DocumentLevelCharge(60, VatCategory::VAT_REVERSE_CHARGE, 'Hoobastank', vatRate: 0), - ], - ]; - } - - /** - * @test - * @testdox BR-AE-8 : In a VAT breakdown (BG-23) where the VAT category code (BT-118) is "Reverse charge" - * the VAT category taxable amount (BT-116) shall equal the sum of Invoice line net amounts (BT-131) minus the sum - * of Document level allowance amounts (BT-92) plus the sum of Document level charge amounts (BT-99) where the VAT - * category codes (BT151, BT-95, BT-102) are “Reverse charge". - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrAE8Error - */ - public function brAE8_error( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges - ); - } - - public static function provideBrAE8Error(): \Generator - { - yield "errored taxable amount" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 110, - 110, - invoiceTotalVatAmount: 10, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(50, 10, VatCategory::STANDARD_RATE, 20), - new VatBreakdown(50, 0, VatCategory::VAT_REVERSE_CHARGE, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, 0), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::VAT_REVERSE_CHARGE, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::VAT_REVERSE_CHARGE, 'Hoobastank', vatRate: 0), - ], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::VAT_REVERSE_CHARGE, 'Hoobastank', vatRate: 0), - ], - ]; - } - - /** - * @test - * @testdox BR-AE-9 : The VAT category tax amount (BT-117) in a VAT breakdown (BG-23) where the VAT category code - * (BT-118) is “Reverse charge” shall be 0 (zero). - */ - public function brAE9_success(): void - { - $vatBreakdown = new VatBreakdown( - 1000, - 0, - VatCategory::VAT_REVERSE_CHARGE, - 0, - vatExemptionReasonText: 'Hoobastank' - ); - - $this->assertInstanceOf(VatBreakdown::class, $vatBreakdown); - } - - /** - * @test - * @testdox BR-AE-9 : The VAT category tax amount (BT-117) in a VAT breakdown (BG-23) where the VAT category code - * (BT-118) is “Reverse charge” shall be 0 (zero). - * @dataProvider provideBrAE9Error - */ - public function brAE9_error(float $vatCategoryTaxAmount): void - { - $this->expectException(\Exception::class); - - new VatBreakdown(1000, $vatCategoryTaxAmount, VatCategory::VAT_REVERSE_CHARGE, 0); - } - - public static function provideBrAE9Error(): \Generator - { - yield 'BR-AE-9 Error #1' => [ - 'vatCategoryTaxAmount' => 10, - ]; - yield 'BR-AE-9 Error #2' => [ - 'vatCategoryTaxAmount' => -10, - ]; - } - - - /** - * @test - * @testdox BR-AE-10 : A VAT Breakdown (BG-23) with VAT Category code (BT-118) "Reverse charge" shall have a VAT - * exemption reason code (BT-121), meaning "Reverse charge" or the VAT exemption reason text (BT-120) "Reverse charge" - * (or the equivalent standard text in another language). - * @dataProvider provideBrAE10Success - */ - public function brAE10_success(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $vatBreakdown = new VatBreakdown(0, 0, VatCategory::VAT_REVERSE_CHARGE, 0, $reasonText, $reasonCode); - - $this->assertInstanceOf(VatBreakdown::class, $vatBreakdown); - } - - public static function provideBrAE10Success(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => VatExemptionReasonCode::REVERSE_CHARGE, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => null, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => VatExemptionReasonCode::REVERSE_CHARGE, - ]; - } - - /** - * @test - * @testdox BR-AE-10 : A VAT Breakdown (BG-23) with VAT Category code (BT-118) "Reverse charge" shall have a VAT - * exemption reason code (BT-121), meaning "Reverse charge" or the VAT exemption reason text (BT-120) "Reverse charge" - * (or the equivalent standard text in another language). - * @dataProvider provideBrAE10Error - */ - public function brAE10_error(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $this->expectException(\Exception::class); - - new VatBreakdown(0, 0, VatCategory::VAT_REVERSE_CHARGE, 0, $reasonText, $reasonCode); - } - - public static function provideBrAE10Error(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => null - ]; - } -} diff --git a/tests/BusinessRulesVatRulesBRETest.php b/tests/BusinessRulesVatRulesBRETest.php deleted file mode 100644 index e64e3d3..0000000 --- a/tests/BusinessRulesVatRulesBRETest.php +++ /dev/null @@ -1,1170 +0,0 @@ - $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brE1_success(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrE1Success(): \Generator - { - yield 'BR-E-1 Success #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, 0), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(1000, 200, VatCategory::STANDARD_RATE, 20), - new VatBreakdown(1000, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank') - ], - 'documentTotals' => new DocumentTotals( - 2000, - 2000, - 2200, - 2200, - invoiceTotalVatAmount: 200, - ) - ]; - } - - /** - * @test - * @testdox BR-E-1 : An Invoice that contains an Invoice line (BG-25), a Document level allowance (BG-20) or a - * Document level charge (BG-21) where the VAT category code (BT-151, BT-95 or BT102) is “Exempt from VAT” shall - * contain exactly one VAT breakdown (BG-23) with the VAT category code (BT-118) equal to "Exempt from VAT". - * @dataProvider provideBrE1Error - * @param array $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brE1_error(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges - ); - } - - public static function provideBrE1Error(): \Generator - { - yield 'BR-E-1 Error #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, 0), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(2000, 400, VatCategory::STANDARD_RATE, 20) - ], - 'documentTotals' => new DocumentTotals( - 2000, - 2000, - 2400, - 2400, - invoiceTotalVatAmount: 400, - ) - ]; - } - - /** - * @test - * @testdox BR-E-2 : An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code - * (BT-151) is “Exempt from VAT” shall contain the Seller VAT Identifier (BT-31), the Seller tax registration - * identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - * @dataProvider provideBrE2Success - */ - public function brE2_success(Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank') - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, 0), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrE2Success(): \Generator - { - yield 'BR-E-2 - Only Seller VatIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-E-2 - Only Seller TaxRegistrationIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-E-2 - Only SellerTaxRepresentativeParty field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-E-2 - Seller VatIdentifier and Seller TaxRegistrationIdentifier fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-E-2 - Seller VatIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-E-2 - Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-E-2 - Seller VatIdentifier and Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR986416485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-E-2 : An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code - * (BT-151) is “Exempt from VAT” shall contain the Seller VAT Identifier (BT-31), the Seller tax registration - * identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - */ - public function brE2_error(): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank') - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, 0), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - sellerTaxRepresentativeParty: null - ); - } - - /** - * @test - * @testdox BR-E-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “Exempt from VAT” shall contain the Seller VAT Identifier (BT-31), the Seller tax - * registration identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - * @dataProvider provideBrE3Success - */ - public function brE3_success(Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank') - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, 0), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [ - new DocumentLevelAllowance(0, VatCategory::EXEMPT_FROM_TAX, 'Hoobastank', vatRate: 0), - ], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrE3Success(): \Generator - { - yield 'BR-E-3 - Only Seller VatIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-E-3 - Only Seller TaxRegistrationIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-E-3 - Only SellerTaxRepresentativeParty field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-E-3 - Seller VatIdentifier and Seller TaxRegistrationIdentifier fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-E-3 - Seller VatIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-E-3 - Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-E-3 - Seller VatIdentifier and Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR986416485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - - /** - * @test - * @testdox BR-E-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “Exempt from VAT” shall contain the Seller VAT Identifier (BT-31), the Seller tax - * registration identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - */ - public function brE3_error(): void - { - $this->markTestSkipped('Same error case as BR-E-2 that\'s why BR-E-2 exception is thrown before BR-E-3 exception'); - } - - /** - * @test - * @testdox BR-E-5 : In an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151) is - * "Exempt from VAT", the Invoiced item VAT rate (BT-152) shall be 0 (zero). - * @dataProvider provideBrE5Success - */ - public function brE5_success(?float $invoicedItemVatRate): void - { - $lineVatInformation = new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, $invoicedItemVatRate); - - $this->assertInstanceOf(LineVatInformation::class, $lineVatInformation); - } - - public static function provideBrE5Success(): \Generator - { - yield 'BR-E-5 Success #1' => [ - 'invoicedItemVatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-E-5 : In an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151) is - * "Exempt from VAT", the Invoiced item VAT rate (BT-152) shall be 0 (zero). - * @dataProvider provideBrE5Error - */ - public function brE5_error(?float $invoicedItemVatRate): void - { - $this->expectException(\Exception::class); - - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, $invoicedItemVatRate); - } - - public static function provideBrE5Error(): \Generator - { - yield 'BR-E-5 Error #1' => [ - 'invoicedItemVatRate' => 10, - ]; - yield 'BR-E-5 Error #2' => [ - 'invoicedItemVatRate' => -10, - ]; - yield 'BR-E-5 Error #3' => [ - 'invoicedItemVatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-E-6 : In a Document level allowance (BG-20) where the Document level allowance VAT category code - * (BT-95) is "Exempt from VAT", the Document level allowance VAT rate (BT-96) shall be 0 (zero). - * @dataProvider provideBrE6Success - */ - public function brE6_success(?float $vatRate): void - { - $documentLevelAllowance = new DocumentLevelAllowance(1, VatCategory::EXEMPT_FROM_TAX, 'Hoobastank', vatRate: $vatRate); - - $this->assertInstanceOf(DocumentLevelAllowance::class, $documentLevelAllowance); - } - - public static function provideBrE6Success(): \Generator - { - yield 'BR-E-6 Success #1' => [ - 'vatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-E-6 : In a Document level allowance (BG-20) where the Document level allowance VAT category code - * (BT-95) is "Exempt from VAT", the Document level allowance VAT rate (BT-96) shall be 0 (zero). - * @dataProvider provideBrE6Error - */ - public function brE6_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelAllowance(1, VatCategory::EXEMPT_FROM_TAX, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrE6Error(): \Generator - { - yield 'BR-E-6 Error #1' => [ - 'vatRate' => 10, - ]; - yield 'BR-E-6 Error #2' => [ - 'vatRate' => -10, - ]; - yield 'BR-E-6 Error #3' => [ - 'vatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-E-7 : In a Document level charge (BG-21) where the Document level charge VAT category code (BT-102) - * is "Exempt from VAT", the Document level charge VAT rate (BT-103) shall be 0 (zero). - * @dataProvider provideBrE7Success - */ - public function brE7_success(?float $vatRate): void - { - $documentLevelCharge = new DocumentLevelCharge(1, VatCategory::EXEMPT_FROM_TAX, 'Hoobastank', vatRate: $vatRate); - - $this->assertInstanceOf(DocumentLevelCharge::class, $documentLevelCharge); - } - - public static function provideBrE7Success(): \Generator - { - yield 'BR-E-7 Success #1' => [ - 'vatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-E-7 : In a Document level charge (BG-21) where the Document level charge VAT category code (BT-102) - * is "Exempt from VAT", the Document level charge VAT rate (BT-103) shall be 0 (zero). - * @dataProvider provideBrE7Error - */ - public function brE7_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelCharge(1, VatCategory::EXEMPT_FROM_TAX, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrE7Error(): \Generator - { - yield 'BR-E-7 Error #1' => [ - 'vatRate' => 10, - ]; - yield 'BR-E-7 Error #2' => [ - 'vatRate' => -10, - ]; - yield 'BR-E-7 Error #3' => [ - 'vatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-E-8 : In a VAT breakdown (BG-23) where the VAT category code (BT-118) is "Exempt from VAT" the VAT - * category taxable amount (BT-116) shall equal the sum of Invoice line net amounts (BT-131) minus the sum of - * Document level allowance amounts (BT-92) plus the sum of Document level charge amounts (BT-99) where the VAT - * category codes (BT151, BT-95, BT-102) are “Exempt from VAT". - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrE8Success - */ - public function brE8_success( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void { - $invoice = new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrE8Success(): \Generator - { - yield "single invoice line" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank') - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "multiple invoice lines" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank') - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, 0), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "single allowance" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -100, - -100, - invoiceTotalVatAmount: 0, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::EXEMPT_FROM_TAX, 'Hoobastank', vatRate: 0) - ], - 'charges' => [], - ]; - - yield "multiple allowances" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -100, - -100, - invoiceTotalVatAmount: 0, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::EXEMPT_FROM_TAX, 'Hoobastank', vatRate: 0), - new DocumentLevelAllowance(60, VatCategory::EXEMPT_FROM_TAX, 'Hoobastank', vatRate: 0) - ], - 'charges' => [], - ]; - - yield "single charge" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 100, - 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::EXEMPT_FROM_TAX, 'Hoobastank', vatRate: 0), - ], - ]; - - yield "multiple charges" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 100, - 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::EXEMPT_FROM_TAX, 'Hoobastank', vatRate: 0), - new DocumentLevelCharge(60, VatCategory::EXEMPT_FROM_TAX, 'Hoobastank', vatRate: 0), - ], - ]; - - yield "lines, allowances and charges" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, 0), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::EXEMPT_FROM_TAX, 'Hoobastank', vatRate: 0), - new DocumentLevelAllowance(60, VatCategory::EXEMPT_FROM_TAX, 'Hoobastank', vatRate: 0) - ], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::EXEMPT_FROM_TAX, 'Hoobastank', vatRate: 0), - new DocumentLevelCharge(60, VatCategory::EXEMPT_FROM_TAX, 'Hoobastank', vatRate: 0), - ], - ]; - } - - /** - * @test - * @testdox BR-E-8 : In a VAT breakdown (BG-23) where the VAT category code (BT-118) is "Exempt from VAT" the VAT - * category taxable amount (BT-116) shall equal the sum of Invoice line net amounts (BT-131) minus the sum of - * Document level allowance amounts (BT-92) plus the sum of Document level charge amounts (BT-99) where the VAT - * category codes (BT151, BT-95, BT-102) are “Exempt from VAT". - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrE8Error - */ - public function brE8_error( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges - ); - } - - public static function provideBrE8Error(): \Generator - { - yield "errored taxable amount" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 110, - 110, - invoiceTotalVatAmount: 10, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(50, 10, VatCategory::STANDARD_RATE, 20), - new VatBreakdown(50, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, 0), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::EXEMPT_FROM_TAX, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::EXEMPT_FROM_TAX, 'Hoobastank', vatRate: 0), - ], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::EXEMPT_FROM_TAX, 'Hoobastank', vatRate: 0), - ], - ]; - } - - /** - * @test - * @testdox BR-E-9 : The VAT category tax amount (BT-117) In a VAT breakdown (BG-23) where the VAT category code - * (BT-118) equals "Exempt from VAT" shall equal 0 (zero). - */ - public function brE9_success(): void - { - $vatBreakdown = new VatBreakdown(1000, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank'); - - $this->assertInstanceOf(VatBreakdown::class, $vatBreakdown); - } - - /** - * @test - * @testdox BR-E-9 : The VAT category tax amount (BT-117) In a VAT breakdown (BG-23) where the VAT category code - * (BT-118) equals "Exempt from VAT" shall equal 0 (zero). - * @dataProvider provideBrE9Error - */ - public function brE9_error(float $vatCategoryTaxAmount): void - { - $this->expectException(\Exception::class); - - new VatBreakdown(1000, $vatCategoryTaxAmount, VatCategory::EXEMPT_FROM_TAX, 0); - } - - public static function provideBrE9Error(): \Generator - { - yield 'BR-E-9 Error #1' => [ - 'vatCategoryTaxAmount' => 10, - ]; - yield 'BR-E-9 Error #2' => [ - 'vatCategoryTaxAmount' => -10, - ]; - } - - /** - * @test - * @testdox BR-E-10 : A VAT Breakdown (BG-23) with VAT Category code (BT-118) "Exempt from VAT" shall have a VAT - * exemption reason code (BT-121) or a VAT exemption reason text (BT-120). - * @dataProvider provideBrE10Success - * @throws \Exception - */ - public function brE10_success(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $vatBreakdown = new VatBreakdown(0, 0, VatCategory::EXEMPT_FROM_TAX, 0, $reasonText, $reasonCode); - - $this->assertInstanceOf(VatBreakdown::class, $vatBreakdown); - } - - public static function provideBrE10Success(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => VatExemptionReasonCode::TRAVEL_AGENTS_VAT_SCHEME, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => null, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => VatExemptionReasonCode::TRAVEL_AGENTS_VAT_SCHEME, - ]; - } - - /** - * @test - * @testdox BR-E-10 : A VAT Breakdown (BG-23) with VAT Category code (BT-118) "Exempt from VAT" shall have a VAT - * exemption reason code (BT-121) or a VAT exemption reason text (BT-120). - * @dataProvider provideBrE10Error - */ - public function brE10_error(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $this->expectException(\Exception::class); - - new VatBreakdown(0, 0, VatCategory::EXEMPT_FROM_TAX, 0, $reasonText, $reasonCode); - } - - public static function provideBrE10Error(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => null - ]; - } - - -} diff --git a/tests/BusinessRulesVatRulesBRGTest.php b/tests/BusinessRulesVatRulesBRGTest.php deleted file mode 100644 index da9fba7..0000000 --- a/tests/BusinessRulesVatRulesBRGTest.php +++ /dev/null @@ -1,1067 +0,0 @@ - $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brG1_success(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrG1Success(): \Generator - { - yield 'BR-G-1 Success #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(1000, 200, VatCategory::STANDARD_RATE, 20), - new VatBreakdown(1000, 0, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0, vatExemptionReasonText: 'Hoobastank') - ], - 'documentTotals' => new DocumentTotals( - 2000, - 2000, - 2200, - 2200, - invoiceTotalVatAmount: 200, - ) - ]; - } - - /** - * @test - * @testdox BR-G-1 : An Invoice that contains an Invoice line (BG-25), a Document level allowance (BG-20) or a - * Document level charge (BG-21) where the VAT category code (BT-151, BT-95 or BT102) is “Export outside the EU” - * shall contain in the VAT breakdown (BG-23) exactly one VAT category code (BT-118) equal with "Export outside the - * EU". - * @dataProvider provideBrG1Error - * @param array $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brG1_error(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges - ); - } - - public static function provideBrG1Error(): \Generator - { - yield 'BR-G-1 Error #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(2000, 400, VatCategory::STANDARD_RATE, 20) - ], - 'documentTotals' => new DocumentTotals( - 2000, - 2000, - 2400, - 2400, - invoiceTotalVatAmount: 400, - ) - ]; - } - - /** - * @test - * @testdox BR-G-2 : An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code - * (BT-151) is “Export outside the EU” shall contain the Seller VAT Identifier (BT-31) or the Seller tax - * representative VAT identifier (BT-63). - * @dataProvider provideBrG2Success - */ - public function brG2_success(Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956454'), - ), - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0, vatExemptionReasonText: 'Hoobastank') - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrG2Success(): \Generator - { - yield 'BR-G-2 - Only (Seller) VatIdentifier' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-G-2 - Only (TaxRepresentativeParty) VatIdentifier' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-G-2 : An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code - * (BT-151) is “Export outside the EU” shall contain the Seller VAT Identifier (BT-31) or the Seller tax - * representative VAT identifier (BT-63). - * @dataProvider provideBrG2Error - */ - public function brG2_error(Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956454'), - ), - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0, vatExemptionReasonText: 'Hoobastank') - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - } - - public static function provideBrG2Error(): \Generator - { - yield 'BR-G-2 - (Seller) VatIdentifier and (TaxRepresentativeParty) VatIdentifier' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-G-2 - No field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => null - ]; - } - - /** - * @test - * @testdox BR-G-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “Export outside the EU” shall contain the Seller VAT Identifier (BT-31) or the - * Seller tax representative VAT identifier (BT-63). - * @dataProvider provideBrG3Success - */ - public function brG3_success(Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956454'), - ), - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0, vatExemptionReasonText: 'Hoobastank') - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [ - new DocumentLevelAllowance(0, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 'Hoobastank', vatRate: 0), - ], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrG3Success(): \Generator - { - yield 'BR-G-3 - Only (Seller) VatIdentifier' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-G-3 - Only (TaxRepresentativeParty) VatIdentifier' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-G-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “Export outside the EU” shall contain the Seller VAT Identifier (BT-31) or the - * Seller tax representative VAT identifier (BT-63). - */ - public function brG3_error(): void - { - $this->markTestSkipped('Same error case as BR-G-2 that\'s why BR-G-2 exception is thrown before BR-G-3 exception'); - } - - /** - * @test - * @testdox BR-G-5 : In an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151) is - * "Export outside the EU" the Invoiced item VAT rate (BT-152) shall be 0 (zero). - * @dataProvider provideBrG5Success - */ - public function brG5_success(?float $invoicedItemVatRate): void - { - $lineVatInformation = new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, $invoicedItemVatRate); - - $this->assertInstanceOf(LineVatInformation::class, $lineVatInformation); - } - - public static function provideBrG5Success(): \Generator - { - yield 'BR-G-5 Success #1' => [ - 'invoicedItemVatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-G-5 : In an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151) is - * "Export outside the EU" the Invoiced item VAT rate (BT-152) shall be 0 (zero). - * @dataProvider provideBrG5Error - */ - public function brG5_error(?float $invoicedItemVatRate): void - { - $this->expectException(\Exception::class); - - new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, $invoicedItemVatRate); - } - - public static function provideBrG5Error(): \Generator - { - yield 'BR-G-5 Error #1' => [ - 'invoicedItemVatRate' => 10, - ]; - yield 'BR-G-5 Error #2' => [ - 'invoicedItemVatRate' => -10, - ]; - yield 'BR-G-5 Error #3' => [ - 'invoicedItemVatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-G-6 : In a Document level allowance (BG-20) where the Document level allowance VAT category code - * (BT-95) is "Export outside the EU" the Document level allowance VAT rate (BT-96) shall be 0 (zero). - * @dataProvider provideBrG6Success - */ - public function brG6_success(?float $vatRate): void - { - $documentLevelAllowance = new DocumentLevelAllowance(1, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 'Hoobastank', vatRate: $vatRate); - - $this->assertInstanceOf(DocumentLevelAllowance::class, $documentLevelAllowance); - } - - public static function provideBrG6Success(): \Generator - { - yield 'BR-G-6 Success #1' => [ - 'vatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-G-6 : In a Document level allowance (BG-20) where the Document level allowance VAT category code - * (BT-95) is "Export outside the EU" the Document level allowance VAT rate (BT-96) shall be 0 (zero). - * @dataProvider provideBrG6Error - */ - public function brG6_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelAllowance(1, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrG6Error(): \Generator - { - yield 'BR-G-6 Error #1' => [ - 'vatRate' => 10, - ]; - yield 'BR-G-6 Error #2' => [ - 'vatRate' => -10, - ]; - yield 'BR-G-6 Error #3' => [ - 'vatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-G-7 : In a Document level charge (BG-21) where the Document level charge VAT category code (BT-102) - * is "Export outside the EU" the Document level charge VAT rate (BT-103) shall be 0 (zero). - * @dataProvider provideBrG7Success - */ - public function brG7_success(?float $vatRate): void - { - $documentLevelCharge = new DocumentLevelCharge(1, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 'Hoobastank', vatRate: $vatRate); - - $this->assertInstanceOf(DocumentLevelCharge::class, $documentLevelCharge); - } - - public static function provideBrG7Success(): \Generator - { - yield 'BR-G-7 Success #1' => [ - 'vatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-G-7 : In a Document level charge (BG-21) where the Document level charge VAT category code (BT-102) - * is "Export outside the EU" the Document level charge VAT rate (BT-103) shall be 0 (zero). - * @dataProvider provideBrG7Error - */ - public function brG7_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelCharge(1, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrG7Error(): \Generator - { - yield 'BR-G-7 Error #1' => [ - 'vatRate' => 10, - ]; - yield 'BR-G-7 Error #2' => [ - 'vatRate' => -10, - ]; - yield 'BR-G-7 Error #3' => [ - 'vatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-G-8 : In a VAT breakdown (BG-23) where the VAT category code (BT-118) is "Export outside the EU" the - * VAT category taxable amount (BT-116) shall equal the sum of Invoice line net amounts (BT-131) minus the sum of - * Document level allowance amounts (BT-92) plus the sum of Document level charge amounts (BT-99) where the VAT - * category codes (BT-151, BT-95, BT-102) are “Export outside the EU". - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrG8Success - */ - public function brG8_success( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void - { - $invoice = new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrG8Success(): \Generator - { - yield "single invoice line" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0, vatExemptionReasonText: 'Hoobastank') - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "multiple invoice lines" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0, vatExemptionReasonText: 'Hoobastank') - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "single allowance" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -100, - -100, - invoiceTotalVatAmount: 0, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, 0, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 'Hoobastank', vatRate: 0) - ], - 'charges' => [], - ]; - - yield "multiple allowances" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -100, - -100, - invoiceTotalVatAmount: 0, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, 0, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 'Hoobastank', vatRate: 0), - new DocumentLevelAllowance(60, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 'Hoobastank', vatRate: 0) - ], - 'charges' => [], - ]; - - yield "single charge" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 100, - 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 'Hoobastank', vatRate: 0), - ], - ]; - - yield "multiple charges" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 100, - 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 'Hoobastank', vatRate: 0), - new DocumentLevelCharge(60, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 'Hoobastank', vatRate: 0), - ], - ]; - - yield "lines, allowances and charges" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 'Hoobastank', vatRate: 0), - new DocumentLevelAllowance(60, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 'Hoobastank', vatRate: 0) - ], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 'Hoobastank', vatRate: 0), - new DocumentLevelCharge(60, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 'Hoobastank', vatRate: 0), - ], - ]; - } - - /** - * @test - * @testdox BR-G-8 : In a VAT breakdown (BG-23) where the VAT category code (BT-118) is "Export outside the EU" the - * VAT category taxable amount (BT-116) shall equal the sum of Invoice line net amounts (BT-131) minus the sum of - * Document level allowance amounts (BT-92) plus the sum of Document level charge amounts (BT-99) where the VAT - * category codes (BT-151, BT-95, BT-102) are “Export outside the EU". - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrG8Error - */ - public function brG8_error( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges - ); - } - - public static function provideBrG8Error(): \Generator - { - yield "errored taxable amount" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 110, - 110, - invoiceTotalVatAmount: 10, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(50, 10, VatCategory::STANDARD_RATE, 20), - new VatBreakdown(50, 0, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 'Hoobastank', vatRate: 0), - ], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 'Hoobastank', vatRate: 0), - ], - ]; - } - - /** - * @test - * @testdox BR-G-9 : The VAT category tax amount (BT-117) in a VAT breakdown (BG-23) where the VAT category code - * (BT-118) is “Export outside the EU” shall be 0 (zero). - */ - public function brG9_success(): void - { - $vatBreakdown = new VatBreakdown(1000, 0, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0, vatExemptionReasonText: 'Hoobastank'); - - $this->assertInstanceOf(VatBreakdown::class, $vatBreakdown); - } - - /** - * @test - * @testdox BR-G-9 : The VAT category tax amount (BT-117) in a VAT breakdown (BG-23) where the VAT category code - * (BT-118) is “Export outside the EU” shall be 0 (zero). - * @dataProvider provideBrG9Error - */ - public function brG9_error(float $vatCategoryTaxAmount): void - { - $this->expectException(\Exception::class); - - new VatBreakdown(1000, $vatCategoryTaxAmount, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0, vatExemptionReasonText: 'Hoobastank'); - } - - public static function provideBrG9Error(): \Generator - { - yield 'BR-G-9 Error #1' => [ - 'vatCategoryTaxAmount' => 10, - ]; - yield 'BR-G-9 Error #2' => [ - 'vatCategoryTaxAmount' => -10, - ]; - } - - /** - * @test - * @testdox BR-G-10 : A VAT Breakdown (BG-23) with the VAT Category code (BT-118) "Export outside the EU" shall have - * a VAT exemption reason code (BT-121), meaning "Export outside the EU" or the VAT exemption reason text (BT-120) - * "Export outside the EU" (or the equivalent standard text in another language). - * @dataProvider provideBrG10Success - */ - public function brG10_success(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $vatBreakdown = new VatBreakdown(0, 0, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0, $reasonText, $reasonCode); - - $this->assertInstanceOf(VatBreakdown::class, $vatBreakdown); - } - - public static function provideBrG10Success(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => VatExemptionReasonCode::EXPORT_OUTSIDE_THE_EU, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => null, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => VatExemptionReasonCode::EXPORT_OUTSIDE_THE_EU, - ]; - } - - /** - * @test - * @testdox BR-G-10 : A VAT Breakdown (BG-23) with the VAT Category code (BT-118) "Export outside the EU" shall have - * a VAT exemption reason code (BT-121), meaning "Export outside the EU" or the VAT exemption reason text (BT-120) - * "Export outside the EU" (or the equivalent standard text in another language). - * @dataProvider provideBrG10Error - */ - public function brG10_error(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $this->expectException(\Exception::class); - - new VatBreakdown(0, 0, VatCategory::FREE_EXPORT_ITEM_TAX_NOT_CHARGED, 0, $reasonText, $reasonCode); - } - - public static function provideBrG10Error(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => null - ]; - } -} diff --git a/tests/BusinessRulesVatRulesBRICTest.php b/tests/BusinessRulesVatRulesBRICTest.php deleted file mode 100644 index 8bed3f1..0000000 --- a/tests/BusinessRulesVatRulesBRICTest.php +++ /dev/null @@ -1,1347 +0,0 @@ - $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brIC1_success(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE), new VatIdentifier('FR966666'),), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges, - (new DeliveryInformation()) - ->setActualDeliveryDate(new \DateTimeImmutable()) - ->setDeliverToAddress(new DeliverToAddress(CountryAlpha2Code::BELGIUM)) - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrIC1Success(): \Generator - { - yield 'BR-IC-1 Success #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(1000, 200, VatCategory::STANDARD_RATE, 20), - new VatBreakdown(1000, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank') - ], - 'documentTotals' => new DocumentTotals( - 2000, - 2000, - 2200, - 2200, - invoiceTotalVatAmount: 200, - ) - ]; - } - - /** - * @test - * @testdox BR-IC-1 : An Invoice that contains an Invoice line (BG-25), a Document level allowance (BG-20) or a - * Document level charge (BG-21) where the VAT category code (BT-151, BT-95 or BT-102) is “Intra-community supply” - * shall contain in the VAT breakdown (BG-23) exactly one VAT category code (BT-118) equal with "Intra-community - * supply". - * @dataProvider provideBrIC1Error - * @param array $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brIC1_error(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges, - (new DeliveryInformation()) - ->setActualDeliveryDate(new \DateTimeImmutable()) - ->setDeliverToAddress(new DeliverToAddress(CountryAlpha2Code::BELGIUM)) - ); - } - - public static function provideBrIC1Error(): \Generator - { - yield 'BR-IC-1 Error #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(2000, 400, VatCategory::STANDARD_RATE, 20) - ], - 'documentTotals' => new DocumentTotals( - 2000, - 2000, - 2400, - 2400, - invoiceTotalVatAmount: 400, - ) - ]; - } - - /** - * @test - * @testdox BR-IC-2 : An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code - * (BT-151) is “Intra-community supply” shall contain the Seller VAT Identifier (BT31) or the Seller tax - * representative VAT identifier (BT-63) and the Buyer VAT identifier (BT-48). - * @dataProvider provideBrIC2Success - */ - public function brIC2_success(Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956454'), - ), - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank') - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - deliveryInformation: (new DeliveryInformation()) - ->setActualDeliveryDate(new \DateTimeImmutable()) - ->setInvoicingPeriod(new InvoicingPeriod(new \DateTimeImmutable('-1 day'), new \DateTimeImmutable())) - ->setDeliverToAddress(new DeliverToAddress(CountryAlpha2Code::BELGIUM)), - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrIC2Success(): \Generator - { - yield 'BR-IC-2 - Only (Seller) VatIdentifier' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-IC-2 - Only (TaxRepresentativeParty) VatIdentifier' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-IC-2 : An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code - * (BT-151) is “Intra-community supply” shall contain the Seller VAT Identifier (BT31) or the Seller tax - * representative VAT identifier (BT-63) and the Buyer VAT identifier (BT-48). - * @dataProvider provideBrIC2Error - */ - public function brIC2_error(Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956454'), - ), - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank') - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - deliveryInformation: (new DeliveryInformation()) - ->setActualDeliveryDate(new \DateTimeImmutable()) - ->setInvoicingPeriod(new InvoicingPeriod(new \DateTimeImmutable('-1 day'), new \DateTimeImmutable())) - ->setDeliverToAddress(new DeliverToAddress(CountryAlpha2Code::BELGIUM)), - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - } - - public static function provideBrIC2Error(): \Generator - { - yield 'BR-IC-2 - (Seller) VatIdentifier and (TaxRepresentativeParty) VatIdentifier' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-IC-2 - No field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => null - ]; - } - - /** - * @test - * @testdox BR-IC-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “Intra-community supply” shall contain the Seller VAT Identifier (BT-31) or the - * Seller tax representative VAT identifier (BT-63) and the Buyer VAT identifier (BT-48). - * @dataProvider provideBrIC3Success - */ - public function brIC3_success(Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956454'), - ), - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank') - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [ - new DocumentLevelAllowance(0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 'Hoobastank', vatRate: 0), - ], - [], - deliveryInformation: (new DeliveryInformation()) - ->setActualDeliveryDate(new \DateTimeImmutable()) - ->setInvoicingPeriod(new InvoicingPeriod(new \DateTimeImmutable('-1 day'), new \DateTimeImmutable())) - ->setDeliverToAddress(new DeliverToAddress(CountryAlpha2Code::BELGIUM)), - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrIC3Success(): \Generator - { - yield 'BR-IC-3 - Only (Seller) VatIdentifier' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-IC-3 - Only (TaxRepresentativeParty) VatIdentifier' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-IC-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “Intra-community supply” shall contain the Seller VAT Identifier (BT-31) or the - * Seller tax representative VAT identifier (BT-63) and the Buyer VAT identifier (BT-48). - */ - public function brIC3_error(): void - { - $this->markTestSkipped('Same error case as BR-IC-2 that\'s why BR-IC-2 exception is thrown before BR-IC-3 exception'); - } - - /** - * @test - * @testdox BR-IC-5 : In an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151) is - * "Intracommunity supply" the Invoiced item VAT rate (BT-152) shall be 0 (zero). - * @dataProvider provideBrIC5Success - */ - public function brIC5_success(?float $invoicedItemVatRate): void - { - $lineVatInformation = new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, $invoicedItemVatRate); - - $this->assertInstanceOf(LineVatInformation::class, $lineVatInformation); - } - - public static function provideBrIC5Success(): \Generator - { - yield 'BR-IC-5 Success #1' => [ - 'invoicedItemVatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-IC-5 : In an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151) is - * "Intracommunity supply" the Invoiced item VAT rate (BT-152) shall be 0 (zero). - * @dataProvider provideBrIC5Error - */ - public function brIC5_error(?float $invoicedItemVatRate): void - { - $this->expectException(\Exception::class); - - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, $invoicedItemVatRate); - } - - public static function provideBrIC5Error(): \Generator - { - yield 'BR-IC-5 Error #1' => [ - 'invoicedItemVatRate' => 10, - ]; - yield 'BR-IC-5 Error #2' => [ - 'invoicedItemVatRate' => -10, - ]; - yield 'BR-IC-5 Error #3' => [ - 'invoicedItemVatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-IC-6 : In a Document level allowance (BG-20) where the Document level allowance VAT category code - * (BT-95) is "Intra-community supply" the Document level allowance VAT rate (BT-96) shall be 0 (zero). - * @dataProvider provideBrIC6Success - */ - public function brIC6_success(?float $vatRate): void - { - $documentLevelAllowance = new DocumentLevelAllowance(1, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 'Hoobastank', vatRate: $vatRate); - - $this->assertInstanceOf(DocumentLevelAllowance::class, $documentLevelAllowance); - } - - public static function provideBrIC6Success(): \Generator - { - yield 'BR-IC-6 Success #1' => [ - 'vatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-IC-6 : In a Document level allowance (BG-20) where the Document level allowance VAT category code - * (BT-95) is "Intra-community supply" the Document level allowance VAT rate (BT-96) shall be 0 (zero). - * @dataProvider provideBrIC6Error - */ - public function brIC6_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelAllowance(1, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrIC6Error(): \Generator - { - yield 'BR-IC-6 Error #1' => [ - 'vatRate' => 10, - ]; - yield 'BR-IC-6 Error #2' => [ - 'vatRate' => -10, - ]; - yield 'BR-IC-6 Error #3' => [ - 'vatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-IC-7 : In a Document level charge (BG-21) where the Document level charge VAT category code (BT-102) - * is "Intra-community supply" the Document level charge VAT rate (BT-103) shall be 0 (zero). - * @dataProvider provideBrIC7Success - */ - public function brIC7_success(?float $vatRate): void - { - $documentLevelCharge = new DocumentLevelCharge(1, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 'Hoobastank', vatRate: $vatRate); - - $this->assertInstanceOf(DocumentLevelCharge::class, $documentLevelCharge); - } - - public static function provideBrIC7Success(): \Generator - { - yield 'BR-IC-7 Success #1' => [ - 'vatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-IC-7 : In a Document level charge (BG-21) where the Document level charge VAT category code (BT-102) - * is "Intra-community supply" the Document level charge VAT rate (BT-103) shall be 0 (zero). - * @dataProvider provideBrIC7Error - */ - public function brIC7_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelCharge(1, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrIC7Error(): \Generator - { - yield 'BR-IC-7 Error #1' => [ - 'vatRate' => 10, - ]; - yield 'BR-IC-7 Error #2' => [ - 'vatRate' => -10, - ]; - yield 'BR-IC-7 Error #3' => [ - 'vatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-IC-8 : In a VAT breakdown (BG-23) where the VAT category code (BT-118) is "Intra-community supply" - * the VAT category taxable amount (BT-116) shall equal the sum of Invoice line net amounts (BT-131) minus the sum - * of Document level allowance amounts (BT-92) plus the sum of Document level charge amounts (BT-99) where the VAT - * category codes (BT-151, BT-95, BT-102) are “Intra-community supply". - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrIC8Success - */ - public function brIC8_success( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void { - $invoice = new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE), new VatIdentifier('FR96666')), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges, - (new DeliveryInformation()) - ->setActualDeliveryDate(new \DateTimeImmutable()) - ->setDeliverToAddress(new DeliverToAddress(CountryAlpha2Code::BELGIUM)) - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrIC8Success(): \Generator - { - yield "single invoice line" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank') - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "multiple invoice lines" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank') - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "single allowance" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -100, - -100, - invoiceTotalVatAmount: 0, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 'Hoobastank', vatRate: 0) - ], - 'charges' => [], - ]; - - yield "multiple allowances" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -100, - -100, - invoiceTotalVatAmount: 0, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 'Hoobastank', vatRate: 0), - new DocumentLevelAllowance(60, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 'Hoobastank', vatRate: 0) - ], - 'charges' => [], - ]; - - yield "single charge" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 100, - 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 'Hoobastank', vatRate: 0), - ], - ]; - - yield "multiple charges" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 100, - 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 'Hoobastank', vatRate: 0), - new DocumentLevelCharge(60, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 'Hoobastank', vatRate: 0), - ], - ]; - - yield "lines, allowances and charges" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 'Hoobastank', vatRate: 0), - new DocumentLevelAllowance(60, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 'Hoobastank', vatRate: 0) - ], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 'Hoobastank', vatRate: 0), - new DocumentLevelCharge(60, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 'Hoobastank', vatRate: 0), - ], - ]; - } - - /** - * @test - * @testdox BR-IC-8 : In a VAT breakdown (BG-23) where the VAT category code (BT-118) is "Intra-community supply" - * the VAT category taxable amount (BT-116) shall equal the sum of Invoice line net amounts (BT-131) minus the sum - * of Document level allowance amounts (BT-92) plus the sum of Document level charge amounts (BT-99) where the VAT - * category codes (BT-151, BT-95, BT-102) are “Intra-community supply". - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrIC8Error - */ - public function brIC8_error( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges, - (new DeliveryInformation()) - ->setActualDeliveryDate(new \DateTimeImmutable()) - ->setDeliverToAddress(new DeliverToAddress(CountryAlpha2Code::BELGIUM)) - ); - } - - public static function provideBrIC8Error(): \Generator - { - yield "errored taxable amount" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 110, - 110, - invoiceTotalVatAmount: 10, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(50, 10, VatCategory::STANDARD_RATE, 20), - new VatBreakdown(50, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 'Hoobastank', vatRate: 0), - ], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 'Hoobastank', vatRate: 0), - ], - ]; - } - - /** - * @test - * @testdox BR-IC-9 : The VAT category tax amount (BT-117) in a VAT breakdown (BG-23) where the VAT category code - * (BT-118) is “Intra-community supply” shall be 0 (zero). - */ - public function brIC9_success(): void - { - $vatBreakdown = new VatBreakdown(1000, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank'); - - $this->assertInstanceOf(VatBreakdown::class, $vatBreakdown); - } - - /** - * @test - * @testdox BR-IC-9 : The VAT category tax amount (BT-117) in a VAT breakdown (BG-23) where the VAT category code - * (BT-118) is “Intra-community supply” shall be 0 (zero). - * @dataProvider provideBrIC9Error - */ - public function brIC9_error(float $vatCategoryTaxAmount): void - { - $this->expectException(\Exception::class); - - new VatBreakdown(1000, $vatCategoryTaxAmount, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank'); - } - - public static function provideBrIC9Error(): \Generator - { - yield 'BR-IC-9 Error #1' => [ - 'vatCategoryTaxAmount' => 10, - ]; - yield 'BR-IC-9 Error #2' => [ - 'vatCategoryTaxAmount' => -10, - ]; - } - - /** - * @test - * @testdox BR-IC-10 : A VAT Breakdown (BG-23) with the VAT Category code (BT-118) "Intra-community supply" shall have - * a VAT exemption reason code (BT-121), meaning "Intra-community supply" or the VAT exemption reason text (BT-120) - * "Intra-community supply" (or the equivalent standard text in another language). - * @dataProvider provideBrIC10Success - */ - public function brIC10_success(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $vatBreakdown = new VatBreakdown( - 0, - 0, - VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, - 0, - $reasonText, - $reasonCode - ); - - $this->assertInstanceOf(VatBreakdown::class, $vatBreakdown); - } - - public static function provideBrIC10Success(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => VatExemptionReasonCode::INTRA_COMMUNITY_SUPPLY, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => null, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => VatExemptionReasonCode::INTRA_COMMUNITY_SUPPLY, - ]; - } - - /** - * @test - * @testdox BR-IC-10 : A VAT Breakdown (BG-23) with the VAT Category code (BT-118) "Intra-community supply" shall have - * a VAT exemption reason code (BT-121), meaning "Intra-community supply" or the VAT exemption reason text (BT-120) - * "Intra-community supply" (or the equivalent standard text in another language). - * @dataProvider provideBrIC10Error - */ - public function brIC10_error(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $this->expectException(\Exception::class); - - new VatBreakdown(0, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, $reasonText, $reasonCode); - } - - public static function provideBrIC10Error(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => null - ]; - } - - /** - * @test - * @testdox BR-IC-11 : In an Invoice with a VAT breakdown (BG-23) where the VAT category code (BT-118) is - * "Intra-community supply" the Actual delivery date (BT-72) or the Invoicing period (BG-14) shall not be blank. - * @dataProvider provideBrIC11Success - */ - public function brIC11_success(DeliveryInformation $deliveryInformation): void - { - $invoice = new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR978494945') - ), - null, - new DocumentTotals(100, 100, 100, 100), - [new VatBreakdown(100, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank')], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - )], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - $deliveryInformation - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrIC11Success(): \Generator - { - yield ['deliveryInformation' => (new DeliveryInformation()) - ->setActualDeliveryDate(new \DateTimeImmutable()) - ->setInvoicingPeriod(new InvoicingPeriod(new \DateTimeImmutable('-1 day'), new \DateTimeImmutable())) - ->setDeliverToAddress(new DeliverToAddress(CountryAlpha2Code::BELGIUM)) - ]; - - yield ['deliveryInformation' => (new DeliveryInformation()) - ->setInvoicingPeriod(new InvoicingPeriod(new \DateTimeImmutable('-1 day'), new \DateTimeImmutable())) - ->setDeliverToAddress(new DeliverToAddress(CountryAlpha2Code::BELGIUM)) - ]; - - yield ['deliveryInformation' => (new DeliveryInformation()) - ->setActualDeliveryDate(new \DateTimeImmutable()) - ->setDeliverToAddress(new DeliverToAddress(CountryAlpha2Code::BELGIUM)) - ]; - } - - /** - * @test - * @testdox BR-IC-11 : In an Invoice with a VAT breakdown (BG-23) where the VAT category code (BT-118) is - * "Intra-community supply" the Actual delivery date (BT-72) or the Invoicing period (BG-14) shall not be blank. - * @dataProvider provideBrIC11Error - */ - public function brIC11_error(?DeliveryInformation $deliveryInformation): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR978494945') - ), - null, - new DocumentTotals(100, 100, 100, 100), - [new VatBreakdown(100, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank')], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - )], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - $deliveryInformation - ); - } - - public static function provideBrIC11Error(): \Generator - { - yield ['deliveryInformation' => (new DeliveryInformation()) - ->setDeliverToAddress(new DeliverToAddress(CountryAlpha2Code::BELGIUM)) - ]; - - yield ['deliveryInformation' => null]; - } - - /** - * @test - * @testdox BR-IC-12 : In an Invoice with a VAT breakdown (BG-23) where the VAT category code (BT-118) is - * "Intra-community supply" the Deliver to country code (BT-80) shall not be blank. - * @dataProvider provideBrIC12Success - */ - public function brIC12_success(DeliveryInformation $deliveryInformation): void - { - $invoice = new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR978494945') - ), - null, - new DocumentTotals(100, 100, 100, 100), - [new VatBreakdown(100, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank')], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - )], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - $deliveryInformation - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrIC12Success(): \Generator - { - yield ['deliveryInformation' => (new DeliveryInformation()) - ->setActualDeliveryDate(new \DateTimeImmutable()) - ->setInvoicingPeriod(new InvoicingPeriod(new \DateTimeImmutable('-1 day'), new \DateTimeImmutable())) - ->setDeliverToAddress(new DeliverToAddress(CountryAlpha2Code::BELGIUM)) - ]; - } - - /** - * @test - * @testdox BR-IC-12 : In an Invoice with a VAT breakdown (BG-23) where the VAT category code (BT-118) is - * "Intra-community supply" the Deliver to country code (BT-80) shall not be blank. - * @dataProvider provideBrIC12Error - */ - public function brIC12_error(DeliveryInformation $deliveryInformation): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR978494945') - ), - null, - new DocumentTotals(100, 100, 100, 100), - [new VatBreakdown(100, 0, VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0, vatExemptionReasonText: 'Hoobastank')], - [new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::VAT_EXEMPT_FOR_EEA_INTRA_COMMUNITY_SUPPLY_OF_GOODS_AND_SERVICES, 0), - new ItemInformation("A thing"), - )], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - $deliveryInformation - ); - } - - public static function provideBrIC12Error(): \Generator - { - yield ['deliveryInformation' => (new DeliveryInformation()) - ->setActualDeliveryDate(new \DateTimeImmutable()) - ]; - } -} diff --git a/tests/BusinessRulesVatRulesBRIGTest.php b/tests/BusinessRulesVatRulesBRIGTest.php deleted file mode 100644 index 5f27563..0000000 --- a/tests/BusinessRulesVatRulesBRIGTest.php +++ /dev/null @@ -1,1221 +0,0 @@ - $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brIG1_success(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrIG1Success(): \Generator - { - yield 'BR-IG-1 Success #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 0), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(1000, 200, VatCategory::STANDARD_RATE, 20), - new VatBreakdown(1000, 0, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 0) - ], - 'documentTotals' => new DocumentTotals( - 2000, - 2000, - 2200, - 2200, - invoiceTotalVatAmount: 200, - ) - ]; - } - - /** - * @test - * @testdox BR-IG-1 : An Invoice that contains an Invoice line (BG-25), a Document level allowance (BG-20) or a - * Document level charge (BG-21) where the VAT category code (BT-151, BT-95 or BT-102) is “IGIC” shall contain in - * the VAT breakdown (BG-23) at least one VAT category code (BT118) equal with "IGIC". - * @dataProvider provideBrIG1Error - * @param array $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brIG1_error(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges - ); - } - - public static function provideBrIG1Error(): \Generator - { - yield 'BR-IG-1 Error #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 0), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(2000, 400, VatCategory::STANDARD_RATE, 20) - ], - 'documentTotals' => new DocumentTotals( - 2000, - 2000, - 2400, - 2400, - invoiceTotalVatAmount: 400, - ) - ]; - } - - /** - * @test - * @testdox BR-IG-2 : An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code - * (BT-151) is “IGIC” shall contain the Seller VAT Identifier (BT-31), the Seller tax registration identifier - * (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - * @dataProvider provideBrIG2Success - */ - public function brIG2_success(Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 3000, - 3000, - 3600, - 3600, - invoiceTotalVatAmount: 600, - ), - [ - new VatBreakdown(3000, 600, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20) - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrIG2Success(): \Generator - { - yield 'BR-IG-2 - Only Seller VatIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-IG-2 - Only Seller TaxRegistrationIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-IG-2 - Only SellerTaxRepresentativeParty field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-IG-2 - Seller VatIdentifier and Seller TaxRegistrationIdentifier fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-IG-2 - Seller VatIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-IG-2 - Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-IG-2 - Seller VatIdentifier and Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR986416485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-IG-2 : An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code - * (BT-151) is “IGIC” shall contain the Seller VAT Identifier (BT-31), the Seller tax registration identifier - * (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - */ - public function brIG2_error(): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 3000, - 3000, - 3600, - 3600, - invoiceTotalVatAmount: 600, - ), - [ - new VatBreakdown(3000, 600, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20) - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - sellerTaxRepresentativeParty: null - ); - } - - /** - * @test - * @testdox BR-IG-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “IGIC” shall contain the Seller VAT Identifier (BT31), the Seller tax registration - * identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - * @dataProvider provideBrIG3Success - */ - public function brIG3_success(Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 3000, - 3000, - 3600, - 3600, - invoiceTotalVatAmount: 600, - ), - [ - new VatBreakdown(3000, 600, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20) - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [ - new DocumentLevelAllowance(0, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: 0), - ], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrIG3Success(): \Generator - { - yield 'BR-IG-2 - Only Seller VatIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-IG-2 - Only Seller TaxRegistrationIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-IG-2 - Only SellerTaxRepresentativeParty field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-IG-2 - Seller VatIdentifier and Seller TaxRegistrationIdentifier fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-IG-2 - Seller VatIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-IG-2 - Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-IG-2 - Seller VatIdentifier and Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR986416485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-IG-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “IGIC” shall contain the Seller VAT Identifier (BT31), the Seller tax registration - * identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - */ - public function brIG3_error(): void - { - $this->markTestSkipped('Same error case as BR-IG-2 that\'s why BR-IG-2 exception is thrown before BR-IG-3 exception'); - } - - /** - * @test - * @testdox BR-IG-5 : In an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151) is "IGIC" the - * invoiced item VAT rate (BT-152) shall be 0 (zero) or greater than zero. - * @dataProvider provideBrIG5Success - */ - public function brIG5_success(?float $invoicedItemVatRate): void - { - $lineVatInformation = new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, $invoicedItemVatRate); - - $this->assertInstanceOf(LineVatInformation::class, $lineVatInformation); - } - - public static function provideBrIG5Success(): \Generator - { - yield 'BR-IG-5 Success #1' => [ - 'invoicedItemVatRate' => 0, - ]; - yield 'BR-IG-5 Success #2' => [ - 'invoicedItemVatRate' => 10, - ]; - } - - /** - * @test - * @testdox BR-IG-5 : In an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151) is "IGIC" the - * invoiced item VAT rate (BT-152) shall be 0 (zero) or greater than zero. - * @dataProvider provideBrIG5Error - */ - public function brIG5_error(?float $invoicedItemVatRate): void - { - $this->expectException(\Exception::class); - - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, $invoicedItemVatRate); - } - - public static function provideBrIG5Error(): \Generator - { - yield 'BR-IG-5 Error #1' => [ - 'invoicedItemVatRate' => -10, - ]; - yield 'BR-IG-5 Error #2' => [ - 'invoicedItemVatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-IG-6 : In a Document level allowance (BG-20) where the Document level allowance VAT category code - * (BT-95) is "IGIC" the Document level allowance VAT rate (BT-96) shall be 0 (zero) or greater than zero. - * @dataProvider provideBrIG6Success - */ - public function brIG6_success(?float $vatRate): void - { - $documentLevelAllowance = new DocumentLevelAllowance(1, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: $vatRate); - - $this->assertInstanceOf(DocumentLevelAllowance::class, $documentLevelAllowance); - } - - public static function provideBrIG6Success(): \Generator - { - yield 'BR-IG-6 Success #1' => [ - 'invoicedItemVatRate' => 0, - ]; - yield 'BR-IG-6 Success #2' => [ - 'invoicedItemVatRate' => 10, - ]; - } - - /** - * @test - * @testdox BR-IG-6 : In a Document level allowance (BG-20) where the Document level allowance VAT category code - * (BT-95) is "IGIC" the Document level allowance VAT rate (BT-96) shall be 0 (zero) or greater than zero. - * @dataProvider provideBrIG6Error - */ - public function brIG6_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelAllowance(1, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrIG6Error(): \Generator - { - yield 'BR-IG-6 Error #1' => [ - 'vatRate' => -10, - ]; - yield 'BR-IG-6 Error #2' => [ - 'vatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-IG-7 : In a Document level charge (BG-21) where the Document level charge VAT category code (BT-102) - * is "IGIC" the Document level charge VAT rate (BT-103) shall be 0 (zero) or greater than zero. - * @dataProvider provideBrIG7Success - */ - public function brIG7_success(?float $vatRate): void - { - $documentLevelCharge = new DocumentLevelCharge(1, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: $vatRate); - - $this->assertInstanceOf(DocumentLevelCharge::class, $documentLevelCharge); - } - - public static function provideBrIG7Success(): \Generator - { - yield 'BR-IG-7 Success #1' => [ - 'vatRate' => 0, - ]; - yield 'BR-IG-7 Success #2' => [ - 'vatRate' => 10, - ]; - } - - /** - * @test - * @testdox BR-IG-7 : In a Document level charge (BG-21) where the Document level charge VAT category code (BT-102) - * is "IGIC" the Document level charge VAT rate (BT-103) shall be 0 (zero) or greater than zero. - * @dataProvider provideBrIG7Error - */ - public function brIG7_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelCharge(1, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrIG7Error(): \Generator - { - yield 'BR-IG-7 Error #1' => [ - 'vatRate' => -10, - ]; - yield 'BR-IG-7 Error #2' => [ - 'vatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-IG-8 : For each different value of VAT category rate (BT-119) where the VAT category code (BT118) is - * "IGIC", the VAT category taxable amount (BT-116) in a VAT breakdown (BG-23) shall equal the sum of Invoice line - * net amounts (BT-131) plus the sum of document level charge amounts (BT-99) minus the sum of document level - * allowance amounts (BT-92) where the VAT category code (BT-151, BT-102, BT-95) is “IGIC” and the VAT rate - * (BT-152, BT-103, BT-96) equals the VAT category rate (BT-119). - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrIG8Success - */ - public function brIG8_success( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void - { - $invoice = new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrIG8Success(): \Generator - { - yield "single invoice line" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 120, - 120, - invoiceTotalVatAmount: 20 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20) - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "multiple invoice lines w/ same rate" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 120, - 120, - invoiceTotalVatAmount: 20 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20) - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "multiple invoice lines w/ different rates" => [ - 'totals' => new DocumentTotals( - 200, - 200, - 230, - 230, - invoiceTotalVatAmount: 30 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new VatBreakdown(100, 10, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 10) - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 10), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "single allowance" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -120, - -120, - invoiceTotalVatAmount: -20, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, -20, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: 20) - ], - 'charges' => [], - ]; - - yield "multiple allowances" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -120, - -120, - invoiceTotalVatAmount: -20, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, -20, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: 20), - new DocumentLevelAllowance(60, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: 20) - ], - 'charges' => [], - ]; - - yield "single charge" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 120, - 120, - invoiceTotalVatAmount: 20, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: 20), - ], - ]; - - yield "multiple charges" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 120, - 120, - invoiceTotalVatAmount: 20, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: 20), - new DocumentLevelCharge(60, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: 20), - ], - ]; - - yield "lines, allowances and charges w/ same rate" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 120, - 120, - invoiceTotalVatAmount: 20, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: 20), - new DocumentLevelAllowance(60, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: 20) - ], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: 20), - new DocumentLevelCharge(60, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: 20), - ], - ]; - - yield "lines, allowances and charges w/ different rates" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 115, - 115, - invoiceTotalVatAmount: 15, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(50, 10, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new VatBreakdown(50, 5, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 10), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 10), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(50, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: 20), - new DocumentLevelAllowance(50, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: 10) - ], - 'charges' => [ - new DocumentLevelCharge(50, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: 20), - new DocumentLevelCharge(50, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: 10), - ], - ]; - } - - /** - * @test - * @testdox BR-IG-8 : For each different value of VAT category rate (BT-119) where the VAT category code (BT118) is - * "IGIC", the VAT category taxable amount (BT-116) in a VAT breakdown (BG-23) shall equal the sum of Invoice line - * net amounts (BT-131) plus the sum of document level charge amounts (BT-99) minus the sum of document level - * allowance amounts (BT-92) where the VAT category code (BT-151, BT-102, BT-95) is “IGIC” and the VAT rate - * (BT-152, BT-103, BT-96) equals the VAT category rate (BT-119). - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrIG8Error - */ - public function brIG8_error( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges - ); - } - - public static function provideBrIG8Error(): \Generator - { - yield "errored taxable amount" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 120, - 120, - invoiceTotalVatAmount: 20, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(50, 10, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new VatBreakdown(100, 10, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 10), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(0), - new LineVatInformation(VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: 20), - ], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 'Hoobastank', vatRate: 20), - ], - ]; - } - - /** - * @test - * @testdox BR-IG-9 : The VAT category tax amount (BT-117) in a VAT breakdown (BG-23) where VAT category code - * (BT-118) is "IGIC" shall equal the VAT category taxable amount (BT-116) multiplied by the VAT category rate - * (BT-119). - */ - public function brIG9(): void - { - $this->assertTrue(true, 'Same as BR-CO-17'); - } - - /** - * @test - * @testdox BR-IG-10 : A VAT Breakdown (BG-23) with VAT Category code (BT-118) "IGIC" shall not have a VAT exemption - * reason code (BT-121) or VAT exemption reason text (BT-120). - * @dataProvider provideBrIG10Success - */ - public function brIG10_success(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $vatBreakdown = new VatBreakdown(0, 0, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 0, $reasonText, $reasonCode); - - $this->assertInstanceOf(VatBreakdown::class, $vatBreakdown); - } - - public static function provideBrIG10Success(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => null - ]; - } - - /** - * @test - * @testdox BR-IG-10 : A VAT Breakdown (BG-23) with VAT Category code (BT-118) "IGIC" shall not have a VAT exemption - * reason code (BT-121) or VAT exemption reason text (BT-120). - * @dataProvider provideBrIG10Error - */ - public function brIG10_error(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $this->expectException(\Exception::class); - - new VatBreakdown(0, 0, VatCategory::CANARY_ISLANDS_GENERAL_INDIRECT_TAX, 0, $reasonText, $reasonCode); - } - - public static function provideBrIG10Error(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => VatExemptionReasonCode::EXEMPT_BASED_ON_ARTICLE_309_OF_COUNCIL_DIRECTIVE_2006_112_EC, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => null, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => VatExemptionReasonCode::EXEMPT_BASED_ON_ARTICLE_309_OF_COUNCIL_DIRECTIVE_2006_112_EC, - ]; - } -} diff --git a/tests/BusinessRulesVatRulesBRIPTest.php b/tests/BusinessRulesVatRulesBRIPTest.php deleted file mode 100644 index 776de23..0000000 --- a/tests/BusinessRulesVatRulesBRIPTest.php +++ /dev/null @@ -1,1221 +0,0 @@ - $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brIP1_success(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrIP1Success(): \Generator - { - yield 'BR-IP-1 Success #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 0), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(1000, 200, VatCategory::STANDARD_RATE, 20), - new VatBreakdown(1000, 0, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 0) - ], - 'documentTotals' => new DocumentTotals( - 2000, - 2000, - 2200, - 2200, - invoiceTotalVatAmount: 200, - ) - ]; - } - - /** - * @test - * @testdox BR-IP-1 : An Invoice that contains an Invoice line (BG-25), a Document level allowance (BG-20) or a - * Document level charge (BG-21) where the VAT category code (BT-151, BT-95 or BT-102) is “IPSI” shall contain in - * the VAT breakdown (BG-23) at least one VAT category code (BT118) equal with "IPSI". - * @dataProvider provideBrIP1Error - * @param array $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brIP1_error(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges - ); - } - - public static function provideBrIP1Error(): \Generator - { - yield 'BR-IP-1 Error #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 0), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(2000, 400, VatCategory::STANDARD_RATE, 20) - ], - 'documentTotals' => new DocumentTotals( - 2000, - 2000, - 2400, - 2400, - invoiceTotalVatAmount: 400, - ) - ]; - } - - /** - * @test - * @testdox BR-IP-2 : An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code - * (BT-151) is “IPSI” shall contain the Seller VAT Identifier (BT-31), the Seller tax registration identifier - * (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - * @dataProvider provideBrIP2Success - */ - public function brIP2_success(Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 3000, - 3000, - 3600, - 3600, - invoiceTotalVatAmount: 600, - ), - [ - new VatBreakdown(3000, 600, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20) - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrIP2Success(): \Generator - { - yield 'BR-IP-2 - Only Seller VatIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-IP-2 - Only Seller TaxRegistrationIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-IP-2 - Only SellerTaxRepresentativeParty field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-IP-2 - Seller VatIdentifier and Seller TaxRegistrationIdentifier fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-IP-2 - Seller VatIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-IP-2 - Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-IP-2 - Seller VatIdentifier and Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR986416485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-IP-2 : An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code - * (BT-151) is “IPSI” shall contain the Seller VAT Identifier (BT-31), the Seller tax registration identifier - * (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - */ - public function brIP2_error(): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 3000, - 3000, - 3600, - 3600, - invoiceTotalVatAmount: 600, - ), - [ - new VatBreakdown(3000, 600, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20) - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - sellerTaxRepresentativeParty: null - ); - } - - /** - * @test - * @testdox BR-IP-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “IPSI” shall contain the Seller VAT Identifier (BT31), the Seller Tax registration - * identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - * @dataProvider provideBrIP3Success - */ - public function brIP3_success(Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 3000, - 3000, - 3600, - 3600, - invoiceTotalVatAmount: 600, - ), - [ - new VatBreakdown(3000, 600, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20) - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [ - new DocumentLevelAllowance(0, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: 0), - ], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrIP3Success(): \Generator - { - yield 'BR-IP-3 - Only Seller VatIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-IP-3 - Only Seller TaxRegistrationIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-IP-3 - Only SellerTaxRepresentativeParty field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-IP-3 - Seller VatIdentifier and Seller TaxRegistrationIdentifier fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-IP-3 - Seller VatIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-IP-3 - Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-IP-3 - Seller VatIdentifier and Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR986416485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-IP-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “IPSI” shall contain the Seller VAT Identifier (BT31), the Seller Tax registration - * identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - */ - public function brIP3_error(): void - { - $this->markTestSkipped('Same error case as BR-IP-2 that\'s why BR-IP-2 exception is thrown before BR-IP-3 exception'); - } - - /** - * @test - * @testdox BR-IP-5 : In an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151) is "IPSI" the - * Invoiced item VAT rate (BT-152) shall be 0 (zero) or greater than zero. - * @dataProvider provideBrIP5Success - */ - public function brIP5_success(?float $invoicedItemVatRate): void - { - $lineVatInformation = new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, $invoicedItemVatRate); - - $this->assertInstanceOf(LineVatInformation::class, $lineVatInformation); - } - - public static function provideBrIP5Success(): \Generator - { - yield 'BR-IP-5 Success #1' => [ - 'invoicedItemVatRate' => 0, - ]; - yield 'BR-IP-5 Success #2' => [ - 'invoicedItemVatRate' => 10, - ]; - } - - /** - * @test - * @testdox BR-IP-5 : In an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151) is "IPSI" the - * Invoiced item VAT rate (BT-152) shall be 0 (zero) or greater than zero. - * @dataProvider provideBrIP5Error - */ - public function brIP5_error(?float $invoicedItemVatRate): void - { - $this->expectException(\Exception::class); - - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, $invoicedItemVatRate); - } - - public static function provideBrIP5Error(): \Generator - { - yield 'BR-IP-5 Error #1' => [ - 'invoicedItemVatRate' => -10, - ]; - yield 'BR-IP-5 Error #2' => [ - 'invoicedItemVatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-IP-6 : In a Document level allowance (BG-20) where the Document level allowance VAT category code - * (BT-95) is "IPSI" the Document level allowance VAT rate (BT-96) shall be 0 (zero) or greater than zero. - * @dataProvider provideBrIP6Success - */ - public function brIP6_success(?float $vatRate): void - { - $documentLevelAllowance = new DocumentLevelAllowance(1, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: $vatRate); - - $this->assertInstanceOf(DocumentLevelAllowance::class, $documentLevelAllowance); - } - - public static function provideBrIP6Success(): \Generator - { - yield 'BR-IP-6 Success #1' => [ - 'invoicedItemVatRate' => 0, - ]; - yield 'BR-IP-6 Success #2' => [ - 'invoicedItemVatRate' => 10, - ]; - } - - /** - * @test - * @testdox BR-IP-6 : In a Document level allowance (BG-20) where the Document level allowance VAT category code - * (BT-95) is "IPSI" the Document level allowance VAT rate (BT-96) shall be 0 (zero) or greater than zero. - * @dataProvider provideBrIP6Error - */ - public function brIP6_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelAllowance(1, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrIP6Error(): \Generator - { - yield 'BR-IP-6 Error #1' => [ - 'vatRate' => -10, - ]; - yield 'BR-IP-6 Error #2' => [ - 'vatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-IP-7 : In a Document level charge (BG-21) where the Document level charge VAT category code (BT-102) - * is "IPSI" the Document level charge VAT rate (BT-103) shall be 0 (zero) or greater than zero. - * @dataProvider provideBrIP7Success - */ - public function brIP7_success(?float $vatRate): void - { - $documentLevelCharge = new DocumentLevelCharge(1, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: $vatRate); - - $this->assertInstanceOf(DocumentLevelCharge::class, $documentLevelCharge); - } - - public static function provideBrIP7Success(): \Generator - { - yield 'BR-IP-7 Success #1' => [ - 'invoicedItemVatRate' => 0, - ]; - yield 'BR-IP-7 Success #2' => [ - 'invoicedItemVatRate' => 10, - ]; - } - - /** - * @test - * @testdox BR-IP-7 : In a Document level charge (BG-21) where the Document level charge VAT category code (BT-102) - * is "IPSI" the Document level charge VAT rate (BT-103) shall be 0 (zero) or greater than zero. - * @dataProvider provideBrIP7Error - */ - public function brIP7_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelCharge(1, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrIP7Error(): \Generator - { - yield 'BR-IP-7 Error #1' => [ - 'vatRate' => -10, - ]; - yield 'BR-IP-7 Error #2' => [ - 'vatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-IP-8 : For each different value of VAT category rate (BT-119) where the VAT category code (BT118) is - * "IPSI", the VAT category taxable amount (BT-116) in a VAT breakdown (BG-23) shall equal the sum of Invoice line - * net amounts (BT-131) plus the sum of document level charge amounts (BT-99) minus the sum of document level - * allowance amounts (BT-92) where the VAT category code (BT-151, BT-102, BT-95) is “IPSI” and the VAT rate - * (BT-152, BT-103, BT-96) equals the VAT category rate (BT-119). - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrIP8Success - */ - public function brIP8_success( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void - { - $invoice = new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrIP8Success(): \Generator - { - yield "single invoice line" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 120, - 120, - invoiceTotalVatAmount: 20 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20) - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "multiple invoice lines w/ same rate" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 120, - 120, - invoiceTotalVatAmount: 20 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20) - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "multiple invoice lines w/ different rates" => [ - 'totals' => new DocumentTotals( - 200, - 200, - 230, - 230, - invoiceTotalVatAmount: 30 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new VatBreakdown(100, 10, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 10) - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 10), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "single allowance" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -120, - -120, - invoiceTotalVatAmount: -20, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, -20, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: 20) - ], - 'charges' => [], - ]; - - yield "multiple allowances" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -120, - -120, - invoiceTotalVatAmount: -20, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, -20, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: 20), - new DocumentLevelAllowance(60, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: 20) - ], - 'charges' => [], - ]; - - yield "single charge" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 120, - 120, - invoiceTotalVatAmount: 20, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: 20), - ], - ]; - - yield "multiple charges" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 120, - 120, - invoiceTotalVatAmount: 20, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: 20), - new DocumentLevelCharge(60, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: 20), - ], - ]; - - yield "lines, allowances and charges w/ same rate" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 120, - 120, - invoiceTotalVatAmount: 20, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: 20), - new DocumentLevelAllowance(60, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: 20) - ], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: 20), - new DocumentLevelCharge(60, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: 20), - ], - ]; - - yield "lines, allowances and charges w/ different rates" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 115, - 115, - invoiceTotalVatAmount: 15, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(50, 10, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new VatBreakdown(50, 5, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 10), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 10), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(50, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: 20), - new DocumentLevelAllowance(50, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: 10) - ], - 'charges' => [ - new DocumentLevelCharge(50, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: 20), - new DocumentLevelCharge(50, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: 10), - ], - ]; - } - - /** - * @test - * @testdox BR-IP-8 : For each different value of VAT category rate (BT-119) where the VAT category code (BT118) is - * "IPSI", the VAT category taxable amount (BT-116) in a VAT breakdown (BG-23) shall equal the sum of Invoice line - * net amounts (BT-131) plus the sum of document level charge amounts (BT-99) minus the sum of document level - * allowance amounts (BT-92) where the VAT category code (BT-151, BT-102, BT-95) is “IPSI” and the VAT rate - * (BT-152, BT-103, BT-96) equals the VAT category rate (BT-119). - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrIP8Error - */ - public function brIP8_error( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges - ); - } - - public static function provideBrIP8Error(): \Generator - { - yield "errored taxable amount" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 120, - 120, - invoiceTotalVatAmount: 20, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(50, 10, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new VatBreakdown(100, 10, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 10), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(0), - new LineVatInformation(VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: 20), - ], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 'Hoobastank', vatRate: 20), - ], - ]; - } - - /** - * @test - * @testdox BR-IP-9 : The VAT category tax amount (BT-117) in a VAT breakdown (BG-23) where VAT category code - * (BT-118) is "IPSI" shall equal the VAT category taxable amount (BT-116) multiplied by the VAT category rate - * (BT-119). - */ - public function brIP9(): void - { - $this->assertTrue(true, 'Same as BR-CO-17'); - } - - /** - * @test - * @testdox BR-IP-10 : A VAT Breakdown (BG-23) with VAT Category code (BT-118) "IPSI" shall not have a VAT exemption - * reason code (BT-121) or VAT exemption reason text (BT-120). - * @dataProvider provideBrIP10Success - */ - public function brIP10_success(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $vatBreakdown = new VatBreakdown(0, 0, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 0, $reasonText, $reasonCode); - - $this->assertInstanceOf(VatBreakdown::class, $vatBreakdown); - } - - public static function provideBrIP10Success(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => null - ]; - } - - /** - * @test - * @testdox BR-IP-10 : A VAT Breakdown (BG-23) with VAT Category code (BT-118) "IPSI" shall not have a VAT exemption - * reason code (BT-121) or VAT exemption reason text (BT-120). - * @dataProvider provideBrIP10Error - */ - public function brIP10_error(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $this->expectException(\Exception::class); - - new VatBreakdown(0, 0, VatCategory::TAX_FOR_PRODUCTION_SERVICES_AND_IMPORTATION_IN_CEUTA_AND_MELILLA, 0, $reasonText, $reasonCode); - } - - public static function provideBrIP10Error(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => VatExemptionReasonCode::EXEMPT_BASED_ON_ARTICLE_309_OF_COUNCIL_DIRECTIVE_2006_112_EC, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => null, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => VatExemptionReasonCode::EXEMPT_BASED_ON_ARTICLE_309_OF_COUNCIL_DIRECTIVE_2006_112_EC, - ]; - } -} diff --git a/tests/BusinessRulesVatRulesBROTest.php b/tests/BusinessRulesVatRulesBROTest.php deleted file mode 100644 index bce4569..0000000 --- a/tests/BusinessRulesVatRulesBROTest.php +++ /dev/null @@ -1,1327 +0,0 @@ - $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brO1_success(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR958954615') - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrO1Success(): \Generator - { - yield 'BR-O-1 Success #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 2000, - new PriceDetails(2000), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, null), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(2000, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, vatExemptionReasonText: 'Hoobastank') - ], - 'documentTotals' => new DocumentTotals( - 2000, - 2000, - 2000, - 2000, - ) - ]; - } - - /** - * @test - * @testdox BR-O-1 : - * @dataProvider provideBrO1Error - * @param array $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brO1_error(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges - ); - } - - public static function provideBrO1Error(): \Generator - { - yield 'BR-O-1 Error #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, null), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(2000, 400, VatCategory::STANDARD_RATE, 20) - ], - 'documentTotals' => new DocumentTotals( - 2000, - 2000, - 2400, - 2400, - invoiceTotalVatAmount: 400, - ) - ]; - } - - /** - * @test - * @testdox BR-O-2 : An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code - * (BT-151) is “Not subject to VAT” shall not contain the Seller VAT identifier (BT-31), the Seller tax - * representative VAT identifier (BT-63) or the Buyer VAT identifier (BT48). - * @dataProvider provideBrO2Success - */ - public function brO2_success(Buyer $buyer, Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - $buyer, - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, vatExemptionReasonText: 'Hoobastank') - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrO2Success(): \Generator - { - yield 'BR-O-2 - No field' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-O-2 - (Seller) VatIdentifier' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR9594515'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-O-2 - (TaxRepresentativeParty) VatIdentifier' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-O-2 - (Buyer) VatIdentifier' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR985465151') - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-O-2 - (Seller) VatIdentifier and (TaxRepresentativeParty) VatIdentifier' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR9594515'), - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-O-2 - (Seller) VatIdentifier and (Buyer) VatIdentifier' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR9594515'), - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR9594515'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-O-2 - (TaxRepresentativeParty) VatIdentifier and (Buyer) VatIdentifier' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR9594515'), - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-O-2 : An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code - * (BT-151) is “Not subject to VAT” shall not contain the Seller VAT identifier (BT-31), the Seller tax - * representative VAT identifier (BT-63) or the Buyer VAT identifier (BT48). - * @dataProvider provideBrO2Error - */ - public function brO2_error(Buyer $buyer, Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - $buyer, - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, vatExemptionReasonText: 'Hoobastank') - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - } - - public static function provideBrO2Error(): \Generator - { - yield 'BR-O-2 - (Seller) VatIdentifier and (TaxRepresentativeParty) VatIdentifier and (Buyer) VatIdentifier' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR9594515'), - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR9594515'), - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-O-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “Not subject to VAT” shall not contain the Seller VAT identifier (BT-31), the Seller - * tax representative VAT identifier (BT-63) or the Buyer VAT identifier (BT-48). - * @dataProvider provideBrO3Success - */ - public function brO3_success(Buyer $buyer, Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - $buyer, - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, vatExemptionReasonText: 'Hoobastank') - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [ - new DocumentLevelAllowance(0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, 'Hoobastank'), - ], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrO3Success(): \Generator - { - yield 'BR-O-3 - No field' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-O-3 - (Seller) VatIdentifier' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR9594515'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-O-3 - (TaxRepresentativeParty) VatIdentifier' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-O-3 - (Buyer) VatIdentifier' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR985465151') - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-O-3 - (Seller) VatIdentifier and (TaxRepresentativeParty) VatIdentifier' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - null - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR9594515'), - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-O-3 - (Seller) VatIdentifier and (Buyer) VatIdentifier' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR9594515'), - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR9594515'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-O-3 - (TaxRepresentativeParty) VatIdentifier and (Buyer) VatIdentifier' => [ - 'buyer' => new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR9594515'), - ), - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - - /** - * @test - * @testdox BR-O-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “Not subject to VAT” shall not contain the Seller VAT identifier (BT-31), the Seller - * tax representative VAT identifier (BT-63) or the Buyer VAT identifier (BT-48). - */ - public function brO3_error(): void - { - $this->markTestSkipped('Same error case as BR-O-2 that\'s why BR-O-2 exception is thrown before BR-O-3 exception'); - } - - /** - * @test - * @testdox BR-O-5 : An Invoice line (BG-25) where the VAT category code (BT-151) is "Not subject to VAT" shall not - * contain an Invoiced item VAT rate (BT-152). - */ - public function brO5_success(): void - { - $lineVatInformation = new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX); - - $this->assertInstanceOf(LineVatInformation::class, $lineVatInformation); - } - - /** - * @test - * @testdox BR-O-5 : An Invoice line (BG-25) where the VAT category code (BT-151) is "Not subject to VAT" shall not - * contain an Invoiced item VAT rate (BT-152). - * @dataProvider provideBrO5Error - */ - public function brO5_error(?float $invoicedItemVatRate): void - { - $this->expectException(\Exception::class); - - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, $invoicedItemVatRate); - } - - public static function provideBrO5Error(): \Generator - { - yield 'BR-O-5 Error #1' => [ - 'invoicedItemVatRate' => 10, - ]; - yield 'BR-O-5 Error #2' => [ - 'invoicedItemVatRate' => -10, - ]; - yield 'BR-O-5 Error #3' => [ - 'invoicedItemVatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-O-6 : A Document level allowance (BG-20) where VAT category code (BT-95) is "Not subject to VAT" - * shall not contain a Document level allowance VAT rate (BT-96). - */ - public function brO6_success(): void - { - $documentLevelAllowance = new DocumentLevelAllowance(1, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, 'Hoobastank'); - - $this->assertInstanceOf(DocumentLevelAllowance::class, $documentLevelAllowance); - } - - /** - * @test - * @testdox BR-O-6 : A Document level allowance (BG-20) where VAT category code (BT-95) is "Not subject to VAT" - * shall not contain a Document level allowance VAT rate (BT-96). - * @dataProvider provideBrO6Error - */ - public function brO6_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelAllowance(1, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrO6Error(): \Generator - { - yield 'BR-O-6 Error #1' => [ - 'vatRate' => 10, - ]; - yield 'BR-O-6 Error #2' => [ - 'vatRate' => -10, - ]; - yield 'BR-O-6 Error #3' => [ - 'vatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-O-7 : A Document level charge (BG-21) where the VAT category code (BT-102) is "Not subject to VAT" - * shall not contain a Document level charge VAT rate (BT-103). - */ - public function brO7_success(): void - { - $documentLevelCharge = new DocumentLevelCharge(1, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, 'Hoobastank'); - - $this->assertInstanceOf(DocumentLevelCharge::class, $documentLevelCharge); - } - - /** - * @test - * @testdox BR-O-7 : A Document level charge (BG-21) where the VAT category code (BT-102) is "Not subject to VAT" - * shall not contain a Document level charge VAT rate (BT-103). - * @dataProvider provideBrO7Error - */ - public function brO7_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelCharge(1, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrO7Error(): \Generator - { - yield 'BR-O-7 Error #1' => [ - 'vatRate' => 10, - ]; - yield 'BR-O-7 Error #2' => [ - 'vatRate' => -10, - ]; - yield 'BR-O-7 Error #3' => [ - 'vatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-O-8 : In a VAT breakdown (BG-23) where the VAT category code (BT-118) is " Not subject to VAT" the - * VAT category taxable amount (BT-116) shall equal the sum of Invoice line net amounts (BT-131) minus the sum of - * Document level allowance amounts (BT-92) plus the sum of Document level charge amounts (BT-99) where the VAT - * category codes (BT-151, BT-95, BT-102) are “Not subject to VAT". - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrO8Success - */ - public function brO8_success( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void - { - $invoice = new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrO8Success(): \Generator - { - yield "single invoice line" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, vatExemptionReasonText: 'Hoobastank') - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "multiple invoice lines" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, vatExemptionReasonText: 'Hoobastank') - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "single allowance" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -100, - -100, - invoiceTotalVatAmount: 0, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, 'Hoobastank') - ], - 'charges' => [], - ]; - - yield "multiple allowances" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -100, - -100, - invoiceTotalVatAmount: 0, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, 'Hoobastank'), - new DocumentLevelAllowance(60, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, 'Hoobastank') - ], - 'charges' => [], - ]; - - yield "single charge" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 100, - 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, 'Hoobastank'), - ], - ]; - - yield "multiple charges" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 100, - 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, 'Hoobastank'), - new DocumentLevelCharge(60, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, 'Hoobastank'), - ], - ]; - - yield "lines, allowances and charges" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, 'Hoobastank'), - new DocumentLevelAllowance(60, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, 'Hoobastank') - ], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, 'Hoobastank'), - new DocumentLevelCharge(60, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, 'Hoobastank'), - ], - ]; - } - - /** - * @test - * @testdox BR-O-8 : In a VAT breakdown (BG-23) where the VAT category code (BT-118) is " Not subject to VAT" the - * VAT category taxable amount (BT-116) shall equal the sum of Invoice line net amounts (BT-131) minus the sum of - * Document level allowance amounts (BT-92) plus the sum of Document level charge amounts (BT-99) where the VAT - * category codes (BT-151, BT-95, BT-102) are “Not subject to VAT". - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrO8Error - */ - public function brO8_error( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges - ); - } - - public static function provideBrO8Error(): \Generator - { - yield "errored taxable amount" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 110, - 110, - invoiceTotalVatAmount: 10, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(50, 10, VatCategory::STANDARD_RATE, 20), - new VatBreakdown(50, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, vatExemptionReasonText: 'Hoobastank'), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, 'Hoobastank'), - ], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, 'Hoobastank'), - ], - ]; - } - - /** - * @test - * @testdox BR-O-9 : The VAT category tax amount (BT-117) in a VAT breakdown (BG-23) where the VAT category code - * (BT-118) is “Not subject to VAT” shall be 0 (zero). - */ - public function brO9_success(): void - { - $vatBreakdown = new VatBreakdown(1000, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, vatExemptionReasonText: 'Hoobastank'); - - $this->assertInstanceOf(VatBreakdown::class, $vatBreakdown); - } - - /** - * @test - * @testdox BR-O-9 : The VAT category tax amount (BT-117) in a VAT breakdown (BG-23) where the VAT category code - * (BT-118) is “Not subject to VAT” shall be 0 (zero). - * @dataProvider provideBrO9Error - */ - public function brO9_error(float $vatCategoryTaxAmount): void - { - $this->expectException(\Exception::class); - - new VatBreakdown(1000, $vatCategoryTaxAmount, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX); - } - - public static function provideBrO9Error(): \Generator - { - yield 'BR-O-9 Error #1' => [ - 'vatCategoryTaxAmount' => 10, - ]; - yield 'BR-O-9 Error #2' => [ - 'vatCategoryTaxAmount' => -10, - ]; - } - - /** - * @test - * @testdox BR-O-10 : An Invoice that contains a VAT breakdown group (BG-23) with a VAT category code (BT118) - * "Not subject to VAT" shall not contain other VAT breakdown groups (BG-23). - * @dataProvider provideBrO10Success - */ - public function brO10_success(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $vatBreakdown = new VatBreakdown(0, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, null, $reasonText, $reasonCode); - - $this->assertInstanceOf(VatBreakdown::class, $vatBreakdown); - } - - public static function provideBrO10Success(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => VatExemptionReasonCode::NOT_SUBJECT_TO_VAT, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => null, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => VatExemptionReasonCode::NOT_SUBJECT_TO_VAT, - ]; - } - - /** - * @test - * @testdox BR-O-10 : An Invoice that contains a VAT breakdown group (BG-23) with a VAT category code (BT118) - * "Not subject to VAT" shall not contain other VAT breakdown groups (BG-23). - * @dataProvider provideBrO10Error - */ - public function brO10_error(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $this->expectException(\Exception::class); - - new VatBreakdown(0, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, null, $reasonText, $reasonCode); - } - - public static function provideBrO10Error(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => null - ]; - } - - /** - * @test - * @testdox BR-O-11 : - */ - public function brO11_success(): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956454'), - ), - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, null, vatExemptionReasonText: 'Hoobastank') - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - /** - * @test - * @testdox BR-O-11 : - */ - public function brO11_error(): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - new Buyer( - 'Richard Roe', - new BuyerPostalAddress(CountryAlpha2Code::FRANCE), - new VatIdentifier('FR956454'), - ), - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX, null, vatExemptionReasonText: 'Hoobastank'), - new VatBreakdown(3000, 0, VatCategory::EXEMPT_FROM_TAX, 0, vatExemptionReasonText: 'Hoobastank'), - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::SERVICE_OUTSIDE_SCOPE_OF_TAX), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - ); - } -} diff --git a/tests/BusinessRulesVatRulesBRSTest.php b/tests/BusinessRulesVatRulesBRSTest.php deleted file mode 100644 index 8f359d4..0000000 --- a/tests/BusinessRulesVatRulesBRSTest.php +++ /dev/null @@ -1,1444 +0,0 @@ - $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brS1_success(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrS1Success(): \Generator - { - yield 'BR-S-1 Success #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("A2"), - 1, - UnitOfMeasurement::BOX_REC21, - 2000, - new PriceDetails(2000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(3000, 600, VatCategory::STANDARD_RATE, 20) - ], - 'documentTotals' => new DocumentTotals( - 3000, - 3000, - 3600, - 3600, - invoiceTotalVatAmount: 600, - ) - ]; - yield 'BR-S-1 Success #2' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [ - new DocumentLevelAllowance(100, VatCategory::STANDARD_RATE, reasonCode: AllowanceReasonCodeUNTDID5189::STANDARD, vatRate: 20) - ], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(900, 180, VatCategory::STANDARD_RATE, 20) - ], - 'documentTotals' => new DocumentTotals( - 1000, - 900, - 1080, - 1080, - invoiceTotalVatAmount: 180, - sumOfAllowancesOnDocumentLevel: 100, - ) - ]; - yield 'BR-S-1 Success #3' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [ - new DocumentLevelCharge(100, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20) - ], - 'vatBreakdowns' => [ - new VatBreakdown(1100, 220, VatCategory::STANDARD_RATE, 20) - ], - 'documentTotals' => new DocumentTotals( - 1000, - 1100, - 1320, - 1320, - invoiceTotalVatAmount: 220, - sumOfChargesOnDocumentLevel: 100, - ) - ]; - } - - /** - * @test - * @testdox BR-S-1 : An Invoice that contains an Invoice line (BG-25), a Document level allowance (BG-20) or a - * Document level charge (BG-21) where the VAT category code (BT-151, BT-95 or BT102) is “Standard rated” shall - * contain in the VAT breakdown (BG-23) at least one VAT category code (BT-118) equal with "Standard rated". - * @dataProvider provideBrS1Error - * @param array $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brS1_error(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges - ); - } - - public static function provideBrS1Error(): \Generator - { - yield 'BR-S-1 Error #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [], - 'documentTotals' => new DocumentTotals( - 2000, - 2000, - 2400, - 2400, - invoiceTotalVatAmount: 400, - ) - ]; - } - - /** - * @test - * @testdox BR-S-2 : An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code - * (BT-151) is “Standard rated” shall contain the Seller VAT Identifier (BT-31), the Seller tax registration - * identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - * @dataProvider provideBrS2Success - */ - public function brS2_success(Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 3000, - 3000, - 3600, - 3600, - invoiceTotalVatAmount: 600, - ), - [ - new VatBreakdown(3000, 600, VatCategory::STANDARD_RATE, 20) - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrS2Success(): \Generator - { - yield 'BR-S-2 - Only Seller VatIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-S-2 - Only Seller TaxRegistrationIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-S-2 - Only SellerTaxRepresentativeParty field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-S-2 - Seller VatIdentifier and Seller TaxRegistrationIdentifier fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-S-2 - Seller VatIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-S-2 - Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-S-2 - Seller VatIdentifier and Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR986416485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-S-2 : An Invoice that contains an Invoice line (BG-25) where the Invoiced item VAT category code - * (BT-151) is “Standard rated” shall contain the Seller VAT Identifier (BT-31), the Seller tax registration - * identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - */ - public function brS2_error(): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 3000, - 3000, - 3600, - 3600, - invoiceTotalVatAmount: 600, - ), - [ - new VatBreakdown(3000, 600, VatCategory::STANDARD_RATE, 20) - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - sellerTaxRepresentativeParty: null - ); - } - - /** - * @test - * @testdox BR-S-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “Standard rated” shall contain the Seller VAT Identifier (BT-31), the Seller tax - * registration identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - * @dataProvider provideBrS3Success - */ - public function brS3_success(Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 3000, - 2900, - 3480, - 3480, - invoiceTotalVatAmount: 580, - sumOfAllowancesOnDocumentLevel: 100, - ), - [ - new VatBreakdown(2900, 580, VatCategory::STANDARD_RATE, 20) - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [ - new DocumentLevelAllowance(100, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20), - ], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrS3Success(): \Generator - { - yield 'BR-S-3 - Only Seller VatIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-S-3 - Only Seller TaxRegistrationIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-S-3 - Only SellerTaxRepresentativeParty field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-S-3 - Seller VatIdentifier and Seller TaxRegistrationIdentifier fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-S-3 - Seller VatIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-S-3 - Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-S-3 - Seller VatIdentifier and Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR986416485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-S-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “Standard rated” shall contain the Seller VAT Identifier (BT-31), the Seller tax - * registration identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - */ - public function brS3_error(): void - { - $this->markTestSkipped('Same error case as BR-S-2 that\'s why BR-S-2 exception is thrown before BR-S-3 exception'); - } - - /** - * @test - * @testdox BR-S-4 : An Invoice that contains a Document level charge (BG-21) where the Document level charge VAT - * category code (BT-102) is “Standard rated” shall contain the Seller VAT Identifier (BT-31), the Seller tax - * registration identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - * @dataProvider provideBrS4Success - */ - public function brS4_success(Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 3000, - 3100, - 3720, - 3720, - invoiceTotalVatAmount: 620, - sumOfChargesOnDocumentLevel: 100, - ), - [ - new VatBreakdown(3100, 620, VatCategory::STANDARD_RATE, 20) - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [ - new DocumentLevelCharge(100, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20), - ], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrS4Success(): \Generator - { - yield 'BR-S-3 - Only Seller VatIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-S-3 - Only Seller TaxRegistrationIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-S-3 - Only SellerTaxRepresentativeParty field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-S-3 - Seller VatIdentifier and Seller TaxRegistrationIdentifier fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-S-3 - Seller VatIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-S-3 - Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-S-3 - Seller VatIdentifier and Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR986416485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-S-4 : An Invoice that contains a Document level charge (BG-21) where the Document level charge VAT - * category code (BT-102) is “Standard rated” shall contain the Seller VAT Identifier (BT-31), the Seller tax - * registration identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - */ - public function brS4_error(): void - { - $this->markTestSkipped('Same error case as BR-S-2 that\'s why BR-S-2 exception is thrown before BR-S-4 exception'); - } - - /** - * @test - * @testdox BR-S-5 : In an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151) is - * "Standard rated" the Invoiced item VAT rate (BT-152) shall be greater than zero. - * @dataProvider provideBrS5Success - */ - public function brS5_success(?float $invoicedItemVatRate): void - { - $lineVatInformation = new LineVatInformation(VatCategory::STANDARD_RATE, $invoicedItemVatRate); - - $this->assertInstanceOf(LineVatInformation::class, $lineVatInformation); - } - - public static function provideBrS5Success(): \Generator - { - yield 'BR-S-5 Success #1' => [ - 'invoicedItemVatRate' => 10, - ]; - } - - /** - * @test - * @testdox BR-S-5 : In an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151) is - * "Standard rated" the Invoiced item VAT rate (BT-152) shall be greater than zero. - * @dataProvider provideBrS5Error - */ - public function brS5_error(?float $invoicedItemVatRate): void - { - $this->expectException(\Exception::class); - - new LineVatInformation(VatCategory::STANDARD_RATE, $invoicedItemVatRate); - } - - public static function provideBrS5Error(): \Generator - { - yield 'BR-S-5 Error #1' => [ - 'invoicedItemVatRate' => 0, - ]; - yield 'BR-S-5 Error #2' => [ - 'invoicedItemVatRate' => -10, - ]; - yield 'BR-S-5 Error #3' => [ - 'invoicedItemVatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-S-6 : In a Document level allowance (BG-20) where the Document level allowance VAT category code - * (BT-95) is "Standard rated" the Document level allowance VAT rate (BT96) shall be greater than zero. - * @dataProvider provideBrS6Success - */ - public function brS6_success(?float $vatRate): void - { - $documentLevelAllowance = new DocumentLevelAllowance(1, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: $vatRate); - - $this->assertInstanceOf(DocumentLevelAllowance::class, $documentLevelAllowance); - } - - public static function provideBrS6Success(): \Generator - { - yield 'BR-S-6 Success #1' => [ - 'vatRate' => 10, - ]; - } - - /** - * @test - * @testdox BR-S-6 : In a Document level allowance (BG-20) where the Document level allowance VAT category code - * (BT-95) is "Standard rated" the Document level allowance VAT rate (BT96) shall be greater than zero. - * @dataProvider provideBrS6Error - */ - public function brS6_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelAllowance(1, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrS6Error(): \Generator - { - yield 'BR-S-6 Error #1' => [ - 'vatRate' => 0, - ]; - yield 'BR-S-6 Error #2' => [ - 'vatRate' => -10, - ]; - yield 'BR-S-6 Error #3' => [ - 'vatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-S-7 : In a Document level charge (BG-21) where the Document level charge VAT category code (BT-102) - * is "Standard rated" the Document level charge VAT rate (BT-103) shall be greater than zero. - * @dataProvider provideBrS7Success - */ - public function brS7_success(?float $vatRate): void - { - $documentLevelCharge = new DocumentLevelCharge(1, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: $vatRate); - - $this->assertInstanceOf(DocumentLevelCharge::class, $documentLevelCharge); - } - - public static function provideBrS7Success(): \Generator - { - yield 'BR-S-7 Success #1' => [ - 'vatRate' => 10, - ]; - } - - /** - * @test - * @testdox BR-S-7 : In a Document level charge (BG-21) where the Document level charge VAT category code (BT-102) - * is "Standard rated" the Document level charge VAT rate (BT-103) shall be greater than zero. - * @dataProvider provideBrS7Error - */ - public function brS7_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelCharge(1, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrS7Error(): \Generator - { - yield 'BR-S-7 Error #1' => [ - 'vatRate' => 0, - ]; - yield 'BR-S-7 Error #2' => [ - 'vatRate' => -10, - ]; - yield 'BR-S-7 Error #3' => [ - 'vatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-S-8 : For each different value of VAT category rate (BT-119) where the VAT category code (BT-118) is - * "Standard rated", the VAT category taxable amount (BT-116) in a VAT breakdown (BG-23) shall equal the sum of - * Invoice line net amounts (BT-131) plus the sum of document level charge amounts (BT-99) minus the sum of - * document level allowance amounts (BT-92) where the VAT category code (BT-151, BT-102, BT-95) is "Standard rated" - * and the VAT rate (BT-152, BT-103, BT-96) equals the VAT category rate (BT-119). - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrS8Success - */ - public function brS8_success( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void { - $invoice = new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrS8Success(): \Generator - { - yield "single invoice line" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 120, - 120, - invoiceTotalVatAmount: 20 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20) - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "multiple invoice lines w/ same rate" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 120, - 120, - invoiceTotalVatAmount: 20 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20) - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "multiple invoice lines w/ different rates" => [ - 'totals' => new DocumentTotals( - 200, - 200, - 230, - 230, - invoiceTotalVatAmount: 30 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20), - new VatBreakdown(100, 10, VatCategory::STANDARD_RATE, 10) - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::STANDARD_RATE, 10), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "single allowance" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -120, - -120, - invoiceTotalVatAmount: -20, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, -20, VatCategory::STANDARD_RATE, 20), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20) - ], - 'charges' => [], - ]; - - yield "multiple allowances" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -120, - -120, - invoiceTotalVatAmount: -20, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, -20, VatCategory::STANDARD_RATE, 20), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20), - new DocumentLevelAllowance(60, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20) - ], - 'charges' => [], - ]; - - yield "single charge" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 120, - 120, - invoiceTotalVatAmount: 20, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20), - ], - ]; - - yield "multiple charges" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 120, - 120, - invoiceTotalVatAmount: 20, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20), - new DocumentLevelCharge(60, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20), - ], - ]; - - yield "lines, allowances and charges w/ same rate" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 120, - 120, - invoiceTotalVatAmount: 20, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 20, VatCategory::STANDARD_RATE, 20), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20), - new DocumentLevelAllowance(60, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20) - ], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20), - new DocumentLevelCharge(60, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20), - ], - ]; - - yield "lines, allowances and charges w/ different rates" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 115, - 115, - invoiceTotalVatAmount: 15, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(50, 10, VatCategory::STANDARD_RATE, 20), - new VatBreakdown(50, 5, VatCategory::STANDARD_RATE, 10), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::STANDARD_RATE, 10), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(50, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20), - new DocumentLevelAllowance(50, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 10) - ], - 'charges' => [ - new DocumentLevelCharge(50, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20), - new DocumentLevelCharge(50, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 10), - ], - ]; - } - - /** - * @test - * @testdox BR-S-8 : For each different value of VAT category rate (BT-119) where the VAT category code (BT-118) is - * "Standard rated", the VAT category taxable amount (BT-116) in a VAT breakdown (BG-23) shall equal the sum of - * Invoice line net amounts (BT-131) plus the sum of document level charge amounts (BT-99) minus the sum of - * document level allowance amounts (BT-92) where the VAT category code (BT-151, BT-102, BT-95) is "Standard rated" - * and the VAT rate (BT-152, BT-103, BT-96) equals the VAT category rate (BT-119). - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrS8Error - */ - public function brS8_error( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges - ); - } - - public static function provideBrS8Error(): \Generator - { - yield "errored taxable amount" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 120, - 120, - invoiceTotalVatAmount: 20, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(50, 10, VatCategory::STANDARD_RATE, 20), - new VatBreakdown(100, 10, VatCategory::STANDARD_RATE, 10), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(0), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20), - ], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::STANDARD_RATE, 'Hoobastank', vatRate: 20), - ], - ]; - } - - /** - * @test - * @testdox BR-S-9 : The VAT category tax amount (BT-117) in a VAT breakdown (BG-23) where VAT category code - * (BT-118) is "Standard rated" shall equal the VAT category taxable amount (BT-116) multiplied by the VAT - * category rate (BT-119). - */ - public function brS9(): void - { - $this->assertTrue(true, 'Same as BR-CO-17'); - } - - - /** - * @test - * @testdox BR-S-10 : A VAT Breakdown (BG-23) with VAT Category code (BT-118) "Standard rate" shall not have a VAT - * exemption reason code (BT-121) or VAT exemption reason text (BT-120). - * @dataProvider provideBrS10Success - */ - public function brS10_success(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $vatBreakdown = new VatBreakdown(0, 0, VatCategory::STANDARD_RATE, 0, $reasonText, $reasonCode); - - $this->assertInstanceOf(VatBreakdown::class, $vatBreakdown); - } - - public static function provideBrS10Success(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => null - ]; - } - - /** - * @test - * @testdox BR-S-10 : A VAT Breakdown (BG-23) with VAT Category code (BT-118) "Standard rate" shall not have a VAT - * exemption reason code (BT-121) or VAT exemption reason text (BT-120). - * @dataProvider provideBrS10Error - */ - public function brS10_error(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $this->expectException(\Exception::class); - - new VatBreakdown(0, 0, VatCategory::STANDARD_RATE, 0, $reasonText, $reasonCode); - } - - public static function provideBrS10Error(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => VatExemptionReasonCode::TRAVEL_AGENTS_VAT_SCHEME, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => null, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => VatExemptionReasonCode::TRAVEL_AGENTS_VAT_SCHEME, - ]; - } - - -} diff --git a/tests/BusinessRulesVatRulesBRZTest.php b/tests/BusinessRulesVatRulesBRZTest.php deleted file mode 100644 index 15bc767..0000000 --- a/tests/BusinessRulesVatRulesBRZTest.php +++ /dev/null @@ -1,1170 +0,0 @@ - $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brZ1_success(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrZ1Success(): \Generator - { - yield 'BR-Z-1 Success #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::ZERO_RATED_GOODS, 0), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(1000, 200, VatCategory::STANDARD_RATE, 20), - new VatBreakdown(1000, 0, VatCategory::ZERO_RATED_GOODS, 0) - ], - 'documentTotals' => new DocumentTotals( - 2000, - 2000, - 2200, - 2200, - invoiceTotalVatAmount: 200, - ) - ]; - } - - /** - * @test - * @testdox BR-Z-1 : An Invoice that contains an Invoice line (BG-25), a Document level allowance (BG-20) or a - * Document level charge (BG-21) where the VAT category code (BT-151, BT-95 or BT102) is “Zero rated” shall contain - * in the VAT breakdown (BG-23) exactly one VAT category code (BT-118) equal with "Zero rated". - * @dataProvider provideBrZ1Error - * @param array $invoiceLines - * @param array $documentLevelAllowances - * @param array $documentLevelCharges - * @param array $vatBreakdowns - */ - public function brZ1_error(array $invoiceLines, array $documentLevelAllowances, array $documentLevelCharges, array $vatBreakdowns, DocumentTotals $documentTotal): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $documentTotal, - $vatBreakdowns, - $invoiceLines, - null, - null, - new \DateTimeImmutable(), - null, - $documentLevelAllowances, - $documentLevelCharges - ); - } - - public static function provideBrZ1Error(): \Generator - { - yield 'BR-Z-1 Error #1' => [ - 'invoiceLines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::STANDARD_RATE, 20), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 1000, - new PriceDetails(1000), - new LineVatInformation(VatCategory::ZERO_RATED_GOODS, 0), - new ItemInformation("A thing"), - ), - ], - 'documentLevelAllowances' => [], - 'documentLevelCharges' => [], - 'vatBreakdowns' => [ - new VatBreakdown(2000, 400, VatCategory::STANDARD_RATE, 20) - ], - 'documentTotals' => new DocumentTotals( - 2000, - 2000, - 2400, - 2400, - invoiceTotalVatAmount: 400, - ) - ]; - } - - /** - * @test - * @testdox BR-Z-2 : An Invoice that contains an Invoice line where the Invoiced item VAT category code (BT151) is - * “Zero rated” shall contain the Seller VAT Identifier (BT-31), the Seller tax registration identifier (BT-32) - * and/or the Seller tax representative VAT identifier (BT63). - * @dataProvider provideBrZ2Success - */ - public function brZ2_success(Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::ZERO_RATED_GOODS, 0), - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::ZERO_RATED_GOODS, 0), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrZ2Success(): \Generator - { - yield 'BR-Z-2 - Only Seller VatIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-Z-2 - Only Seller TaxRegistrationIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-Z-2 - Only SellerTaxRepresentativeParty field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-Z-2 - Seller VatIdentifier and Seller TaxRegistrationIdentifier fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-Z-2 - Seller VatIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-Z-2 - Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-Z-2 - Seller VatIdentifier and Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR986416485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-Z-2 : An Invoice that contains an Invoice line where the Invoiced item VAT category code (BT151) is - * “Zero rated” shall contain the Seller VAT Identifier (BT-31), the Seller tax registration identifier (BT-32) - * and/or the Seller tax representative VAT identifier (BT63). - */ - public function brZ2_error(): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::ZERO_RATED_GOODS, 0), - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::ZERO_RATED_GOODS, 0), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [], - [], - sellerTaxRepresentativeParty: null - ); - } - - /** - * @test - * @testdox BR-Z-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “Zero rated” shall contain the Seller VAT Identifier (BT-31), the Seller tax - * registration identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - * @dataProvider provideBrZ3Success - */ - public function brZ3_success(Seller $seller, ?SellerTaxRepresentativeParty $sellerTaxRepresentativeParty): void - { - $invoice = new Invoice( - new InvoiceIdentifier('34'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - $seller, - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - new DocumentTotals( - 3000, - 3000, - 3000, - 3000, - invoiceTotalVatAmount: 0, - ), - [ - new VatBreakdown(3000, 0, VatCategory::ZERO_RATED_GOODS, 0), - ], - [ - new InvoiceLine( - new InvoiceLineIdentifier("A1"), - 1, - UnitOfMeasurement::BOX_REC21, - 3000, - new PriceDetails(3000), - new LineVatInformation(VatCategory::ZERO_RATED_GOODS, 0), - new ItemInformation("A thing"), - ) - ], - null, - null, - new \DateTimeImmutable(), - null, - [ - new DocumentLevelAllowance(0, VatCategory::ZERO_RATED_GOODS, 'Hoobastank', vatRate: 0), - ], - [], - sellerTaxRepresentativeParty: $sellerTaxRepresentativeParty - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrZ3Success(): \Generator - { - yield 'BR-Z-3 - Only Seller VatIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-Z-3 - Only Seller TaxRegistrationIdentifier field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-Z-3 - Only SellerTaxRepresentativeParty field' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-Z-3 - Seller VatIdentifier and Seller TaxRegistrationIdentifier fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => null - ]; - - yield 'BR-Z-3 - Seller VatIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-Z-3 - Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - - yield 'BR-Z-3 - Seller VatIdentifier and Seller TaxRegistrationIdentifier and SellerTaxRepresentativeParty fields' => [ - 'seller' => new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR986416485'), - new TaxRegistrationIdentifier('FR995464564') - ), - 'sellerTaxRepresentativeParty' => new SellerTaxRepresentativeParty( - 'SellerTaxRepresentativeParty', - new VatIdentifier('FR986416485'), - new SellerTaxRepresentativePostalAddress(CountryAlpha2Code::FRANCE) - ) - ]; - } - - /** - * @test - * @testdox BR-Z-3 : An Invoice that contains a Document level allowance (BG-20) where the Document level allowance - * VAT category code (BT-95) is “Zero rated” shall contain the Seller VAT Identifier (BT-31), the Seller tax - * registration identifier (BT-32) and/or the Seller tax representative VAT identifier (BT-63). - */ - public function brZ3_error(): void - { - $this->markTestSkipped('Same error case as BR-Z-2 that\'s why BR-Z-2 exception is thrown before BR-Z-3 exception'); - } - - /** - * @test - * @testdox BR-Z-5 : In an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151) is "Zero rated" - * the Invoiced item VAT rate (BT-152) shall be 0 (zero). - * @dataProvider provideBrZ5Success - */ - public function brZ5_success(?float $invoicedItemVatRate): void - { - $lineVatInformation = new LineVatInformation(VatCategory::ZERO_RATED_GOODS, $invoicedItemVatRate); - - $this->assertInstanceOf(LineVatInformation::class, $lineVatInformation); - } - - public static function provideBrZ5Success(): \Generator - { - yield 'BR-Z-5 Success #1' => [ - 'invoicedItemVatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-Z-5 : In an Invoice line (BG-25) where the Invoiced item VAT category code (BT-151) is "Zero rated" - * the Invoiced item VAT rate (BT-152) shall be 0 (zero). - * @dataProvider provideBrZ5Error - */ - public function brZ5_error(?float $invoicedItemVatRate): void - { - $this->expectException(\Exception::class); - - new LineVatInformation(VatCategory::ZERO_RATED_GOODS, $invoicedItemVatRate); - } - - public static function provideBrZ5Error(): \Generator - { - yield 'BR-Z-5 Error #1' => [ - 'invoicedItemVatRate' => 10, - ]; - yield 'BR-Z-5 Error #2' => [ - 'invoicedItemVatRate' => -10, - ]; - yield 'BR-Z-5 Error #3' => [ - 'invoicedItemVatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-Z-6 : In a Document level allowance (BG-20) where the Document level allowance VAT category code - * (BT-95) is "Zero rated" the Document level allowance VAT rate (BT-96) shall be 0 (zero). - * @dataProvider provideBrZ6Success - */ - public function brZ6_success(?float $vatRate): void - { - $documentLevelAllowance = new DocumentLevelAllowance(1, VatCategory::ZERO_RATED_GOODS, 'Hoobastank', vatRate: $vatRate); - - $this->assertInstanceOf(DocumentLevelAllowance::class, $documentLevelAllowance); - } - - public static function provideBrZ6Success(): \Generator - { - yield 'BR-Z-6 Success #1' => [ - 'vatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-Z-6 : In a Document level allowance (BG-20) where the Document level allowance VAT category code - * (BT-95) is "Zero rated" the Document level allowance VAT rate (BT-96) shall be 0 (zero). - * @dataProvider provideBrZ6Error - */ - public function brZ6_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelAllowance(1, VatCategory::ZERO_RATED_GOODS, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrZ6Error(): \Generator - { - yield 'BR-Z-6 Error #1' => [ - 'vatRate' => 10, - ]; - yield 'BR-Z-6 Error #2' => [ - 'vatRate' => -10, - ]; - yield 'BR-Z-6 Error #3' => [ - 'vatRate' => null, - ]; - } - - - /** - * @test - * @testdox BR-Z-7 : In a Document level charge (BG-21) where the Document level charge VAT category code (BT-102) - * is "Zero rated" the Document level charge VAT rate (BT-103) shall be 0 (zero). - * @dataProvider provideBrZ7Success - */ - public function brZ7_success(?float $vatRate): void - { - $documentLevelCharge = new DocumentLevelCharge(1, VatCategory::ZERO_RATED_GOODS, 'Hoobastank', vatRate: $vatRate); - - $this->assertInstanceOf(DocumentLevelCharge::class, $documentLevelCharge); - } - - public static function provideBrZ7Success(): \Generator - { - yield 'BR-Z-7 Success #1' => [ - 'vatRate' => 0, - ]; - } - - /** - * @test - * @testdox BR-Z-7 : In a Document level charge (BG-21) where the Document level charge VAT category code (BT-102) - * is "Zero rated" the Document level charge VAT rate (BT-103) shall be 0 (zero). - * @dataProvider provideBrZ7Error - */ - public function brZ7_error(?float $vatRate): void - { - $this->expectException(\Exception::class); - - new DocumentLevelCharge(1, VatCategory::ZERO_RATED_GOODS, 'Hoobastank', vatRate: $vatRate); - } - - public static function provideBrZ7Error(): \Generator - { - yield 'BR-Z-7 Error #1' => [ - 'vatRate' => 10, - ]; - yield 'BR-Z-7 Error #2' => [ - 'vatRate' => -10, - ]; - yield 'BR-Z-7 Error #3' => [ - 'vatRate' => null, - ]; - } - - /** - * @test - * @testdox BR-Z-8 : In a VAT breakdown (BG-23) where VAT category code (BT-118) is "Zero rated" the VAT - * category taxable amount (BT-116) shall equal the sum of Invoice line net amount (BT131) minus the sum of - * Document level allowance amounts (BT-92) plus the sum of Document level charge amounts (BT-99) - * where the VAT category codes (BT-151, BT-95, BT-102) are “Zero rated". - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrZ8Success - */ - public function brZ8_success( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void { - $invoice = new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - new VatIdentifier('FR978515485'), - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges - ); - - $this->assertInstanceOf(Invoice::class, $invoice); - } - - public static function provideBrZ8Success(): \Generator - { - yield "single invoice line" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::ZERO_RATED_GOODS, 0) - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 100, - new PriceDetails(100), - new LineVatInformation(VatCategory::ZERO_RATED_GOODS, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "multiple invoice lines" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::ZERO_RATED_GOODS, 0) - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::ZERO_RATED_GOODS, 0), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(50), - new LineVatInformation(VatCategory::ZERO_RATED_GOODS, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [], - ]; - - yield "single allowance" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -100, - -100, - invoiceTotalVatAmount: 0, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, 0, VatCategory::ZERO_RATED_GOODS, 0), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::ZERO_RATED_GOODS, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::ZERO_RATED_GOODS, 'Hoobastank', vatRate: 0) - ], - 'charges' => [], - ]; - - yield "multiple allowances" => [ - 'totals' => new DocumentTotals( - 0, - -100, - -100, - -100, - invoiceTotalVatAmount: 0, - sumOfAllowancesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(-100, 0, VatCategory::ZERO_RATED_GOODS, 0), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::ZERO_RATED_GOODS, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::ZERO_RATED_GOODS, 'Hoobastank', vatRate: 0), - new DocumentLevelAllowance(60, VatCategory::ZERO_RATED_GOODS, 'Hoobastank', vatRate: 0) - ], - 'charges' => [], - ]; - - yield "single charge" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 100, - 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::ZERO_RATED_GOODS, 0), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::ZERO_RATED_GOODS, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::ZERO_RATED_GOODS, 'Hoobastank', vatRate: 0), - ], - ]; - - yield "multiple charges" => [ - 'totals' => new DocumentTotals( - 0, - 100, - 100, - 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::ZERO_RATED_GOODS, 0), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 0, - new PriceDetails(0), - new LineVatInformation(VatCategory::ZERO_RATED_GOODS, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::ZERO_RATED_GOODS, 'Hoobastank', vatRate: 0), - new DocumentLevelCharge(60, VatCategory::ZERO_RATED_GOODS, 'Hoobastank', vatRate: 0), - ], - ]; - - yield "lines, allowances and charges" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 100, - 100, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(100, 0, VatCategory::ZERO_RATED_GOODS, 0), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::ZERO_RATED_GOODS, 0), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::ZERO_RATED_GOODS, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(40, VatCategory::ZERO_RATED_GOODS, 'Hoobastank', vatRate: 0), - new DocumentLevelAllowance(60, VatCategory::ZERO_RATED_GOODS, 'Hoobastank', vatRate: 0) - ], - 'charges' => [ - new DocumentLevelCharge(40, VatCategory::ZERO_RATED_GOODS, 'Hoobastank', vatRate: 0), - new DocumentLevelCharge(60, VatCategory::ZERO_RATED_GOODS, 'Hoobastank', vatRate: 0), - ], - ]; - } - - /** - * @test - * @testdox BR-Z-8 : In a VAT breakdown (BG-23) where VAT category code (BT-118) is "Zero rated" the VAT - * category taxable amount (BT-116) shall equal the sum of Invoice line net amount (BT131) minus the sum of - * Document level allowance amounts (BT-92) plus the sum of Document level charge amounts (BT-99) - * where the VAT category codes (BT-151, BT-95, BT-102) are “Zero rated". - * - * @param array $vatBreakdowns - * @param array $lines - * @param array $allowances - * @param array $charges - * - * @dataProvider provideBrZ8Error - */ - public function brZ8_error( - DocumentTotals $totals, - array $vatBreakdowns, - array $lines, - array $allowances, - array $charges, - ): void - { - $this->expectException(\Exception::class); - - new Invoice( - new InvoiceIdentifier('1'), - new \DateTimeImmutable(), - InvoiceTypeCode::COMMERCIAL_INVOICE, - CurrencyCode::EURO, - (new ProcessControl(new SpecificationIdentifier(SpecificationIdentifier::BASIC))) - ->setBusinessProcessType('A1'), - new Seller( - 'John Doe', - new SellerPostalAddress(CountryAlpha2Code::FRANCE), - [new SellerIdentifier('10000000900017', InternationalCodeDesignator::SIRET_CODE)], - null, - null, - ), - new Buyer('Richard Roe', new BuyerPostalAddress(CountryAlpha2Code::FRANCE)), - null, - $totals, - $vatBreakdowns, - $lines, - null, - null, - new \DateTimeImmutable(), - null, - $allowances, - $charges - ); - } - - public static function provideBrZ8Error(): \Generator - { - yield "errored taxable amount" => [ - 'totals' => new DocumentTotals( - 100, - 100, - 110, - 110, - invoiceTotalVatAmount: 10, - sumOfAllowancesOnDocumentLevel: 100, - sumOfChargesOnDocumentLevel: 100 - ), - 'vatBreakdowns' => [ - new VatBreakdown(50, 10, VatCategory::STANDARD_RATE, 20), - new VatBreakdown(50, 0, VatCategory::ZERO_RATED_GOODS, 0), - ], - 'lines' => [ - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::ZERO_RATED_GOODS, 0), - new ItemInformation("A thing"), - ), - new InvoiceLine( - new InvoiceLineIdentifier("1"), - 1, - UnitOfMeasurement::BOX_REC21, - 50, - new PriceDetails(0), - new LineVatInformation(VatCategory::ZERO_RATED_GOODS, 0), - new ItemInformation("A thing"), - ) - ], - 'allowances' => [ - new DocumentLevelAllowance(100, VatCategory::ZERO_RATED_GOODS, 'Hoobastank', vatRate: 0), - ], - 'charges' => [ - new DocumentLevelCharge(100, VatCategory::ZERO_RATED_GOODS, 'Hoobastank', vatRate: 0), - ], - ]; - } - - /** - * @test - * @testdox BR-Z-9 : The VAT category tax amount (BT-117) in a VAT breakdown (BG-23) where VAT category code - * (BT-118) is "Zero rated" shall equal 0 (zero). - */ - public function brZ9_success(): void - { - $vatBreakdown = new VatBreakdown(1000, 0, VatCategory::ZERO_RATED_GOODS, 0); - - $this->assertInstanceOf(VatBreakdown::class, $vatBreakdown); - } - - /** - * @test - * @testdox BR-Z-9 : The VAT category tax amount (BT-117) in a VAT breakdown (BG-23) where VAT category code - * (BT-118) is "Zero rated" shall equal 0 (zero). - * @dataProvider provideBrZ9Error - */ - public function brZ9_error(float $vatCategoryTaxAmount): void - { - $this->expectException(\Exception::class); - - new VatBreakdown(1000, $vatCategoryTaxAmount, VatCategory::ZERO_RATED_GOODS, 0); - } - - public static function provideBrZ9Error(): \Generator - { - yield 'BR-Z-9 Error #1' => [ - 'vatCategoryTaxAmount' => 10, - ]; - yield 'BR-Z-9 Error #2' => [ - 'vatCategoryTaxAmount' => -10, - ]; - } - - - /** - * @test - * @testdox BR-Z-10 : A VAT Breakdown (BG-23) with VAT Category code (BT-118) "Zero rated" shall not have a VAT - * exemption reason code (BT-121) or VAT exemption reason text (BT-120). - * @dataProvider provideBrZ10Success - */ - public function brZ10_success(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $vatBreakdown = new VatBreakdown(0, 0, VatCategory::ZERO_RATED_GOODS, 0, $reasonText, $reasonCode); - - $this->assertInstanceOf(VatBreakdown::class, $vatBreakdown); - } - - public static function provideBrZ10Success(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => null - ]; - } - - /** - * @test - * @testdox BR-Z-10 : A VAT Breakdown (BG-23) with VAT Category code (BT-118) "Zero rated" shall not have a VAT - * exemption reason code (BT-121) or VAT exemption reason text (BT-120). - * @dataProvider provideBrZ10Error - */ - public function brZ10_error(?string $reasonText, ?VatExemptionReasonCode $reasonCode): void - { - $this->expectException(\Exception::class); - - new VatBreakdown(0, 0, VatCategory::ZERO_RATED_GOODS, 0, $reasonText, $reasonCode); - } - - public static function provideBrZ10Error(): \Generator - { - yield [ - 'reasonText' => null, - 'reasonCode' => VatExemptionReasonCode::TRAVEL_AGENTS_VAT_SCHEME, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => null, - ]; - - yield [ - 'reasonText' => 'Hoobastank', - 'reasonCode' => VatExemptionReasonCode::TRAVEL_AGENTS_VAT_SCHEME, - ]; - } - -}