From c4393dbf0f234a62d49c4f3de8ac8f52192fc679 Mon Sep 17 00:00:00 2001 From: HorstOeko Date: Wed, 6 Nov 2024 18:31:54 +0100 Subject: [PATCH] Some fixes (Cardinality, etc.) --- src/XmlConverterCiiToUbl.php | 106 +++++++++++++-------- src/XmlConverterUblToCii.php | 114 ++++++++++++++++++++--- tests/testcases/CiiToUblExtendedTest.php | 2 +- 3 files changed, 171 insertions(+), 51 deletions(-) diff --git a/src/XmlConverterCiiToUbl.php b/src/XmlConverterCiiToUbl.php index fd93388..98c786a 100644 --- a/src/XmlConverterCiiToUbl.php +++ b/src/XmlConverterCiiToUbl.php @@ -176,6 +176,7 @@ private function convertGeneral(): void ); $this->destination->elementIf($this->getIsCreditNote(), 'cbc:CreditNoteTypeCode', $this->source->queryValue('./ram:TypeCode', $invoiceExchangeDocument)); + $this->destination->elementIf(!$this->getIsCreditNote(), 'cbc:InvoiceTypeCode', $this->source->queryValue('./ram:TypeCode', $invoiceExchangeDocument)); $this->source->queryAll('./ram:IncludedNote', $invoiceExchangeDocument)->forEach( @@ -844,27 +845,6 @@ function ($sellerTaxRepresentativePartyUniversalCommNode) { } ); - $this->source->whenExists( - './ram:GlobalID', - $sellerTaxRepresentativePartyNode, - function ($sellerTaxRepresentativePartyGlobalIdNode) { - $this->destination->startElement('cac:PartyIdentification'); - $this->destination->elementWithAttribute('cbc:ID', $sellerTaxRepresentativePartyGlobalIdNode->nodeValue, 'schemeID', $sellerTaxRepresentativePartyGlobalIdNode->getAttribute('schemeID')); - $this->destination->endElement(); - }, - function () use ($sellerTaxRepresentativePartyNode) { - $this->source->whenExists( - './ram:ID', - $sellerTaxRepresentativePartyNode, - function ($sellerTaxRepresentativePartyIdNode) { - $this->destination->startElement('cac:PartyIdentification'); - $this->destination->elementWithAttribute('cbc:ID', $sellerTaxRepresentativePartyIdNode->nodeValue, 'schemeID', $sellerTaxRepresentativePartyIdNode->getAttribute('schemeID')); - $this->destination->endElement(); - } - ); - } - ); - $this->source->whenExists( './ram:Name', $sellerTaxRepresentativePartyNode, @@ -933,17 +913,6 @@ function ($sellerTradePartyTaxRegNode) { } ); - $this->source->whenExists( - './ram:DefinedTradeContact', - $sellerTaxRepresentativePartyNode, - function ($sellerTaxRepresentativePartyContactNode) { - $this->destination->startElement('cac:Contact'); - $this->destination->element('cbc:Name', $this->source->queryValue('./ram:PersonName', $sellerTaxRepresentativePartyContactNode)); - $this->destination->element('cbc:Telephone', $this->source->queryValue('./ram:TelephoneUniversalCommunication/ram:CompleteNumber', $sellerTaxRepresentativePartyContactNode)); - $this->destination->element('cbc:ElectronicMail', $this->source->queryValue('./ram:EmailURIUniversalCommunication/ram:URIID', $sellerTaxRepresentativePartyContactNode)); - $this->destination->endElement(); - } - ); $this->destination->endElement(); } ); @@ -965,6 +934,7 @@ private function convertShipToTradeParty(): void $invoiceHeaderDelivery, function ($shipToTradePartyNode) use ($invoiceHeaderDelivery) { $this->destination->startElement('cac:Delivery'); + $this->destination->element( 'cbc:ActualDeliveryDate', $this->convertDateTime( @@ -972,23 +942,35 @@ function ($shipToTradePartyNode) use ($invoiceHeaderDelivery) { $this->source->queryValue('./ram:ActualDeliverySupplyChainEvent/ram:OccurrenceDateTime/udt:DateTimeString/@format', $invoiceHeaderDelivery) ) ); + $this->destination->startElement('cac:DeliveryLocation'); + $this->source->whenExists( - './ram:ID', + './ram:GlobalID', $shipToTradePartyNode, - function ($shipToTradePartyIdNode) use ($invoiceHeaderDelivery) { - $this->destination->startElement('cbc:ID', $shipToTradePartyIdNode->nodeValue); - $this->destination->attribute('schemeID', $this->source->queryValue('./ram:ShipToTradeParty/ram:GlobalID/@schemeID', $invoiceHeaderDelivery)); - $this->destination->endElement(); + function ($shipToTradePartyGlobalIdNode) { + $this->destination->elementWithAttribute('cbc:ID', $shipToTradePartyGlobalIdNode->nodeValue, 'schemeID', $shipToTradePartyGlobalIdNode->getAttribute('schemeID')); + }, + function () use ($shipToTradePartyNode) { + $this->source->whenExists( + './ram:ID', + $shipToTradePartyNode, + function ($shipToTradePartyIdNode) { + $this->destination->elementWithAttribute('cbc:ID', $shipToTradePartyIdNode->nodeValue, 'schemeID', $shipToTradePartyIdNode->getAttribute('schemeID')); + } + ); } ); + $this->source->whenExists( './ram:PostalTradeAddress', $shipToTradePartyNode, function ($shipToTradePartyPostalAddressNode) { $this->destination->startElement('cac:Address'); + $this->destination->element('cbc:StreetName', $this->source->queryValue('./ram:LineOne', $shipToTradePartyPostalAddressNode)); $this->destination->element('cbc:AdditionalStreetName', $this->source->queryValue('./ram:LineTwo', $shipToTradePartyPostalAddressNode)); + $this->source->whenExists( './ram:LineThree', $shipToTradePartyPostalAddressNode, @@ -998,9 +980,11 @@ function ($shipToTradePartyPostalAddressNode) { $this->destination->endElement(); } ); + $this->destination->element('cbc:CityName', $this->source->queryValue('./ram:CityName', $shipToTradePartyPostalAddressNode)); $this->destination->element('cbc:PostalZone', $this->source->queryValue('./ram:PostcodeCode', $shipToTradePartyPostalAddressNode)); $this->destination->element('cbc:CountrySubentity', $this->source->queryValue('./ram:CountrySubDivisionName', $shipToTradePartyPostalAddressNode)); + $this->source->whenExists( './ram:CountryID', $shipToTradePartyPostalAddressNode, @@ -1013,7 +997,9 @@ function ($shipToTradePartyPostalAddressCountryNode) { $this->destination->endElement(); } ); + $this->destination->endElement(); + $this->source->whenExists( './ram:Name', $shipToTradePartyNode, @@ -1025,6 +1011,7 @@ function ($shipToTradePartyNameNode) { $this->destination->endElement(); } ); + $this->destination->endElement(); }, function () use ($invoiceHeaderDelivery) { @@ -1064,6 +1051,7 @@ private function convertPaymentMeans(): void )->forEach( function ($paymentMeansNode) use ($invoiceHeaderSettlement) { $this->destination->startElement('cac:PaymentMeans'); + $this->source->whenExists( './ram:TypeCode', $paymentMeansNode, @@ -1073,7 +1061,9 @@ function ($paymentMeansTypeCodeNode) use ($paymentMeansNode) { $this->destination->endElement(); } ); + $this->destination->element('cbc:PaymentID', $this->source->queryValue('./ram:PaymentReference', $invoiceHeaderSettlement)); + $this->source->whenExists( './ram:ApplicableTradeSettlementFinancialCard', $paymentMeansNode, @@ -1085,6 +1075,7 @@ function ($paymentMeansFinancialCardNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './ram:PayeePartyCreditorFinancialAccount', $paymentMeansNode, @@ -1104,6 +1095,7 @@ function ($paymentMeansCreditorFinancialInstNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './ram:SpecifiedTradePaymentTerms/ram:DirectDebitMandateID', $invoiceHeaderSettlement, @@ -1122,6 +1114,7 @@ function ($paymentMeansDebtorFinancialAccountNode) { $this->destination->endElement(); } ); + $this->destination->endElement(); } ); @@ -1163,12 +1156,14 @@ private function convertDocumentLevelAllowanceCharge(): void $this->source->queryAll('./ram:SpecifiedTradeAllowanceCharge', $invoiceHeaderSettlement)->forEach( function ($tradeAllowanceChargeNode) use ($invoiceHeaderSettlement) { $this->destination->startElement('cac:AllowanceCharge'); + $this->destination->element('cbc:ChargeIndicator', $this->source->queryValue('./ram:ChargeIndicator/udt:Indicator', $tradeAllowanceChargeNode)); $this->destination->element('cbc:AllowanceChargeReasonCode', $this->source->queryValue('./ram:ReasonCode', $tradeAllowanceChargeNode)); $this->destination->element('cbc:AllowanceChargeReason', $this->source->queryValue('./ram:Reason', $tradeAllowanceChargeNode)); $this->destination->element('cbc:MultiplierFactorNumeric', $this->source->queryValue('./ram:CalculationPercent', $tradeAllowanceChargeNode)); $this->destination->elementWithAttribute('cbc:Amount', $this->formatAmount($this->source->queryValue('./ram:ActualAmount', $tradeAllowanceChargeNode)), 'currencyID', $this->source->queryValue('./ram:InvoiceCurrencyCode', $invoiceHeaderSettlement)); $this->destination->elementWithAttribute('cbc:BaseAmount', $this->formatAmount($this->source->queryValue('./ram:BasisAmount', $tradeAllowanceChargeNode)), 'currencyID', $this->source->queryValue('./ram:InvoiceCurrencyCode', $invoiceHeaderSettlement)); + $this->source->whenExists( './ram:CategoryTradeTax', $tradeAllowanceChargeNode, @@ -1182,6 +1177,7 @@ function ($tradeAllowanceChargeTaxNode) { $this->destination->endElement(); } ); + $this->destination->endElement(); } ); @@ -1206,6 +1202,7 @@ private function convertDocumentLevelTax(): void $invoiceHeaderSettlement, function () use ($invoiceHeaderSettlement, $invoiceCurrencyCode, $taxCurrencyCode) { $this->destination->startElement('cac:TaxTotal'); + $this->source->whenExists( sprintf('./ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:TaxTotalAmount[@currencyID=\'%s\']', $invoiceCurrencyCode), $invoiceHeaderSettlement, @@ -1218,9 +1215,11 @@ function ($taxTotalAmountNode) { ); } ); + $this->source->queryAll('./ram:ApplicableTradeTax', $invoiceHeaderSettlement)->forEach( function ($tradeTaxNode) use ($invoiceHeaderSettlement) { $this->destination->startElement('cac:TaxSubtotal'); + $this->destination->elementWithAttribute( 'cbc:TaxableAmount', $this->formatAmount($this->source->queryValue('./ram:BasisAmount', $tradeTaxNode)), @@ -1233,6 +1232,7 @@ function ($tradeTaxNode) use ($invoiceHeaderSettlement) { 'currencyID', $this->source->queryValue('./ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:TaxTotalAmount/@currencyID', $invoiceHeaderSettlement) ); + $this->destination->startElement('cac:TaxCategory'); $this->destination->element('cbc:ID', $this->source->queryValue('./ram:CategoryCode', $tradeTaxNode)); $this->destination->element('cbc:Percent', $this->source->queryValue('./ram:RateApplicablePercent', $tradeTaxNode)); @@ -1242,6 +1242,7 @@ function ($tradeTaxNode) use ($invoiceHeaderSettlement) { $this->destination->element('cbc:ID', $this->source->queryValue('./ram:TypeCode', $tradeTaxNode)); $this->destination->endElement(); $this->destination->endElement(); + $this->destination->endElement(); } ); @@ -1253,12 +1254,14 @@ function ($tradeTaxNode) use ($invoiceHeaderSettlement) { $invoiceHeaderSettlement, function ($taxTotalAmountNode) { $this->destination->startElement('cac:TaxTotal'); + $this->destination->elementWithAttribute( 'cbc:TaxAmount', $this->formatAmount($taxTotalAmountNode->nodeValue), 'currencyID', $taxTotalAmountNode->getAttribute('currencyID') ); + $this->destination->endElement(); } ); @@ -1283,54 +1286,63 @@ private function convertDocumentSummation(): void $invoiceHeaderSettlement, function ($monetarySummationNode) use ($invoiceHeaderSettlement) { $this->destination->startElement('cac:LegalMonetaryTotal'); + $this->destination->elementWithAttribute( 'cbc:LineExtensionAmount', $this->formatAmount($this->source->queryValue('./ram:LineTotalAmount', $monetarySummationNode)), 'currencyID', $this->source->queryValue('./ram:InvoiceCurrencyCode', $invoiceHeaderSettlement) ); + $this->destination->elementWithAttribute( 'cbc:TaxExclusiveAmount', $this->formatAmount($this->source->queryValue('./ram:TaxBasisTotalAmount', $monetarySummationNode)), 'currencyID', $this->source->queryValue('./ram:InvoiceCurrencyCode', $invoiceHeaderSettlement) ); + $this->destination->elementWithAttribute( 'cbc:TaxInclusiveAmount', $this->formatAmount($this->source->queryValue('./ram:GrandTotalAmount', $monetarySummationNode)), 'currencyID', $this->source->queryValue('./ram:InvoiceCurrencyCode', $invoiceHeaderSettlement) ); + $this->destination->elementWithAttribute( 'cbc:AllowanceTotalAmount', $this->formatAmount($this->source->queryValue('./ram:AllowanceTotalAmount', $monetarySummationNode)), 'currencyID', $this->source->queryValue('./ram:InvoiceCurrencyCode', $invoiceHeaderSettlement) ); + $this->destination->elementWithAttribute( 'cbc:ChargeTotalAmount', $this->formatAmount($this->source->queryValue('./ram:ChargeTotalAmount', $monetarySummationNode)), 'currencyID', $this->source->queryValue('./ram:InvoiceCurrencyCode', $invoiceHeaderSettlement) ); + $this->destination->elementWithAttribute( 'cbc:PrepaidAmount', $this->formatAmount($this->source->queryValue('./ram:TotalPrepaidAmount', $monetarySummationNode)), 'currencyID', $this->source->queryValue('./ram:InvoiceCurrencyCode', $invoiceHeaderSettlement) ); + $this->destination->elementWithAttribute( 'cbc:PayableRoundingAmount', $this->formatAmount($this->source->queryValue('./ram:RoundingAmount', $monetarySummationNode)), 'currencyID', $this->source->queryValue('./ram:InvoiceCurrencyCode', $invoiceHeaderSettlement) ); + $this->destination->elementWithAttribute( 'cbc:PayableAmount', $this->formatAmount($this->source->queryValue('./ram:DuePayableAmount', $monetarySummationNode)), 'currencyID', $this->source->queryValue('./ram:InvoiceCurrencyCode', $invoiceHeaderSettlement) ); + $this->destination->endElement(); } ); @@ -1357,21 +1369,26 @@ function () use ($invoiceSuppyChainTradeTransaction, $invoiceHeaderSettlement) { )->forEach( function ($tradeLineItemNode) use ($invoiceHeaderSettlement) { $this->destination->startElement($this->getIsCreditNote() ? 'cac:CreditNoteLine' : 'cac:InvoiceLine'); + $this->destination->element('cbc:ID', $this->source->queryValue('./ram:AssociatedDocumentLineDocument/ram:LineID', $tradeLineItemNode)); $this->destination->element('cbc:Note', $this->source->queryValue('./ram:AssociatedDocumentLineDocument/ram:IncludedNote/ram:Content', $tradeLineItemNode)); + $this->destination->elementWithAttribute( $this->getIsCreditNote() ? 'cbc:CreditedQuantity' : 'cbc:InvoicedQuantity', $this->source->queryValue('./ram:SpecifiedLineTradeDelivery/ram:BilledQuantity', $tradeLineItemNode), 'unitCode', $this->source->queryValue('./ram:SpecifiedLineTradeDelivery/ram:BilledQuantity/@unitCode', $tradeLineItemNode) ); + $this->destination->elementWithAttribute( 'cbc:LineExtensionAmount', $this->formatAmount($this->source->queryValue('./ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeSettlementLineMonetarySummation/ram:LineTotalAmount', $tradeLineItemNode)), 'currencyID', $this->source->queryValue('./ram:InvoiceCurrencyCode', $invoiceHeaderSettlement) ); + $this->destination->element('cbc:AccountingCost', $this->source->queryValue('./ram:SpecifiedLineTradeSettlement/ram:ReceivableSpecifiedTradeAccountingAccount/ram:ID', $tradeLineItemNode)); + $this->source->whenExists( './ram:SpecifiedLineTradeSettlement/ram:BillingSpecifiedPeriod', $tradeLineItemNode, @@ -1394,6 +1411,7 @@ function ($billingSpecifiedPeriodNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './ram:SpecifiedLineTradeAgreement/ram:BuyerOrderReferencedDocument/ram:LineID', $tradeLineItemNode, @@ -1403,6 +1421,7 @@ function ($buyerOrderReferencedDocumentNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './ram:SpecifiedLineTradeSettlement/ram:AdditionalReferencedDocument/ram:IssuerAssignedID', $tradeLineItemNode, @@ -1412,15 +1431,18 @@ function ($additionalReferencedDocumentNode) { $this->destination->endElement(); } ); + $this->source->queryAll('./ram:SpecifiedLineTradeSettlement/ram:SpecifiedTradeAllowanceCharge', $tradeLineItemNode)->forEach( function ($tradeLineItemAllowanceChargeNode) use ($invoiceHeaderSettlement) { $this->destination->startElement('cac:AllowanceCharge'); + $this->destination->element('cbc:ChargeIndicator', $this->source->queryValue('./ram:ChargeIndicator/udt:Indicator', $tradeLineItemAllowanceChargeNode)); $this->destination->element('cbc:AllowanceChargeReasonCode', $this->source->queryValue('./ram:ReasonCode', $tradeLineItemAllowanceChargeNode)); $this->destination->element('cbc:AllowanceChargeReason', $this->source->queryValue('./ram:Reason', $tradeLineItemAllowanceChargeNode)); $this->destination->element('cbc:MultiplierFactorNumeric', $this->source->queryValue('./ram:CalculationPercent', $tradeLineItemAllowanceChargeNode)); $this->destination->elementWithAttribute('cbc:Amount', $this->formatAmount($this->source->queryValue('./ram:ActualAmount', $tradeLineItemAllowanceChargeNode)), 'currencyID', $this->source->queryValue('./ram:InvoiceCurrencyCode', $invoiceHeaderSettlement)); $this->destination->elementWithAttribute('cbc:BaseAmount', $this->formatAmount($this->source->queryValue('./ram:BasisAmount', $tradeLineItemAllowanceChargeNode)), 'currencyID', $this->source->queryValue('./ram:InvoiceCurrencyCode', $invoiceHeaderSettlement)); + $this->source->whenExists( './ram:CategoryTradeTax', $tradeLineItemAllowanceChargeNode, @@ -1434,6 +1456,7 @@ function ($tradeLineItemAllowanceChargeTaxNode) { $this->destination->endElement(); } ); + $this->destination->endElement(); } ); @@ -1442,8 +1465,10 @@ function ($tradeLineItemAllowanceChargeTaxNode) { $tradeLineItemNode, function ($tradeLineItemProductNode) use ($tradeLineItemNode) { $this->destination->startElement('cac:Item'); + $this->destination->element('cbc:Description', $this->source->queryValue('./ram:Description', $tradeLineItemProductNode)); $this->destination->element('cbc:Name', $this->source->queryValue('./ram:Name', $tradeLineItemProductNode)); + $this->source->whenExists( './ram:BuyerAssignedID', $tradeLineItemProductNode, @@ -1453,6 +1478,7 @@ function ($tradeLineItemProductIdNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './ram:SellerAssignedID', $tradeLineItemProductNode, @@ -1462,6 +1488,7 @@ function ($tradeLineItemProductIdNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './ram:GlobalID', $tradeLineItemProductNode, @@ -1471,6 +1498,7 @@ function ($tradeLineItemProductGlobalIdNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './ram:OriginTradeCountry/ram:ID', $tradeLineItemProductNode, @@ -1480,6 +1508,7 @@ function ($tradeLineItemProductOriginTradeCountryNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './ram:DesignatedProductClassification/ram:ClassCode', $tradeLineItemProductNode, @@ -1489,6 +1518,7 @@ function ($tradeLineItemProductClassificationNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './ram:SpecifiedLineTradeSettlement', $tradeLineItemNode, @@ -1508,6 +1538,7 @@ function ($tradeLineItemSettlementTaxNode) { ); } ); + $this->source->whenExists( './ram:SpecifiedTradeProduct', $tradeLineItemNode, @@ -1524,6 +1555,7 @@ function ($tradeLineProductCharacteristicNode) { ); } ); + $this->destination->endElement(); } ); diff --git a/src/XmlConverterUblToCii.php b/src/XmlConverterUblToCii.php index ed93eb3..f0d04ff 100644 --- a/src/XmlConverterUblToCii.php +++ b/src/XmlConverterUblToCii.php @@ -153,6 +153,7 @@ private function convertExchangedDocumentContext(): void $docRootElement = $this->source->query(sprintf('//%s', $this->ublRootName))->item(0); $this->destination->startElement('rsm:ExchangedDocumentContext'); + $this->source->whenExists( './cbc:ProfileID', $docRootElement, @@ -162,6 +163,7 @@ function ($profileIdNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cbc:CustomizationID', $docRootElement, @@ -171,6 +173,7 @@ function ($customizationIdNode) { $this->destination->endElement(); } ); + $this->destination->endElement(); } @@ -184,8 +187,11 @@ private function convertExchangedDocument(): void $docRootElement = $this->source->query(sprintf('//%s', $this->ublRootName))->item(0); $this->destination->startElement('rsm:ExchangedDocument'); + $this->destination->element('ram:ID', $this->source->queryValue('./cbc:ID', $docRootElement)); + $this->destination->element('ram:TypeCode', $this->source->queryValue('./cbc:InvoiceTypeCode', $docRootElement)); + $this->source->whenExists( './cbc:IssueDate', $docRootElement, @@ -195,6 +201,7 @@ function ($issueDateNode) { $this->destination->endElement(); } ); + $this->source->queryAll('./cbc:Note', $docRootElement)->foreach( function ($noteNode) { $splittedNode = explode('#', $noteNode->nodeValue); @@ -206,6 +213,7 @@ function ($noteNode) { } } ); + $this->destination->endElement(); } @@ -238,9 +246,9 @@ private function convertIncludedSupplyChainTradeLineItem(): void $this->source->queryAll(sprintf('./%s', $this->ublLineRootName), $docRootElement)->forEach( function ($invoiceLineNode) { $this->destination->startElement('ram:IncludedSupplyChainTradeLineItem'); - $this->destination->startElement('ram:AssociatedDocumentLineDocument'); $this->destination->element('ram:LineID', $this->source->queryValue('./cbc:ID', $invoiceLineNode)); + $this->source->whenExists( './cbc:Note', $invoiceLineNode, @@ -250,6 +258,7 @@ function ($invoiceLineNoteNode) { $this->destination->endElement(); } ); + $this->destination->endElement(); $this->destination->startElement('ram:SpecifiedTradeProduct'); @@ -258,6 +267,7 @@ function ($invoiceLineNoteNode) { $this->destination->elementWithAttribute('ram:GlobalID', $this->source->queryValue('./cac:Item/cac:StandardItemIdentification/cbc:ID', $invoiceLineNode), 'schemeID', $this->source->queryValue('./cac:Item/cac:StandardItemIdentification/cbc:ID/@schemeID', $invoiceLineNode)); $this->destination->element('ram:Name', $this->source->queryValue('./cac:Item/cbc:Name', $invoiceLineNode)); $this->destination->element('ram:Description', $this->source->queryValue('./cac:Item/cbc:Description', $invoiceLineNode)); + $this->source->queryAll('./cac:Item/cac:CommodityClassification/cbc:ItemClassificationCode', $invoiceLineNode)->forEach( function ($invoiceLineItemClassificationCode) { $this->destination->elementWithMultipleAttributes('ram:ClassCode', $invoiceLineItemClassificationCode->nodeValue, ['listID' => $invoiceLineItemClassificationCode->getAttribute('listID'), 'listVersionID' => $invoiceLineItemClassificationCode->getAttribute('listVersionID')]); @@ -275,6 +285,7 @@ function () { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:Item/cac:OriginCountry/cbc:IdentificationCode', $invoiceLineNode, @@ -284,9 +295,11 @@ function ($invoiceLineOriginCountryNode) { $this->destination->endElement(); } ); + $this->destination->endElement(); $this->destination->startElement('ram:SpecifiedLineTradeAgreement'); + $this->source->whenExists( './cac:OrderLineReference/cbc:LineID', $invoiceLineNode, @@ -501,12 +514,23 @@ function ($invoiceAccountingSupplierPartyTaxSchemeNode) { $docRootElement, function ($invoiceAccountingCustomerPartyNode) { $this->destination->startElement('ram:BuyerTradeParty'); - $this->destination->element('ram:ID', $this->source->queryValue('./cac:PartyIdentification/cbc:ID[not(@schemeID)]', $invoiceAccountingCustomerPartyNode)); - $this->source->queryAll('./cac:PartyIdentification/cbc:ID[@schemeID != \'\' and @schemeID != \'SEPA\']', $invoiceAccountingCustomerPartyNode)->forEach( + + $this->source->whenExists( + './cac:PartyIdentification/cbc:ID[not(@schemeID)]', + $invoiceAccountingCustomerPartyNode, + function ($invoiceAccountingCustomerPartyIdNode) { + $this->destination->element('ram:ID', $invoiceAccountingCustomerPartyIdNode->nodeValue); + } + ); + + $this->source->whenExists( + './cac:PartyIdentification/cbc:ID[@schemeID != \'\' and @schemeID != \'SEPA\']', + $invoiceAccountingCustomerPartyNode, function ($invoiceAccountingCustomerPartyIdNode) { $this->destination->elementWithAttribute('ram:GlobalID', $invoiceAccountingCustomerPartyIdNode->nodeValue, 'schemeID', $invoiceAccountingCustomerPartyIdNode->getAttribute('schemeID')); } ); + $this->source->whenExists( './cac:PartyLegalEntity/cbc:RegistrationName', $invoiceAccountingCustomerPartyNode, @@ -514,6 +538,7 @@ function ($invoiceAccountingCustomerPartyNodeRegNameNode) { $this->destination->element('ram:Name', $invoiceAccountingCustomerPartyNodeRegNameNode->nodeValue); } ); + $this->source->whenExists( './cac:PartyLegalEntity/cbc:CompanyLegalForm', $invoiceAccountingCustomerPartyNode, @@ -521,6 +546,7 @@ function ($invoiceAccountingCustomerPartyLegalEntityNode) { $this->destination->element('ram:Description', $invoiceAccountingCustomerPartyLegalEntityNode->nodeValue); } ); + $this->source->whenOneExists( ['./cac:PartyLegalEntity/cbc:CompanyID', './cac:PartyName/cbc:Name'], [$invoiceAccountingCustomerPartyNode, $invoiceAccountingCustomerPartyNode], @@ -531,6 +557,7 @@ function () use ($invoiceAccountingCustomerPartyNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:Contact', $invoiceAccountingCustomerPartyNode, @@ -558,6 +585,7 @@ function ($invoiceAccountingCustomerPartyContactMailNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:PostalAddress', $invoiceAccountingCustomerPartyNode, @@ -572,6 +600,7 @@ function ($invoiceAccountingCustomerPartyPostalAddressNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cbc:EndpointID[@schemeID=\'EM\']', $invoiceAccountingCustomerPartyNode, @@ -581,6 +610,7 @@ function ($invoiceAccountingCustomerPartyEndpointNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:PartyTaxScheme/cac:TaxScheme/cbc:ID[text() = \'VAT\']', $invoiceAccountingCustomerPartyNode, @@ -590,6 +620,7 @@ function ($invoiceAccountingCustomerPartyTaxSchemeNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:PartyTaxScheme/cac:TaxScheme/cbc:ID[text() = \'TAX\']', $invoiceAccountingCustomerPartyNode, @@ -599,6 +630,7 @@ function ($invoiceAccountingCustomerPartyTaxSchemeNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:PartyTaxScheme/cac:TaxScheme/cbc:ID[text() = \'FC\']', $invoiceAccountingCustomerPartyNode, @@ -608,6 +640,7 @@ function ($invoiceAccountingCustomerPartyTaxSchemeNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:PartyTaxScheme/cac:TaxScheme/cbc:ID[text() = \'???\']', $invoiceAccountingCustomerPartyNode, @@ -617,6 +650,7 @@ function ($invoiceAccountingCustomerPartyTaxSchemeNode) { $this->destination->endElement(); } ); + $this->destination->endElement(); } ); @@ -626,13 +660,9 @@ function ($invoiceAccountingCustomerPartyTaxSchemeNode) { $docRootElement, function ($invoiceTaxRepresentativePartyNode) { $this->destination->startElement('ram:SellerTaxRepresentativeTradeParty'); - $this->destination->element('ram:ID', $this->source->queryValue('./cbc:ID[not(@schemeID)]', $invoiceTaxRepresentativePartyNode)); - $this->source->queryAll('./cac:PartyIdentification/cbc:ID[@schemeID != \'\' and @schemeID != \'SEPA\']', $invoiceTaxRepresentativePartyNode)->forEach( - function ($invoiceAccountingCustomerPartyIdNode) { - $this->destination->elementWithAttribute('ram:GlobalID', $invoiceAccountingCustomerPartyIdNode->nodeValue, 'schemeID', $invoiceAccountingCustomerPartyIdNode->getAttribute('schemeID')); - } - ); + $this->destination->element('ram:Name', $this->source->queryValue('./cac:PartyName/cbc:Name', $invoiceTaxRepresentativePartyNode)); + $this->source->whenExists( './cac:PostalAddress', $invoiceTaxRepresentativePartyNode, @@ -647,6 +677,7 @@ function ($invoiceTaxRepresentativePartyPostalAddressNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:PartyTaxScheme/cac:TaxScheme/cbc:ID[text() = \'VAT\']', $invoiceTaxRepresentativePartyNode, @@ -656,6 +687,7 @@ function ($invoiceTaxRepresentativePartyTaxSchemeNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:PartyTaxScheme/cac:TaxScheme/cbc:ID[text() = \'TAX\']', $invoiceTaxRepresentativePartyNode, @@ -665,6 +697,7 @@ function ($invoiceTaxRepresentativePartyTaxSchemeNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:PartyTaxScheme/cac:TaxScheme/cbc:ID[text() = \'FC\']', $invoiceTaxRepresentativePartyNode, @@ -674,6 +707,7 @@ function ($invoiceTaxRepresentativePartyTaxSchemeNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:PartyTaxScheme/cac:TaxScheme/cbc:ID[text() = \'???\']', $invoiceTaxRepresentativePartyNode, @@ -683,6 +717,7 @@ function ($invoiceTaxRepresentativePartyTaxSchemeNode) { $this->destination->endElement(); } ); + $this->destination->endElement(); } ); @@ -773,13 +808,25 @@ private function convertApplicableHeaderTradeDelivery(): void $docRootElement, function ($deliveryLocationNode, $deliveryNode) { $this->destination->startElement('ram:ShipToTradeParty'); - $this->destination->element('ram:ID', $this->source->queryValue('./cbc:ID[not(@schemeID)]', $deliveryLocationNode)); - $this->source->queryAll('./cbc:ID[@schemeID != \'\' and @schemeID != \'SEPA\']', $deliveryLocationNode)->forEach( + + $this->source->whenExists( + './cbc:ID[not(@schemeID)]', + $deliveryLocationNode, + function ($deliveryLocationIdNode) { + $this->destination->element('ram:ID', $deliveryLocationIdNode->nodeValue); + } + ); + + $this->source->whenExists( + './cbc:ID[@schemeID != \'\' and @schemeID != \'SEPA\']', + $deliveryLocationNode, function ($deliveryLocationIdNode) { $this->destination->elementWithAttribute('ram:GlobalID', $deliveryLocationIdNode->nodeValue, 'schemeID', $deliveryLocationIdNode->getAttribute('schemeID')); } ); + $this->destination->element('ram:Name', $this->source->queryValue('./cac:DeliveryParty/cac:PartyName/cbc:Name', $deliveryNode)); + $this->source->whenExists( './cac:Address', $deliveryLocationNode, @@ -794,6 +841,7 @@ function ($deliveryLocationAddressNode) { $this->destination->endElement(); } ); + $this->destination->endElement(); } ); @@ -839,6 +887,7 @@ function ($paymentMeansNode) { $this->destination->element('ram:PaymentReference', $this->source->queryValue('./cbc:PaymentID', $paymentMeansNode)); } ); + $this->source->whenExists( './cbc:TaxCurrencyCode', $docRootElement, @@ -846,6 +895,7 @@ function ($documentCUrrencyNode) { $this->destination->element('ram:TaxCurrencyCode', $documentCUrrencyNode->nodeValue); } ); + $this->source->whenExists( './cbc:DocumentCurrencyCode', $docRootElement, @@ -853,22 +903,31 @@ function ($documentCUrrencyNode) { $this->destination->element('ram:InvoiceCurrencyCode', $documentCUrrencyNode->nodeValue); } ); + $this->source->whenExists( './cac:PayeeParty', $docRootElement, function ($invoicePayeePartyNode) { $this->destination->startElement('ram:PayeeTradeParty'); - $this->source->queryAll('./cac:PartyIdentification/cbc:ID[not(@schemeID)]', $invoicePayeePartyNode)->forEach( + + $this->source->whenExists( + './cac:PartyIdentification/cbc:ID[not(@schemeID)]', + $invoicePayeePartyNode, function ($invoiceAccountingCustomerPartyIdNode) { $this->destination->element('ram:ID', $invoiceAccountingCustomerPartyIdNode->nodeValue); } ); - $this->source->queryAll('./cac:PartyIdentification/cbc:ID[@schemeID != \'\' and @schemeID != \'SEPA\']', $invoicePayeePartyNode)->forEach( + + $this->source->whenExists( + './cac:PartyIdentification/cbc:ID[@schemeID != \'\' and @schemeID != \'SEPA\']', + $invoicePayeePartyNode, function ($invoiceAccountingCustomerPartyIdNode) { $this->destination->elementWithAttribute('ram:GlobalID', $invoiceAccountingCustomerPartyIdNode->nodeValue, 'schemeID', $invoiceAccountingCustomerPartyIdNode->getAttribute('schemeID')); } ); + $this->destination->element('ram:Name', $this->source->queryValue('./cac:PartyName/cbc:Name', $invoicePayeePartyNode)); + $this->source->whenExists( './cac:PartyLegalEntity/cbc:CompanyID', $invoicePayeePartyNode, @@ -878,6 +937,7 @@ function ($invoiceAccountingSupplierPartyLegalEntityCompanyIdNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:Contact', $invoicePayeePartyNode, @@ -905,6 +965,7 @@ function ($invoiceAccountingCustomerPartyContactMailNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:PostalAddress', $invoicePayeePartyNode, @@ -919,6 +980,7 @@ function ($invoicePayeePartyyPostalAddressNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cbc:EndpointID[@schemeID=\'EM\']', $invoicePayeePartyNode, @@ -928,6 +990,7 @@ function ($invoiceAccountingCustomerPartyEndpointNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:PartyTaxScheme/cac:TaxScheme/cbc:ID[text() = \'VAT\']', $invoicePayeePartyNode, @@ -937,6 +1000,7 @@ function ($invoiceAccountingCustomerPartyTaxSchemeNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:PartyTaxScheme/cac:TaxScheme/cbc:ID[text() = \'TAX\']', $invoicePayeePartyNode, @@ -946,6 +1010,7 @@ function ($invoiceAccountingCustomerPartyTaxSchemeNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:PartyTaxScheme/cac:TaxScheme/cbc:ID[text() = \'FC\']', $invoicePayeePartyNode, @@ -955,6 +1020,7 @@ function ($invoiceAccountingCustomerPartyTaxSchemeNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:PartyTaxScheme/cac:TaxScheme/cbc:ID[text() = \'???\']', $invoicePayeePartyNode, @@ -964,15 +1030,19 @@ function ($invoiceAccountingCustomerPartyTaxSchemeNode) { $this->destination->endElement(); } ); + $this->destination->endElement(); } ); + $this->source->whenExists( './cac:PaymentMeans', $docRootElement, function ($paymentMeansNode) { $this->destination->startElement('ram:SpecifiedTradeSettlementPaymentMeans'); + $this->destination->element('ram:TypeCode', $this->source->queryValue('./cbc:PaymentMeansCode', $paymentMeansNode)); + $this->source->whenExists( './cac:CardAccount', $paymentMeansNode, @@ -983,6 +1053,7 @@ function ($payeeCardAccountNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:PaymentMandate', $paymentMeansNode, @@ -992,6 +1063,7 @@ function ($paymentMandateNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cac:PayeeFinancialAccount', $paymentMeansNode, @@ -1011,6 +1083,7 @@ function ($financialInstitutionBranchNode) { ); } ); + $this->destination->endElement(); } ); @@ -1022,6 +1095,7 @@ function ($taxSubtotalNode) use ($docRootElement) { $this->destination->element('ram:TypeCode', $this->source->queryValue('./cac:TaxCategory/cac:TaxScheme/cbc:ID', $taxSubtotalNode)); $this->destination->element('ram:BasisAmount', $this->source->queryValue('./cbc:TaxableAmount', $taxSubtotalNode)); $this->destination->element('ram:CategoryCode', $this->source->queryValue('./cac:TaxCategory/cbc:ID', $taxSubtotalNode)); + if ($this->source->queryValue('./cac:TaxCategory/cbc:ID', $taxSubtotalNode) != "E") { $this->source->whenExists( './cbc:TaxPointDate', @@ -1033,6 +1107,7 @@ function ($taxPointDateNode) { } ); } + $this->destination->element('ram:ExemptionReasonCode', $this->source->queryValue('./cac:TaxCategory/cbc:TaxExemptionReasonCode', $taxSubtotalNode)); $this->destination->element('ram:RateApplicablePercent', $this->source->queryValue('./cac:TaxCategory/cbc:Percent', $taxSubtotalNode)); $this->destination->endElement(); @@ -1044,6 +1119,7 @@ function ($taxPointDateNode) { $docRootElement, function ($invoicePeriodNode) { $this->destination->startElement('ram:BillingSpecifiedPeriod'); + $this->source->whenExists( './cbc:StartDate', $invoicePeriodNode, @@ -1053,6 +1129,7 @@ function ($invoicePeriodStartDateNode) { $this->destination->endElement(); } ); + $this->source->whenExists( './cbc:EndDate', $invoicePeriodNode, @@ -1062,6 +1139,7 @@ function ($invoicePeriodStartDateNode) { $this->destination->endElement(); } ); + $this->destination->endElement(); } ); @@ -1069,6 +1147,7 @@ function ($invoicePeriodStartDateNode) { $this->source->queryAll('./cac:AllowanceCharge', $docRootElement)->forEach( function ($allowanceChargeNode) { $this->destination->startElement('ram:SpecifiedTradeAllowanceCharge'); + $this->source->whenExists( './cbc:ChargeIndicator', $allowanceChargeNode, @@ -1078,11 +1157,13 @@ function ($chargeIndicatorNode) { $this->destination->endElement(); } ); + $this->destination->element('ram:CalculationPercent', $this->source->queryValue('./cbc:MultiplierFactorNumeric', $allowanceChargeNode)); $this->destination->element('ram:BasisAmount', $this->source->queryValue('./cbc:BaseAmount', $allowanceChargeNode)); $this->destination->element('ram:ActualAmount', $this->source->queryValue('./cbc:Amount', $allowanceChargeNode)); $this->destination->element('ram:ReasonCode', $this->source->queryValue('./cbc:AllowanceChargeReasonCode', $allowanceChargeNode)); $this->destination->element('ram:Reason', $this->source->queryValue('./cbc:AllowanceChargeReason', $allowanceChargeNode)); + $this->source->whenExists( './cac:TaxCategory', $allowanceChargeNode, @@ -1094,6 +1175,7 @@ function ($AllowanceChargeTaxNode) { $this->destination->endElement(); } ); + $this->destination->endElement(); } ); @@ -1130,12 +1212,15 @@ function ($paymentTermaNoteNode) { function ($invoiceMoneraryTotalNode) use ($docRootElement) { $invoiceCurrencyCode = $this->source->queryValue('./cbc:DocumentCurrencyCode', $docRootElement); $taxCurrencyCode = $this->source->queryValue('./cbc:TaxCurrencyCode', $docRootElement); + $this->destination->startElement('ram:SpecifiedTradeSettlementHeaderMonetarySummation'); + $this->destination->element('ram:LineTotalAmount', $this->source->queryValue('./cbc:LineExtensionAmount', $invoiceMoneraryTotalNode)); $this->destination->element('ram:ChargeTotalAmount', $this->source->queryValue('./cbc:ChargeTotalAmount', $invoiceMoneraryTotalNode)); $this->destination->element('ram:AllowanceTotalAmount', $this->source->queryValue('./cbc:AllowanceTotalAmount', $invoiceMoneraryTotalNode)); $this->destination->element('ram:TaxBasisTotalAmount', $this->source->queryValue('./cbc:TaxExclusiveAmount', $invoiceMoneraryTotalNode)); $this->destination->elementWithAttribute('ram:TaxTotalAmount', $this->source->queryValue(sprintf('./cac:TaxTotal/cbc:TaxAmount[@currencyID=\'%s\']', $invoiceCurrencyCode), $docRootElement), 'currencyID', $invoiceCurrencyCode); + $this->source->whenExists( sprintf('./cac:TaxTotal/cbc:TaxAmount[@currencyID=\'%s\']', $taxCurrencyCode), $docRootElement, @@ -1143,6 +1228,7 @@ function ($diffTaxNode) use ($taxCurrencyCode) { $this->destination->elementWithAttribute('ram:TaxTotalAmount', $diffTaxNode->nodeValue, 'currencyID', $taxCurrencyCode); } ); + $this->source->whenExists( './cbc:PayableRoundingAmount', $invoiceMoneraryTotalNode, @@ -1153,9 +1239,11 @@ function () { $this->destination->element('ram:RoundingAmount', '0'); } ); + $this->destination->element('ram:GrandTotalAmount', $this->source->queryValue('./cbc:TaxInclusiveAmount', $invoiceMoneraryTotalNode)); $this->destination->element('ram:TotalPrepaidAmount', $this->source->queryValue('./cbc:PrepaidAmount', $invoiceMoneraryTotalNode)); $this->destination->element('ram:DuePayableAmount', $this->source->queryValue('./cbc:PayableAmount', $invoiceMoneraryTotalNode)); + $this->destination->endElement(); } ); diff --git a/tests/testcases/CiiToUblExtendedTest.php b/tests/testcases/CiiToUblExtendedTest.php index 69d4db0..85b35cd 100644 --- a/tests/testcases/CiiToUblExtendedTest.php +++ b/tests/testcases/CiiToUblExtendedTest.php @@ -110,7 +110,7 @@ public function testDelivery(): void { $this->assertXPathValueWithIndex('/ubl:Invoice/cac:Delivery/cbc:ActualDeliveryDate', 0, "2018-09-30"); $this->assertXPathNotExistsWithIndex('/ubl:Invoice/cac:Delivery/cbc:ActualDeliveryDate', 1); - $this->assertXPathNotExistsWithIndex('/ubl:Invoice/cac:Delivery/cac:DeliveryLocation/cbc:ID', 0); + $this->assertXPathValueWithIndexAndAttribute('/ubl:Invoice/cac:Delivery/cac:DeliveryLocation/cbc:ID', 0, '4304171088093', 'schemeID', '0088'); $this->assertXPathValueWithIndex('/ubl:Invoice/cac:Delivery/cac:DeliveryLocation/cac:Address/cbc:StreetName', 0, 'HAUPTSTRASSE 44'); $this->assertXPathNotExistsWithIndex('/ubl:Invoice/cac:Delivery/cac:DeliveryLocation/cac:Address/cbc:AdditionalStreetName', 0); $this->assertXPathNotExistsWithIndex('/ubl:Invoice/cac:Delivery/cac:DeliveryLocation/cac:Address/cac:AddressLine', 0);