@taxora/sdk 1.9.0 → 1.10.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/CHANGELOG.md +29 -0
- package/README.md +54 -0
- package/dist/index.cjs +692 -236
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +271 -50
- package/dist/index.d.ts +271 -50
- package/dist/index.js +684 -236
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -440,17 +440,144 @@ var AuthEndpoint = class {
|
|
|
440
440
|
}
|
|
441
441
|
};
|
|
442
442
|
|
|
443
|
-
// src/dto/
|
|
443
|
+
// src/dto/EInvoicingQuota.ts
|
|
444
|
+
function asString(value, fallback = "") {
|
|
445
|
+
return typeof value === "string" ? value : fallback;
|
|
446
|
+
}
|
|
447
|
+
function asNullableString(value) {
|
|
448
|
+
return typeof value === "string" ? value : null;
|
|
449
|
+
}
|
|
450
|
+
function asInt(value) {
|
|
451
|
+
return typeof value === "number" ? Math.trunc(value) : Number(value ?? 0) || 0;
|
|
452
|
+
}
|
|
444
453
|
function asRecord(value) {
|
|
445
454
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
446
455
|
}
|
|
456
|
+
var EInvoicingQuotaPeriod = class _EInvoicingQuotaPeriod {
|
|
457
|
+
constructor(period, used, included, freeUsed, freeRemaining, billableUnits, amount, monthlyFee, total, state, byCountry, billedAt, manualReference, monthlyFeeReference) {
|
|
458
|
+
this.period = period;
|
|
459
|
+
this.used = used;
|
|
460
|
+
this.included = included;
|
|
461
|
+
this.freeUsed = freeUsed;
|
|
462
|
+
this.freeRemaining = freeRemaining;
|
|
463
|
+
this.billableUnits = billableUnits;
|
|
464
|
+
this.amount = amount;
|
|
465
|
+
this.monthlyFee = monthlyFee;
|
|
466
|
+
this.total = total;
|
|
467
|
+
this.state = state;
|
|
468
|
+
this.byCountry = byCountry;
|
|
469
|
+
this.billedAt = billedAt;
|
|
470
|
+
this.manualReference = manualReference;
|
|
471
|
+
this.monthlyFeeReference = monthlyFeeReference;
|
|
472
|
+
}
|
|
473
|
+
period;
|
|
474
|
+
used;
|
|
475
|
+
included;
|
|
476
|
+
freeUsed;
|
|
477
|
+
freeRemaining;
|
|
478
|
+
billableUnits;
|
|
479
|
+
amount;
|
|
480
|
+
monthlyFee;
|
|
481
|
+
total;
|
|
482
|
+
state;
|
|
483
|
+
byCountry;
|
|
484
|
+
billedAt;
|
|
485
|
+
manualReference;
|
|
486
|
+
monthlyFeeReference;
|
|
487
|
+
static fromArray(data) {
|
|
488
|
+
const byCountry = {};
|
|
489
|
+
if (Array.isArray(data["by_country"])) {
|
|
490
|
+
for (const row of data["by_country"]) {
|
|
491
|
+
const entry = asRecord(row);
|
|
492
|
+
if (entry && typeof entry["country"] === "string") {
|
|
493
|
+
byCountry[entry["country"]] = asInt(entry["used"]);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return new _EInvoicingQuotaPeriod(
|
|
498
|
+
asString(data["period"]),
|
|
499
|
+
asInt(data["used"]),
|
|
500
|
+
asInt(data["included"]),
|
|
501
|
+
asInt(data["free_used"]),
|
|
502
|
+
asInt(data["free_remaining"]),
|
|
503
|
+
asInt(data["billable_units"]),
|
|
504
|
+
asString(data["amount"], "0.00"),
|
|
505
|
+
asNullableString(data["monthly_fee"]),
|
|
506
|
+
asString(data["total"], "0.00"),
|
|
507
|
+
asString(data["state"], "open"),
|
|
508
|
+
byCountry,
|
|
509
|
+
asNullableString(data["billed_at"]),
|
|
510
|
+
asNullableString(data["manual_reference"]),
|
|
511
|
+
asNullableString(data["monthly_fee_reference"])
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
var EInvoicingQuota = class _EInvoicingQuota {
|
|
516
|
+
constructor(billing, plan, currency, included, tiers, countries, monthlyFee, current, history) {
|
|
517
|
+
this.billing = billing;
|
|
518
|
+
this.plan = plan;
|
|
519
|
+
this.currency = currency;
|
|
520
|
+
this.included = included;
|
|
521
|
+
this.tiers = tiers;
|
|
522
|
+
this.countries = countries;
|
|
523
|
+
this.monthlyFee = monthlyFee;
|
|
524
|
+
this.current = current;
|
|
525
|
+
this.history = history;
|
|
526
|
+
}
|
|
527
|
+
billing;
|
|
528
|
+
plan;
|
|
529
|
+
currency;
|
|
530
|
+
included;
|
|
531
|
+
tiers;
|
|
532
|
+
countries;
|
|
533
|
+
monthlyFee;
|
|
534
|
+
current;
|
|
535
|
+
history;
|
|
536
|
+
static fromArray(data) {
|
|
537
|
+
const tiers = [];
|
|
538
|
+
if (Array.isArray(data["tiers"])) {
|
|
539
|
+
for (const row of data["tiers"]) {
|
|
540
|
+
const tier = asRecord(row);
|
|
541
|
+
if (tier) {
|
|
542
|
+
tiers.push({
|
|
543
|
+
upTo: tier["up_to"] === null || tier["up_to"] === void 0 ? null : asInt(tier["up_to"]),
|
|
544
|
+
unitPrice: asString(tier["unit_price"], "0")
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
const history = [];
|
|
550
|
+
if (Array.isArray(data["history"])) {
|
|
551
|
+
for (const row of data["history"]) {
|
|
552
|
+
const period = asRecord(row);
|
|
553
|
+
if (period) history.push(EInvoicingQuotaPeriod.fromArray(period));
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
return new _EInvoicingQuota(
|
|
557
|
+
asString(data["billing"], "invoice"),
|
|
558
|
+
asNullableString(data["plan"]),
|
|
559
|
+
asString(data["currency"], "EUR"),
|
|
560
|
+
asInt(data["included"]),
|
|
561
|
+
tiers,
|
|
562
|
+
Array.isArray(data["countries"]) ? data["countries"].map(String) : [],
|
|
563
|
+
asNullableString(data["monthly_fee"]),
|
|
564
|
+
EInvoicingQuotaPeriod.fromArray(asRecord(data["current"]) ?? {}),
|
|
565
|
+
history
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
// src/dto/UsageSummary.ts
|
|
571
|
+
function asRecord2(value) {
|
|
572
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
573
|
+
}
|
|
447
574
|
function asRecordList(value) {
|
|
448
|
-
return Array.isArray(value) ? value.filter((row) =>
|
|
575
|
+
return Array.isArray(value) ? value.filter((row) => asRecord2(row) !== null) : [];
|
|
449
576
|
}
|
|
450
|
-
function
|
|
577
|
+
function asString2(value, fallback = "") {
|
|
451
578
|
return typeof value === "string" ? value : fallback;
|
|
452
579
|
}
|
|
453
|
-
function
|
|
580
|
+
function asNullableString2(value) {
|
|
454
581
|
return typeof value === "string" ? value : null;
|
|
455
582
|
}
|
|
456
583
|
function asNumber(value) {
|
|
@@ -507,35 +634,35 @@ var UsageSummary = class _UsageSummary {
|
|
|
507
634
|
return new _UsageSummary(
|
|
508
635
|
asNumber(data["id"]),
|
|
509
636
|
asNumber(data["company_id"]),
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
637
|
+
asString2(data["feature"]),
|
|
638
|
+
asNullableString2(data["country"]),
|
|
639
|
+
asNullableString2(data["regime"]),
|
|
640
|
+
asString2(data["billing_period"]),
|
|
514
641
|
asNumber(data["event_count"]),
|
|
515
642
|
typeof amount === "string" ? amount : typeof amount === "number" ? String(amount) : null,
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
643
|
+
asNullableString2(data["state"]),
|
|
644
|
+
asNullableString2(data["state_label"]),
|
|
645
|
+
asNullableString2(data["period_closed_at"]),
|
|
646
|
+
asNullableString2(data["billing_triggered_at"]),
|
|
647
|
+
asNullableString2(data["billed_at"]),
|
|
648
|
+
asNullableString2(data["stripe_invoice_id"]),
|
|
649
|
+
asNullableString2(data["stripe_subscription_item_id"]),
|
|
650
|
+
asNullableString2(data["billing_notes"]),
|
|
524
651
|
asRecordList(data["events"]).map((event) => ({
|
|
525
652
|
id: asNumber(event["id"]),
|
|
526
653
|
usageSummaryId: asNullableNumber(event["usage_summary_id"]),
|
|
527
|
-
feature:
|
|
528
|
-
country:
|
|
529
|
-
regime:
|
|
530
|
-
billingPeriod:
|
|
531
|
-
resourceType:
|
|
654
|
+
feature: asString2(event["feature"]),
|
|
655
|
+
country: asNullableString2(event["country"]),
|
|
656
|
+
regime: asNullableString2(event["regime"]),
|
|
657
|
+
billingPeriod: asString2(event["billing_period"]),
|
|
658
|
+
resourceType: asNullableString2(event["resource_type"]),
|
|
532
659
|
resourceId: asNullableNumber(event["resource_id"]),
|
|
533
|
-
stripeUsageRecordId:
|
|
534
|
-
stripeReportedAt:
|
|
535
|
-
createdAt:
|
|
660
|
+
stripeUsageRecordId: asNullableString2(event["stripe_usage_record_id"]),
|
|
661
|
+
stripeReportedAt: asNullableString2(event["stripe_reported_at"]),
|
|
662
|
+
createdAt: asNullableString2(event["created_at"])
|
|
536
663
|
})),
|
|
537
|
-
|
|
538
|
-
|
|
664
|
+
asNullableString2(data["created_at"]),
|
|
665
|
+
asNullableString2(data["updated_at"])
|
|
539
666
|
);
|
|
540
667
|
}
|
|
541
668
|
};
|
|
@@ -553,9 +680,9 @@ var UsageSummaryPage = class _UsageSummaryPage {
|
|
|
553
680
|
total;
|
|
554
681
|
lastPage;
|
|
555
682
|
static fromResponse(payload) {
|
|
556
|
-
const obj =
|
|
683
|
+
const obj = asRecord2(payload) ?? {};
|
|
557
684
|
const rows = asRecordList(obj["data"]).map(UsageSummary.fromArray);
|
|
558
|
-
const meta =
|
|
685
|
+
const meta = asRecord2(obj["meta"]) ?? {};
|
|
559
686
|
const num = (value, fallback) => typeof value === "number" ? value : fallback;
|
|
560
687
|
return new _UsageSummaryPage(
|
|
561
688
|
rows,
|
|
@@ -607,6 +734,22 @@ var BillingEndpoint = class {
|
|
|
607
734
|
const data = await this.getJson(`${this.baseUrl}/billing/usage-summaries/${period}`);
|
|
608
735
|
return Array.isArray(data) ? data.filter((row) => typeof row === "object" && row !== null).map(UsageSummary.fromArray) : [];
|
|
609
736
|
}
|
|
737
|
+
/**
|
|
738
|
+
* The e-invoicing allowance: documents included per month, used, still free and
|
|
739
|
+
* what is due for the documents beyond it — one pool over all e-invoicing
|
|
740
|
+
* countries, current month first, then up to `months - 1` earlier months (1-24).
|
|
741
|
+
* Resolves to null when the company has no e-invoicing.
|
|
742
|
+
*/
|
|
743
|
+
async getEInvoicingQuota(months = 6) {
|
|
744
|
+
if (!Number.isInteger(months) || months < 1 || months > 24) {
|
|
745
|
+
throw new TaxoraException("months must be an integer between 1 and 24.");
|
|
746
|
+
}
|
|
747
|
+
const data = await this.getJson(`${this.baseUrl}/billing/einvoicing-quota?months=${months}`);
|
|
748
|
+
if (typeof data !== "object" || data === null || Array.isArray(data) || !("billing" in data)) {
|
|
749
|
+
return null;
|
|
750
|
+
}
|
|
751
|
+
return EInvoicingQuota.fromArray(data);
|
|
752
|
+
}
|
|
610
753
|
buildHeaders() {
|
|
611
754
|
const headers = {
|
|
612
755
|
"Content-Type": "application/json",
|
|
@@ -712,6 +855,67 @@ var CompanyEndpoint = class {
|
|
|
712
855
|
}
|
|
713
856
|
};
|
|
714
857
|
|
|
858
|
+
// src/enums/ComplianceDeliveryAction.ts
|
|
859
|
+
var ComplianceDeliveryAction = {
|
|
860
|
+
/** The buyer can receive e-invoices: create the transaction, Taxora sends it. */
|
|
861
|
+
EINVOICE: "einvoice",
|
|
862
|
+
/** The buyer is not on the network: send your regular invoice yourself (a transaction would end as not_required and is not billed). */
|
|
863
|
+
REGULAR_INVOICE: "regular_invoice",
|
|
864
|
+
/** No definite directory answer yet: create the transaction anyway, Taxora asks again before sending. */
|
|
865
|
+
EINVOICE_PENDING: "einvoice_pending"
|
|
866
|
+
};
|
|
867
|
+
|
|
868
|
+
// src/enums/PeppolLookupStatus.ts
|
|
869
|
+
var PeppolLookupStatus = {
|
|
870
|
+
REACHABLE: "reachable",
|
|
871
|
+
NOT_REACHABLE: "not_reachable",
|
|
872
|
+
PENDING: "pending",
|
|
873
|
+
UNKNOWN: "unknown"
|
|
874
|
+
};
|
|
875
|
+
var VALUES = Object.values(PeppolLookupStatus);
|
|
876
|
+
function toPeppolLookupStatus(value) {
|
|
877
|
+
if (typeof value === "string") {
|
|
878
|
+
const normalized = value.trim().toLowerCase();
|
|
879
|
+
if (VALUES.includes(normalized)) {
|
|
880
|
+
return normalized;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
return PeppolLookupStatus.UNKNOWN;
|
|
884
|
+
}
|
|
885
|
+
var DESCRIPTIONS = {
|
|
886
|
+
[PeppolLookupStatus.REACHABLE]: "The participant is registered on Peppol and can receive e-invoices.",
|
|
887
|
+
[PeppolLookupStatus.NOT_REACHABLE]: "The participant is not registered on Peppol.",
|
|
888
|
+
[PeppolLookupStatus.PENDING]: "The directory lookup is still resolving \u2014 ask again in a few seconds.",
|
|
889
|
+
[PeppolLookupStatus.UNKNOWN]: "Unknown lookup status."
|
|
890
|
+
};
|
|
891
|
+
function describePeppolLookupStatus(status) {
|
|
892
|
+
return DESCRIPTIONS[status];
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
// src/dto/ComplianceDeliveryDecision.ts
|
|
896
|
+
var ComplianceDeliveryDecision = class _ComplianceDeliveryDecision {
|
|
897
|
+
constructor(action, lookup) {
|
|
898
|
+
this.action = action;
|
|
899
|
+
this.lookup = lookup;
|
|
900
|
+
}
|
|
901
|
+
action;
|
|
902
|
+
lookup;
|
|
903
|
+
/** True unless the buyer is not on the network. */
|
|
904
|
+
get sendsEInvoice() {
|
|
905
|
+
return this.action !== ComplianceDeliveryAction.REGULAR_INVOICE;
|
|
906
|
+
}
|
|
907
|
+
static fromLookup(lookup) {
|
|
908
|
+
switch (lookup.status) {
|
|
909
|
+
case PeppolLookupStatus.REACHABLE:
|
|
910
|
+
return new _ComplianceDeliveryDecision(ComplianceDeliveryAction.EINVOICE, lookup);
|
|
911
|
+
case PeppolLookupStatus.NOT_REACHABLE:
|
|
912
|
+
return new _ComplianceDeliveryDecision(ComplianceDeliveryAction.REGULAR_INVOICE, lookup);
|
|
913
|
+
default:
|
|
914
|
+
return new _ComplianceDeliveryDecision(ComplianceDeliveryAction.EINVOICE_PENDING, lookup);
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
|
|
715
919
|
// src/enums/ComplianceEnrollmentStatus.ts
|
|
716
920
|
var ComplianceEnrollmentStatus = {
|
|
717
921
|
PENDING_DATA: "pending_data",
|
|
@@ -723,17 +927,17 @@ var ComplianceEnrollmentStatus = {
|
|
|
723
927
|
ERROR_ACTIVATION: "error_activation",
|
|
724
928
|
UNKNOWN: "unknown"
|
|
725
929
|
};
|
|
726
|
-
var
|
|
930
|
+
var VALUES2 = Object.values(ComplianceEnrollmentStatus);
|
|
727
931
|
function toComplianceEnrollmentStatus(value) {
|
|
728
932
|
if (typeof value === "string") {
|
|
729
933
|
const normalized = value.trim().toLowerCase();
|
|
730
|
-
if (
|
|
934
|
+
if (VALUES2.includes(normalized)) {
|
|
731
935
|
return normalized;
|
|
732
936
|
}
|
|
733
937
|
}
|
|
734
938
|
return ComplianceEnrollmentStatus.UNKNOWN;
|
|
735
939
|
}
|
|
736
|
-
var
|
|
940
|
+
var DESCRIPTIONS2 = {
|
|
737
941
|
[ComplianceEnrollmentStatus.PENDING_DATA]: "Awaiting merchant data before provisioning can start.",
|
|
738
942
|
[ComplianceEnrollmentStatus.ACCOUNT_CREATED]: "Provider account exists. Regime not yet activated.",
|
|
739
943
|
[ComplianceEnrollmentStatus.REGIME_ACTIVATED]: "Compliance regime activated at provider. Ready to submit transactions.",
|
|
@@ -744,7 +948,7 @@ var DESCRIPTIONS = {
|
|
|
744
948
|
[ComplianceEnrollmentStatus.UNKNOWN]: "Unknown status."
|
|
745
949
|
};
|
|
746
950
|
function describeComplianceEnrollmentStatus(status) {
|
|
747
|
-
return
|
|
951
|
+
return DESCRIPTIONS2[status];
|
|
748
952
|
}
|
|
749
953
|
|
|
750
954
|
// src/enums/ComplianceService.ts
|
|
@@ -753,30 +957,30 @@ var ComplianceService = {
|
|
|
753
957
|
E_INVOICING: "e_invoicing",
|
|
754
958
|
UNKNOWN: "unknown"
|
|
755
959
|
};
|
|
756
|
-
var
|
|
960
|
+
var VALUES3 = Object.values(ComplianceService);
|
|
757
961
|
function toComplianceService(value) {
|
|
758
962
|
if (typeof value === "string") {
|
|
759
963
|
const normalized = value.trim().toLowerCase();
|
|
760
|
-
if (
|
|
964
|
+
if (VALUES3.includes(normalized)) {
|
|
761
965
|
return normalized;
|
|
762
966
|
}
|
|
763
967
|
}
|
|
764
968
|
return ComplianceService.UNKNOWN;
|
|
765
969
|
}
|
|
766
|
-
var
|
|
970
|
+
var DESCRIPTIONS3 = {
|
|
767
971
|
[ComplianceService.E_REPORTING]: "E-reporting of transaction data to the tax authority (France: DGFiP Flux 10).",
|
|
768
972
|
[ComplianceService.E_INVOICING]: "Structured e-invoices delivered to the buyer (Norway: EHF / Peppol BIS 3.0).",
|
|
769
973
|
[ComplianceService.UNKNOWN]: "Unknown service."
|
|
770
974
|
};
|
|
771
975
|
function describeComplianceService(service) {
|
|
772
|
-
return
|
|
976
|
+
return DESCRIPTIONS3[service];
|
|
773
977
|
}
|
|
774
978
|
|
|
775
979
|
// src/dto/ComplianceEnrollment.ts
|
|
776
|
-
function
|
|
980
|
+
function asString3(value, fallback = "") {
|
|
777
981
|
return typeof value === "string" ? value : fallback;
|
|
778
982
|
}
|
|
779
|
-
function
|
|
983
|
+
function asNullableString3(value) {
|
|
780
984
|
return typeof value === "string" ? value : null;
|
|
781
985
|
}
|
|
782
986
|
function asNumber2(value) {
|
|
@@ -828,38 +1032,38 @@ var ComplianceEnrollment = class _ComplianceEnrollment {
|
|
|
828
1032
|
return new _ComplianceEnrollment(
|
|
829
1033
|
asNumber2(data["id"]),
|
|
830
1034
|
asNumber2(data["company_id"]),
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
1035
|
+
asString3(data["country"]),
|
|
1036
|
+
asString3(data["regime"]),
|
|
1037
|
+
asString3(data["provider"]),
|
|
834
1038
|
toComplianceEnrollmentStatus(data["status"]),
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
1039
|
+
asString3(data["status_label"]),
|
|
1040
|
+
asNullableString3(data["status_error"]),
|
|
1041
|
+
asNullableString3(data["provider_account_id"]),
|
|
1042
|
+
asNullableString3(data["tax_id"]),
|
|
1043
|
+
asNullableString3(data["company_register_id"]),
|
|
1044
|
+
asNullableString3(data["company_register_scheme"]),
|
|
841
1045
|
regimeConfig,
|
|
842
|
-
|
|
843
|
-
|
|
1046
|
+
asNullableString3(data["reporting_start_date"]),
|
|
1047
|
+
asNullableString3(data["notification_email"]),
|
|
844
1048
|
data["auto_send"] === true,
|
|
845
|
-
|
|
846
|
-
|
|
1049
|
+
asNullableString3(data["created_at"]),
|
|
1050
|
+
asNullableString3(data["updated_at"]),
|
|
847
1051
|
toComplianceService(data["service"])
|
|
848
1052
|
);
|
|
849
1053
|
}
|
|
850
1054
|
};
|
|
851
1055
|
|
|
852
1056
|
// src/dto/ComplianceOfferings.ts
|
|
853
|
-
function
|
|
1057
|
+
function asRecord3(value) {
|
|
854
1058
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
855
1059
|
}
|
|
856
1060
|
function asRecordList2(value) {
|
|
857
|
-
return Array.isArray(value) ? value.filter((row) =>
|
|
1061
|
+
return Array.isArray(value) ? value.filter((row) => asRecord3(row) !== null) : [];
|
|
858
1062
|
}
|
|
859
|
-
function
|
|
1063
|
+
function asString4(value, fallback = "") {
|
|
860
1064
|
return typeof value === "string" ? value : fallback;
|
|
861
1065
|
}
|
|
862
|
-
function
|
|
1066
|
+
function asNullableString4(value) {
|
|
863
1067
|
return typeof value === "string" ? value : null;
|
|
864
1068
|
}
|
|
865
1069
|
function asNullableNumber2(value) {
|
|
@@ -871,8 +1075,8 @@ function asStringList(value) {
|
|
|
871
1075
|
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
872
1076
|
}
|
|
873
1077
|
function toRequires(value) {
|
|
874
|
-
const record =
|
|
875
|
-
return record === null ? null : { country:
|
|
1078
|
+
const record = asRecord3(value);
|
|
1079
|
+
return record === null ? null : { country: asString4(record["country"]), service: asString4(record["service"]) };
|
|
876
1080
|
}
|
|
877
1081
|
var ComplianceOfferings = class _ComplianceOfferings {
|
|
878
1082
|
constructor(offerings, coverage, access, accessByCountry) {
|
|
@@ -887,16 +1091,16 @@ var ComplianceOfferings = class _ComplianceOfferings {
|
|
|
887
1091
|
accessByCountry;
|
|
888
1092
|
static fromArray(data) {
|
|
889
1093
|
const offerings = asRecordList2(data["data"]).map((row) => ({
|
|
890
|
-
country:
|
|
891
|
-
service:
|
|
892
|
-
currency:
|
|
1094
|
+
country: asString4(row["country"]),
|
|
1095
|
+
service: asString4(row["service"]),
|
|
1096
|
+
currency: asString4(row["currency"], "EUR"),
|
|
893
1097
|
active: row["active"] === true,
|
|
894
1098
|
viaStripe: row["via_stripe"] === true,
|
|
895
|
-
plan:
|
|
896
|
-
status:
|
|
1099
|
+
plan: asNullableString4(row["plan"]),
|
|
1100
|
+
status: asNullableString4(row["status"]),
|
|
897
1101
|
enrolled: row["enrolled"] === true,
|
|
898
1102
|
plans: asRecordList2(row["plans"]).map((plan) => ({
|
|
899
|
-
key:
|
|
1103
|
+
key: asString4(plan["key"]),
|
|
900
1104
|
monthlyFee: asNullableNumber2(plan["monthly_fee"]),
|
|
901
1105
|
setupFee: asNullableNumber2(plan["setup_fee"]),
|
|
902
1106
|
usageTiers: Array.isArray(plan["usage_tiers"]) ? plan["usage_tiers"] : [],
|
|
@@ -908,19 +1112,19 @@ var ComplianceOfferings = class _ComplianceOfferings {
|
|
|
908
1112
|
}))
|
|
909
1113
|
}));
|
|
910
1114
|
const coverage = asRecordList2(data["coverage"]).map((row) => ({
|
|
911
|
-
country:
|
|
912
|
-
availability:
|
|
1115
|
+
country: asString4(row["country"]),
|
|
1116
|
+
availability: asString4(row["availability"]),
|
|
913
1117
|
services: asStringList(row["services"]),
|
|
914
|
-
network:
|
|
915
|
-
format:
|
|
916
|
-
mandate:
|
|
917
|
-
support:
|
|
1118
|
+
network: asNullableString4(row["network"]),
|
|
1119
|
+
format: asNullableString4(row["format"]),
|
|
1120
|
+
mandate: asNullableString4(row["mandate"]),
|
|
1121
|
+
support: asString4(row["support"], "yes")
|
|
918
1122
|
}));
|
|
919
|
-
const access =
|
|
1123
|
+
const access = asRecord3(data["access"]) ?? {};
|
|
920
1124
|
const accessByCountry = {};
|
|
921
|
-
for (const [country, services] of Object.entries(
|
|
1125
|
+
for (const [country, services] of Object.entries(asRecord3(data["access_by_country"]) ?? {})) {
|
|
922
1126
|
const flags = {};
|
|
923
|
-
for (const [service, value] of Object.entries(
|
|
1127
|
+
for (const [service, value] of Object.entries(asRecord3(services) ?? {})) {
|
|
924
1128
|
flags[service] = value === true;
|
|
925
1129
|
}
|
|
926
1130
|
accessByCountry[country] = flags;
|
|
@@ -979,17 +1183,17 @@ var ComplianceTaxReportState = {
|
|
|
979
1183
|
ERROR: "error",
|
|
980
1184
|
UNKNOWN: "unknown"
|
|
981
1185
|
};
|
|
982
|
-
var
|
|
1186
|
+
var VALUES4 = Object.values(ComplianceTaxReportState);
|
|
983
1187
|
function toComplianceTaxReportState(value) {
|
|
984
1188
|
if (typeof value === "string") {
|
|
985
1189
|
const normalized = value.trim().toLowerCase();
|
|
986
|
-
if (
|
|
1190
|
+
if (VALUES4.includes(normalized)) {
|
|
987
1191
|
return normalized;
|
|
988
1192
|
}
|
|
989
1193
|
}
|
|
990
1194
|
return ComplianceTaxReportState.UNKNOWN;
|
|
991
1195
|
}
|
|
992
|
-
var
|
|
1196
|
+
var DESCRIPTIONS4 = {
|
|
993
1197
|
[ComplianceTaxReportState.NEW]: "Created at provider, waiting for the daily ledger batch.",
|
|
994
1198
|
[ComplianceTaxReportState.SENT]: "Ledger transmitted to PPF.",
|
|
995
1199
|
[ComplianceTaxReportState.ACKNOWLEDGED]: "PPF acknowledged receipt of the ledger.",
|
|
@@ -999,14 +1203,14 @@ var DESCRIPTIONS3 = {
|
|
|
999
1203
|
[ComplianceTaxReportState.UNKNOWN]: "Unknown state."
|
|
1000
1204
|
};
|
|
1001
1205
|
function describeComplianceTaxReportState(state) {
|
|
1002
|
-
return
|
|
1206
|
+
return DESCRIPTIONS4[state];
|
|
1003
1207
|
}
|
|
1004
1208
|
|
|
1005
1209
|
// src/dto/ComplianceTaxReport.ts
|
|
1006
|
-
function
|
|
1210
|
+
function asString5(value, fallback = "") {
|
|
1007
1211
|
return typeof value === "string" ? value : fallback;
|
|
1008
1212
|
}
|
|
1009
|
-
function
|
|
1213
|
+
function asNullableString5(value) {
|
|
1010
1214
|
return typeof value === "string" ? value : null;
|
|
1011
1215
|
}
|
|
1012
1216
|
function asNumber3(value) {
|
|
@@ -1067,21 +1271,21 @@ var ComplianceTaxReport = class _ComplianceTaxReport {
|
|
|
1067
1271
|
asNumber3(data["company_id"]),
|
|
1068
1272
|
asNullableNumber3(data["compliance_transaction_id"]),
|
|
1069
1273
|
asNullableNumber3(data["ledger_id"]),
|
|
1070
|
-
|
|
1071
|
-
|
|
1274
|
+
asString5(data["country"]),
|
|
1275
|
+
asString5(data["regime"]),
|
|
1072
1276
|
toComplianceTaxReportState(data["state"]),
|
|
1073
|
-
|
|
1277
|
+
asString5(data["state_label"]),
|
|
1074
1278
|
data["is_terminal"] === true,
|
|
1075
|
-
|
|
1076
|
-
|
|
1279
|
+
asNullableString5(data["provider_tax_report_id"]),
|
|
1280
|
+
asNullableString5(data["provider_ledger_id"]),
|
|
1077
1281
|
asMoney(data["base_amount"]),
|
|
1078
1282
|
asMoney(data["tax_amount"]),
|
|
1079
1283
|
asMoney(data["total_amount"]),
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1284
|
+
asNullableString5(data["refusal_reason"]),
|
|
1285
|
+
asNullableString5(data["registered_at"]),
|
|
1286
|
+
asNullableString5(data["refused_at"]),
|
|
1287
|
+
asNullableString5(data["created_at"]),
|
|
1288
|
+
asNullableString5(data["updated_at"])
|
|
1085
1289
|
);
|
|
1086
1290
|
}
|
|
1087
1291
|
};
|
|
@@ -1127,23 +1331,23 @@ var ComplianceDocumentType = {
|
|
|
1127
1331
|
CREDIT_NOTE: "credit_note",
|
|
1128
1332
|
UNKNOWN: "unknown"
|
|
1129
1333
|
};
|
|
1130
|
-
var
|
|
1334
|
+
var VALUES5 = Object.values(ComplianceDocumentType);
|
|
1131
1335
|
function toComplianceDocumentType(value) {
|
|
1132
1336
|
if (typeof value === "string") {
|
|
1133
1337
|
const normalized = value.trim().toLowerCase();
|
|
1134
|
-
if (
|
|
1338
|
+
if (VALUES5.includes(normalized)) {
|
|
1135
1339
|
return normalized;
|
|
1136
1340
|
}
|
|
1137
1341
|
}
|
|
1138
1342
|
return ComplianceDocumentType.UNKNOWN;
|
|
1139
1343
|
}
|
|
1140
|
-
var
|
|
1344
|
+
var DESCRIPTIONS5 = {
|
|
1141
1345
|
[ComplianceDocumentType.INVOICE]: "Commercial invoice.",
|
|
1142
1346
|
[ComplianceDocumentType.CREDIT_NOTE]: "Credit note correcting a previously issued invoice.",
|
|
1143
1347
|
[ComplianceDocumentType.UNKNOWN]: "Unknown document type."
|
|
1144
1348
|
};
|
|
1145
1349
|
function describeComplianceDocumentType(type) {
|
|
1146
|
-
return
|
|
1350
|
+
return DESCRIPTIONS5[type];
|
|
1147
1351
|
}
|
|
1148
1352
|
|
|
1149
1353
|
// src/enums/ComplianceTransactionState.ts
|
|
@@ -1156,17 +1360,17 @@ var ComplianceTransactionState = {
|
|
|
1156
1360
|
NOT_REQUIRED: "not_required",
|
|
1157
1361
|
UNKNOWN: "unknown"
|
|
1158
1362
|
};
|
|
1159
|
-
var
|
|
1363
|
+
var VALUES6 = Object.values(ComplianceTransactionState);
|
|
1160
1364
|
function toComplianceTransactionState(value) {
|
|
1161
1365
|
if (typeof value === "string") {
|
|
1162
1366
|
const normalized = value.trim().toLowerCase();
|
|
1163
|
-
if (
|
|
1367
|
+
if (VALUES6.includes(normalized)) {
|
|
1164
1368
|
return normalized;
|
|
1165
1369
|
}
|
|
1166
1370
|
}
|
|
1167
1371
|
return ComplianceTransactionState.UNKNOWN;
|
|
1168
1372
|
}
|
|
1169
|
-
var
|
|
1373
|
+
var DESCRIPTIONS6 = {
|
|
1170
1374
|
[ComplianceTransactionState.PENDING]: "Recorded locally, not yet submitted to the provider.",
|
|
1171
1375
|
[ComplianceTransactionState.SENDING]: "Submission to the provider in progress.",
|
|
1172
1376
|
[ComplianceTransactionState.SUBMITTED]: "Successfully submitted to the provider.",
|
|
@@ -1175,7 +1379,7 @@ var DESCRIPTIONS5 = {
|
|
|
1175
1379
|
[ComplianceTransactionState.UNKNOWN]: "Unknown state."
|
|
1176
1380
|
};
|
|
1177
1381
|
function describeComplianceTransactionState(state) {
|
|
1178
|
-
return
|
|
1382
|
+
return DESCRIPTIONS6[state];
|
|
1179
1383
|
}
|
|
1180
1384
|
|
|
1181
1385
|
// src/enums/ComplianceTransactionType.ts
|
|
@@ -1187,17 +1391,17 @@ var ComplianceTransactionType = {
|
|
|
1187
1391
|
CROSSBORDER_INBOUND: "crossborder_inbound",
|
|
1188
1392
|
UNKNOWN: "unknown"
|
|
1189
1393
|
};
|
|
1190
|
-
var
|
|
1394
|
+
var VALUES7 = Object.values(ComplianceTransactionType);
|
|
1191
1395
|
function toComplianceTransactionType(value) {
|
|
1192
1396
|
if (typeof value === "string") {
|
|
1193
1397
|
const normalized = value.trim().toLowerCase();
|
|
1194
|
-
if (
|
|
1398
|
+
if (VALUES7.includes(normalized)) {
|
|
1195
1399
|
return normalized;
|
|
1196
1400
|
}
|
|
1197
1401
|
}
|
|
1198
1402
|
return ComplianceTransactionType.UNKNOWN;
|
|
1199
1403
|
}
|
|
1200
|
-
var
|
|
1404
|
+
var DESCRIPTIONS7 = {
|
|
1201
1405
|
[ComplianceTransactionType.B2C_OUTBOUND]: "Sale to a private person in the merchant country (DGFiP Flux 10.3).",
|
|
1202
1406
|
[ComplianceTransactionType.B2B_DOMESTIC_OUTBOUND]: "Sale to a domestic business (DGFiP Flux 1, Phase 2).",
|
|
1203
1407
|
[ComplianceTransactionType.B2B_DOMESTIC_INBOUND]: "Purchase from a domestic business (DGFiP Flux 1, Phase 2).",
|
|
@@ -1206,14 +1410,14 @@ var DESCRIPTIONS6 = {
|
|
|
1206
1410
|
[ComplianceTransactionType.UNKNOWN]: "Unknown transaction type."
|
|
1207
1411
|
};
|
|
1208
1412
|
function describeComplianceTransactionType(type) {
|
|
1209
|
-
return
|
|
1413
|
+
return DESCRIPTIONS7[type];
|
|
1210
1414
|
}
|
|
1211
1415
|
|
|
1212
1416
|
// src/dto/ComplianceTransaction.ts
|
|
1213
|
-
function
|
|
1417
|
+
function asString6(value, fallback = "") {
|
|
1214
1418
|
return typeof value === "string" ? value : fallback;
|
|
1215
1419
|
}
|
|
1216
|
-
function
|
|
1420
|
+
function asNullableString6(value) {
|
|
1217
1421
|
return typeof value === "string" ? value : null;
|
|
1218
1422
|
}
|
|
1219
1423
|
function asNumber4(value) {
|
|
@@ -1229,45 +1433,45 @@ function asNullableNumber4(value) {
|
|
|
1229
1433
|
if (typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value))) return Number(value);
|
|
1230
1434
|
return null;
|
|
1231
1435
|
}
|
|
1232
|
-
function
|
|
1436
|
+
function asRecord4(value) {
|
|
1233
1437
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
1234
1438
|
}
|
|
1235
1439
|
function asRecordList3(value) {
|
|
1236
|
-
return Array.isArray(value) ? value.filter((row) =>
|
|
1440
|
+
return Array.isArray(value) ? value.filter((row) => asRecord4(row) !== null) : [];
|
|
1237
1441
|
}
|
|
1238
1442
|
function toInvoicePdf(value) {
|
|
1239
|
-
const pdf =
|
|
1443
|
+
const pdf = asRecord4(value);
|
|
1240
1444
|
if (pdf === null) return null;
|
|
1241
1445
|
return {
|
|
1242
|
-
filename:
|
|
1446
|
+
filename: asNullableString6(pdf["filename"]),
|
|
1243
1447
|
size: asNullableNumber4(pdf["size"]),
|
|
1244
1448
|
attached: pdf["attached"] === true
|
|
1245
1449
|
};
|
|
1246
1450
|
}
|
|
1247
1451
|
function toEurEquivalent(value) {
|
|
1248
|
-
const eur =
|
|
1452
|
+
const eur = asRecord4(value);
|
|
1249
1453
|
if (eur === null) return null;
|
|
1250
1454
|
return {
|
|
1251
1455
|
subtotal: asMoney2(eur["subtotal"]),
|
|
1252
1456
|
taxAmount: asMoney2(eur["tax_amount"]),
|
|
1253
1457
|
total: asMoney2(eur["total"]),
|
|
1254
|
-
rate:
|
|
1255
|
-
rateDate:
|
|
1256
|
-
source:
|
|
1458
|
+
rate: asString6(eur["rate"]),
|
|
1459
|
+
rateDate: asNullableString6(eur["rate_date"]),
|
|
1460
|
+
source: asString6(eur["source"], "ECB")
|
|
1257
1461
|
};
|
|
1258
1462
|
}
|
|
1259
1463
|
function toInvoiceLines(providerPayload) {
|
|
1260
|
-
const invoice =
|
|
1464
|
+
const invoice = asRecord4(asRecord4(providerPayload)?.["invoice"]);
|
|
1261
1465
|
return asRecordList3(invoice?.["invoice_lines_attributes"]).map((line) => ({
|
|
1262
|
-
description:
|
|
1466
|
+
description: asString6(line["description"]),
|
|
1263
1467
|
quantity: asNullableNumber4(line["quantity"]),
|
|
1264
1468
|
price: asMoney2(line["price"]),
|
|
1265
1469
|
unit: asNullableNumber4(line["unit"]),
|
|
1266
1470
|
taxes: asRecordList3(line["taxes_attributes"]).map((tax) => ({
|
|
1267
|
-
name:
|
|
1471
|
+
name: asString6(tax["name"]),
|
|
1268
1472
|
percent: asNullableNumber4(tax["percent"]),
|
|
1269
|
-
category:
|
|
1270
|
-
comment:
|
|
1473
|
+
category: asNullableString6(tax["category"]),
|
|
1474
|
+
comment: asNullableString6(tax["comment"])
|
|
1271
1475
|
}))
|
|
1272
1476
|
}));
|
|
1273
1477
|
}
|
|
@@ -1375,48 +1579,48 @@ var ComplianceTransaction = class _ComplianceTransaction {
|
|
|
1375
1579
|
asNumber4(data["id"]),
|
|
1376
1580
|
asNumber4(data["company_id"]),
|
|
1377
1581
|
asNumber4(data["compliance_enrollment_id"]),
|
|
1378
|
-
|
|
1379
|
-
|
|
1582
|
+
asString6(data["country"]),
|
|
1583
|
+
asString6(data["regime"]),
|
|
1380
1584
|
toComplianceTransactionType(data["transaction_type"]),
|
|
1381
|
-
|
|
1585
|
+
asString6(data["transaction_type_label"]),
|
|
1382
1586
|
toComplianceTransactionState(data["state"]),
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1587
|
+
asString6(data["state_label"]),
|
|
1588
|
+
asString6(data["invoice_number"]),
|
|
1589
|
+
asNullableString6(data["invoice_date"]),
|
|
1590
|
+
asNullableString6(data["due_date"]),
|
|
1591
|
+
asString6(data["currency"], "EUR"),
|
|
1388
1592
|
asMoney2(data["subtotal"]),
|
|
1389
1593
|
asMoney2(data["tax_amount"]),
|
|
1390
1594
|
asMoney2(data["total"]),
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1595
|
+
asNullableString6(data["counterparty_name"]),
|
|
1596
|
+
asNullableString6(data["counterparty_country"]),
|
|
1597
|
+
asNullableString6(data["counterparty_vat_number"]),
|
|
1394
1598
|
data["is_paid"] === true,
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1599
|
+
asNullableString6(data["paid_at"]),
|
|
1600
|
+
asNullableString6(data["provider_invoice_id"]),
|
|
1601
|
+
asNullableString6(data["submission_error"]),
|
|
1602
|
+
asNullableString6(data["reported_at"]),
|
|
1399
1603
|
taxReport,
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1604
|
+
asNullableString6(data["created_at"]),
|
|
1605
|
+
asNullableString6(data["updated_at"]),
|
|
1606
|
+
asNullableString6(data["counterparty_register_id"]),
|
|
1607
|
+
asNullableString6(data["counterparty_address"]),
|
|
1608
|
+
asNullableString6(data["counterparty_city"]),
|
|
1609
|
+
asNullableString6(data["counterparty_postalcode"]),
|
|
1610
|
+
asNullableString6(data["counterparty_email"]),
|
|
1611
|
+
asNullableString6(data["buyer_reference"]),
|
|
1408
1612
|
data["document_type"] === void 0 || data["document_type"] === null ? ComplianceDocumentType.INVOICE : toComplianceDocumentType(data["document_type"]),
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1613
|
+
asNullableString6(data["amended_number"]),
|
|
1614
|
+
asNullableString6(data["amended_date"]),
|
|
1615
|
+
asNullableString6(data["provider_state"]),
|
|
1412
1616
|
toInvoiceLines(data["provider_payload"]),
|
|
1413
|
-
|
|
1414
|
-
|
|
1617
|
+
asNullableString6(data["document_url"]),
|
|
1618
|
+
asRecord4(data["delivery_check"]),
|
|
1415
1619
|
toInvoicePdf(data["invoice_pdf"]),
|
|
1416
|
-
|
|
1417
|
-
|
|
1620
|
+
asNullableString6(data["internal_reference"]),
|
|
1621
|
+
asNullableString6(data["pdf_url"]),
|
|
1418
1622
|
data["buyer_rejected"] === true,
|
|
1419
|
-
|
|
1623
|
+
asNullableString6(data["rejection_reason"]),
|
|
1420
1624
|
toEurEquivalent(data["eur_equivalent"])
|
|
1421
1625
|
);
|
|
1422
1626
|
}
|
|
@@ -1476,38 +1680,11 @@ var ImportResult = class _ImportResult {
|
|
|
1476
1680
|
}
|
|
1477
1681
|
};
|
|
1478
1682
|
|
|
1479
|
-
// src/enums/PeppolLookupStatus.ts
|
|
1480
|
-
var PeppolLookupStatus = {
|
|
1481
|
-
REACHABLE: "reachable",
|
|
1482
|
-
NOT_REACHABLE: "not_reachable",
|
|
1483
|
-
PENDING: "pending",
|
|
1484
|
-
UNKNOWN: "unknown"
|
|
1485
|
-
};
|
|
1486
|
-
var VALUES7 = Object.values(PeppolLookupStatus);
|
|
1487
|
-
function toPeppolLookupStatus(value) {
|
|
1488
|
-
if (typeof value === "string") {
|
|
1489
|
-
const normalized = value.trim().toLowerCase();
|
|
1490
|
-
if (VALUES7.includes(normalized)) {
|
|
1491
|
-
return normalized;
|
|
1492
|
-
}
|
|
1493
|
-
}
|
|
1494
|
-
return PeppolLookupStatus.UNKNOWN;
|
|
1495
|
-
}
|
|
1496
|
-
var DESCRIPTIONS7 = {
|
|
1497
|
-
[PeppolLookupStatus.REACHABLE]: "The participant is registered on Peppol and can receive e-invoices.",
|
|
1498
|
-
[PeppolLookupStatus.NOT_REACHABLE]: "The participant is not registered on Peppol.",
|
|
1499
|
-
[PeppolLookupStatus.PENDING]: "The directory lookup is still resolving \u2014 ask again in a few seconds.",
|
|
1500
|
-
[PeppolLookupStatus.UNKNOWN]: "Unknown lookup status."
|
|
1501
|
-
};
|
|
1502
|
-
function describePeppolLookupStatus(status) {
|
|
1503
|
-
return DESCRIPTIONS7[status];
|
|
1504
|
-
}
|
|
1505
|
-
|
|
1506
1683
|
// src/dto/PeppolLookupResult.ts
|
|
1507
|
-
function
|
|
1684
|
+
function asString7(value, fallback = "") {
|
|
1508
1685
|
return typeof value === "string" ? value : fallback;
|
|
1509
1686
|
}
|
|
1510
|
-
function
|
|
1687
|
+
function asNullableString7(value) {
|
|
1511
1688
|
return typeof value === "string" ? value : null;
|
|
1512
1689
|
}
|
|
1513
1690
|
var PeppolLookupResult = class _PeppolLookupResult {
|
|
@@ -1538,21 +1715,21 @@ var PeppolLookupResult = class _PeppolLookupResult {
|
|
|
1538
1715
|
return new _PeppolLookupResult(
|
|
1539
1716
|
toPeppolLookupStatus(data["status"]),
|
|
1540
1717
|
typeof data["reachable"] === "boolean" ? data["reachable"] : null,
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1718
|
+
asString7(data["country"]),
|
|
1719
|
+
asString7(data["scheme"]),
|
|
1720
|
+
asString7(data["id"]),
|
|
1544
1721
|
documentTypes,
|
|
1545
|
-
|
|
1546
|
-
|
|
1722
|
+
asNullableString7(data["transport_type_code"]),
|
|
1723
|
+
asNullableString7(data["checked_at"])
|
|
1547
1724
|
);
|
|
1548
1725
|
}
|
|
1549
1726
|
};
|
|
1550
1727
|
|
|
1551
1728
|
// src/dto/RegistryCompany.ts
|
|
1552
|
-
function
|
|
1729
|
+
function asString8(value, fallback = "") {
|
|
1553
1730
|
return typeof value === "string" ? value : fallback;
|
|
1554
1731
|
}
|
|
1555
|
-
function
|
|
1732
|
+
function asNullableString8(value) {
|
|
1556
1733
|
return typeof value === "string" ? value : null;
|
|
1557
1734
|
}
|
|
1558
1735
|
var RegistryCompany = class _RegistryCompany {
|
|
@@ -1584,24 +1761,24 @@ var RegistryCompany = class _RegistryCompany {
|
|
|
1584
1761
|
country;
|
|
1585
1762
|
static fromArray(data) {
|
|
1586
1763
|
return new _RegistryCompany(
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1764
|
+
asString8(data["org_number"]),
|
|
1765
|
+
asString8(data["company_name"]),
|
|
1766
|
+
asNullableString8(data["organisation_form"]),
|
|
1590
1767
|
data["vat_registered"] === true,
|
|
1591
|
-
|
|
1768
|
+
asNullableString8(data["vat_number"]),
|
|
1592
1769
|
data["enterprise_register"] === true,
|
|
1593
1770
|
data["bankrupt"] === true,
|
|
1594
1771
|
data["under_liquidation"] === true,
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1772
|
+
asNullableString8(data["address"]),
|
|
1773
|
+
asNullableString8(data["postalcode"]),
|
|
1774
|
+
asNullableString8(data["city"]),
|
|
1775
|
+
asString8(data["country"])
|
|
1599
1776
|
);
|
|
1600
1777
|
}
|
|
1601
1778
|
};
|
|
1602
1779
|
|
|
1603
1780
|
// src/dto/RevenueStatistics.ts
|
|
1604
|
-
function
|
|
1781
|
+
function asString9(value, fallback = "") {
|
|
1605
1782
|
return typeof value === "string" ? value : fallback;
|
|
1606
1783
|
}
|
|
1607
1784
|
function asNumber5(value) {
|
|
@@ -1653,35 +1830,35 @@ var RevenueStatistics = class _RevenueStatistics {
|
|
|
1653
1830
|
typeof data["totals"] === "object" && data["totals"] !== null ? data["totals"] : {}
|
|
1654
1831
|
);
|
|
1655
1832
|
const timeSeries = asRecords(data["time_series"]).map((row) => ({
|
|
1656
|
-
bucket:
|
|
1833
|
+
bucket: asString9(row["bucket"]),
|
|
1657
1834
|
...toTotals(row)
|
|
1658
1835
|
}));
|
|
1659
1836
|
const byType = asRecords(data["by_type"]).map((row) => ({
|
|
1660
|
-
type:
|
|
1661
|
-
typeLabel:
|
|
1837
|
+
type: asString9(row["type"]),
|
|
1838
|
+
typeLabel: asString9(row["type_label"]),
|
|
1662
1839
|
count: asNumber5(row["count"]),
|
|
1663
1840
|
total: asMoney3(row["total"])
|
|
1664
1841
|
}));
|
|
1665
1842
|
const byCountry = asRecords(data["by_country"]).map((row) => ({
|
|
1666
|
-
country:
|
|
1843
|
+
country: asString9(row["country"], "unknown"),
|
|
1667
1844
|
count: asNumber5(row["count"]),
|
|
1668
1845
|
total: asMoney3(row["total"])
|
|
1669
1846
|
}));
|
|
1670
1847
|
const byState = asRecords(data["by_state"]).map((row) => ({
|
|
1671
|
-
state:
|
|
1672
|
-
stateLabel:
|
|
1848
|
+
state: asString9(row["state"]),
|
|
1849
|
+
stateLabel: asString9(row["state_label"]),
|
|
1673
1850
|
count: asNumber5(row["count"]),
|
|
1674
1851
|
total: asMoney3(row["total"])
|
|
1675
1852
|
}));
|
|
1676
1853
|
const byCurrency = asRecords(data["by_currency"]).map((row) => ({
|
|
1677
|
-
currency:
|
|
1854
|
+
currency: asString9(row["currency"]),
|
|
1678
1855
|
...toTotals(row)
|
|
1679
1856
|
}));
|
|
1680
1857
|
return new _RevenueStatistics(
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1858
|
+
asString9(range["date_from"]) || void 0,
|
|
1859
|
+
asString9(range["date_to"]) || void 0,
|
|
1860
|
+
asString9(range["interval"]) || void 0,
|
|
1861
|
+
asString9(data["primary_currency"], "EUR"),
|
|
1685
1862
|
data["is_multi_currency"] === true,
|
|
1686
1863
|
totals,
|
|
1687
1864
|
timeSeries,
|
|
@@ -1694,10 +1871,10 @@ var RevenueStatistics = class _RevenueStatistics {
|
|
|
1694
1871
|
};
|
|
1695
1872
|
|
|
1696
1873
|
// src/dto/SireneLookupResult.ts
|
|
1697
|
-
function
|
|
1874
|
+
function asString10(value, fallback = "") {
|
|
1698
1875
|
return typeof value === "string" ? value : fallback;
|
|
1699
1876
|
}
|
|
1700
|
-
function
|
|
1877
|
+
function asNullableString9(value) {
|
|
1701
1878
|
return typeof value === "string" ? value : null;
|
|
1702
1879
|
}
|
|
1703
1880
|
var SireneLookupResult = class _SireneLookupResult {
|
|
@@ -1723,21 +1900,21 @@ var SireneLookupResult = class _SireneLookupResult {
|
|
|
1723
1900
|
postalcode;
|
|
1724
1901
|
static fromArray(data) {
|
|
1725
1902
|
return new _SireneLookupResult(
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1903
|
+
asString10(data["company_name"]),
|
|
1904
|
+
asString10(data["siren"]),
|
|
1905
|
+
asNullableString9(data["siret"]),
|
|
1906
|
+
asNullableString9(data["naf_code"]),
|
|
1907
|
+
asNullableString9(data["naf_full"]),
|
|
1908
|
+
asNullableString9(data["enterprise_size"]),
|
|
1909
|
+
asNullableString9(data["address"]),
|
|
1910
|
+
asNullableString9(data["city"]),
|
|
1911
|
+
asNullableString9(data["postalcode"])
|
|
1735
1912
|
);
|
|
1736
1913
|
}
|
|
1737
1914
|
};
|
|
1738
1915
|
|
|
1739
1916
|
// src/dto/VatRates.ts
|
|
1740
|
-
function
|
|
1917
|
+
function asString11(value, fallback = "") {
|
|
1741
1918
|
return typeof value === "string" ? value : fallback;
|
|
1742
1919
|
}
|
|
1743
1920
|
function asNumber6(value) {
|
|
@@ -1755,12 +1932,12 @@ var VatRates = class _VatRates {
|
|
|
1755
1932
|
static fromArray(data) {
|
|
1756
1933
|
const rates = (Array.isArray(data["rates"]) ? data["rates"] : []).filter((row) => typeof row === "object" && row !== null).map((row) => ({
|
|
1757
1934
|
percent: asNumber6(row["percent"]),
|
|
1758
|
-
category:
|
|
1759
|
-
labelKey:
|
|
1760
|
-
taxName:
|
|
1935
|
+
category: asString11(row["category"]),
|
|
1936
|
+
labelKey: asString11(row["label_key"]),
|
|
1937
|
+
taxName: asString11(row["tax_name"]),
|
|
1761
1938
|
requiresVatex: row["requires_vatex"] === true
|
|
1762
1939
|
}));
|
|
1763
|
-
return new _VatRates(
|
|
1940
|
+
return new _VatRates(asString11(data["country"]), asString11(data["currency"], "EUR"), rates);
|
|
1764
1941
|
}
|
|
1765
1942
|
};
|
|
1766
1943
|
|
|
@@ -1814,6 +1991,25 @@ var NorwegianOrgNumber = {
|
|
|
1814
1991
|
}
|
|
1815
1992
|
};
|
|
1816
1993
|
|
|
1994
|
+
// src/enums/ComplianceTaxCategory.ts
|
|
1995
|
+
var ComplianceTaxCategory = {
|
|
1996
|
+
STANDARD: "S",
|
|
1997
|
+
REDUCED: "AA",
|
|
1998
|
+
SUPER_REDUCED: "AAA",
|
|
1999
|
+
INTRA_COMMUNITY: "K",
|
|
2000
|
+
EXPORT: "G",
|
|
2001
|
+
REVERSE_CHARGE: "AE",
|
|
2002
|
+
EXEMPT: "E",
|
|
2003
|
+
ZERO: "Z"
|
|
2004
|
+
};
|
|
2005
|
+
var CODES = Object.values(ComplianceTaxCategory);
|
|
2006
|
+
function parseComplianceTaxCategory(value) {
|
|
2007
|
+
if (typeof value !== "string") return null;
|
|
2008
|
+
const code = value.trim().toUpperCase();
|
|
2009
|
+
return CODES.includes(code) ? code : null;
|
|
2010
|
+
}
|
|
2011
|
+
var COMPLIANCE_TAX_CATEGORY_CODES = CODES;
|
|
2012
|
+
|
|
1817
2013
|
// src/endpoints/EReportingEndpoint.ts
|
|
1818
2014
|
var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
1819
2015
|
var NAF_CODE_REGEX = /^\d{2}$/;
|
|
@@ -1998,6 +2194,19 @@ var EReportingEndpoint = class {
|
|
|
1998
2194
|
const data = await this.parseJsonResponse(response);
|
|
1999
2195
|
return PeppolLookupResult.fromArray(data);
|
|
2000
2196
|
}
|
|
2197
|
+
/**
|
|
2198
|
+
* What to do with an invoice to this buyer: peppolLookup() turned into an action,
|
|
2199
|
+
* e.g. in a shop checkout when a business buyer enters its number.
|
|
2200
|
+
*
|
|
2201
|
+
* - `einvoice`: create the transaction, Taxora sends the e-invoice;
|
|
2202
|
+
* - `regular_invoice`: the buyer is not on the network — send your regular invoice
|
|
2203
|
+
* yourself (a transaction would end as not_required and is not billed);
|
|
2204
|
+
* - `einvoice_pending`: no definite answer yet — create the transaction anyway,
|
|
2205
|
+
* Taxora asks the directory again before sending.
|
|
2206
|
+
*/
|
|
2207
|
+
async decideDelivery(country, id, scheme) {
|
|
2208
|
+
return ComplianceDeliveryDecision.fromLookup(await this.peppolLookup(country, id, scheme));
|
|
2209
|
+
}
|
|
2001
2210
|
// ---------------------------------------------------------------------
|
|
2002
2211
|
// Transactions
|
|
2003
2212
|
// ---------------------------------------------------------------------
|
|
@@ -2024,6 +2233,7 @@ var EReportingEndpoint = class {
|
|
|
2024
2233
|
this.validateBuyerFields(input);
|
|
2025
2234
|
this.validateInternalReference(input.internalReference);
|
|
2026
2235
|
this.validateInvoicePdfFilename(input);
|
|
2236
|
+
this.validateDocument(input);
|
|
2027
2237
|
const body = {
|
|
2028
2238
|
compliance_enrollment_id: input.complianceEnrollmentId,
|
|
2029
2239
|
transaction_type: input.transactionType,
|
|
@@ -2039,6 +2249,101 @@ var EReportingEndpoint = class {
|
|
|
2039
2249
|
const data = await this.parseJsonResponse(response);
|
|
2040
2250
|
return ComplianceTransaction.fromArray(data);
|
|
2041
2251
|
}
|
|
2252
|
+
/**
|
|
2253
|
+
* Issue a credit note for an invoice you sent through Taxora. Everything that must
|
|
2254
|
+
* match the corrected invoice is taken from `original`: enrollment, transaction type,
|
|
2255
|
+
* currency, buyer (name, register id, address, e-mail, VAT number, buyer reference) —
|
|
2256
|
+
* and the reference to the corrected invoice (number and date) is set for you.
|
|
2257
|
+
*
|
|
2258
|
+
* Without invoiceLines and amounts it credits the whole invoice: lines and amounts are
|
|
2259
|
+
* taken over as they are (the document type, not the sign, makes it a credit note).
|
|
2260
|
+
* For a partial credit pass invoiceLines, subtotal, taxAmount and total together.
|
|
2261
|
+
*
|
|
2262
|
+
* Not possible for an invoice that was never sent to the buyer (state not_required)
|
|
2263
|
+
* or for a credit note. A buyer rejected the invoice? Correct it with a credit note and
|
|
2264
|
+
* send a new invoice (`original.buyerRejected`).
|
|
2265
|
+
*/
|
|
2266
|
+
async createCreditNote(original, input) {
|
|
2267
|
+
if (original.documentType === ComplianceDocumentType.CREDIT_NOTE) {
|
|
2268
|
+
throw new TaxoraException("A credit note cannot be credited again; issue a new invoice instead.");
|
|
2269
|
+
}
|
|
2270
|
+
if (original.state === ComplianceTransactionState.NOT_REQUIRED) {
|
|
2271
|
+
throw new TaxoraException(
|
|
2272
|
+
"The invoice was never sent as an e-invoice (the buyer is not on the network), so there is nothing to credit; correct your regular invoice instead."
|
|
2273
|
+
);
|
|
2274
|
+
}
|
|
2275
|
+
if (original.invoiceNumber === "") {
|
|
2276
|
+
throw new TaxoraException("The original transaction has no invoice number.");
|
|
2277
|
+
}
|
|
2278
|
+
if (original.transactionType === "unknown") {
|
|
2279
|
+
throw new TaxoraException("The original transaction has an unknown transaction type.");
|
|
2280
|
+
}
|
|
2281
|
+
const partial = [input.invoiceLines, input.subtotal, input.taxAmount, input.total];
|
|
2282
|
+
if (![0, 4].includes(partial.filter((value) => value !== void 0).length)) {
|
|
2283
|
+
throw new TaxoraException("For a partial credit pass invoiceLines, subtotal, taxAmount and total together.");
|
|
2284
|
+
}
|
|
2285
|
+
let invoiceLines;
|
|
2286
|
+
let subtotal = input.subtotal;
|
|
2287
|
+
let taxAmount = input.taxAmount;
|
|
2288
|
+
let total = input.total;
|
|
2289
|
+
if (input.invoiceLines !== void 0) {
|
|
2290
|
+
invoiceLines = input.invoiceLines;
|
|
2291
|
+
} else {
|
|
2292
|
+
invoiceLines = original.invoiceLines.map((line) => ({
|
|
2293
|
+
description: line.description,
|
|
2294
|
+
quantity: line.quantity ?? 0,
|
|
2295
|
+
price: Number(line.price),
|
|
2296
|
+
...line.unit !== null ? { unit: line.unit } : {},
|
|
2297
|
+
taxes: line.taxes.map((tax) => ({
|
|
2298
|
+
name: tax.name,
|
|
2299
|
+
percent: tax.percent ?? 0,
|
|
2300
|
+
category: this.storedTaxCategory(tax.category),
|
|
2301
|
+
...tax.comment !== null ? { comment: tax.comment } : {}
|
|
2302
|
+
}))
|
|
2303
|
+
}));
|
|
2304
|
+
if (invoiceLines.length === 0) {
|
|
2305
|
+
throw new TaxoraException(
|
|
2306
|
+
"The original transaction carries no invoice lines; pass invoiceLines and the amounts explicitly."
|
|
2307
|
+
);
|
|
2308
|
+
}
|
|
2309
|
+
subtotal = Number(original.subtotal);
|
|
2310
|
+
taxAmount = Number(original.taxAmount);
|
|
2311
|
+
total = Number(original.total);
|
|
2312
|
+
}
|
|
2313
|
+
const buyer = Object.fromEntries(
|
|
2314
|
+
Object.entries({
|
|
2315
|
+
counterpartyName: original.counterpartyName,
|
|
2316
|
+
counterpartyCountry: original.counterpartyCountry,
|
|
2317
|
+
counterpartyVatNumber: original.counterpartyVatNumber,
|
|
2318
|
+
counterpartyRegisterId: original.counterpartyRegisterId,
|
|
2319
|
+
counterpartyAddress: original.counterpartyAddress,
|
|
2320
|
+
counterpartyCity: original.counterpartyCity,
|
|
2321
|
+
counterpartyPostalcode: original.counterpartyPostalcode,
|
|
2322
|
+
counterpartyEmail: original.counterpartyEmail,
|
|
2323
|
+
buyerReference: original.buyerReference
|
|
2324
|
+
}).filter(([, value]) => value !== null && value !== "")
|
|
2325
|
+
);
|
|
2326
|
+
return this.createTransaction({
|
|
2327
|
+
complianceEnrollmentId: original.complianceEnrollmentId,
|
|
2328
|
+
transactionType: original.transactionType,
|
|
2329
|
+
invoiceNumber: input.creditNoteNumber,
|
|
2330
|
+
invoiceDate: input.invoiceDate ?? /* @__PURE__ */ new Date(),
|
|
2331
|
+
subtotal: subtotal ?? 0,
|
|
2332
|
+
total: total ?? 0,
|
|
2333
|
+
invoiceLines,
|
|
2334
|
+
currency: original.currency,
|
|
2335
|
+
...taxAmount !== void 0 ? { taxAmount } : {},
|
|
2336
|
+
...buyer,
|
|
2337
|
+
isCreditNote: true,
|
|
2338
|
+
amendedNumber: original.invoiceNumber,
|
|
2339
|
+
...original.invoiceDate !== null ? { amendedDate: original.invoiceDate } : {},
|
|
2340
|
+
...input.extraInfo !== void 0 ? { extraInfo: input.extraInfo } : {},
|
|
2341
|
+
...input.internalReference !== void 0 ? { internalReference: input.internalReference } : {},
|
|
2342
|
+
...input.submitNow !== void 0 ? { submitNow: input.submitNow } : {},
|
|
2343
|
+
...input.invoicePdf !== void 0 ? { invoicePdf: input.invoicePdf } : {},
|
|
2344
|
+
...input.invoicePdfFilename !== void 0 ? { invoicePdfFilename: input.invoicePdfFilename } : {}
|
|
2345
|
+
});
|
|
2346
|
+
}
|
|
2042
2347
|
/** Paginated list of the company's transactions (newest invoice date first), filterable by date / state / type / enrollment / country / search / internal reference / provider state. */
|
|
2043
2348
|
async listTransactions(filters = {}) {
|
|
2044
2349
|
const params = this.buildTransactionFilterParams(filters);
|
|
@@ -2607,6 +2912,26 @@ var EReportingEndpoint = class {
|
|
|
2607
2912
|
if (line.taxes.length === 0) {
|
|
2608
2913
|
throw new TaxoraException(`invoiceLines[${index}].taxes must contain at least one tax.`);
|
|
2609
2914
|
}
|
|
2915
|
+
line.taxes.forEach((tax, taxIndex) => {
|
|
2916
|
+
const where = `invoiceLines[${index}].taxes[${taxIndex}]`;
|
|
2917
|
+
const category = parseComplianceTaxCategory(tax.category);
|
|
2918
|
+
if (category === null) {
|
|
2919
|
+
throw new TaxoraException(
|
|
2920
|
+
`${where}.category "${String(tax.category)}" is unknown. Valid: ${COMPLIANCE_TAX_CATEGORY_CODES.join(", ")}.`
|
|
2921
|
+
);
|
|
2922
|
+
}
|
|
2923
|
+
if (!Number.isFinite(tax.percent) || tax.percent < 0 || tax.percent > 100) {
|
|
2924
|
+
throw new TaxoraException(`${where}.percent must be between 0 and 100.`);
|
|
2925
|
+
}
|
|
2926
|
+
if (category === "E" && (tax.comment === void 0 || tax.comment.trim() === "")) {
|
|
2927
|
+
throw new TaxoraException(
|
|
2928
|
+
`${where}: an exempt (category E) tax needs the exemption code (VATEX) as comment.`
|
|
2929
|
+
);
|
|
2930
|
+
}
|
|
2931
|
+
if (tax.comment !== void 0 && tax.comment.length > 255) {
|
|
2932
|
+
throw new TaxoraException(`${where}.comment must not exceed 255 characters.`);
|
|
2933
|
+
}
|
|
2934
|
+
});
|
|
2610
2935
|
});
|
|
2611
2936
|
}
|
|
2612
2937
|
validateInvoicePdfFilename(input) {
|
|
@@ -2623,12 +2948,65 @@ var EReportingEndpoint = class {
|
|
|
2623
2948
|
throw new TaxoraException("internalReference must not exceed 100 characters.");
|
|
2624
2949
|
}
|
|
2625
2950
|
}
|
|
2951
|
+
/**
|
|
2952
|
+
* Relations that cannot be right: a due date before the invoice date, a credit note without (or an
|
|
2953
|
+
* invoice with) a corrected invoice, a credit note that reuses the number it corrects, a corrected
|
|
2954
|
+
* invoice dated after the credit note.
|
|
2955
|
+
*/
|
|
2956
|
+
validateDocument(input) {
|
|
2957
|
+
for (const [field, value] of [
|
|
2958
|
+
["subtotal", input.subtotal],
|
|
2959
|
+
["taxAmount", input.taxAmount],
|
|
2960
|
+
["total", input.total]
|
|
2961
|
+
]) {
|
|
2962
|
+
if (value !== void 0 && !Number.isFinite(Number(value))) {
|
|
2963
|
+
throw new TaxoraException(`${field} must be a finite number.`);
|
|
2964
|
+
}
|
|
2965
|
+
}
|
|
2966
|
+
for (const line of input.invoiceLines ?? []) {
|
|
2967
|
+
if (!Number.isFinite(line.quantity) || !Number.isFinite(line.price)) {
|
|
2968
|
+
throw new TaxoraException("Every invoice line needs a numeric quantity and price.");
|
|
2969
|
+
}
|
|
2970
|
+
}
|
|
2971
|
+
const invoiceDate = this.formatDate(input.invoiceDate);
|
|
2972
|
+
if (input.dueDate !== void 0 && this.formatDate(input.dueDate) < invoiceDate) {
|
|
2973
|
+
throw new TaxoraException("dueDate must not be before invoiceDate.");
|
|
2974
|
+
}
|
|
2975
|
+
if (input.counterpartyVatNumber !== void 0 && input.counterpartyVatNumber.length > 50) {
|
|
2976
|
+
throw new TaxoraException("counterpartyVatNumber must not exceed 50 characters.");
|
|
2977
|
+
}
|
|
2978
|
+
const amended = input.amendedNumber?.trim() ?? "";
|
|
2979
|
+
if (input.isCreditNote === true && amended === "") {
|
|
2980
|
+
throw new TaxoraException("A credit note needs amendedNumber, the number of the invoice it corrects.");
|
|
2981
|
+
}
|
|
2982
|
+
if (input.isCreditNote !== true && amended !== "") {
|
|
2983
|
+
throw new TaxoraException("amendedNumber is only for credit notes; set isCreditNote to issue one.");
|
|
2984
|
+
}
|
|
2985
|
+
if (amended !== "" && amended === input.invoiceNumber.trim()) {
|
|
2986
|
+
throw new TaxoraException(
|
|
2987
|
+
"A credit note needs its own number; it cannot reuse the number of the invoice it corrects."
|
|
2988
|
+
);
|
|
2989
|
+
}
|
|
2990
|
+
if (input.amendedDate !== void 0 && this.formatDate(input.amendedDate) > invoiceDate) {
|
|
2991
|
+
throw new TaxoraException("amendedDate (the corrected invoice) must not be after the credit note date.");
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
/** A category read back from a stored invoice; one that is not a known code cannot be re-sent. */
|
|
2995
|
+
storedTaxCategory(category) {
|
|
2996
|
+
const parsed = parseComplianceTaxCategory(category);
|
|
2997
|
+
if (parsed === null) {
|
|
2998
|
+
throw new TaxoraException(
|
|
2999
|
+
`The original invoice has an unknown tax category "${String(category)}"; pass invoiceLines and the amounts explicitly.`
|
|
3000
|
+
);
|
|
3001
|
+
}
|
|
3002
|
+
return parsed;
|
|
3003
|
+
}
|
|
2626
3004
|
validateOptionalCodes(input) {
|
|
2627
|
-
if (input.currency !== void 0 && input.currency
|
|
2628
|
-
throw new TaxoraException("currency must be
|
|
3005
|
+
if (input.currency !== void 0 && !/^[A-Za-z]{3}$/.test(input.currency)) {
|
|
3006
|
+
throw new TaxoraException("currency must be an ISO 4217 code, three letters (e.g. NOK, EUR).");
|
|
2629
3007
|
}
|
|
2630
|
-
if (input.counterpartyCountry !== void 0 && input.counterpartyCountry
|
|
2631
|
-
throw new TaxoraException("counterpartyCountry must be
|
|
3008
|
+
if (input.counterpartyCountry !== void 0 && !/^[A-Za-z]{2}$/.test(input.counterpartyCountry)) {
|
|
3009
|
+
throw new TaxoraException("counterpartyCountry must be an ISO 3166-1 alpha-2 code, two letters (e.g. NO).");
|
|
2632
3010
|
}
|
|
2633
3011
|
}
|
|
2634
3012
|
/**
|
|
@@ -2671,7 +3049,7 @@ var EReportingEndpoint = class {
|
|
|
2671
3049
|
const taxBuilt = {
|
|
2672
3050
|
name: tax.name,
|
|
2673
3051
|
percent: tax.percent,
|
|
2674
|
-
category: tax.category
|
|
3052
|
+
category: parseComplianceTaxCategory(tax.category) ?? tax.category
|
|
2675
3053
|
};
|
|
2676
3054
|
if (tax.comment !== void 0) taxBuilt["comment"] = tax.comment;
|
|
2677
3055
|
return taxBuilt;
|
|
@@ -2684,10 +3062,10 @@ var EReportingEndpoint = class {
|
|
|
2684
3062
|
/** Applies the optional scalar fields shared by create and update. */
|
|
2685
3063
|
applyOptionalTransactionFields(body, input) {
|
|
2686
3064
|
if (input.dueDate !== void 0) body["due_date"] = this.formatDate(input.dueDate);
|
|
2687
|
-
if (input.currency !== void 0) body["currency"] = input.currency;
|
|
3065
|
+
if (input.currency !== void 0) body["currency"] = input.currency.toUpperCase();
|
|
2688
3066
|
if (input.taxAmount !== void 0) body["tax_amount"] = input.taxAmount;
|
|
2689
3067
|
if (input.counterpartyName !== void 0) body["counterparty_name"] = input.counterpartyName;
|
|
2690
|
-
if (input.counterpartyCountry !== void 0) body["counterparty_country"] = input.counterpartyCountry;
|
|
3068
|
+
if (input.counterpartyCountry !== void 0) body["counterparty_country"] = input.counterpartyCountry.toUpperCase();
|
|
2691
3069
|
if (input.counterpartyVatNumber !== void 0) body["counterparty_vat_number"] = input.counterpartyVatNumber;
|
|
2692
3070
|
if (input.providerContactId !== void 0) body["provider_contact_id"] = input.providerContactId;
|
|
2693
3071
|
if (input.paymentMethod !== void 0) body["payment_method"] = input.paymentMethod;
|
|
@@ -3355,13 +3733,13 @@ var SmartEnrichmentHistoryPage = class _SmartEnrichmentHistoryPage {
|
|
|
3355
3733
|
};
|
|
3356
3734
|
|
|
3357
3735
|
// src/dto/SmartEnrichmentStatistics.ts
|
|
3358
|
-
function
|
|
3736
|
+
function asString12(value, fallback = "") {
|
|
3359
3737
|
return typeof value === "string" ? value : fallback;
|
|
3360
3738
|
}
|
|
3361
3739
|
function asNumber7(value) {
|
|
3362
3740
|
return typeof value === "number" ? value : Number(value ?? 0) || 0;
|
|
3363
3741
|
}
|
|
3364
|
-
function
|
|
3742
|
+
function asRecord5(value) {
|
|
3365
3743
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
3366
3744
|
}
|
|
3367
3745
|
function asRecords2(value) {
|
|
@@ -3384,32 +3762,32 @@ var SmartEnrichmentStatistics = class _SmartEnrichmentStatistics {
|
|
|
3384
3762
|
byOutcome;
|
|
3385
3763
|
confidenceBuckets;
|
|
3386
3764
|
static fromArray(data) {
|
|
3387
|
-
const range =
|
|
3388
|
-
const totals =
|
|
3765
|
+
const range = asRecord5(data["range"]);
|
|
3766
|
+
const totals = asRecord5(data["totals"]);
|
|
3389
3767
|
const timeSeries = asRecords2(data["time_series"]).map((row) => ({
|
|
3390
|
-
bucket:
|
|
3768
|
+
bucket: asString12(row["bucket"]),
|
|
3391
3769
|
jobs: asNumber7(row["jobs"]),
|
|
3392
3770
|
items: asNumber7(row["items"]),
|
|
3393
3771
|
found: asNumber7(row["found"])
|
|
3394
3772
|
}));
|
|
3395
3773
|
const bySource = asRecords2(data["by_source"]).map((row) => ({
|
|
3396
|
-
source:
|
|
3774
|
+
source: asString12(row["source"]),
|
|
3397
3775
|
jobs: asNumber7(row["jobs"]),
|
|
3398
3776
|
found: asNumber7(row["found"])
|
|
3399
3777
|
}));
|
|
3400
3778
|
const byOutcome = asRecords2(data["by_outcome"]).map((row) => ({
|
|
3401
|
-
outcome:
|
|
3779
|
+
outcome: asString12(row["outcome"]),
|
|
3402
3780
|
count: asNumber7(row["count"])
|
|
3403
3781
|
}));
|
|
3404
3782
|
const confidenceBuckets = asRecords2(data["confidence_buckets"]).map((row) => ({
|
|
3405
|
-
bucket:
|
|
3783
|
+
bucket: asString12(row["bucket"]),
|
|
3406
3784
|
count: asNumber7(row["count"])
|
|
3407
3785
|
}));
|
|
3408
3786
|
return new _SmartEnrichmentStatistics(
|
|
3409
3787
|
{
|
|
3410
|
-
dateFrom:
|
|
3411
|
-
dateTo:
|
|
3412
|
-
interval:
|
|
3788
|
+
dateFrom: asString12(range["date_from"]),
|
|
3789
|
+
dateTo: asString12(range["date_to"]),
|
|
3790
|
+
interval: asString12(range["interval"])
|
|
3413
3791
|
},
|
|
3414
3792
|
{
|
|
3415
3793
|
jobs: asNumber7(totals["jobs"]),
|
|
@@ -4766,6 +5144,68 @@ var Language = {
|
|
|
4766
5144
|
GERMAN: "de"
|
|
4767
5145
|
};
|
|
4768
5146
|
|
|
5147
|
+
// src/support/calculateInvoiceTotals.ts
|
|
5148
|
+
function round2(value) {
|
|
5149
|
+
const magnitude = Math.round(Number((Math.abs(value) * 100).toPrecision(15)));
|
|
5150
|
+
return (value < 0 ? -magnitude : magnitude) / 100;
|
|
5151
|
+
}
|
|
5152
|
+
function calculateInvoiceTotals(lines, options = {}) {
|
|
5153
|
+
let net = 0;
|
|
5154
|
+
let tax = 0;
|
|
5155
|
+
for (const line of lines) {
|
|
5156
|
+
const lineNet = round2(line.quantity * line.price);
|
|
5157
|
+
const percent = line.taxes.reduce((sum, t) => sum + t.percent, 0);
|
|
5158
|
+
net += lineNet;
|
|
5159
|
+
tax += round2(lineNet * percent / 100);
|
|
5160
|
+
}
|
|
5161
|
+
const subtotal = round2(net);
|
|
5162
|
+
const taxAmount = round2(tax);
|
|
5163
|
+
const total = round2(subtotal + taxAmount);
|
|
5164
|
+
let roundingDifference = 0;
|
|
5165
|
+
if (options.expectedTotal !== void 0) {
|
|
5166
|
+
if (!Number.isFinite(options.expectedTotal)) {
|
|
5167
|
+
throw new Error("The expected total must be numeric.");
|
|
5168
|
+
}
|
|
5169
|
+
const tolerance = options.tolerance ?? 0.05;
|
|
5170
|
+
roundingDifference = round2(options.expectedTotal - total);
|
|
5171
|
+
if (Math.abs(roundingDifference) > tolerance) {
|
|
5172
|
+
throw new Error(
|
|
5173
|
+
`The expected total ${options.expectedTotal.toFixed(2)} differs from the invoice lines (${total.toFixed(2)}) by ${roundingDifference.toFixed(2)}, more than the rounding tolerance of ${tolerance.toFixed(2)}. Check quantities, prices and tax rates.`
|
|
5174
|
+
);
|
|
5175
|
+
}
|
|
5176
|
+
}
|
|
5177
|
+
return { subtotal, taxAmount, total, roundingDifference };
|
|
5178
|
+
}
|
|
5179
|
+
|
|
5180
|
+
// src/support/complianceTax.ts
|
|
5181
|
+
var ComplianceTax = {
|
|
5182
|
+
/**
|
|
5183
|
+
* A taxed rate above 0 %, category S (Norway: 25 / 15 / 12 % are all S). Where a country files reduced rates
|
|
5184
|
+
* under their own category (France: AA / AAA), pass it as `category`.
|
|
5185
|
+
*/
|
|
5186
|
+
rate(percent, name = "VAT", category = ComplianceTaxCategory.STANDARD) {
|
|
5187
|
+
if (!Number.isFinite(percent) || percent <= 0) {
|
|
5188
|
+
throw new Error("rate() needs a percent above 0; for 0 % use zeroRated(), exempt() or reverseCharge().");
|
|
5189
|
+
}
|
|
5190
|
+
return { name, percent, category };
|
|
5191
|
+
},
|
|
5192
|
+
/** 0 % but taxable (category Z). */
|
|
5193
|
+
zeroRated(name = "VAT") {
|
|
5194
|
+
return { name, percent: 0, category: ComplianceTaxCategory.ZERO };
|
|
5195
|
+
},
|
|
5196
|
+
/** Exempt from VAT (category E); the VATEX exemption code is mandatory. */
|
|
5197
|
+
exempt(exemptionCode, name = "VAT") {
|
|
5198
|
+
if (exemptionCode.trim() === "") {
|
|
5199
|
+
throw new Error("An exempt (category E) tax needs the exemption code (VATEX).");
|
|
5200
|
+
}
|
|
5201
|
+
return { name, percent: 0, category: ComplianceTaxCategory.EXEMPT, comment: exemptionCode };
|
|
5202
|
+
},
|
|
5203
|
+
/** Reverse charge (category AE); the mandatory legal text is added by Taxora. */
|
|
5204
|
+
reverseCharge(name = "VAT") {
|
|
5205
|
+
return { name, percent: 0, category: ComplianceTaxCategory.REVERSE_CHARGE };
|
|
5206
|
+
}
|
|
5207
|
+
};
|
|
5208
|
+
|
|
4769
5209
|
// src/webhooks/WebhookSignature.ts
|
|
4770
5210
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
4771
5211
|
var WEBHOOK_SIGNATURE_HEADER = "Taxora-Signature";
|
|
@@ -4897,12 +5337,16 @@ export {
|
|
|
4897
5337
|
BillingEndpoint,
|
|
4898
5338
|
CompanyAddress,
|
|
4899
5339
|
CompanyEndpoint,
|
|
5340
|
+
ComplianceDeliveryAction,
|
|
5341
|
+
ComplianceDeliveryDecision,
|
|
4900
5342
|
ComplianceDocumentType,
|
|
4901
5343
|
ComplianceEnrollment,
|
|
4902
5344
|
ComplianceEnrollmentPage,
|
|
4903
5345
|
ComplianceEnrollmentStatus,
|
|
4904
5346
|
ComplianceOfferings,
|
|
4905
5347
|
ComplianceService,
|
|
5348
|
+
ComplianceTax,
|
|
5349
|
+
ComplianceTaxCategory,
|
|
4906
5350
|
ComplianceTaxReport,
|
|
4907
5351
|
ComplianceTaxReportPage,
|
|
4908
5352
|
ComplianceTaxReportState,
|
|
@@ -4911,6 +5355,8 @@ export {
|
|
|
4911
5355
|
ComplianceTransactionState,
|
|
4912
5356
|
ComplianceTransactionType,
|
|
4913
5357
|
DEFAULT_WEBHOOK_TOLERANCE_SECONDS,
|
|
5358
|
+
EInvoicingQuota,
|
|
5359
|
+
EInvoicingQuotaPeriod,
|
|
4914
5360
|
EReportingEndpoint,
|
|
4915
5361
|
Environment,
|
|
4916
5362
|
FetchHttpClient,
|
|
@@ -4958,6 +5404,7 @@ export {
|
|
|
4958
5404
|
WEBHOOK_ID_HEADER,
|
|
4959
5405
|
WEBHOOK_SIGNATURE_HEADER,
|
|
4960
5406
|
WebhookSignatureVerificationError,
|
|
5407
|
+
calculateInvoiceTotals,
|
|
4961
5408
|
computeWebhookSignature,
|
|
4962
5409
|
constructWebhookEvent,
|
|
4963
5410
|
describeApiError,
|
|
@@ -4976,6 +5423,7 @@ export {
|
|
|
4976
5423
|
getBaseUrl,
|
|
4977
5424
|
getFailedVatStates,
|
|
4978
5425
|
isTransactionBuyerRejected,
|
|
5426
|
+
parseComplianceTaxCategory,
|
|
4979
5427
|
parseLocalTaxNumbersCsv,
|
|
4980
5428
|
parseWebhookSignatureHeader,
|
|
4981
5429
|
toComplianceDocumentType,
|