@getpeppr/cli 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -65,7 +65,7 @@ function formatWarning(item) {
65
65
  function formatSection(title, errors, warnings) {
66
66
  const lines = [sectionHeader(title)];
67
67
  if (errors.length === 0 && warnings.length === 0) {
68
- lines.push(` ${pc.green("\u2713")} All rules passed`);
68
+ lines.push(` ${pc.green("\u2713")} No findings`);
69
69
  return lines.join("\n");
70
70
  }
71
71
  if (errors.length === 0) {
@@ -94,7 +94,7 @@ Validating: ${pc.bold(filename)}
94
94
  lines.push("");
95
95
  lines.push(
96
96
  formatSection(
97
- "Business Rules (Peppol BIS 3.0)",
97
+ "Offline Checks (partial)",
98
98
  result.schematron.errors,
99
99
  result.schematron.warnings
100
100
  )
@@ -111,10 +111,10 @@ Validating: ${pc.bold(filename)}
111
111
  lines.push(sectionHeader("Summary"));
112
112
  const { totalErrors, totalWarnings, valid } = result;
113
113
  if (valid && totalWarnings === 0) {
114
- lines.push(` ${pc.green(pc.bold("\u2713 Invoice is valid"))}`);
114
+ lines.push(` ${pc.green(pc.bold("\u2713 Pre-flight checks passed"))}`);
115
115
  } else if (valid) {
116
116
  lines.push(
117
- ` ${pc.green(pc.bold("\u2713 Invoice is valid"))} ${pc.dim(`(${totalWarnings} warning${totalWarnings === 1 ? "" : "s"})`)}`
117
+ ` ${pc.green(pc.bold("\u2713 Pre-flight checks passed"))} ${pc.dim(`(${totalWarnings} warning${totalWarnings === 1 ? "" : "s"})`)}`
118
118
  );
119
119
  } else {
120
120
  const parts = [];
@@ -123,14 +123,14 @@ Validating: ${pc.bold(filename)}
123
123
  parts.push(`${totalWarnings} warning${totalWarnings === 1 ? "" : "s"}`);
124
124
  }
125
125
  lines.push(
126
- ` ${pc.red(pc.bold(`\u2717 ${parts.join(", ")}`))} \u2014 invoice non-compliant`
126
+ ` ${pc.red(pc.bold("\u2717 Pre-flight checks found errors"))} ${pc.dim(`(${parts.join(", ")})`)}`
127
127
  );
128
128
  }
129
129
  lines.push("");
130
130
  return lines.join("\n");
131
131
  }
132
132
 
133
- // ../sdk/dist/core/canonical-schemes.js
133
+ // ../../../../../../Users/sylvain/Code/Projets/getpeppr/packages/sdk/dist/core/canonical-schemes.js
134
134
  var ALIAS_TO_EAS = /* @__PURE__ */ new Map([
135
135
  ["AD:VAT", "9922"],
136
136
  ["AE:TIN", "0235"],
@@ -356,7 +356,7 @@ function countryForScheme(scheme) {
356
356
  var CANONICAL_SCHEME_COUNT = ALIAS_TO_EAS.size;
357
357
  var SCHEME_COUNTRY_COUNT = EAS_TO_COUNTRY.size;
358
358
 
359
- // ../sdk/dist/core/peppol-id.js
359
+ // ../../../../../../Users/sylvain/Code/Projets/getpeppr/packages/sdk/dist/core/peppol-id.js
360
360
  function isWellFormedPeppolId(peppolId) {
361
361
  if (!peppolId.includes(":"))
362
362
  return false;
@@ -382,7 +382,7 @@ function parsePeppolId(peppolId) {
382
382
  };
383
383
  }
384
384
 
385
- // ../sdk/dist/core/iso6523-icd-codes.js
385
+ // ../../../../../../Users/sylvain/Code/Projets/getpeppr/packages/sdk/dist/core/iso6523-icd-codes.js
386
386
  var ICD_CODES = /* @__PURE__ */ new Set([
387
387
  "0002",
388
388
  "0003",
@@ -645,7 +645,7 @@ function canCarryPartyIdentification(scheme, context) {
645
645
  return scheme === "SEPA" && context !== "AccountingCustomerParty";
646
646
  }
647
647
 
648
- // ../sdk/dist/core/ubl-builder.js
648
+ // ../../../../../../Users/sylvain/Code/Projets/getpeppr/packages/sdk/dist/core/ubl-builder.js
649
649
  var UBL_NS = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2";
650
650
  var CAC_NS = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2";
651
651
  var CBC_NS = "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2";
@@ -1296,7 +1296,7 @@ function buildCreditNoteXml(input) {
1296
1296
  </CreditNote>`;
1297
1297
  }
1298
1298
 
1299
- // ../sdk/dist/core/checksums/luhn.js
1299
+ // ../../../../../../Users/sylvain/Code/Projets/getpeppr/packages/sdk/dist/core/checksums/luhn.js
1300
1300
  function isValidLuhn(input) {
1301
1301
  if (typeof input !== "string")
1302
1302
  return false;
@@ -1337,7 +1337,7 @@ function isValidLuhnSiret(input) {
1337
1337
  return false;
1338
1338
  }
1339
1339
 
1340
- // ../sdk/dist/core/country-rules.js
1340
+ // ../../../../../../Users/sylvain/Code/Projets/getpeppr/packages/sdk/dist/core/country-rules.js
1341
1341
  function warn(field, message, ruleId) {
1342
1342
  return { field, message, ruleId };
1343
1343
  }
@@ -1478,7 +1478,7 @@ function validateCountryRules(input) {
1478
1478
  return { errors, warnings };
1479
1479
  }
1480
1480
 
1481
- // ../sdk/dist/core/code-lists.js
1481
+ // ../../../../../../Users/sylvain/Code/Projets/getpeppr/packages/sdk/dist/core/code-lists.js
1482
1482
  var CURRENCIES = /* @__PURE__ */ new Map([
1483
1483
  ["EUR", { code: "EUR", name: "Euro", minorUnits: 2 }],
1484
1484
  ["USD", { code: "USD", name: "US Dollar", minorUnits: 2 }],
@@ -1681,7 +1681,7 @@ function getCreditNoteTypeCodes() {
1681
1681
  return [...CREDIT_NOTE_TYPE_CODES];
1682
1682
  }
1683
1683
 
1684
- // ../sdk/dist/core/validator.js
1684
+ // ../../../../../../Users/sylvain/Code/Projets/getpeppr/packages/sdk/dist/core/validator.js
1685
1685
  function error(field, message, ruleId, suggestion) {
1686
1686
  return { field, message, ruleId, suggestion };
1687
1687
  }
@@ -1698,16 +1698,19 @@ function assertString(value, fieldPath, errors) {
1698
1698
  var ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
1699
1699
  var ALLOWANCE_CHARGE_CONTRACT_RULE = "GETPEPPR-ALLOWANCE-CHARGE-AMOUNT";
1700
1700
  var DERIVED_AMOUNT_CONTRACT_RULE2 = "GETPEPPR-DERIVED-AMOUNT";
1701
+ var BUYER_ADDRESS_DELIVERY_RULE = "GETPEPPR-BUYER-ADDRESS";
1702
+ var LINE_VAT_RATE_RULE = "GETPEPPR-LINE-VAT-RATE";
1703
+ var TAX_CURRENCY_RATE_RULE = "GETPEPPR-TAX-CURRENCY-RATE";
1701
1704
  function survivesCents2(value) {
1702
1705
  return Number.isFinite(value) && Number.isFinite(value * 100);
1703
1706
  }
1704
1707
  function validateParty(party, path) {
1705
1708
  const errors = [];
1706
1709
  if (party.name === void 0 || party.name === null || party.name === "") {
1707
- errors.push(error(`${path}.name`, "Business name is required", "BR-06"));
1710
+ errors.push(error(`${path}.name`, "Business name is required", "BR-07"));
1708
1711
  } else if (!assertString(party.name, `${path}.name`, errors)) {
1709
1712
  } else if (!party.name.trim()) {
1710
- errors.push(error(`${path}.name`, "Business name is required", "BR-06"));
1713
+ errors.push(error(`${path}.name`, "Business name is required", "BR-07"));
1711
1714
  }
1712
1715
  if (party.peppolId === void 0 || party.peppolId === null || party.peppolId === "") {
1713
1716
  errors.push(error(`${path}.peppolId`, "Peppol participant ID is required", void 0, 'Format: "scheme:id", e.g. "0208:0685660237" for Belgian companies'));
@@ -1726,22 +1729,22 @@ function validateParty(party, path) {
1726
1729
  function validateBuyerAddress(party, path) {
1727
1730
  const errors = [];
1728
1731
  if (party.street === void 0 || party.street === null || party.street === "") {
1729
- errors.push(error(`${path}.street`, "Street address is required for the buyer", "BR-50", 'e.g. "123 Business Street"'));
1732
+ errors.push(error(`${path}.street`, "Street address is required for the buyer", BUYER_ADDRESS_DELIVERY_RULE, 'e.g. "123 Business Street"'));
1730
1733
  } else if (!assertString(party.street, `${path}.street`, errors)) {
1731
1734
  } else if (!party.street.trim()) {
1732
- errors.push(error(`${path}.street`, "Street address is required for the buyer", "BR-50", 'e.g. "123 Business Street"'));
1735
+ errors.push(error(`${path}.street`, "Street address is required for the buyer", BUYER_ADDRESS_DELIVERY_RULE, 'e.g. "123 Business Street"'));
1733
1736
  }
1734
1737
  if (party.city === void 0 || party.city === null || party.city === "") {
1735
- errors.push(error(`${path}.city`, "City is required for the buyer", "BR-51", 'e.g. "Brussels"'));
1738
+ errors.push(error(`${path}.city`, "City is required for the buyer", BUYER_ADDRESS_DELIVERY_RULE, 'e.g. "Brussels"'));
1736
1739
  } else if (!assertString(party.city, `${path}.city`, errors)) {
1737
1740
  } else if (!party.city.trim()) {
1738
- errors.push(error(`${path}.city`, "City is required for the buyer", "BR-51", 'e.g. "Brussels"'));
1741
+ errors.push(error(`${path}.city`, "City is required for the buyer", BUYER_ADDRESS_DELIVERY_RULE, 'e.g. "Brussels"'));
1739
1742
  }
1740
1743
  if (party.postalCode === void 0 || party.postalCode === null || party.postalCode === "") {
1741
- errors.push(error(`${path}.postalCode`, "Postal code is required for the buyer", "BR-53", 'e.g. "1000"'));
1744
+ errors.push(error(`${path}.postalCode`, "Postal code is required for the buyer", BUYER_ADDRESS_DELIVERY_RULE, 'e.g. "1000"'));
1742
1745
  } else if (!assertString(party.postalCode, `${path}.postalCode`, errors)) {
1743
1746
  } else if (!party.postalCode.trim()) {
1744
- errors.push(error(`${path}.postalCode`, "Postal code is required for the buyer", "BR-53", 'e.g. "1000"'));
1747
+ errors.push(error(`${path}.postalCode`, "Postal code is required for the buyer", BUYER_ADDRESS_DELIVERY_RULE, 'e.g. "1000"'));
1745
1748
  }
1746
1749
  return errors;
1747
1750
  }
@@ -1770,7 +1773,7 @@ function validateLine(line, index, isCreditNote = false) {
1770
1773
  }
1771
1774
  }
1772
1775
  if (line.vatRate === void 0 || line.vatRate === null) {
1773
- errors.push(error(`${path}.vatRate`, "VAT rate is required", "BR-CO-17"));
1776
+ errors.push(error(`${path}.vatRate`, "VAT rate is required", LINE_VAT_RATE_RULE));
1774
1777
  } else if (line.vatRate < 0 || line.vatRate > 100) {
1775
1778
  errors.push(error(`${path}.vatRate`, `VAT rate must be between 0 and 100, got ${line.vatRate}`, void 0, "Use 0 for zero-rated, 21 for standard Belgian VAT, etc."));
1776
1779
  }
@@ -1945,10 +1948,25 @@ function validateInvoice(input) {
1945
1948
  }
1946
1949
  }
1947
1950
  if (!input.buyerReference && !input.orderReference) {
1948
- warnings.push(warning("buyerReference", "Either buyerReference or orderReference is required by Peppol BIS 3.0 (BT-10).", "BR-10"));
1951
+ warnings.push(warning(
1952
+ "buyerReference",
1953
+ "Either buyerReference or orderReference is required by Peppol BIS 3.0 (BT-10).",
1954
+ // GPR-1267 — PEPPOL-EN16931-R003 IS this rule: "A buyer reference or
1955
+ // purchase order reference MUST be provided." BR-10 is the buyer
1956
+ // postal address.
1957
+ "PEPPOL-EN16931-R003"
1958
+ ));
1949
1959
  }
1950
1960
  if (input.taxCurrency && input.taxCurrency !== (input.currency ?? "EUR") && !input.taxCurrencyRate) {
1951
- errors.push(error("taxCurrencyRate", "Tax currency rate is required when taxCurrency differs from document currency", "BR-53", "Set taxCurrencyRate to the exchange rate from document currency to tax currency"));
1961
+ errors.push(error(
1962
+ "taxCurrencyRate",
1963
+ "Tax currency rate is required when taxCurrency differs from document currency",
1964
+ // GPR-1267 — BR-53 mandates the BT-111 total in accounting currency,
1965
+ // which the builder derives itself; the client-supplied rate is an
1966
+ // input-contract requirement, not that rule.
1967
+ TAX_CURRENCY_RATE_RULE,
1968
+ "Set taxCurrencyRate to the exchange rate from document currency to tax currency"
1969
+ ));
1952
1970
  }
1953
1971
  if (input.taxCurrency && input.taxCurrency === (input.currency ?? "EUR")) {
1954
1972
  warnings.push(warning("taxCurrency", "Tax currency is the same as document currency \u2014 TaxCurrencyCode will be omitted"));
@@ -1963,7 +1981,7 @@ function validateInvoice(input) {
1963
1981
  errors.push(error("taxCurrency", `Invalid tax currency code: "${input.taxCurrency}"`, void 0, 'Use ISO 4217 (e.g., "EUR", "USD")'));
1964
1982
  }
1965
1983
  if (!input.dueDate) {
1966
- warnings.push(warning("dueDate", "No due date specified. Recommended for payment terms.", "BR-09"));
1984
+ warnings.push(warning("dueDate", "No due date specified. Recommended for payment terms."));
1967
1985
  }
1968
1986
  if (!input.to?.vatNumber) {
1969
1987
  warnings.push(warning("to.vatNumber", "Buyer VAT number not provided. May be required for B2B."));
@@ -1983,16 +2001,16 @@ function validateInvoice(input) {
1983
2001
  };
1984
2002
  }
1985
2003
 
1986
- // ../sdk/dist/core/schematron.js
2004
+ // ../../../../../../Users/sylvain/Code/Projets/getpeppr/packages/sdk/dist/core/schematron.js
1987
2005
  function violation(ruleId, severity, message, field) {
1988
2006
  return { ruleId, severity, message, field };
1989
2007
  }
1990
- var _knownUnitCodes;
1991
- function getKnownUnitCodes() {
1992
- if (!_knownUnitCodes) {
1993
- _knownUnitCodes = new Set(getAllUnits().map((u) => u.code));
2008
+ var _sdkUnitCodes;
2009
+ function getSdkUnitCodes() {
2010
+ if (!_sdkUnitCodes) {
2011
+ _sdkUnitCodes = new Set(getAllUnits().map((u) => u.code));
1994
2012
  }
1995
- return _knownUnitCodes;
2013
+ return _sdkUnitCodes;
1996
2014
  }
1997
2015
  var VALID_VAT_CATEGORIES = /* @__PURE__ */ new Set(["S", "Z", "E", "AE", "K", "G", "O", "L", "M", "B"]);
1998
2016
  var SENDABLE_VAT_CATEGORIES = ["S", "Z", "E", "AE", "K", "G", "O"];
@@ -2012,18 +2030,18 @@ var br02 = (input) => {
2012
2030
  }
2013
2031
  return [];
2014
2032
  };
2015
- var br03 = (input) => {
2033
+ var issueDateDefaulted = (input) => {
2016
2034
  if (!input.date) {
2017
2035
  return [
2018
- violation("BR-03", "warning", "Invoice issue date is not set. The SDK will default to today's date.", "date")
2036
+ violation("GETPEPPR-ISSUE-DATE-DEFAULTED", "warning", "Invoice issue date is not set. The SDK will default to today's date.", "date")
2019
2037
  ];
2020
2038
  }
2021
2039
  return [];
2022
2040
  };
2023
- var br06 = (input) => {
2041
+ var sellerVatRecommendation = (input) => {
2024
2042
  if (input.from && !input.from.vatNumber) {
2025
2043
  return [
2026
- violation("BR-06", "warning", "Seller party has no VAT number. The gateway will use the account's VAT registration.", "from.vatNumber")
2044
+ violation("GETPEPPR-FROM-VAT-RECOMMENDED", "warning", "Seller party has no VAT number. The gateway will use the account's VAT registration.", "from.vatNumber")
2027
2045
  ];
2028
2046
  }
2029
2047
  return [];
@@ -2034,29 +2052,29 @@ var br07 = (input) => {
2034
2052
  }
2035
2053
  return [];
2036
2054
  };
2037
- var br08 = (input) => {
2055
+ var br16 = (input) => {
2038
2056
  if (!input.lines || input.lines.length === 0) {
2039
- return [violation("BR-08", "error", "Invoice must have at least one line item.", "lines")];
2057
+ return [violation("BR-16", "error", "Invoice must have at least one line item.", "lines")];
2040
2058
  }
2041
2059
  return [];
2042
2060
  };
2043
- var br09 = (input) => {
2061
+ var paymentTimingRecommendation = (input) => {
2044
2062
  if (!input.dueDate && !input.paymentTerms) {
2045
2063
  return [
2046
- violation("BR-09", "warning", "Neither due date nor payment terms specified. At least one is recommended.", "dueDate")
2064
+ violation("GETPEPPR-PAYMENT-TIMING-RECOMMENDED", "warning", "Neither due date nor payment terms specified. At least one is recommended.", "dueDate")
2047
2065
  ];
2048
2066
  }
2049
2067
  return [];
2050
2068
  };
2051
- var br10 = (input) => {
2069
+ var buyerOrOrderReferenceRecommendation = (input) => {
2052
2070
  if (!input.buyerReference && !input.orderReference) {
2053
2071
  return [
2054
- violation("BR-10", "warning", "Neither buyerReference nor orderReference specified. Peppol BIS 3.0 requires at least one.", "buyerReference")
2072
+ violation("GETPEPPR-BUYER-OR-ORDER-REFERENCE-RECOMMENDED", "warning", "Neither buyerReference nor orderReference specified. Peppol BIS 3.0 requires at least one.", "buyerReference")
2055
2073
  ];
2056
2074
  }
2057
2075
  return [];
2058
2076
  };
2059
- var brCo10 = (input) => {
2077
+ var lineNetSanity = (input) => {
2060
2078
  const violations = [];
2061
2079
  if (!input.lines)
2062
2080
  return violations;
@@ -2066,12 +2084,12 @@ var brCo10 = (input) => {
2066
2084
  if (!Number.isFinite(net)) {
2067
2085
  const baseQty = line.baseQuantity ?? 1;
2068
2086
  const detail = baseQty === 0 ? "baseQuantity is 0, causing division by zero." : "Computed line amount is not a finite number.";
2069
- violations.push(violation("BR-CO-10", "error", `Line ${i}: invalid net amount. ${detail}`, `lines[${i}]`));
2087
+ violations.push(violation("GETPEPPR-LINE-NET-SANITY", "error", `Line ${i}: invalid net amount. ${detail}`, `lines[${i}]`));
2070
2088
  }
2071
2089
  }
2072
2090
  return violations;
2073
2091
  };
2074
- var brCo13 = (input) => {
2092
+ var computedVatSanity = (input) => {
2075
2093
  if (!input.lines || input.lines.length === 0)
2076
2094
  return [];
2077
2095
  let totalVat = 0;
@@ -2090,17 +2108,17 @@ var brCo13 = (input) => {
2090
2108
  }
2091
2109
  if (!Number.isFinite(totalVat)) {
2092
2110
  return [
2093
- violation("BR-CO-13", "error", "Computed total VAT amount is not a finite number. Check line amounts and VAT rates.")
2111
+ violation("GETPEPPR-COMPUTED-VAT-SANITY", "error", "Computed total VAT amount is not a finite number. Check line amounts and VAT rates.")
2094
2112
  ];
2095
2113
  }
2096
2114
  if (totalVat < -0.01) {
2097
2115
  return [
2098
- violation("BR-CO-13", "warning", `Computed total VAT is negative (${totalVat.toFixed(2)}). This is unusual for an invoice.`)
2116
+ violation("GETPEPPR-COMPUTED-VAT-SANITY", "warning", `Computed total VAT is negative (${totalVat.toFixed(2)}). This is unusual for an invoice.`)
2099
2117
  ];
2100
2118
  }
2101
2119
  return [];
2102
2120
  };
2103
- var brCo15 = (input) => {
2121
+ var taxInclusiveSanity = (input) => {
2104
2122
  if (!input.lines || input.lines.length === 0)
2105
2123
  return [];
2106
2124
  let lineTotal = 0;
@@ -2123,17 +2141,17 @@ var brCo15 = (input) => {
2123
2141
  const taxInclusive = lineTotal + vatTotal;
2124
2142
  if (!Number.isFinite(taxInclusive)) {
2125
2143
  return [
2126
- violation("BR-CO-15", "error", "Computed tax-inclusive amount is not a finite number.")
2144
+ violation("GETPEPPR-TAX-INCLUSIVE-SANITY", "error", "Computed tax-inclusive amount is not a finite number.")
2127
2145
  ];
2128
2146
  }
2129
2147
  if (taxInclusive < -0.01) {
2130
2148
  return [
2131
- violation("BR-CO-15", "warning", `Computed tax-inclusive amount is negative (${taxInclusive.toFixed(2)}). Consider using a credit note instead.`)
2149
+ violation("GETPEPPR-TAX-INCLUSIVE-SANITY", "warning", `Computed tax-inclusive amount is negative (${taxInclusive.toFixed(2)}). Consider using a credit note instead.`)
2132
2150
  ];
2133
2151
  }
2134
2152
  return [];
2135
2153
  };
2136
- var brCo16 = (input) => {
2154
+ var payableSanity = (input) => {
2137
2155
  if (!input.lines || input.lines.length === 0)
2138
2156
  return [];
2139
2157
  let lineTotal = 0;
@@ -2159,12 +2177,12 @@ var brCo16 = (input) => {
2159
2177
  const payable = taxInclusive - prepaid + rounding;
2160
2178
  if (!Number.isFinite(payable)) {
2161
2179
  return [
2162
- violation("BR-CO-16", "error", "Computed payable amount is not a finite number.")
2180
+ violation("GETPEPPR-PAYABLE-SANITY", "error", "Computed payable amount is not a finite number.")
2163
2181
  ];
2164
2182
  }
2165
2183
  if (payable < -0.01) {
2166
2184
  return [
2167
- violation("BR-CO-16", "warning", `Computed payable amount is negative (${payable.toFixed(2)}). Prepaid amount (${prepaid}) exceeds the invoice total.`)
2185
+ violation("GETPEPPR-PAYABLE-SANITY", "warning", `Computed payable amount is negative (${payable.toFixed(2)}). Check invoice totals, prepaid amount (${prepaid}), and rounding amount (${rounding}).`)
2168
2186
  ];
2169
2187
  }
2170
2188
  return [];
@@ -2372,14 +2390,98 @@ function validateUblBuilderVat(input) {
2372
2390
  ...UBL_BUILDER_VAT_RULES.flatMap((rule) => rule(input))
2373
2391
  ];
2374
2392
  }
2375
- var peppolR004 = (input) => {
2393
+ var buyerPeppolIdRequired = (input) => {
2376
2394
  if (!input.to?.peppolId) {
2377
2395
  return [
2378
- violation("PEPPOL-EN16931-R004", "error", "Buyer electronic address (peppolId) is required for Peppol delivery.", "to.peppolId")
2396
+ violation("GETPEPPR-BUYER-PEPPOL-ID-REQUIRED", "error", "Buyer electronic address (peppolId) is required for Peppol delivery.", "to.peppolId")
2379
2397
  ];
2380
2398
  }
2381
2399
  return [];
2382
2400
  };
2401
+ var PROFILE_INVOICE_TYPE_CODES = /* @__PURE__ */ new Set([
2402
+ "71",
2403
+ "80",
2404
+ "82",
2405
+ "84",
2406
+ "102",
2407
+ "218",
2408
+ "219",
2409
+ "326",
2410
+ "331",
2411
+ "380",
2412
+ "382",
2413
+ "383",
2414
+ "384",
2415
+ "386",
2416
+ "388",
2417
+ "393",
2418
+ "395",
2419
+ "553",
2420
+ "575",
2421
+ "623",
2422
+ "780",
2423
+ "817",
2424
+ "870",
2425
+ "875",
2426
+ "876",
2427
+ "877"
2428
+ ]);
2429
+ var PROFILE_CREDIT_NOTE_TYPE_CODES = /* @__PURE__ */ new Set([
2430
+ "381",
2431
+ "396",
2432
+ "81",
2433
+ "83",
2434
+ "532"
2435
+ ]);
2436
+ function normalizeXmlSpace(value) {
2437
+ return value.replace(/[\u0009\u000A\u000D\u0020]+/g, " ").replace(/^ /, "").replace(/ $/, "");
2438
+ }
2439
+ function normalizedTypeCode(value, fallback) {
2440
+ if (value === void 0 || value === null)
2441
+ return String(fallback);
2442
+ if (typeof value === "number" && Number.isFinite(value))
2443
+ return String(value);
2444
+ if (typeof value === "string" && value.length <= 16)
2445
+ return normalizeXmlSpace(value);
2446
+ return void 0;
2447
+ }
2448
+ function normalizedCountry(value) {
2449
+ return typeof value === "string" ? normalizeXmlSpace(value).toUpperCase() : void 0;
2450
+ }
2451
+ var invoiceTypeCodeForProfile = (input) => {
2452
+ if (input.isCreditNote)
2453
+ return [];
2454
+ const invoiceTypeCode = normalizedTypeCode(input.invoiceTypeCode, 380);
2455
+ if (invoiceTypeCode !== void 0 && PROFILE_INVOICE_TYPE_CODES.has(invoiceTypeCode))
2456
+ return [];
2457
+ return [
2458
+ violation("PEPPOL-EN16931-P0100", "error", "Invoice type code is not allowed by the Peppol billing profile used by the local UBL builder.", "invoiceTypeCode")
2459
+ ];
2460
+ };
2461
+ var creditNoteTypeCodeForProfile = (input) => {
2462
+ if (!input.isCreditNote)
2463
+ return [];
2464
+ const invoiceTypeCode = normalizedTypeCode(input.invoiceTypeCode, 381);
2465
+ if (invoiceTypeCode !== void 0 && PROFILE_CREDIT_NOTE_TYPE_CODES.has(invoiceTypeCode))
2466
+ return [];
2467
+ return [
2468
+ violation("PEPPOL-EN16931-P0101", "error", "Credit note type code is not allowed by the Peppol billing profile used by the local UBL builder.", "invoiceTypeCode")
2469
+ ];
2470
+ };
2471
+ var germanInvoiceTypeCode = (input) => {
2472
+ if (input.isCreditNote)
2473
+ return [];
2474
+ const invoiceTypeCode = normalizedTypeCode(input.invoiceTypeCode, 380);
2475
+ if (invoiceTypeCode !== "326" && invoiceTypeCode !== "384")
2476
+ return [];
2477
+ const sellerCountry = normalizedCountry(input.from?.country);
2478
+ const buyerCountry = normalizedCountry(input.to?.country);
2479
+ if (sellerCountry === "DE" && buyerCountry === "DE")
2480
+ return [];
2481
+ return [
2482
+ violation("PEPPOL-EN16931-P0112", "error", "Invoice type code 326 or 384 is only allowed when both buyer and seller are German organizations.", "invoiceTypeCode")
2483
+ ];
2484
+ };
2383
2485
  var vatCategoryCodes = (input) => {
2384
2486
  const violations = [];
2385
2487
  const sendable = SENDABLE_VAT_CATEGORIES.join(", ");
@@ -2400,17 +2502,17 @@ var vatCategoryCodes = (input) => {
2400
2502
  (input.charges ?? []).forEach((c, i) => check(c.vatCategory, `charges[${i}].vatCategory`, `Charge ${i}`));
2401
2503
  return violations;
2402
2504
  };
2403
- var peppolR080 = (input) => {
2505
+ var unitCodeRecognised = (input) => {
2404
2506
  const violations = [];
2405
2507
  if (!input.lines)
2406
2508
  return violations;
2407
- const knownCodes = getKnownUnitCodes();
2509
+ const knownCodes = getSdkUnitCodes();
2408
2510
  for (let i = 0; i < input.lines.length; i++) {
2409
2511
  const line = input.lines[i];
2410
2512
  if (line.unit) {
2411
2513
  const resolved = resolveUnit(line.unit);
2412
2514
  if (!knownCodes.has(resolved)) {
2413
- violations.push(violation("PEPPOL-EN16931-R080", "warning", `Line ${i}: unit "${line.unit}" (resolved: "${resolved}") is not a known UN/ECE Rec20 code. Common codes: EA, HUR, DAY, KGM.`, `lines[${i}].unit`));
2515
+ violations.push(violation("GETPEPPR-UNIT-CODE-RECOGNISED", "warning", `Line ${i}: unit "${line.unit}" (resolved: "${resolved}") is not in the SDK's common unit list. It may still be a valid UN/ECE Rec20/21 code; network validation decides. Common codes: EA, HUR, DAY, KGM.`, `lines[${i}].unit`));
2414
2516
  }
2415
2517
  }
2416
2518
  }
@@ -2419,17 +2521,17 @@ var peppolR080 = (input) => {
2419
2521
  var ALL_RULES = [
2420
2522
  // Required fields (BR)
2421
2523
  br02,
2422
- br03,
2423
- br06,
2524
+ issueDateDefaulted,
2525
+ sellerVatRecommendation,
2424
2526
  br07,
2425
- br08,
2426
- br09,
2427
- br10,
2527
+ br16,
2528
+ paymentTimingRecommendation,
2529
+ buyerOrOrderReferenceRecommendation,
2428
2530
  // Calculations (BR-CO)
2429
- brCo10,
2430
- brCo13,
2431
- brCo15,
2432
- brCo16,
2531
+ lineNetSanity,
2532
+ computedVatSanity,
2533
+ taxInclusiveSanity,
2534
+ payableSanity,
2433
2535
  // Tax categories (one family per category)
2434
2536
  brS05,
2435
2537
  brZ05,
@@ -2444,9 +2546,12 @@ var ALL_RULES = [
2444
2546
  brO10,
2445
2547
  brIc10,
2446
2548
  // Peppol-specific
2447
- peppolR004,
2549
+ buyerPeppolIdRequired,
2550
+ invoiceTypeCodeForProfile,
2551
+ creditNoteTypeCodeForProfile,
2552
+ germanInvoiceTypeCode,
2448
2553
  vatCategoryCodes,
2449
- peppolR080
2554
+ unitCodeRecognised
2450
2555
  ];
2451
2556
  function validateSchematron(input) {
2452
2557
  const errors = [];
@@ -2470,17 +2575,17 @@ function validateSchematron(input) {
2470
2575
  }
2471
2576
  var SDK_SCHEMATRON_RULE_IDS = [
2472
2577
  "BR-02",
2473
- "BR-03",
2474
- "BR-06",
2578
+ "GETPEPPR-ISSUE-DATE-DEFAULTED",
2579
+ "GETPEPPR-FROM-VAT-RECOMMENDED",
2475
2580
  "BR-07",
2476
- "BR-08",
2477
- "BR-09",
2478
- "BR-10",
2581
+ "BR-16",
2582
+ "GETPEPPR-PAYMENT-TIMING-RECOMMENDED",
2583
+ "GETPEPPR-BUYER-OR-ORDER-REFERENCE-RECOMMENDED",
2479
2584
  "BR-CL-17",
2480
- "BR-CO-10",
2481
- "BR-CO-13",
2482
- "BR-CO-15",
2483
- "BR-CO-16",
2585
+ "GETPEPPR-LINE-NET-SANITY",
2586
+ "GETPEPPR-COMPUTED-VAT-SANITY",
2587
+ "GETPEPPR-TAX-INCLUSIVE-SANITY",
2588
+ "GETPEPPR-PAYABLE-SANITY",
2484
2589
  "BR-S-05",
2485
2590
  "BR-Z-05",
2486
2591
  "BR-E-05",
@@ -2504,11 +2609,14 @@ var SDK_SCHEMATRON_RULE_IDS = [
2504
2609
  "BR-G-10",
2505
2610
  "BR-O-10",
2506
2611
  "BR-IC-10",
2507
- "PEPPOL-EN16931-R004",
2508
- "PEPPOL-EN16931-R080"
2612
+ "GETPEPPR-BUYER-PEPPOL-ID-REQUIRED",
2613
+ "PEPPOL-EN16931-P0100",
2614
+ "PEPPOL-EN16931-P0101",
2615
+ "PEPPOL-EN16931-P0112",
2616
+ "GETPEPPR-UNIT-CODE-RECOGNISED"
2509
2617
  ];
2510
2618
 
2511
- // ../sdk/dist/core/status-precedence.js
2619
+ // ../../../../../../Users/sylvain/Code/Projets/getpeppr/packages/sdk/dist/core/status-precedence.js
2512
2620
  var STATUS_PRECEDENCE = [
2513
2621
  { status: "failed", family: "terminal-failure" },
2514
2622
  { status: "rejected", family: "terminal-failure" },
@@ -2532,10 +2640,10 @@ function statusFamily(status) {
2532
2640
  }
2533
2641
  var TERMINAL_FAILURE_STATUSES = STATUS_PRECEDENCE.filter((e) => e.family === "terminal-failure").map((e) => e.status);
2534
2642
 
2535
- // ../sdk/dist/version.js
2536
- var SDK_VERSION = "5.1.0";
2643
+ // ../../../../../../Users/sylvain/Code/Projets/getpeppr/packages/sdk/dist/version.js
2644
+ var SDK_VERSION = "5.2.0";
2537
2645
 
2538
- // ../sdk/dist/core/api-result.js
2646
+ // ../../../../../../Users/sylvain/Code/Projets/getpeppr/packages/sdk/dist/core/api-result.js
2539
2647
  var API_RESULT_HEADER_NAMES = {
2540
2648
  requestId: "Getpeppr-Request-Id",
2541
2649
  resultCode: "Getpeppr-Result-Code",
@@ -2652,7 +2760,7 @@ function parseApiResultHeaders(headers) {
2652
2760
  return Object.keys(result).length === 0 ? void 0 : result;
2653
2761
  }
2654
2762
 
2655
- // ../sdk/dist/core/client.js
2763
+ // ../../../../../../Users/sylvain/Code/Projets/getpeppr/packages/sdk/dist/core/client.js
2656
2764
  function normalizeHeaderValue(value) {
2657
2765
  return value.replace(/^[\t\n\r ]+|[\t\n\r ]+$/g, "");
2658
2766
  }
@@ -4158,7 +4266,8 @@ ${validation.errors.map((e) => ` - ${e.field}: ${e.message}${e.suggestion ? ` (
4158
4266
  /**
4159
4267
  * Validate an invoice server-side using the getpeppr gateway's offline SDK-backed checks.
4160
4268
  * The gateway runs SDK validation, verifies UBL XML generation, and evaluates offline
4161
- * Peppol business rules without sending the invoice to Storecove.
4269
+ * pre-flight checks without sending the invoice to Storecove. This is not a Peppol
4270
+ * conformance verdict.
4162
4271
  *
4163
4272
  * @example
4164
4273
  * ```ts
@@ -4423,6 +4532,8 @@ var DirectoryOperations = class {
4423
4532
  }
4424
4533
  /**
4425
4534
  * Search the Peppol Directory for participants.
4535
+ * Pagination is exact and participant-based. Queries wider than the public
4536
+ * Directory's accessible result window are rejected; add narrower criteria.
4426
4537
  *
4427
4538
  * @example
4428
4539
  * ```ts
@@ -4888,14 +4999,32 @@ var TransportOperations = class {
4888
4999
  };
4889
5000
 
4890
5001
  // src/commands/validate.ts
4891
- function runValidation(input) {
5002
+ var SEND_INERT_INVOICE_TYPE_PROFILE_RULES = /* @__PURE__ */ new Set([
5003
+ "PEPPOL-EN16931-P0100",
5004
+ "PEPPOL-EN16931-P0101",
5005
+ "PEPPOL-EN16931-P0112"
5006
+ ]);
5007
+ function isSendRelevantSchematronViolation(violation2) {
5008
+ return !(violation2.field === "invoiceTypeCode" && SEND_INERT_INVOICE_TYPE_PROFILE_RULES.has(violation2.ruleId));
5009
+ }
5010
+ function runMergedValidation(input, schematronFilter) {
4892
5011
  const structure = validateInvoice(input);
4893
- const schematron = validateSchematron(input);
5012
+ const completeSchematron = validateSchematron(input);
5013
+ const schematron = {
5014
+ errors: completeSchematron.errors.filter(schematronFilter),
5015
+ warnings: completeSchematron.warnings
5016
+ };
4894
5017
  const countryRules = validateCountryRules(input);
5018
+ const countryKeys = new Set(
5019
+ countryRules.warnings.map((w) => JSON.stringify([w.field, w.message, w.ruleId]))
5020
+ );
5021
+ const structureWarnings = structure.warnings.filter(
5022
+ (w) => !countryKeys.has(JSON.stringify([w.field, w.message, w.ruleId]))
5023
+ );
4895
5024
  const totalErrors = structure.errors.length + schematron.errors.length + countryRules.errors.length;
4896
- const totalWarnings = structure.warnings.length + schematron.warnings.length + countryRules.warnings.length;
5025
+ const totalWarnings = structureWarnings.length + schematron.warnings.length + countryRules.warnings.length;
4897
5026
  return {
4898
- structure: { errors: structure.errors, warnings: structure.warnings },
5027
+ structure: { errors: structure.errors, warnings: structureWarnings },
4899
5028
  schematron: { errors: schematron.errors, warnings: schematron.warnings },
4900
5029
  countryRules: {
4901
5030
  errors: countryRules.errors,
@@ -4906,6 +5035,12 @@ function runValidation(input) {
4906
5035
  valid: totalErrors === 0
4907
5036
  };
4908
5037
  }
5038
+ function runValidation(input) {
5039
+ return runMergedValidation(input, () => true);
5040
+ }
5041
+ function runSendPreflight(input) {
5042
+ return runMergedValidation(input, isSendRelevantSchematronViolation);
5043
+ }
4909
5044
  function registerValidateCommand(program2) {
4910
5045
  program2.command("validate").description("Validate a Peppol invoice JSON file").argument("<file>", "path to invoice JSON file").option("--json", "output results as JSON").option("--quiet", "exit code only, no output").action(async (file, options) => {
4911
5046
  const input = readAndValidateInvoiceJson(file);
@@ -5753,7 +5888,7 @@ function formatSendResult(result, mode) {
5753
5888
  var API_BASE = "https://api.getpeppr.dev/v1";
5754
5889
  var LOCAL_BASE = "http://localhost:3001/api/v1";
5755
5890
  function registerSendCommand(program2) {
5756
- program2.command("send").description("Send an invoice to the Peppol network via getpeppr API").argument("[file]", "optional path to invoice JSON (mutex with --to/--amount/...)").option("--prod", "target production (live keys + confirmation)").option("--local", "target localhost:3001 dev server").option("--key <key>", "override API key \u2014 for CI/scripted use only; visible in `ps` and shell history. Prefer GETPEPPR_API_KEY env var.").option("--to <peppol-id>", "recipient peppol id (e.g., 9925:BE0314595348)").option("--country <iso>", "recipient ISO 3166-1 alpha-2 country override (e.g., BE)").option("--amount <number>", "line amount in major currency units (decimal allowed)").option("--currency <iso>", "ISO 4217 currency (default EUR)").option("--desc <text>", "line description").option("--attachment", "attach the test PDF").option("--watch", "poll status until a terminal state (60s timeout)").option("-y, --yes", "skip --prod confirmation prompt").option("--no-validate", "skip pre-validation locally").option("--json", "output JSON").option("--quiet", "exit code only, no output").action(async (file, flags) => {
5891
+ program2.command("send").description("Send an invoice to the Peppol network via getpeppr API").argument("[file]", "optional path to invoice JSON (mutex with --to/--amount/...)").option("--prod", "target production (live keys + confirmation)").option("--local", "target localhost:3001 dev server").option("--key <key>", "override API key \u2014 for CI/scripted use only; visible in `ps` and shell history. Prefer GETPEPPR_API_KEY env var.").option("--to <peppol-id>", "recipient peppol id (e.g., 9925:BE0314595348)").option("--country <iso>", "recipient ISO 3166-1 alpha-2 country override (e.g., BE)").option("--amount <number>", "line amount in major currency units (decimal allowed)").option("--currency <iso>", "ISO 4217 currency (default EUR)").option("--desc <text>", "line description").option("--attachment", "attach the test PDF").option("--watch", "poll status until a terminal state (60s timeout)").option("-y, --yes", "skip --prod confirmation prompt").option("--no-validate", "skip the JSON send preflight").option("--json", "output JSON").option("--quiet", "exit code only, no output").action(async (file, flags) => {
5757
5892
  let auth;
5758
5893
  try {
5759
5894
  auth = resolveApiKey({
@@ -5827,7 +5962,7 @@ function registerSendCommand(program2) {
5827
5962
  }
5828
5963
  }
5829
5964
  if (flags.validate !== false) {
5830
- const result2 = runValidation(payload);
5965
+ const result2 = runSendPreflight(payload);
5831
5966
  if (!result2.valid) {
5832
5967
  process.stderr.write(
5833
5968
  `${pc6.red("\u2717")} Pre-validation failed (${result2.totalErrors} errors). Use --no-validate to skip.