horstoeko / zugferd

ZUGFeRD/XRechnung/Factur-X Library
MIT License
169 stars 27 forks source link

[QUESTION] Correct usage of addDiscountTermsToPaymentTerms() #167

Open sirbenson opened 2 hours ago

sirbenson commented 2 hours ago

Your question Hello,

what is the correct usage of addDiscountTermsToPaymentTerms()? addDocumentPaymentTerm() works without problems. We use additionaly Skonto1 + Skonto2. But that wont work. addDiscountTermsToPaymentTerms() is called without any results in the xml.

ZugferdProfiles::PROFILE_EN16931

XML Sample

</ram:ApplicableTradeTax>
<ram:SpecifiedTradePaymentTerms>
  <ram:Description>Bitte zahlen Sie mit Skonto 1 und Skonto 2</ram:Description>
    <ram:DueDateDateTime>
      <udt:DateTimeString format="102">20241207</udt:DateTimeString>
    </ram:DueDateDateTime>
  </ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>

Sample Code

$document->addDocumentPaymentTerm(htmlspecialchars_decode($dbPaymentType->PaymentText), $processPaymentTermDate);

$document->addDiscountTermsToPaymentTerms($dbPaymentType->CashDiscount, $processDate, $dbPaymentType->PaymentDiscountDays, "DAY", 0, 0);

$document->addDiscountTermsToPaymentTerms($dbPaymentType->CashDiscount2, $processDate, $dbPaymentType->PaymentDiscountDays2, "DAY", 0, 0);
horstoeko commented 1 hour ago

Hi @sirbenson,

Hi, Thanks for the question. But please do me a favor and provide the information in full. It's not helpful for me to have to guess things: For example, the profile used. PaymentDiscount only works in EXTENDED profiles. Please also consult the official ZUGFeRD documentation. This can be downloaded after simple registration.

Kind regards

sirbenson commented 1 hour ago

Hello @horstoeko

thanks for your work on this nice lib, btw :) It helps us a lot!

Oh Sorry, Profile: PROFILE_EN16931.

Test Code

