office-alexander-logistics/office-alexander-logistics-app/src/main/java/com/alexanderlogistics/einvoice/TaxCode.java

172 lines
No EOL
6.2 KiB
Java

package com.alexanderlogistics.einvoice;
import org.imixs.workflow.exceptions.PluginException;
/**
* Single source of truth for the mapping between CargoSoft VAT codes and the
* Polish KSeF FA(3) XML schema fields.
* <p>
* Each enum constant maps a CargoSoft VAT code (as it appears in the
* {@code cargosoft.vat.code} item of an invoice line) to:
* <ul>
* <li>the value to be written into the {@code <P_12>} element of a
* {@code <FaWiersz>} (line item) block,</li>
* <li>the target net summary field in the {@code <Fa>} block (one of
* {@code P_13_1}, {@code P_13_2}, {@code P_13_6_1}, {@code P_13_8},
* {@code P_13_9}),</li>
* <li>the optional target VAT summary field in the {@code <Fa>} block
* ({@code P_14_1}, {@code P_14_2}) - {@code null} for 0% / non-taxable
* codes.</li>
* </ul>
* <p>
* The mapping is derived from the field-mapping document provided by the
* Polish tax advisor of AGLP sp. z o.o. and reflects the requirements of the
* Polish VAT act (UStG-PL) and the SAF-T reporting (JPK_V7).
* <p>
* <b>Note on Java identifiers:</b> The enum constants are prefixed with
* {@code CARGO_} because plain numeric names like {@code 8} or {@code 23} are
* not valid Java identifiers. The CargoSoft code itself is held as a String
* field and matches the original code unchanged ({@code "8"}, {@code "23"}).
* <p>
* <b>Mixed code "023":</b> The CargoSoft code {@code 023} is intentionally
* NOT defined here. It is a CargoSoft-internal mixed code (either 0% or 23%)
* for which no deterministic mapping exists. Such codes will trigger a
* {@link PluginException} via {@link #fromCargosoftCode(String)}.
*
* @see <a href="http://crd.gov.pl/wzor/2025/06/25/13775/schemat.xsd">FA(3) XSD
* schema</a>
*/
public enum TaxCode {
/**
* Domestic 0% rate, services in Polish seaports (Art. 83 sec. 1 no. 9 UStG-PL).
*/
CARGO_0("0", "0 KR", "P_13_6_1", null),
/**
* Domestic 0% rate, forwarding services for export of goods (Art. 83 sec. 1 no.
* 19 UStG-PL).
*/
CARGO_0E("0%E", "0 KR", "P_13_6_1", null),
/**
* Domestic 0% rate, shipping agency services (Art. 83 sec. 1 no. 17 UStG-PL).
*/
CARGO_01("01", "0 KR", "P_13_6_1", null),
/**
* Domestic 0% rate, other maritime transport services (Art. 83 sec. 1 no. 17 or
* 20 UStG-PL).
*/
CARGO_0MR("0MR", "0 KR", "P_13_6_1", null),
/** Standard tax rate 23% (Art. 41 sec. 1 / Art. 146ef UStG-PL). */
CARGO_23("23", "23", "P_13_1", "P_14_1"),
/** First reduced tax rate 8% (Art. 41 sec. 2 UStG-PL). */
CARGO_8("8", "8", "P_13_2", "P_14_2"),
/**
* Not subject to Polish VAT, B2B service to an EU taxable person
* (Art. 28b + Art. 100 sec. 1 no. 4 UStG-PL).
* Reportable in the EU recapitulative statement (VAT-UE / ZM).
*/
CARGO_NP("NP", "np II", "P_13_9", null),
/**
* Not subject to Polish VAT, customer outside the EU or transit
* (Art. 28b UStG-PL, excluding Art. 100 sec. 1 no. 4).
* NOT reportable in VAT-UE.
*/
CARGO_NPT("NPT", "np I", "P_13_8", null),
/**
* Art. 83 ust. 1 pkt 23 ustawy o VAT — usługi transportu międzynarodowego (z
* definicją z ust. 3)
*/
CARGO_023("023", "0 KR", "P_13_6_1", null);
private final String cargosoftCode;
private final String p12Value;
private final String netSummaryField;
private final String vatSummaryField;
TaxCode(String cargosoftCode, String p12Value, String netSummaryField, String vatSummaryField) {
this.cargosoftCode = cargosoftCode;
this.p12Value = p12Value;
this.netSummaryField = netSummaryField;
this.vatSummaryField = vatSummaryField;
}
/**
* @return the original CargoSoft VAT code (e.g. "23", "0%E", "NP")
*/
public String getCargosoftCode() {
return cargosoftCode;
}
/**
* @return the value to be written into the {@code <P_12>} element of a
* {@code <FaWiersz>} block (e.g. "23", "0 KR", "np II")
*/
public String getP12Value() {
return p12Value;
}
/**
* @return the name of the target net summary tag in the {@code <Fa>}
* block (e.g. "P_13_1", "P_13_6_1", "P_13_9")
*/
public String getNetSummaryField() {
return netSummaryField;
}
/**
* @return the name of the target VAT summary tag in the {@code <Fa>}
* block (e.g. "P_14_1") or {@code null} for 0% / non-taxable codes
*/
public String getVatSummaryField() {
return vatSummaryField;
}
/**
* @return {@code true} if this code carries a non-zero VAT amount
* (i.e. a VAT summary field exists); {@code false} otherwise
*/
public boolean hasVat() {
return vatSummaryField != null;
}
/**
* Resolves a CargoSoft VAT code string to the corresponding {@link TaxCode}
* enum constant.
* <p>
* Throws a {@link PluginException} if the code is unknown, blank or
* {@code null}. This is by design: an unmapped code MUST stop processing,
* because writing the wrong summary field would silently produce an
* invalid JPK_V7 entry while still passing KSeF XSD validation.
*
* @param cargosoftCode the value of {@code cargosoft.vat.code} from a
* CargoSoft invoice line (e.g. "23", "NP")
* @return the matching {@link TaxCode} enum constant
* @throws PluginException if the code is unknown, blank or {@code null}
*/
public static TaxCode fromCargosoftCode(String cargosoftCode) throws PluginException {
if (cargosoftCode == null || cargosoftCode.isBlank()) {
throw new PluginException(
TaxCode.class.getSimpleName(),
"TAX_CODE_ERROR",
"CargoSoft VAT code is null or blank - cannot map to KSeF tax field");
}
for (TaxCode tc : values()) {
if (tc.cargosoftCode.equals(cargosoftCode)) {
return tc;
}
}
throw new PluginException(
TaxCode.class.getSimpleName(),
"TAX_CODE_ERROR",
"Unknown CargoSoft VAT code: '" + cargosoftCode
+ "' - no mapping to a KSeF FA(3) tax field defined");
}
}