Added AmountAdjustments

This commit is contained in:
dankito 2024-11-25 17:27:26 +01:00
parent 556c59ba3a
commit f1a364866c
4 changed files with 118 additions and 2 deletions

View File

@ -1,10 +1,13 @@
package net.codinux.invoicing.mapper
import net.codinux.invoicing.model.AmountAdjustments
import net.codinux.invoicing.model.ChargeOrAllowance
import net.codinux.invoicing.model.InvoiceItem
import net.codinux.invoicing.model.Party
import org.mustangproject.*
import org.mustangproject.ZUGFeRD.IExportableTransaction
import org.mustangproject.ZUGFeRD.IZUGFeRDExportableItem
import java.math.BigDecimal
import java.time.Instant
import java.time.LocalDate
import java.time.ZoneId
@ -24,6 +27,12 @@ open class MustangMapper {
this.paymentTermDescription = invoice.paymentDescription
this.referenceNumber = invoice.buyerReference
invoice.amountAdjustments?.let { adjustments ->
this.totalPrepaidAmount = adjustments.prepaidAmounts
adjustments.charges.forEach { this.addCharge(mapCharge(it)) }
adjustments.allowances.forEach { this.addAllowance(mapAllowance(it)) }
}
}
open fun mapParty(party: Party): TradeParty = TradeParty(
@ -52,6 +61,26 @@ open class MustangMapper {
}
protected open fun mapCharge(charge: ChargeOrAllowance) = Charge(charge.actualAmount).apply {
this.percent = charge.calculationPercent
this.reason = charge.reason
this.reasonCode = charge.reasonCode
this.taxPercent = charge.taxRateApplicablePercent
this.categoryCode = charge.taxCategoryCode
}
protected open fun mapAllowance(allowance: ChargeOrAllowance) = Allowance(allowance.actualAmount).apply {
this.percent = allowance.calculationPercent
this.reason = allowance.reason
this.reasonCode = allowance.reasonCode
this.taxPercent = allowance.taxRateApplicablePercent
this.categoryCode = allowance.taxCategoryCode
}
open fun mapToInvoice(invoice: Invoice) = net.codinux.invoicing.model.Invoice(
invoiceNumber = invoice.number,
@ -63,7 +92,9 @@ open class MustangMapper {
dueDate = map(invoice.dueDate ?: invoice.paymentTerms?.dueDate),
paymentDescription = invoice.paymentTermDescription ?: invoice.paymentTerms?.description,
buyerReference = invoice.referenceNumber
buyerReference = invoice.referenceNumber,
amountAdjustments = mapAmountAdjustments(invoice),
)
open fun mapParty(party: TradeParty) = Party(
@ -76,6 +107,23 @@ open class MustangMapper {
item.product.name, item.quantity, item.product.unit, item.price, item.product.vatPercent, item.product.description.takeUnless { it.isBlank() }
)
protected open fun mapAmountAdjustments(invoice: Invoice): AmountAdjustments? {
if ((invoice.totalPrepaidAmount == null || invoice.totalPrepaidAmount == BigDecimal.ZERO) && invoice.zfCharges.isEmpty() && invoice.zfAllowances.isEmpty()) {
return null
}
return AmountAdjustments(
invoice.totalPrepaidAmount,
invoice.zfCharges.mapNotNull { mapChargeOrAllowance(it as? Charge) },
invoice.zfAllowances.mapNotNull { mapChargeOrAllowance(it as? Allowance ?: it as? Charge) }
)
}
private fun mapChargeOrAllowance(chargeOrAllowance: Charge?) = chargeOrAllowance?.let {
ChargeOrAllowance(it.totalAmount, null, null, it.percent, it.reason, it.reasonCode, it.taxPercent, it.categoryCode)
}
@JvmName("mapNullable")
protected fun map(date: LocalDate?) =

View File

@ -0,0 +1,22 @@
package net.codinux.invoicing.model
import java.math.BigDecimal
class AmountAdjustments(
/**
* Vorauszahlungen.
*/
val prepaidAmounts: BigDecimal = BigDecimal.ZERO,
/**
* Zusätzliche Gebühren.
*/
val charges: List<ChargeOrAllowance> = emptyList(),
/**
* Abzüge / Nachlässe.
*/
val allowances: List<ChargeOrAllowance> = emptyList()
) {
override fun toString() = "${prepaidAmounts.toPlainString()} prepaid, ${charges.size} charges, ${allowances.size} allowances"
}

View File

@ -0,0 +1,44 @@
package net.codinux.invoicing.model
import java.math.BigDecimal
class ChargeOrAllowance(
/**
* Gesamtbetrag der Gebühr oder des Nachlasses.
* Evtl. berechnet aus [basisAmount] und [calculationPercent].
*/
val actualAmount: BigDecimal,
/**
* Der Ausgangsbetrag auf den die Gebühr oder der Nachlass angewendet wird.
*/
val basisAmount: BigDecimal? = null,
/**
* Menge der Ware oder Dienstleistung auf die die Gebühr oder der Nachlass angewendet wird.
*/
val basisQuantity: BigDecimal? = null,
/**
* Der auf [basisAmount] anwendbare Prozentsatz der Gebühr oder des Nachlasses.
*/
val calculationPercent: BigDecimal? = null,
/**
* Menschenlesbare Beschreibung der Gebühr oder des Nachlasses.
*/
val reason: String? = null,
/**
* Code für Begründung der Gebühr oder des Nachlasses aus [UNTDID 5189](https://unece.org/fileadmin/DAM/trade/untdid/d16b/tred/tred5189.htm).
*/
val reasonCode: String? = null,
/**
* Anzuwendender Steuersatz (z. B. in Deutschland 7 % oder 19 %).
*/
val taxRateApplicablePercent: BigDecimal? = null,
/**
* Steuer Kategorie Code
*/
val taxCategoryCode: String? = null
) {
override fun toString() = "${reason?.let { "$it: " } ?: ""}${actualAmount.toPlainString()}"
}

View File

@ -15,7 +15,9 @@ class Invoice(
/**
* Unique reference number of the buyer, e.g. the Leitweg-ID required by German authorities (Behörden)
*/
val buyerReference: String? = null
val buyerReference: String? = null,
val amountAdjustments: AmountAdjustments? = null,
) {
override fun toString() = "$invoicingDate $invoiceNumber to $recipient"
}