179 lines
No EOL
6.4 KiB
Java
179 lines
No EOL
6.4 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 {
|
|
|
|
/** Standard tax rate 23% (Art. 41 sec. 1 / Art. 146ef UStG-PL). */
|
|
CARGO_23("23", "23", "P_13_1", "P_14_1", "2"),
|
|
|
|
/** First reduced tax rate 8% (Art. 41 sec. 2 UStG-PL). */
|
|
CARGO_8("8", "8", "P_13_2", "P_14_2", "2"),
|
|
|
|
/**
|
|
* 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, "2"),
|
|
|
|
/**
|
|
* Domestic 0% rate, shipping agency services (Art. 83 sec. 1 no. 17 UStG-PL).
|
|
*/
|
|
CARGO_01("01", "0 KR", "P_13_6_1", null, "2"),
|
|
|
|
/**
|
|
* 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, "2"),
|
|
|
|
/**
|
|
* 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, "2"),
|
|
|
|
/**
|
|
* 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, "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, "1"),
|
|
|
|
/**
|
|
* 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, "1"),
|
|
CARGO_NP3("NP3", "np I", "P_13_8", null, "1");
|
|
|
|
private final String cargosoftCode;
|
|
private final String p12Value;
|
|
private final String netSummaryField;
|
|
private final String vatSummaryField;
|
|
private final String p18Value;
|
|
|
|
TaxCode(String cargosoftCode, String p12Value, String netSummaryField, String vatSummaryField, String p18value) {
|
|
this.cargosoftCode = cargosoftCode;
|
|
this.p12Value = p12Value;
|
|
this.netSummaryField = netSummaryField;
|
|
this.vatSummaryField = vatSummaryField;
|
|
this.p18Value = p18value;
|
|
}
|
|
|
|
/**
|
|
* @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;
|
|
}
|
|
|
|
public String getP18Value() {
|
|
return p18Value;
|
|
}
|
|
|
|
/**
|
|
* @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");
|
|
}
|
|
} |