$document = ZugferdDocumentBuilder::CreateNew(ZugferdProfiles::PROFILE_EN16931)
            ->setDocumentInformation(
                $dbProcess->ProcessNumber,
                "380",
                \DateTime::createFromFormat("Ymd", date("Ymd", $dbProcess->ProcessedDate)),
                "EUR"
            )
            ->addDocumentNote(htmlspecialchars_decode($dbProcess->Subject))
            ->setDocumentSupplyChainEvent(\DateTime::createFromFormat('Ymd', date("Ymd", $dbProcess->ExpectedShippingDate)))

            ->setDocumentSeller(htmlspecialchars_decode($dbCompany->CompanyName))
            ->addDocumentSellerTaxRegistration("FC", $dbCompany->TaxNumber)
            ->addDocumentSellerTaxRegistration("VA", $dbCompany->TaxId)
            ->setDocumentSellerAddress(
                htmlspecialchars_decode($dbCompany->Address) . " " . htmlspecialchars_decode($dbCompany->AddressNumber),
                "",
                "",
                htmlspecialchars_decode($dbCompany->Postcode),
                htmlspecialchars_decode($dbCompany->City),
                htmlspecialchars_decode($dbSellerCountryCode)
            )
            //->addDocumentSellerGlobalId("4000001123452", "0088")

            ->setDocumentBuyer(
                htmlspecialchars_decode($dbProcess->CustomerCompany),
                htmlspecialchars_decode($dbProcess->CustomerNumber)
            )
            ->addDocumentBuyerTaxRegistration("FC", $dbCustomer->TaxNumber)
            ->setDocumentBuyerAddress(
                htmlspecialchars_decode($dbProcess->CustomerAddress) . " " . htmlspecialchars_decode($dbProcess->CustomerAddressNumber),
                htmlspecialchars_decode($dbProcess->CustomerAdditionalAddressInfo),
                "",
                htmlspecialchars_decode($dbProcess->CustomerPostcode),
                htmlspecialchars_decode($dbProcess->CustomerCity),
                htmlspecialchars_decode($dbBuyerCountryCode)
            )

            ->setDocumentSummation(
                $dbProcess->ProcessAmountBrutto,
                $dbProcess->ProcessAmountBrutto,
                $dbProcess->ProcessAmountNetto,
                0,
                0,
                $dbProcess->ProcessAmountNetto,
                $dbProcess->TaxAmount,
                null,
                0
            )

            ->addDocumentPaymentMean(58, "");

        $processDate = new \DateTime();
        $processPaymentTermDate = new \DateTime();
        $processDate->setTimestamp($dbProcess->ProcessedDate);
        $processPaymentTermDate->setTimestamp($dbProcess->ProcessedDate + (86400 * $dbPaymentType->PaymentDays));

        $document->addDocumentPaymentTerm(htmlspecialchars_decode($dbPaymentType->PaymentText), $processPaymentTermDate);

            $document->addDiscountTermsToPaymentTerms($dbPaymentType->CashDiscount, $processDate, $dbPaymentType->PaymentDiscountDays, "DAY", 0, 0);

            $document->addDiscountTermsToPaymentTerms($dbPaymentType->CashDiscount2, $processDate, $dbPaymentType->PaymentDiscountDays2, "DAY", 0, 0);

        foreach($dbProcessTaxs as $dbProcessTax) {
            $document->addDocumentTax("S", "VAT", $dbProcessTax->AmountNetto, $dbProcessTax->TaxAmount, intval($dbProcessTax->Tax));
        }

        foreach($dbProcessDetails as $processDetail){
            if($processDetail->ArticlePositionType == 4 || $processDetail->ArticlePositionType == 5) continue;

            $document->addNewPosition($processDetail->Position)
            ->setDocumentPositionProductDetails(htmlspecialchars_decode($processDetail->ArticleName), htmlspecialchars_decode($processDetail->ArticleDescription), htmlspecialchars_decode($processDetail->ArticleNumber))
            ->setDocumentPositionGrossPrice($processDetail->ArticleSinglePrice)
            ->setDocumentPositionNetPrice($processDetail->ArticleSinglePrice)
            ->setDocumentPositionQuantity($processDetail->ArticleCount, ArticleUnitType::getUnitCodeFromId($processDetail->ArticleUnitType))
            ->addDocumentPositionTax('S', 'VAT', intval($processDetail->ArticleTax))
            ->setDocumentPositionLineSummation($processDetail->ArticlePrice);
        }
sirbenson commented 53 minutes ago

I found the problem. The profile must be Extended...

But now it adds only the second discount (Skonto2). Skonto1 is irgnored in the xml file. Skonto 1: 5%, 7 Days Skonto 2: 3%, 14 Days

<ram:SpecifiedTradePaymentTerms>
  <ram:Description>Bitte zahlen Sie mit Skonto 1 und Skonto 2</ram:Description>
  <ram:DueDateDateTime>
    <udt:DateTimeString format="102">20241207</udt:DateTimeString>
  </ram:DueDateDateTime>
  <ram:ApplicableTradePaymentDiscountTerms>
    <ram:BasisDateTime>
      <udt:DateTimeString format="102">20241107</udt:DateTimeString>
    </ram:BasisDateTime>
    <ram:BasisPeriodMeasure unitCode="DAY">14.0</ram:BasisPeriodMeasure>
    <ram:BasisAmount>57.12</ram:BasisAmount>
    <ram:CalculationPercent>3.00</ram:CalculationPercent>
    <ram:ActualDiscountAmount>1.71</ram:ActualDiscountAmount>
  </ram:ApplicableTradePaymentDiscountTerms>
</ram:SpecifiedTradePaymentTerms>
horstoeko commented 35 minutes ago

Hi @sirbenson,

According to the official documentation, the cardinality of the cash discount information is 0..1 as you can see here:

image

Maybe the naming is confusing because the method starts with “add”... But here, discount information is “added” to a payment term... Perhaps consider a second payment term?

Kind regards.