@taxora/sdk 1.2.0 → 1.3.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 +22 -0
- package/README.md +191 -0
- package/dist/index.cjs +741 -86
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +497 -20
- package/dist/index.d.ts +497 -20
- package/dist/index.js +719 -85
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -26,9 +26,11 @@ __export(index_exports, {
|
|
|
26
26
|
AuthenticationException: () => AuthenticationException,
|
|
27
27
|
CompanyAddress: () => CompanyAddress,
|
|
28
28
|
CompanyEndpoint: () => CompanyEndpoint,
|
|
29
|
+
ComplianceDocumentType: () => ComplianceDocumentType,
|
|
29
30
|
ComplianceEnrollment: () => ComplianceEnrollment,
|
|
30
31
|
ComplianceEnrollmentPage: () => ComplianceEnrollmentPage,
|
|
31
32
|
ComplianceEnrollmentStatus: () => ComplianceEnrollmentStatus,
|
|
33
|
+
ComplianceService: () => ComplianceService,
|
|
32
34
|
ComplianceTaxReport: () => ComplianceTaxReport,
|
|
33
35
|
ComplianceTaxReportPage: () => ComplianceTaxReportPage,
|
|
34
36
|
ComplianceTaxReportState: () => ComplianceTaxReportState,
|
|
@@ -36,6 +38,7 @@ __export(index_exports, {
|
|
|
36
38
|
ComplianceTransactionPage: () => ComplianceTransactionPage,
|
|
37
39
|
ComplianceTransactionState: () => ComplianceTransactionState,
|
|
38
40
|
ComplianceTransactionType: () => ComplianceTransactionType,
|
|
41
|
+
DEFAULT_WEBHOOK_TOLERANCE_SECONDS: () => DEFAULT_WEBHOOK_TOLERANCE_SECONDS,
|
|
39
42
|
EReportingEndpoint: () => EReportingEndpoint,
|
|
40
43
|
Environment: () => Environment,
|
|
41
44
|
FetchHttpClient: () => FetchHttpClient,
|
|
@@ -44,8 +47,12 @@ __export(index_exports, {
|
|
|
44
47
|
InMemoryTokenStorage: () => InMemoryTokenStorage,
|
|
45
48
|
Language: () => Language,
|
|
46
49
|
LoginIdentifier: () => LoginIdentifier,
|
|
50
|
+
NorwegianOrgNumber: () => NorwegianOrgNumber,
|
|
51
|
+
PeppolLookupResult: () => PeppolLookupResult,
|
|
52
|
+
PeppolLookupStatus: () => PeppolLookupStatus,
|
|
47
53
|
ProviderDocument: () => ProviderDocument,
|
|
48
54
|
ProviderDocumentLine: () => ProviderDocumentLine,
|
|
55
|
+
RegistryCompany: () => RegistryCompany,
|
|
49
56
|
RetryPolicy: () => RetryPolicy,
|
|
50
57
|
RevenueStatistics: () => RevenueStatistics,
|
|
51
58
|
ScoreBreakdown: () => ScoreBreakdown,
|
|
@@ -70,22 +77,36 @@ __export(index_exports, {
|
|
|
70
77
|
VatResource: () => VatResource,
|
|
71
78
|
VatState: () => VatState,
|
|
72
79
|
VatValidationAddressInput: () => VatValidationAddressInput,
|
|
80
|
+
WEBHOOK_ID_HEADER: () => WEBHOOK_ID_HEADER,
|
|
81
|
+
WEBHOOK_SIGNATURE_HEADER: () => WEBHOOK_SIGNATURE_HEADER,
|
|
82
|
+
WebhookSignatureVerificationError: () => WebhookSignatureVerificationError,
|
|
83
|
+
computeWebhookSignature: () => computeWebhookSignature,
|
|
84
|
+
constructWebhookEvent: () => constructWebhookEvent,
|
|
73
85
|
describeApiError: () => describeApiError,
|
|
86
|
+
describeComplianceDocumentType: () => describeComplianceDocumentType,
|
|
74
87
|
describeComplianceEnrollmentStatus: () => describeComplianceEnrollmentStatus,
|
|
88
|
+
describeComplianceService: () => describeComplianceService,
|
|
75
89
|
describeComplianceTaxReportState: () => describeComplianceTaxReportState,
|
|
76
90
|
describeComplianceTransactionState: () => describeComplianceTransactionState,
|
|
77
91
|
describeComplianceTransactionType: () => describeComplianceTransactionType,
|
|
92
|
+
describePeppolLookupStatus: () => describePeppolLookupStatus,
|
|
78
93
|
describeSmartEnrichmentMode: () => describeSmartEnrichmentMode,
|
|
79
94
|
describeSmartEnrichmentStatus: () => describeSmartEnrichmentStatus,
|
|
80
95
|
describeVatState: () => describeVatState,
|
|
96
|
+
generateWebhookSignatureHeader: () => generateWebhookSignatureHeader,
|
|
81
97
|
getBaseUrl: () => getBaseUrl,
|
|
82
98
|
getFailedVatStates: () => getFailedVatStates,
|
|
99
|
+
parseWebhookSignatureHeader: () => parseWebhookSignatureHeader,
|
|
100
|
+
toComplianceDocumentType: () => toComplianceDocumentType,
|
|
83
101
|
toComplianceEnrollmentStatus: () => toComplianceEnrollmentStatus,
|
|
102
|
+
toComplianceService: () => toComplianceService,
|
|
84
103
|
toComplianceTaxReportState: () => toComplianceTaxReportState,
|
|
85
104
|
toComplianceTransactionState: () => toComplianceTransactionState,
|
|
86
105
|
toComplianceTransactionType: () => toComplianceTransactionType,
|
|
106
|
+
toPeppolLookupStatus: () => toPeppolLookupStatus,
|
|
87
107
|
toSmartEnrichmentMode: () => toSmartEnrichmentMode,
|
|
88
|
-
toSmartEnrichmentStatus: () => toSmartEnrichmentStatus
|
|
108
|
+
toSmartEnrichmentStatus: () => toSmartEnrichmentStatus,
|
|
109
|
+
verifyWebhookSignature: () => verifyWebhookSignature
|
|
89
110
|
});
|
|
90
111
|
module.exports = __toCommonJS(index_exports);
|
|
91
112
|
|
|
@@ -414,13 +435,7 @@ async function withResponseRetries(policy, operation, send) {
|
|
|
414
435
|
if (!policy.shouldRetry(response.status, attempt, retryAfter)) {
|
|
415
436
|
if (attempt > 1 && policy.isRetryable(response.status, retryAfter)) {
|
|
416
437
|
const body = await response.text();
|
|
417
|
-
const last = new HttpException(
|
|
418
|
-
describeApiError(body, response.status),
|
|
419
|
-
response.status,
|
|
420
|
-
body,
|
|
421
|
-
{},
|
|
422
|
-
retryAfter
|
|
423
|
-
);
|
|
438
|
+
const last = new HttpException(describeApiError(body, response.status), response.status, body, {}, retryAfter);
|
|
424
439
|
throw HttpException.afterAttempts(operation, attempt, last);
|
|
425
440
|
}
|
|
426
441
|
return response;
|
|
@@ -637,6 +652,31 @@ function describeComplianceEnrollmentStatus(status) {
|
|
|
637
652
|
return DESCRIPTIONS[status];
|
|
638
653
|
}
|
|
639
654
|
|
|
655
|
+
// src/enums/ComplianceService.ts
|
|
656
|
+
var ComplianceService = {
|
|
657
|
+
E_REPORTING: "e_reporting",
|
|
658
|
+
E_INVOICING: "e_invoicing",
|
|
659
|
+
UNKNOWN: "unknown"
|
|
660
|
+
};
|
|
661
|
+
var VALUES2 = Object.values(ComplianceService);
|
|
662
|
+
function toComplianceService(value) {
|
|
663
|
+
if (typeof value === "string") {
|
|
664
|
+
const normalized = value.trim().toLowerCase();
|
|
665
|
+
if (VALUES2.includes(normalized)) {
|
|
666
|
+
return normalized;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
return ComplianceService.UNKNOWN;
|
|
670
|
+
}
|
|
671
|
+
var DESCRIPTIONS2 = {
|
|
672
|
+
[ComplianceService.E_REPORTING]: "E-reporting of transaction data to the tax authority (France: DGFiP Flux 10).",
|
|
673
|
+
[ComplianceService.E_INVOICING]: "Structured e-invoices delivered to the buyer (Norway: EHF / Peppol BIS 3.0).",
|
|
674
|
+
[ComplianceService.UNKNOWN]: "Unknown service."
|
|
675
|
+
};
|
|
676
|
+
function describeComplianceService(service) {
|
|
677
|
+
return DESCRIPTIONS2[service];
|
|
678
|
+
}
|
|
679
|
+
|
|
640
680
|
// src/dto/ComplianceEnrollment.ts
|
|
641
681
|
function asString(value, fallback = "") {
|
|
642
682
|
return typeof value === "string" ? value : fallback;
|
|
@@ -648,7 +688,7 @@ function asNumber(value) {
|
|
|
648
688
|
return typeof value === "number" ? value : Number(value ?? 0) || 0;
|
|
649
689
|
}
|
|
650
690
|
var ComplianceEnrollment = class _ComplianceEnrollment {
|
|
651
|
-
constructor(id, companyId, country, regime, provider, status, statusLabel, statusError, providerAccountId, taxId, companyRegisterId, companyRegisterScheme, regimeConfig, reportingStartDate, notificationEmail, autoSend, createdAt, updatedAt) {
|
|
691
|
+
constructor(id, companyId, country, regime, provider, status, statusLabel, statusError, providerAccountId, taxId, companyRegisterId, companyRegisterScheme, regimeConfig, reportingStartDate, notificationEmail, autoSend, createdAt, updatedAt, service = ComplianceService.UNKNOWN) {
|
|
652
692
|
this.id = id;
|
|
653
693
|
this.companyId = companyId;
|
|
654
694
|
this.country = country;
|
|
@@ -667,6 +707,7 @@ var ComplianceEnrollment = class _ComplianceEnrollment {
|
|
|
667
707
|
this.autoSend = autoSend;
|
|
668
708
|
this.createdAt = createdAt;
|
|
669
709
|
this.updatedAt = updatedAt;
|
|
710
|
+
this.service = service;
|
|
670
711
|
}
|
|
671
712
|
id;
|
|
672
713
|
companyId;
|
|
@@ -686,6 +727,7 @@ var ComplianceEnrollment = class _ComplianceEnrollment {
|
|
|
686
727
|
autoSend;
|
|
687
728
|
createdAt;
|
|
688
729
|
updatedAt;
|
|
730
|
+
service;
|
|
689
731
|
static fromArray(data) {
|
|
690
732
|
const regimeConfig = typeof data["regime_config"] === "object" && data["regime_config"] !== null && !Array.isArray(data["regime_config"]) ? data["regime_config"] : null;
|
|
691
733
|
return new _ComplianceEnrollment(
|
|
@@ -706,7 +748,8 @@ var ComplianceEnrollment = class _ComplianceEnrollment {
|
|
|
706
748
|
asNullableString(data["notification_email"]),
|
|
707
749
|
data["auto_send"] === true,
|
|
708
750
|
asNullableString(data["created_at"]),
|
|
709
|
-
asNullableString(data["updated_at"])
|
|
751
|
+
asNullableString(data["updated_at"]),
|
|
752
|
+
toComplianceService(data["service"])
|
|
710
753
|
);
|
|
711
754
|
}
|
|
712
755
|
};
|
|
@@ -756,17 +799,17 @@ var ComplianceTaxReportState = {
|
|
|
756
799
|
ERROR: "error",
|
|
757
800
|
UNKNOWN: "unknown"
|
|
758
801
|
};
|
|
759
|
-
var
|
|
802
|
+
var VALUES3 = Object.values(ComplianceTaxReportState);
|
|
760
803
|
function toComplianceTaxReportState(value) {
|
|
761
804
|
if (typeof value === "string") {
|
|
762
805
|
const normalized = value.trim().toLowerCase();
|
|
763
|
-
if (
|
|
806
|
+
if (VALUES3.includes(normalized)) {
|
|
764
807
|
return normalized;
|
|
765
808
|
}
|
|
766
809
|
}
|
|
767
810
|
return ComplianceTaxReportState.UNKNOWN;
|
|
768
811
|
}
|
|
769
|
-
var
|
|
812
|
+
var DESCRIPTIONS3 = {
|
|
770
813
|
[ComplianceTaxReportState.NEW]: "Created at provider, waiting for the daily ledger batch.",
|
|
771
814
|
[ComplianceTaxReportState.SENT]: "Ledger transmitted to PPF.",
|
|
772
815
|
[ComplianceTaxReportState.ACKNOWLEDGED]: "PPF acknowledged receipt of the ledger.",
|
|
@@ -776,7 +819,7 @@ var DESCRIPTIONS2 = {
|
|
|
776
819
|
[ComplianceTaxReportState.UNKNOWN]: "Unknown state."
|
|
777
820
|
};
|
|
778
821
|
function describeComplianceTaxReportState(state) {
|
|
779
|
-
return
|
|
822
|
+
return DESCRIPTIONS3[state];
|
|
780
823
|
}
|
|
781
824
|
|
|
782
825
|
// src/dto/ComplianceTaxReport.ts
|
|
@@ -898,6 +941,31 @@ var ComplianceTaxReportPage = class _ComplianceTaxReportPage {
|
|
|
898
941
|
}
|
|
899
942
|
};
|
|
900
943
|
|
|
944
|
+
// src/enums/ComplianceDocumentType.ts
|
|
945
|
+
var ComplianceDocumentType = {
|
|
946
|
+
INVOICE: "invoice",
|
|
947
|
+
CREDIT_NOTE: "credit_note",
|
|
948
|
+
UNKNOWN: "unknown"
|
|
949
|
+
};
|
|
950
|
+
var VALUES4 = Object.values(ComplianceDocumentType);
|
|
951
|
+
function toComplianceDocumentType(value) {
|
|
952
|
+
if (typeof value === "string") {
|
|
953
|
+
const normalized = value.trim().toLowerCase();
|
|
954
|
+
if (VALUES4.includes(normalized)) {
|
|
955
|
+
return normalized;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
return ComplianceDocumentType.UNKNOWN;
|
|
959
|
+
}
|
|
960
|
+
var DESCRIPTIONS4 = {
|
|
961
|
+
[ComplianceDocumentType.INVOICE]: "Commercial invoice.",
|
|
962
|
+
[ComplianceDocumentType.CREDIT_NOTE]: "Credit note correcting a previously issued invoice.",
|
|
963
|
+
[ComplianceDocumentType.UNKNOWN]: "Unknown document type."
|
|
964
|
+
};
|
|
965
|
+
function describeComplianceDocumentType(type) {
|
|
966
|
+
return DESCRIPTIONS4[type];
|
|
967
|
+
}
|
|
968
|
+
|
|
901
969
|
// src/enums/ComplianceTransactionState.ts
|
|
902
970
|
var ComplianceTransactionState = {
|
|
903
971
|
PENDING: "pending",
|
|
@@ -906,17 +974,17 @@ var ComplianceTransactionState = {
|
|
|
906
974
|
ERROR: "error",
|
|
907
975
|
UNKNOWN: "unknown"
|
|
908
976
|
};
|
|
909
|
-
var
|
|
977
|
+
var VALUES5 = Object.values(ComplianceTransactionState);
|
|
910
978
|
function toComplianceTransactionState(value) {
|
|
911
979
|
if (typeof value === "string") {
|
|
912
980
|
const normalized = value.trim().toLowerCase();
|
|
913
|
-
if (
|
|
981
|
+
if (VALUES5.includes(normalized)) {
|
|
914
982
|
return normalized;
|
|
915
983
|
}
|
|
916
984
|
}
|
|
917
985
|
return ComplianceTransactionState.UNKNOWN;
|
|
918
986
|
}
|
|
919
|
-
var
|
|
987
|
+
var DESCRIPTIONS5 = {
|
|
920
988
|
[ComplianceTransactionState.PENDING]: "Recorded locally, not yet submitted to the provider.",
|
|
921
989
|
[ComplianceTransactionState.SENDING]: "Submission to the provider in progress.",
|
|
922
990
|
[ComplianceTransactionState.SUBMITTED]: "Successfully submitted to the provider.",
|
|
@@ -924,7 +992,7 @@ var DESCRIPTIONS3 = {
|
|
|
924
992
|
[ComplianceTransactionState.UNKNOWN]: "Unknown state."
|
|
925
993
|
};
|
|
926
994
|
function describeComplianceTransactionState(state) {
|
|
927
|
-
return
|
|
995
|
+
return DESCRIPTIONS5[state];
|
|
928
996
|
}
|
|
929
997
|
|
|
930
998
|
// src/enums/ComplianceTransactionType.ts
|
|
@@ -936,17 +1004,17 @@ var ComplianceTransactionType = {
|
|
|
936
1004
|
CROSSBORDER_INBOUND: "crossborder_inbound",
|
|
937
1005
|
UNKNOWN: "unknown"
|
|
938
1006
|
};
|
|
939
|
-
var
|
|
1007
|
+
var VALUES6 = Object.values(ComplianceTransactionType);
|
|
940
1008
|
function toComplianceTransactionType(value) {
|
|
941
1009
|
if (typeof value === "string") {
|
|
942
1010
|
const normalized = value.trim().toLowerCase();
|
|
943
|
-
if (
|
|
1011
|
+
if (VALUES6.includes(normalized)) {
|
|
944
1012
|
return normalized;
|
|
945
1013
|
}
|
|
946
1014
|
}
|
|
947
1015
|
return ComplianceTransactionType.UNKNOWN;
|
|
948
1016
|
}
|
|
949
|
-
var
|
|
1017
|
+
var DESCRIPTIONS6 = {
|
|
950
1018
|
[ComplianceTransactionType.B2C_OUTBOUND]: "Sale to a private person in the merchant country (DGFiP Flux 10.3).",
|
|
951
1019
|
[ComplianceTransactionType.B2B_DOMESTIC_OUTBOUND]: "Sale to a domestic business (DGFiP Flux 1, Phase 2).",
|
|
952
1020
|
[ComplianceTransactionType.B2B_DOMESTIC_INBOUND]: "Purchase from a domestic business (DGFiP Flux 1, Phase 2).",
|
|
@@ -955,7 +1023,7 @@ var DESCRIPTIONS4 = {
|
|
|
955
1023
|
[ComplianceTransactionType.UNKNOWN]: "Unknown transaction type."
|
|
956
1024
|
};
|
|
957
1025
|
function describeComplianceTransactionType(type) {
|
|
958
|
-
return
|
|
1026
|
+
return DESCRIPTIONS6[type];
|
|
959
1027
|
}
|
|
960
1028
|
|
|
961
1029
|
// src/dto/ComplianceTransaction.ts
|
|
@@ -973,8 +1041,34 @@ function asMoney2(value) {
|
|
|
973
1041
|
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
974
1042
|
return "0.00";
|
|
975
1043
|
}
|
|
1044
|
+
function asNullableNumber2(value) {
|
|
1045
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
1046
|
+
if (typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value))) return Number(value);
|
|
1047
|
+
return null;
|
|
1048
|
+
}
|
|
1049
|
+
function asRecord(value) {
|
|
1050
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
1051
|
+
}
|
|
1052
|
+
function asRecordList(value) {
|
|
1053
|
+
return Array.isArray(value) ? value.filter((row) => asRecord(row) !== null) : [];
|
|
1054
|
+
}
|
|
1055
|
+
function toInvoiceLines(providerPayload) {
|
|
1056
|
+
const invoice = asRecord(asRecord(providerPayload)?.["invoice"]);
|
|
1057
|
+
return asRecordList(invoice?.["invoice_lines_attributes"]).map((line) => ({
|
|
1058
|
+
description: asString3(line["description"]),
|
|
1059
|
+
quantity: asNullableNumber2(line["quantity"]),
|
|
1060
|
+
price: asMoney2(line["price"]),
|
|
1061
|
+
unit: asNullableNumber2(line["unit"]),
|
|
1062
|
+
taxes: asRecordList(line["taxes_attributes"]).map((tax) => ({
|
|
1063
|
+
name: asString3(tax["name"]),
|
|
1064
|
+
percent: asNullableNumber2(tax["percent"]),
|
|
1065
|
+
category: asNullableString3(tax["category"]),
|
|
1066
|
+
comment: asNullableString3(tax["comment"])
|
|
1067
|
+
}))
|
|
1068
|
+
}));
|
|
1069
|
+
}
|
|
976
1070
|
var ComplianceTransaction = class _ComplianceTransaction {
|
|
977
|
-
constructor(id, companyId, complianceEnrollmentId, country, regime, transactionType, transactionTypeLabel, state, stateLabel, invoiceNumber, invoiceDate, dueDate, currency, subtotal, taxAmount, total, counterpartyName, counterpartyCountry, counterpartyVatNumber, isPaid, paidAt, providerInvoiceId, submissionError, reportedAt, taxReport, createdAt, updatedAt) {
|
|
1071
|
+
constructor(id, companyId, complianceEnrollmentId, country, regime, transactionType, transactionTypeLabel, state, stateLabel, invoiceNumber, invoiceDate, dueDate, currency, subtotal, taxAmount, total, counterpartyName, counterpartyCountry, counterpartyVatNumber, isPaid, paidAt, providerInvoiceId, submissionError, reportedAt, taxReport, createdAt, updatedAt, counterpartyRegisterId = null, counterpartyAddress = null, counterpartyCity = null, counterpartyPostalcode = null, counterpartyEmail = null, buyerReference = null, documentType = ComplianceDocumentType.INVOICE, amendedNumber = null, amendedDate = null, providerState = null, invoiceLines = []) {
|
|
978
1072
|
this.id = id;
|
|
979
1073
|
this.companyId = companyId;
|
|
980
1074
|
this.complianceEnrollmentId = complianceEnrollmentId;
|
|
@@ -1002,6 +1096,17 @@ var ComplianceTransaction = class _ComplianceTransaction {
|
|
|
1002
1096
|
this.taxReport = taxReport;
|
|
1003
1097
|
this.createdAt = createdAt;
|
|
1004
1098
|
this.updatedAt = updatedAt;
|
|
1099
|
+
this.counterpartyRegisterId = counterpartyRegisterId;
|
|
1100
|
+
this.counterpartyAddress = counterpartyAddress;
|
|
1101
|
+
this.counterpartyCity = counterpartyCity;
|
|
1102
|
+
this.counterpartyPostalcode = counterpartyPostalcode;
|
|
1103
|
+
this.counterpartyEmail = counterpartyEmail;
|
|
1104
|
+
this.buyerReference = buyerReference;
|
|
1105
|
+
this.documentType = documentType;
|
|
1106
|
+
this.amendedNumber = amendedNumber;
|
|
1107
|
+
this.amendedDate = amendedDate;
|
|
1108
|
+
this.providerState = providerState;
|
|
1109
|
+
this.invoiceLines = invoiceLines;
|
|
1005
1110
|
}
|
|
1006
1111
|
id;
|
|
1007
1112
|
companyId;
|
|
@@ -1030,6 +1135,20 @@ var ComplianceTransaction = class _ComplianceTransaction {
|
|
|
1030
1135
|
taxReport;
|
|
1031
1136
|
createdAt;
|
|
1032
1137
|
updatedAt;
|
|
1138
|
+
counterpartyRegisterId;
|
|
1139
|
+
counterpartyAddress;
|
|
1140
|
+
counterpartyCity;
|
|
1141
|
+
counterpartyPostalcode;
|
|
1142
|
+
counterpartyEmail;
|
|
1143
|
+
buyerReference;
|
|
1144
|
+
documentType;
|
|
1145
|
+
amendedNumber;
|
|
1146
|
+
amendedDate;
|
|
1147
|
+
providerState;
|
|
1148
|
+
invoiceLines;
|
|
1149
|
+
get isCreditNote() {
|
|
1150
|
+
return this.documentType === ComplianceDocumentType.CREDIT_NOTE;
|
|
1151
|
+
}
|
|
1033
1152
|
static fromArray(data) {
|
|
1034
1153
|
const taxReport = typeof data["tax_report"] === "object" && data["tax_report"] !== null && !Array.isArray(data["tax_report"]) ? ComplianceTaxReport.fromArray(data["tax_report"]) : void 0;
|
|
1035
1154
|
return new _ComplianceTransaction(
|
|
@@ -1059,7 +1178,18 @@ var ComplianceTransaction = class _ComplianceTransaction {
|
|
|
1059
1178
|
asNullableString3(data["reported_at"]),
|
|
1060
1179
|
taxReport,
|
|
1061
1180
|
asNullableString3(data["created_at"]),
|
|
1062
|
-
asNullableString3(data["updated_at"])
|
|
1181
|
+
asNullableString3(data["updated_at"]),
|
|
1182
|
+
asNullableString3(data["counterparty_register_id"]),
|
|
1183
|
+
asNullableString3(data["counterparty_address"]),
|
|
1184
|
+
asNullableString3(data["counterparty_city"]),
|
|
1185
|
+
asNullableString3(data["counterparty_postalcode"]),
|
|
1186
|
+
asNullableString3(data["counterparty_email"]),
|
|
1187
|
+
asNullableString3(data["buyer_reference"]),
|
|
1188
|
+
data["document_type"] === void 0 || data["document_type"] === null ? ComplianceDocumentType.INVOICE : toComplianceDocumentType(data["document_type"]),
|
|
1189
|
+
asNullableString3(data["amended_number"]),
|
|
1190
|
+
asNullableString3(data["amended_date"]),
|
|
1191
|
+
asNullableString3(data["provider_state"]),
|
|
1192
|
+
toInvoiceLines(data["provider_payload"])
|
|
1063
1193
|
);
|
|
1064
1194
|
}
|
|
1065
1195
|
};
|
|
@@ -1118,10 +1248,134 @@ var ImportResult = class _ImportResult {
|
|
|
1118
1248
|
}
|
|
1119
1249
|
};
|
|
1120
1250
|
|
|
1121
|
-
// src/
|
|
1251
|
+
// src/enums/PeppolLookupStatus.ts
|
|
1252
|
+
var PeppolLookupStatus = {
|
|
1253
|
+
REACHABLE: "reachable",
|
|
1254
|
+
NOT_REACHABLE: "not_reachable",
|
|
1255
|
+
PENDING: "pending",
|
|
1256
|
+
UNKNOWN: "unknown"
|
|
1257
|
+
};
|
|
1258
|
+
var VALUES7 = Object.values(PeppolLookupStatus);
|
|
1259
|
+
function toPeppolLookupStatus(value) {
|
|
1260
|
+
if (typeof value === "string") {
|
|
1261
|
+
const normalized = value.trim().toLowerCase();
|
|
1262
|
+
if (VALUES7.includes(normalized)) {
|
|
1263
|
+
return normalized;
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
return PeppolLookupStatus.UNKNOWN;
|
|
1267
|
+
}
|
|
1268
|
+
var DESCRIPTIONS7 = {
|
|
1269
|
+
[PeppolLookupStatus.REACHABLE]: "The participant is registered on Peppol and can receive e-invoices.",
|
|
1270
|
+
[PeppolLookupStatus.NOT_REACHABLE]: "The participant is not registered on Peppol.",
|
|
1271
|
+
[PeppolLookupStatus.PENDING]: "The directory lookup is still resolving \u2014 ask again in a few seconds.",
|
|
1272
|
+
[PeppolLookupStatus.UNKNOWN]: "Unknown lookup status."
|
|
1273
|
+
};
|
|
1274
|
+
function describePeppolLookupStatus(status) {
|
|
1275
|
+
return DESCRIPTIONS7[status];
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
// src/dto/PeppolLookupResult.ts
|
|
1122
1279
|
function asString4(value, fallback = "") {
|
|
1123
1280
|
return typeof value === "string" ? value : fallback;
|
|
1124
1281
|
}
|
|
1282
|
+
function asNullableString4(value) {
|
|
1283
|
+
return typeof value === "string" ? value : null;
|
|
1284
|
+
}
|
|
1285
|
+
var PeppolLookupResult = class _PeppolLookupResult {
|
|
1286
|
+
constructor(status, reachable, country, scheme, id, documentTypes, transportTypeCode, checkedAt) {
|
|
1287
|
+
this.status = status;
|
|
1288
|
+
this.reachable = reachable;
|
|
1289
|
+
this.country = country;
|
|
1290
|
+
this.scheme = scheme;
|
|
1291
|
+
this.id = id;
|
|
1292
|
+
this.documentTypes = documentTypes;
|
|
1293
|
+
this.transportTypeCode = transportTypeCode;
|
|
1294
|
+
this.checkedAt = checkedAt;
|
|
1295
|
+
}
|
|
1296
|
+
status;
|
|
1297
|
+
reachable;
|
|
1298
|
+
country;
|
|
1299
|
+
scheme;
|
|
1300
|
+
id;
|
|
1301
|
+
documentTypes;
|
|
1302
|
+
transportTypeCode;
|
|
1303
|
+
checkedAt;
|
|
1304
|
+
/** True while the directory is still resolving — ask again in a few seconds. */
|
|
1305
|
+
get isPending() {
|
|
1306
|
+
return this.status === PeppolLookupStatus.PENDING;
|
|
1307
|
+
}
|
|
1308
|
+
static fromArray(data) {
|
|
1309
|
+
const documentTypes = Array.isArray(data["document_types"]) ? data["document_types"].filter((t) => typeof t === "string") : [];
|
|
1310
|
+
return new _PeppolLookupResult(
|
|
1311
|
+
toPeppolLookupStatus(data["status"]),
|
|
1312
|
+
typeof data["reachable"] === "boolean" ? data["reachable"] : null,
|
|
1313
|
+
asString4(data["country"]),
|
|
1314
|
+
asString4(data["scheme"]),
|
|
1315
|
+
asString4(data["id"]),
|
|
1316
|
+
documentTypes,
|
|
1317
|
+
asNullableString4(data["transport_type_code"]),
|
|
1318
|
+
asNullableString4(data["checked_at"])
|
|
1319
|
+
);
|
|
1320
|
+
}
|
|
1321
|
+
};
|
|
1322
|
+
|
|
1323
|
+
// src/dto/RegistryCompany.ts
|
|
1324
|
+
function asString5(value, fallback = "") {
|
|
1325
|
+
return typeof value === "string" ? value : fallback;
|
|
1326
|
+
}
|
|
1327
|
+
function asNullableString5(value) {
|
|
1328
|
+
return typeof value === "string" ? value : null;
|
|
1329
|
+
}
|
|
1330
|
+
var RegistryCompany = class _RegistryCompany {
|
|
1331
|
+
constructor(orgNumber, companyName, organisationForm, vatRegistered, vatNumber, enterpriseRegister, bankrupt, underLiquidation, address, postalcode, city, country) {
|
|
1332
|
+
this.orgNumber = orgNumber;
|
|
1333
|
+
this.companyName = companyName;
|
|
1334
|
+
this.organisationForm = organisationForm;
|
|
1335
|
+
this.vatRegistered = vatRegistered;
|
|
1336
|
+
this.vatNumber = vatNumber;
|
|
1337
|
+
this.enterpriseRegister = enterpriseRegister;
|
|
1338
|
+
this.bankrupt = bankrupt;
|
|
1339
|
+
this.underLiquidation = underLiquidation;
|
|
1340
|
+
this.address = address;
|
|
1341
|
+
this.postalcode = postalcode;
|
|
1342
|
+
this.city = city;
|
|
1343
|
+
this.country = country;
|
|
1344
|
+
}
|
|
1345
|
+
orgNumber;
|
|
1346
|
+
companyName;
|
|
1347
|
+
organisationForm;
|
|
1348
|
+
vatRegistered;
|
|
1349
|
+
vatNumber;
|
|
1350
|
+
enterpriseRegister;
|
|
1351
|
+
bankrupt;
|
|
1352
|
+
underLiquidation;
|
|
1353
|
+
address;
|
|
1354
|
+
postalcode;
|
|
1355
|
+
city;
|
|
1356
|
+
country;
|
|
1357
|
+
static fromArray(data) {
|
|
1358
|
+
return new _RegistryCompany(
|
|
1359
|
+
asString5(data["org_number"]),
|
|
1360
|
+
asString5(data["company_name"]),
|
|
1361
|
+
asNullableString5(data["organisation_form"]),
|
|
1362
|
+
data["vat_registered"] === true,
|
|
1363
|
+
asNullableString5(data["vat_number"]),
|
|
1364
|
+
data["enterprise_register"] === true,
|
|
1365
|
+
data["bankrupt"] === true,
|
|
1366
|
+
data["under_liquidation"] === true,
|
|
1367
|
+
asNullableString5(data["address"]),
|
|
1368
|
+
asNullableString5(data["postalcode"]),
|
|
1369
|
+
asNullableString5(data["city"]),
|
|
1370
|
+
asString5(data["country"])
|
|
1371
|
+
);
|
|
1372
|
+
}
|
|
1373
|
+
};
|
|
1374
|
+
|
|
1375
|
+
// src/dto/RevenueStatistics.ts
|
|
1376
|
+
function asString6(value, fallback = "") {
|
|
1377
|
+
return typeof value === "string" ? value : fallback;
|
|
1378
|
+
}
|
|
1125
1379
|
function asNumber4(value) {
|
|
1126
1380
|
return typeof value === "number" ? value : Number(value ?? 0) || 0;
|
|
1127
1381
|
}
|
|
@@ -1171,35 +1425,35 @@ var RevenueStatistics = class _RevenueStatistics {
|
|
|
1171
1425
|
typeof data["totals"] === "object" && data["totals"] !== null ? data["totals"] : {}
|
|
1172
1426
|
);
|
|
1173
1427
|
const timeSeries = asRecords(data["time_series"]).map((row) => ({
|
|
1174
|
-
bucket:
|
|
1428
|
+
bucket: asString6(row["bucket"]),
|
|
1175
1429
|
...toTotals(row)
|
|
1176
1430
|
}));
|
|
1177
1431
|
const byType = asRecords(data["by_type"]).map((row) => ({
|
|
1178
|
-
type:
|
|
1179
|
-
typeLabel:
|
|
1432
|
+
type: asString6(row["type"]),
|
|
1433
|
+
typeLabel: asString6(row["type_label"]),
|
|
1180
1434
|
count: asNumber4(row["count"]),
|
|
1181
1435
|
total: asMoney3(row["total"])
|
|
1182
1436
|
}));
|
|
1183
1437
|
const byCountry = asRecords(data["by_country"]).map((row) => ({
|
|
1184
|
-
country:
|
|
1438
|
+
country: asString6(row["country"], "unknown"),
|
|
1185
1439
|
count: asNumber4(row["count"]),
|
|
1186
1440
|
total: asMoney3(row["total"])
|
|
1187
1441
|
}));
|
|
1188
1442
|
const byState = asRecords(data["by_state"]).map((row) => ({
|
|
1189
|
-
state:
|
|
1190
|
-
stateLabel:
|
|
1443
|
+
state: asString6(row["state"]),
|
|
1444
|
+
stateLabel: asString6(row["state_label"]),
|
|
1191
1445
|
count: asNumber4(row["count"]),
|
|
1192
1446
|
total: asMoney3(row["total"])
|
|
1193
1447
|
}));
|
|
1194
1448
|
const byCurrency = asRecords(data["by_currency"]).map((row) => ({
|
|
1195
|
-
currency:
|
|
1449
|
+
currency: asString6(row["currency"]),
|
|
1196
1450
|
...toTotals(row)
|
|
1197
1451
|
}));
|
|
1198
1452
|
return new _RevenueStatistics(
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1453
|
+
asString6(range["date_from"]) || void 0,
|
|
1454
|
+
asString6(range["date_to"]) || void 0,
|
|
1455
|
+
asString6(range["interval"]) || void 0,
|
|
1456
|
+
asString6(data["primary_currency"], "EUR"),
|
|
1203
1457
|
data["is_multi_currency"] === true,
|
|
1204
1458
|
totals,
|
|
1205
1459
|
timeSeries,
|
|
@@ -1212,10 +1466,10 @@ var RevenueStatistics = class _RevenueStatistics {
|
|
|
1212
1466
|
};
|
|
1213
1467
|
|
|
1214
1468
|
// src/dto/SireneLookupResult.ts
|
|
1215
|
-
function
|
|
1469
|
+
function asString7(value, fallback = "") {
|
|
1216
1470
|
return typeof value === "string" ? value : fallback;
|
|
1217
1471
|
}
|
|
1218
|
-
function
|
|
1472
|
+
function asNullableString6(value) {
|
|
1219
1473
|
return typeof value === "string" ? value : null;
|
|
1220
1474
|
}
|
|
1221
1475
|
var SireneLookupResult = class _SireneLookupResult {
|
|
@@ -1241,21 +1495,21 @@ var SireneLookupResult = class _SireneLookupResult {
|
|
|
1241
1495
|
postalcode;
|
|
1242
1496
|
static fromArray(data) {
|
|
1243
1497
|
return new _SireneLookupResult(
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1498
|
+
asString7(data["company_name"]),
|
|
1499
|
+
asString7(data["siren"]),
|
|
1500
|
+
asNullableString6(data["siret"]),
|
|
1501
|
+
asNullableString6(data["naf_code"]),
|
|
1502
|
+
asNullableString6(data["naf_full"]),
|
|
1503
|
+
asNullableString6(data["enterprise_size"]),
|
|
1504
|
+
asNullableString6(data["address"]),
|
|
1505
|
+
asNullableString6(data["city"]),
|
|
1506
|
+
asNullableString6(data["postalcode"])
|
|
1253
1507
|
);
|
|
1254
1508
|
}
|
|
1255
1509
|
};
|
|
1256
1510
|
|
|
1257
1511
|
// src/dto/VatRates.ts
|
|
1258
|
-
function
|
|
1512
|
+
function asString8(value, fallback = "") {
|
|
1259
1513
|
return typeof value === "string" ? value : fallback;
|
|
1260
1514
|
}
|
|
1261
1515
|
function asNumber5(value) {
|
|
@@ -1273,12 +1527,12 @@ var VatRates = class _VatRates {
|
|
|
1273
1527
|
static fromArray(data) {
|
|
1274
1528
|
const rates = (Array.isArray(data["rates"]) ? data["rates"] : []).filter((row) => typeof row === "object" && row !== null).map((row) => ({
|
|
1275
1529
|
percent: asNumber5(row["percent"]),
|
|
1276
|
-
category:
|
|
1277
|
-
labelKey:
|
|
1278
|
-
taxName:
|
|
1530
|
+
category: asString8(row["category"]),
|
|
1531
|
+
labelKey: asString8(row["label_key"]),
|
|
1532
|
+
taxName: asString8(row["tax_name"]),
|
|
1279
1533
|
requiresVatex: row["requires_vatex"] === true
|
|
1280
1534
|
}));
|
|
1281
|
-
return new _VatRates(
|
|
1535
|
+
return new _VatRates(asString8(data["country"]), asString8(data["currency"], "EUR"), rates);
|
|
1282
1536
|
}
|
|
1283
1537
|
};
|
|
1284
1538
|
|
|
@@ -1297,10 +1551,48 @@ var ValidationException = class extends TaxoraException {
|
|
|
1297
1551
|
}
|
|
1298
1552
|
};
|
|
1299
1553
|
|
|
1554
|
+
// src/support/NorwegianOrgNumber.ts
|
|
1555
|
+
var WEIGHTS = [3, 2, 7, 6, 5, 4, 3, 2];
|
|
1556
|
+
var NorwegianOrgNumber = {
|
|
1557
|
+
/** Peppol identifier scheme for Norwegian organisation numbers. */
|
|
1558
|
+
PEPPOL_SCHEME: "0192",
|
|
1559
|
+
/**
|
|
1560
|
+
* Strips whitespace, dots, dashes, a "0192:" Peppol scheme prefix, the "NO"
|
|
1561
|
+
* prefix and the "MVA" suffix: "NO 923 609 016 MVA", "923609016MVA" and
|
|
1562
|
+
* "923 609 016" all become "923609016". Does not validate.
|
|
1563
|
+
*/
|
|
1564
|
+
normalize(value) {
|
|
1565
|
+
let v = (value ?? "").trim().toUpperCase().replace(/[\s.-]/g, "");
|
|
1566
|
+
if (v.startsWith("0192:")) v = v.slice(5);
|
|
1567
|
+
if (v.startsWith("NO")) v = v.slice(2);
|
|
1568
|
+
if (v.endsWith("MVA")) v = v.slice(0, -3);
|
|
1569
|
+
return v;
|
|
1570
|
+
},
|
|
1571
|
+
/** True when the (normalized) value is 9 digits with a valid mod-11 check digit. */
|
|
1572
|
+
isValid(value) {
|
|
1573
|
+
const digits = NorwegianOrgNumber.normalize(value);
|
|
1574
|
+
if (!/^\d{9}$/.test(digits)) return false;
|
|
1575
|
+
let sum = 0;
|
|
1576
|
+
for (let i = 0; i < WEIGHTS.length; i++) {
|
|
1577
|
+
sum += Number(digits[i]) * WEIGHTS[i];
|
|
1578
|
+
}
|
|
1579
|
+
let check = 11 - sum % 11;
|
|
1580
|
+
if (check === 11) check = 0;
|
|
1581
|
+
return check !== 10 && check === Number(digits[8]);
|
|
1582
|
+
},
|
|
1583
|
+
/** "NO923609016MVA" — the Norwegian VAT number of an MVA-registered entity. Does not validate. */
|
|
1584
|
+
toVatNumber(value) {
|
|
1585
|
+
return `NO${NorwegianOrgNumber.normalize(value)}MVA`;
|
|
1586
|
+
}
|
|
1587
|
+
};
|
|
1588
|
+
|
|
1300
1589
|
// src/endpoints/EReportingEndpoint.ts
|
|
1301
1590
|
var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
1302
1591
|
var NAF_CODE_REGEX = /^\d{2}$/;
|
|
1592
|
+
var COUNTRY_REGEX = /^[A-Za-z]{2}$/;
|
|
1593
|
+
var PEPPOL_SCHEME_REGEX = /^\d{4}$/;
|
|
1303
1594
|
var INTERVALS = ["day", "week", "month"];
|
|
1595
|
+
var SERVICES = ["e_reporting", "e_invoicing"];
|
|
1304
1596
|
var ENTERPRISE_SIZES = ["micro", "pme", "eti", "ge"];
|
|
1305
1597
|
var TYPE_OPERATIONS = ["services", "goods", "mixed"];
|
|
1306
1598
|
var TRANSACTION_TYPES = [
|
|
@@ -1328,14 +1620,23 @@ var EReportingEndpoint = class {
|
|
|
1328
1620
|
// ---------------------------------------------------------------------
|
|
1329
1621
|
/**
|
|
1330
1622
|
* Create a compliance enrollment and provision the provider account. By
|
|
1331
|
-
* default the
|
|
1623
|
+
* default the country regime is activated right away (France: DGFiP tax
|
|
1624
|
+
* report setting; Norway: Peppol registration); pass `autoActivate: false`
|
|
1332
1625
|
* to only create the account.
|
|
1333
1626
|
*
|
|
1334
|
-
*
|
|
1335
|
-
* the
|
|
1627
|
+
* The input shape depends on `country`: omitted/"FR" takes the France input
|
|
1628
|
+
* (unchanged, backwards compatible), "NO" the Norway input — see also the
|
|
1629
|
+
* createNorwayEnrollment() shortcut.
|
|
1630
|
+
*
|
|
1631
|
+
* Errors: 403 (HttpException, body code `service_not_active`) when the company
|
|
1632
|
+
* lacks the requested service; on provider failure 502 (HttpException) — the
|
|
1633
|
+
* enrollment is then persisted in `error_account`/`error_activation` state so
|
|
1336
1634
|
* provisioning can be retried.
|
|
1337
1635
|
*/
|
|
1338
1636
|
async createEnrollment(input) {
|
|
1637
|
+
if (this.isNorwayEnrollmentInput(input)) {
|
|
1638
|
+
return this.createEnrollmentFromBody(this.buildNorwayEnrollmentBody(input));
|
|
1639
|
+
}
|
|
1339
1640
|
this.validateEnrollmentInput(input);
|
|
1340
1641
|
const body = {
|
|
1341
1642
|
email: input.email,
|
|
@@ -1345,6 +1646,7 @@ var EReportingEndpoint = class {
|
|
|
1345
1646
|
reporting_start_date: this.formatDate(input.reportingStartDate)
|
|
1346
1647
|
};
|
|
1347
1648
|
if (input.country !== void 0) body["country"] = input.country;
|
|
1649
|
+
if (input.service !== void 0) body["service"] = input.service;
|
|
1348
1650
|
if (input.regime !== void 0) body["regime"] = input.regime;
|
|
1349
1651
|
if (input.siret !== void 0) body["siret"] = input.siret;
|
|
1350
1652
|
if (input.siren !== void 0) body["siren"] = input.siren;
|
|
@@ -1355,9 +1657,15 @@ var EReportingEndpoint = class {
|
|
|
1355
1657
|
if (input.postalcode !== void 0) body["postalcode"] = input.postalcode;
|
|
1356
1658
|
if (input.province !== void 0) body["province"] = input.province;
|
|
1357
1659
|
if (input.autoActivate !== void 0) body["auto_activate"] = input.autoActivate;
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1660
|
+
return this.createEnrollmentFromBody(body);
|
|
1661
|
+
}
|
|
1662
|
+
/**
|
|
1663
|
+
* Enroll the company for Norway e-invoicing (EHF / Peppol BIS 3.0) — shortcut
|
|
1664
|
+
* for createEnrollment({ country: 'NO', ... }). The organisation number is
|
|
1665
|
+
* checked (mod-11) and normalized to 9 digits before sending.
|
|
1666
|
+
*/
|
|
1667
|
+
async createNorwayEnrollment(input) {
|
|
1668
|
+
return this.createEnrollment({ ...input, country: "NO" });
|
|
1361
1669
|
}
|
|
1362
1670
|
/** Paginated list of the company's enrollments (newest first). `perPage` is capped at 100 server-side. */
|
|
1363
1671
|
async listEnrollments(page = 1, perPage = 25) {
|
|
@@ -1391,6 +1699,72 @@ var EReportingEndpoint = class {
|
|
|
1391
1699
|
const data = await this.parseJsonResponse(response);
|
|
1392
1700
|
return SireneLookupResult.fromArray(data);
|
|
1393
1701
|
}
|
|
1702
|
+
/**
|
|
1703
|
+
* Look up companies in a national company register — currently Norway
|
|
1704
|
+
* (Brønnøysund Enhetsregisteret). `q` is an organisation number, a "NO…MVA"
|
|
1705
|
+
* VAT number or a company name; an exact number match yields one result.
|
|
1706
|
+
* Ideal for prefilling createNorwayEnrollment() and the buyer fields of an
|
|
1707
|
+
* e-invoice. For France use sireneLookup().
|
|
1708
|
+
*
|
|
1709
|
+
* Errors: 404 (HttpException) when nothing is found, 422 (ValidationException)
|
|
1710
|
+
* on invalid input / unsupported country, 429 (HttpException) when the
|
|
1711
|
+
* per-user rate limit (30/min) is exceeded.
|
|
1712
|
+
*/
|
|
1713
|
+
async registryLookup(country, q) {
|
|
1714
|
+
const normalizedCountry = this.normalizeLookupCountry(country);
|
|
1715
|
+
const query = q.trim();
|
|
1716
|
+
if (query === "") {
|
|
1717
|
+
throw new TaxoraException("q must not be empty.");
|
|
1718
|
+
}
|
|
1719
|
+
if (normalizedCountry === "NO") {
|
|
1720
|
+
const digits = NorwegianOrgNumber.normalize(query);
|
|
1721
|
+
if (/^\d{9}$/.test(digits) && !NorwegianOrgNumber.isValid(digits)) {
|
|
1722
|
+
throw new TaxoraException(`Invalid Norwegian organisation number "${query}" (check digit).`);
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
const params = new URLSearchParams();
|
|
1726
|
+
params.set("country", normalizedCountry);
|
|
1727
|
+
params.set("q", query);
|
|
1728
|
+
const response = await this.sendRequest("GET", `${this.baseUrl}/compliance/registry-lookup?${params.toString()}`);
|
|
1729
|
+
const data = await this.parseJsonResponse(response);
|
|
1730
|
+
const results = Array.isArray(data["results"]) ? data["results"] : [];
|
|
1731
|
+
return results.filter((row) => typeof row === "object" && row !== null && !Array.isArray(row)).map((row) => RegistryCompany.fromArray(row));
|
|
1732
|
+
}
|
|
1733
|
+
/**
|
|
1734
|
+
* Check whether a participant (typically the buyer) can receive e-invoices
|
|
1735
|
+
* over Peppol. For Norway pass the organisation number (scheme defaults to
|
|
1736
|
+
* "0192"): `reachable === true` means the buyer is registered in ELMA and must
|
|
1737
|
+
* receive an EHF e-invoice. The directory resolves asynchronously —
|
|
1738
|
+
* `status === 'pending'` (`reachable === null`) means ask again in a few
|
|
1739
|
+
* seconds. Free of charge; definite answers are cached for 24h server-side.
|
|
1740
|
+
*
|
|
1741
|
+
* A Norwegian organisation number is checked (mod-11) and normalized before
|
|
1742
|
+
* sending. Errors: 422 (ValidationException) on invalid input, 502
|
|
1743
|
+
* (HttpException) on provider failure.
|
|
1744
|
+
*/
|
|
1745
|
+
async peppolLookup(country, id, scheme) {
|
|
1746
|
+
const normalizedCountry = this.normalizeLookupCountry(country);
|
|
1747
|
+
let participantId = id.trim();
|
|
1748
|
+
if (participantId === "") {
|
|
1749
|
+
throw new TaxoraException("id must not be empty.");
|
|
1750
|
+
}
|
|
1751
|
+
if (scheme !== void 0 && !PEPPOL_SCHEME_REGEX.test(scheme)) {
|
|
1752
|
+
throw new TaxoraException('scheme must be a 4-digit Peppol identifier scheme, e.g. "0192".');
|
|
1753
|
+
}
|
|
1754
|
+
if (normalizedCountry === "NO" && (scheme === void 0 || scheme === NorwegianOrgNumber.PEPPOL_SCHEME)) {
|
|
1755
|
+
if (!NorwegianOrgNumber.isValid(participantId)) {
|
|
1756
|
+
throw new TaxoraException(`Invalid Norwegian organisation number "${participantId}".`);
|
|
1757
|
+
}
|
|
1758
|
+
participantId = NorwegianOrgNumber.normalize(participantId);
|
|
1759
|
+
}
|
|
1760
|
+
const params = new URLSearchParams();
|
|
1761
|
+
params.set("country", normalizedCountry);
|
|
1762
|
+
params.set("id", participantId);
|
|
1763
|
+
if (scheme !== void 0) params.set("scheme", scheme);
|
|
1764
|
+
const response = await this.sendRequest("GET", `${this.baseUrl}/compliance/peppol-lookup?${params.toString()}`);
|
|
1765
|
+
const data = await this.parseJsonResponse(response);
|
|
1766
|
+
return PeppolLookupResult.fromArray(data);
|
|
1767
|
+
}
|
|
1394
1768
|
// ---------------------------------------------------------------------
|
|
1395
1769
|
// Transactions
|
|
1396
1770
|
// ---------------------------------------------------------------------
|
|
@@ -1414,6 +1788,7 @@ var EReportingEndpoint = class {
|
|
|
1414
1788
|
this.validateInvoiceNumber(input.invoiceNumber);
|
|
1415
1789
|
this.validateInvoiceLines(input.invoiceLines);
|
|
1416
1790
|
this.validateOptionalCodes(input);
|
|
1791
|
+
this.validateBuyerFields(input);
|
|
1417
1792
|
const body = {
|
|
1418
1793
|
compliance_enrollment_id: input.complianceEnrollmentId,
|
|
1419
1794
|
transaction_type: input.transactionType,
|
|
@@ -1429,13 +1804,23 @@ var EReportingEndpoint = class {
|
|
|
1429
1804
|
const data = await this.parseJsonResponse(response);
|
|
1430
1805
|
return ComplianceTransaction.fromArray(data);
|
|
1431
1806
|
}
|
|
1432
|
-
/** Paginated list of the company's transactions (newest invoice date first), filterable by date / state / type. */
|
|
1807
|
+
/** Paginated list of the company's transactions (newest invoice date first), filterable by date / state / type / enrollment / country. */
|
|
1433
1808
|
async listTransactions(filters = {}) {
|
|
1809
|
+
if (filters.complianceEnrollmentId !== void 0) {
|
|
1810
|
+
this.validateId(filters.complianceEnrollmentId, "complianceEnrollmentId");
|
|
1811
|
+
}
|
|
1812
|
+
if (filters.country !== void 0 && !COUNTRY_REGEX.test(filters.country)) {
|
|
1813
|
+
throw new TaxoraException("country must be a 2-character ISO 3166-1 alpha-2 code.");
|
|
1814
|
+
}
|
|
1434
1815
|
const params = new URLSearchParams();
|
|
1435
1816
|
if (filters.dateFrom !== void 0) params.set("date_from", this.formatDate(filters.dateFrom));
|
|
1436
1817
|
if (filters.dateTo !== void 0) params.set("date_to", this.formatDate(filters.dateTo));
|
|
1437
1818
|
if (filters.state !== void 0) params.set("state", filters.state);
|
|
1438
1819
|
if (filters.transactionType !== void 0) params.set("transaction_type", filters.transactionType);
|
|
1820
|
+
if (filters.complianceEnrollmentId !== void 0) {
|
|
1821
|
+
params.set("compliance_enrollment_id", String(filters.complianceEnrollmentId));
|
|
1822
|
+
}
|
|
1823
|
+
if (filters.country !== void 0) params.set("country", filters.country.toUpperCase());
|
|
1439
1824
|
if (filters.page !== void 0) params.set("page", String(filters.page));
|
|
1440
1825
|
if (filters.perPage !== void 0) params.set("per_page", String(filters.perPage));
|
|
1441
1826
|
const queryString = params.toString();
|
|
@@ -1457,6 +1842,7 @@ var EReportingEndpoint = class {
|
|
|
1457
1842
|
if (input.invoiceNumber !== void 0) this.validateInvoiceNumber(input.invoiceNumber);
|
|
1458
1843
|
if (input.invoiceLines !== void 0) this.validateInvoiceLines(input.invoiceLines);
|
|
1459
1844
|
this.validateOptionalCodes(input);
|
|
1845
|
+
this.validateBuyerFields(input);
|
|
1460
1846
|
const body = {};
|
|
1461
1847
|
if (input.transactionType !== void 0) body["transaction_type"] = input.transactionType;
|
|
1462
1848
|
if (input.invoiceNumber !== void 0) body["invoice_number"] = input.invoiceNumber;
|
|
@@ -1579,6 +1965,14 @@ var EReportingEndpoint = class {
|
|
|
1579
1965
|
* returned as HTTP 400 (surfaced as HttpException), not 422.
|
|
1580
1966
|
*/
|
|
1581
1967
|
async requestEReportingAccess(input = {}) {
|
|
1968
|
+
if (input.service !== void 0) this.validateService(input.service);
|
|
1969
|
+
if (input.countries !== void 0) {
|
|
1970
|
+
input.countries.forEach((country, index) => {
|
|
1971
|
+
if (!COUNTRY_REGEX.test(country)) {
|
|
1972
|
+
throw new TaxoraException(`countries[${index}] must be a 2-character ISO 3166-1 alpha-2 code.`);
|
|
1973
|
+
}
|
|
1974
|
+
});
|
|
1975
|
+
}
|
|
1582
1976
|
const body = {};
|
|
1583
1977
|
if (input.name !== void 0) body["name"] = input.name;
|
|
1584
1978
|
if (input.email !== void 0) body["email"] = input.email;
|
|
@@ -1586,6 +1980,8 @@ var EReportingEndpoint = class {
|
|
|
1586
1980
|
if (input.phone !== void 0) body["phone"] = input.phone;
|
|
1587
1981
|
if (input.message !== void 0) body["message"] = input.message;
|
|
1588
1982
|
if (input.language !== void 0) body["language"] = input.language;
|
|
1983
|
+
if (input.service !== void 0) body["service"] = input.service;
|
|
1984
|
+
if (input.countries !== void 0) body["countries"] = input.countries.map((c) => c.toUpperCase());
|
|
1589
1985
|
const response = await this.sendRequest("POST", `${this.baseUrl}/compliance/e-reporting-request`, body);
|
|
1590
1986
|
await this.parseJsonResponse(response);
|
|
1591
1987
|
}
|
|
@@ -1621,6 +2017,73 @@ var EReportingEndpoint = class {
|
|
|
1621
2017
|
if (input.country !== void 0 && input.country.length !== 2) {
|
|
1622
2018
|
throw new TaxoraException("country must be a 2-character ISO 3166-1 alpha-2 code.");
|
|
1623
2019
|
}
|
|
2020
|
+
if (input.service !== void 0) this.validateService(input.service);
|
|
2021
|
+
}
|
|
2022
|
+
isNorwayEnrollmentInput(input) {
|
|
2023
|
+
return typeof input.country === "string" && input.country.trim().toUpperCase() === "NO";
|
|
2024
|
+
}
|
|
2025
|
+
/** Validates the Norway input and builds its wire body (org number normalized to 9 digits). */
|
|
2026
|
+
buildNorwayEnrollmentBody(input) {
|
|
2027
|
+
if (typeof input.orgNumber !== "string" || !NorwegianOrgNumber.isValid(input.orgNumber)) {
|
|
2028
|
+
throw new TaxoraException(
|
|
2029
|
+
"orgNumber must be a valid 9-digit Norwegian organisation number (mod-11 check digit)."
|
|
2030
|
+
);
|
|
2031
|
+
}
|
|
2032
|
+
for (const field of ["companyName", "address", "city", "postalcode"]) {
|
|
2033
|
+
if (typeof input[field] !== "string" || input[field].trim() === "") {
|
|
2034
|
+
throw new TaxoraException(`${field} is required for a Norway enrollment.`);
|
|
2035
|
+
}
|
|
2036
|
+
}
|
|
2037
|
+
this.validateEmail(input.email, "email");
|
|
2038
|
+
if (input.service !== void 0) this.validateService(input.service);
|
|
2039
|
+
if (input.legalCountry !== void 0 && !COUNTRY_REGEX.test(input.legalCountry)) {
|
|
2040
|
+
throw new TaxoraException("legalCountry must be a 2-character ISO 3166-1 alpha-2 code.");
|
|
2041
|
+
}
|
|
2042
|
+
const body = {
|
|
2043
|
+
country: "NO",
|
|
2044
|
+
org_number: NorwegianOrgNumber.normalize(input.orgNumber),
|
|
2045
|
+
company_name: input.companyName,
|
|
2046
|
+
address: input.address,
|
|
2047
|
+
city: input.city,
|
|
2048
|
+
postalcode: input.postalcode,
|
|
2049
|
+
email: input.email
|
|
2050
|
+
};
|
|
2051
|
+
if (input.service !== void 0) body["service"] = input.service;
|
|
2052
|
+
if (input.regime !== void 0) body["regime"] = input.regime;
|
|
2053
|
+
if (input.vatNumber !== void 0) body["vat_number"] = input.vatNumber;
|
|
2054
|
+
if (input.province !== void 0) body["province"] = input.province;
|
|
2055
|
+
if (input.vatRegistered !== void 0) body["vat_registered"] = input.vatRegistered;
|
|
2056
|
+
if (input.enterpriseRegister !== void 0) body["enterprise_register"] = input.enterpriseRegister;
|
|
2057
|
+
if (input.reception !== void 0) body["reception"] = input.reception;
|
|
2058
|
+
if (input.legalCountry !== void 0) body["legal_country"] = input.legalCountry.toUpperCase();
|
|
2059
|
+
if (input.reportingStartDate !== void 0) {
|
|
2060
|
+
body["reporting_start_date"] = this.formatDate(input.reportingStartDate);
|
|
2061
|
+
}
|
|
2062
|
+
if (input.autoActivate !== void 0) body["auto_activate"] = input.autoActivate;
|
|
2063
|
+
return body;
|
|
2064
|
+
}
|
|
2065
|
+
async createEnrollmentFromBody(body) {
|
|
2066
|
+
const response = await this.sendRequest("POST", `${this.baseUrl}/compliance/enrollments`, body);
|
|
2067
|
+
const data = await this.parseJsonResponse(response);
|
|
2068
|
+
return ComplianceEnrollment.fromArray(data);
|
|
2069
|
+
}
|
|
2070
|
+
validateService(service) {
|
|
2071
|
+
if (!SERVICES.includes(service)) {
|
|
2072
|
+
throw new TaxoraException(`Invalid service "${String(service)}". Expected one of: ${SERVICES.join(", ")}.`);
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
validateEmail(email, name) {
|
|
2076
|
+
if (typeof email !== "string" || email.trim() === "" || !email.includes("@")) {
|
|
2077
|
+
throw new TaxoraException(`${name} must be a valid email address.`);
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
/** Lookup routes take a 2-letter country; the API expects it upper-case. */
|
|
2081
|
+
normalizeLookupCountry(country) {
|
|
2082
|
+
const normalized = country.trim().toUpperCase();
|
|
2083
|
+
if (!COUNTRY_REGEX.test(normalized)) {
|
|
2084
|
+
throw new TaxoraException("country must be a 2-character ISO 3166-1 alpha-2 code.");
|
|
2085
|
+
}
|
|
2086
|
+
return normalized;
|
|
1624
2087
|
}
|
|
1625
2088
|
validateId(id, name) {
|
|
1626
2089
|
if (!Number.isInteger(id) || id <= 0) {
|
|
@@ -1660,6 +2123,33 @@ var EReportingEndpoint = class {
|
|
|
1660
2123
|
throw new TaxoraException("counterpartyCountry must be a 2-character ISO 3166-1 alpha-2 code.");
|
|
1661
2124
|
}
|
|
1662
2125
|
}
|
|
2126
|
+
/**
|
|
2127
|
+
* Format checks for the buyer/document fields. Country rules (e.g. the Norway
|
|
2128
|
+
* org number being required) depend on the enrollment and stay server-side;
|
|
2129
|
+
* a register id is only check-digit validated when the buyer is Norwegian.
|
|
2130
|
+
*/
|
|
2131
|
+
validateBuyerFields(input) {
|
|
2132
|
+
if (input.counterpartyRegisterId !== void 0) {
|
|
2133
|
+
if (input.counterpartyRegisterId.length > 30) {
|
|
2134
|
+
throw new TaxoraException("counterpartyRegisterId must not exceed 30 characters.");
|
|
2135
|
+
}
|
|
2136
|
+
if (input.counterpartyCountry?.toUpperCase() === "NO" && !NorwegianOrgNumber.isValid(input.counterpartyRegisterId)) {
|
|
2137
|
+
throw new TaxoraException(
|
|
2138
|
+
"counterpartyRegisterId must be a valid 9-digit Norwegian organisation number (mod-11 check digit)."
|
|
2139
|
+
);
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
if (input.counterpartyEmail !== void 0) this.validateEmail(input.counterpartyEmail, "counterpartyEmail");
|
|
2143
|
+
if (input.buyerReference !== void 0 && input.buyerReference.length > 100) {
|
|
2144
|
+
throw new TaxoraException("buyerReference must not exceed 100 characters.");
|
|
2145
|
+
}
|
|
2146
|
+
if (input.amendedNumber !== void 0 && input.amendedNumber.length > 50) {
|
|
2147
|
+
throw new TaxoraException("amendedNumber must not exceed 50 characters.");
|
|
2148
|
+
}
|
|
2149
|
+
if (input.extraInfo !== void 0 && input.extraInfo.length > 1e3) {
|
|
2150
|
+
throw new TaxoraException("extraInfo must not exceed 1000 characters.");
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
1663
2153
|
// ---------------------------------------------------------------------
|
|
1664
2154
|
// Body building (camelCase input → snake_case wire format)
|
|
1665
2155
|
// ---------------------------------------------------------------------
|
|
@@ -1696,6 +2186,16 @@ var EReportingEndpoint = class {
|
|
|
1696
2186
|
if (input.remittanceInformation !== void 0) body["remittance_information"] = input.remittanceInformation;
|
|
1697
2187
|
if (input.paymentMethodText !== void 0) body["payment_method_text"] = input.paymentMethodText;
|
|
1698
2188
|
if (input.paymentTerms !== void 0) body["payment_terms"] = input.paymentTerms;
|
|
2189
|
+
if (input.counterpartyRegisterId !== void 0) body["counterparty_register_id"] = input.counterpartyRegisterId;
|
|
2190
|
+
if (input.counterpartyAddress !== void 0) body["counterparty_address"] = input.counterpartyAddress;
|
|
2191
|
+
if (input.counterpartyCity !== void 0) body["counterparty_city"] = input.counterpartyCity;
|
|
2192
|
+
if (input.counterpartyPostalcode !== void 0) body["counterparty_postalcode"] = input.counterpartyPostalcode;
|
|
2193
|
+
if (input.counterpartyEmail !== void 0) body["counterparty_email"] = input.counterpartyEmail;
|
|
2194
|
+
if (input.buyerReference !== void 0) body["buyer_reference"] = input.buyerReference;
|
|
2195
|
+
if (input.isCreditNote !== void 0) body["is_credit_note"] = input.isCreditNote;
|
|
2196
|
+
if (input.amendedNumber !== void 0) body["amended_number"] = input.amendedNumber;
|
|
2197
|
+
if (input.amendedDate !== void 0) body["amended_date"] = this.formatDate(input.amendedDate);
|
|
2198
|
+
if (input.extraInfo !== void 0) body["extra_info"] = input.extraInfo;
|
|
1699
2199
|
}
|
|
1700
2200
|
// ---------------------------------------------------------------------
|
|
1701
2201
|
// HTTP plumbing (kept in sync with SmartEnrichmentEndpoint)
|
|
@@ -1818,22 +2318,22 @@ var SmartEnrichmentMode = {
|
|
|
1818
2318
|
DEFAULT: "default",
|
|
1819
2319
|
COMPLEX: "complex"
|
|
1820
2320
|
};
|
|
1821
|
-
var
|
|
2321
|
+
var VALUES8 = Object.values(SmartEnrichmentMode);
|
|
1822
2322
|
function toSmartEnrichmentMode(value) {
|
|
1823
2323
|
if (typeof value === "string") {
|
|
1824
2324
|
const normalized = value.trim().toLowerCase();
|
|
1825
|
-
if (
|
|
2325
|
+
if (VALUES8.includes(normalized)) {
|
|
1826
2326
|
return normalized;
|
|
1827
2327
|
}
|
|
1828
2328
|
}
|
|
1829
2329
|
return void 0;
|
|
1830
2330
|
}
|
|
1831
|
-
var
|
|
2331
|
+
var DESCRIPTIONS8 = {
|
|
1832
2332
|
[SmartEnrichmentMode.DEFAULT]: "One provider searches; a second is consulted only if it finds nothing.",
|
|
1833
2333
|
[SmartEnrichmentMode.COMPLEX]: "Two providers search independently and are cross-checked against the tax authority. Costs more."
|
|
1834
2334
|
};
|
|
1835
2335
|
function describeSmartEnrichmentMode(mode) {
|
|
1836
|
-
return
|
|
2336
|
+
return DESCRIPTIONS8[mode];
|
|
1837
2337
|
}
|
|
1838
2338
|
|
|
1839
2339
|
// src/enums/SmartEnrichmentStatus.ts
|
|
@@ -1847,17 +2347,17 @@ var SmartEnrichmentStatus = {
|
|
|
1847
2347
|
FAILED: "failed",
|
|
1848
2348
|
UNKNOWN: "unknown"
|
|
1849
2349
|
};
|
|
1850
|
-
var
|
|
2350
|
+
var VALUES9 = Object.values(SmartEnrichmentStatus);
|
|
1851
2351
|
function toSmartEnrichmentStatus(value) {
|
|
1852
2352
|
if (typeof value === "string") {
|
|
1853
2353
|
const normalized = value.trim().toLowerCase();
|
|
1854
|
-
if (
|
|
2354
|
+
if (VALUES9.includes(normalized)) {
|
|
1855
2355
|
return normalized;
|
|
1856
2356
|
}
|
|
1857
2357
|
}
|
|
1858
2358
|
return SmartEnrichmentStatus.UNKNOWN;
|
|
1859
2359
|
}
|
|
1860
|
-
var
|
|
2360
|
+
var DESCRIPTIONS9 = {
|
|
1861
2361
|
[SmartEnrichmentStatus.FOUND]: "A VAT number was resolved and confirmed.",
|
|
1862
2362
|
[SmartEnrichmentStatus.NO_VAT_EXISTS]: "The company was identified but has no VAT number.",
|
|
1863
2363
|
[SmartEnrichmentStatus.NOT_FOUND]: "No sufficiently-confident match could be resolved.",
|
|
@@ -1868,7 +2368,7 @@ var DESCRIPTIONS6 = {
|
|
|
1868
2368
|
[SmartEnrichmentStatus.UNKNOWN]: "Unknown status."
|
|
1869
2369
|
};
|
|
1870
2370
|
function describeSmartEnrichmentStatus(status) {
|
|
1871
|
-
return
|
|
2371
|
+
return DESCRIPTIONS9[status];
|
|
1872
2372
|
}
|
|
1873
2373
|
|
|
1874
2374
|
// src/dto/SmartEnrichmentResource.ts
|
|
@@ -2086,13 +2586,13 @@ var SmartEnrichmentHistoryPage = class _SmartEnrichmentHistoryPage {
|
|
|
2086
2586
|
};
|
|
2087
2587
|
|
|
2088
2588
|
// src/dto/SmartEnrichmentStatistics.ts
|
|
2089
|
-
function
|
|
2589
|
+
function asString9(value, fallback = "") {
|
|
2090
2590
|
return typeof value === "string" ? value : fallback;
|
|
2091
2591
|
}
|
|
2092
2592
|
function asNumber6(value) {
|
|
2093
2593
|
return typeof value === "number" ? value : Number(value ?? 0) || 0;
|
|
2094
2594
|
}
|
|
2095
|
-
function
|
|
2595
|
+
function asRecord2(value) {
|
|
2096
2596
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
2097
2597
|
}
|
|
2098
2598
|
function asRecords2(value) {
|
|
@@ -2115,32 +2615,32 @@ var SmartEnrichmentStatistics = class _SmartEnrichmentStatistics {
|
|
|
2115
2615
|
byOutcome;
|
|
2116
2616
|
confidenceBuckets;
|
|
2117
2617
|
static fromArray(data) {
|
|
2118
|
-
const range =
|
|
2119
|
-
const totals =
|
|
2618
|
+
const range = asRecord2(data["range"]);
|
|
2619
|
+
const totals = asRecord2(data["totals"]);
|
|
2120
2620
|
const timeSeries = asRecords2(data["time_series"]).map((row) => ({
|
|
2121
|
-
bucket:
|
|
2621
|
+
bucket: asString9(row["bucket"]),
|
|
2122
2622
|
jobs: asNumber6(row["jobs"]),
|
|
2123
2623
|
items: asNumber6(row["items"]),
|
|
2124
2624
|
found: asNumber6(row["found"])
|
|
2125
2625
|
}));
|
|
2126
2626
|
const bySource = asRecords2(data["by_source"]).map((row) => ({
|
|
2127
|
-
source:
|
|
2627
|
+
source: asString9(row["source"]),
|
|
2128
2628
|
jobs: asNumber6(row["jobs"]),
|
|
2129
2629
|
found: asNumber6(row["found"])
|
|
2130
2630
|
}));
|
|
2131
2631
|
const byOutcome = asRecords2(data["by_outcome"]).map((row) => ({
|
|
2132
|
-
outcome:
|
|
2632
|
+
outcome: asString9(row["outcome"]),
|
|
2133
2633
|
count: asNumber6(row["count"])
|
|
2134
2634
|
}));
|
|
2135
2635
|
const confidenceBuckets = asRecords2(data["confidence_buckets"]).map((row) => ({
|
|
2136
|
-
bucket:
|
|
2636
|
+
bucket: asString9(row["bucket"]),
|
|
2137
2637
|
count: asNumber6(row["count"])
|
|
2138
2638
|
}));
|
|
2139
2639
|
return new _SmartEnrichmentStatistics(
|
|
2140
2640
|
{
|
|
2141
|
-
dateFrom:
|
|
2142
|
-
dateTo:
|
|
2143
|
-
interval:
|
|
2641
|
+
dateFrom: asString9(range["date_from"]),
|
|
2642
|
+
dateTo: asString9(range["date_to"]),
|
|
2643
|
+
interval: asString9(range["interval"])
|
|
2144
2644
|
},
|
|
2145
2645
|
{
|
|
2146
2646
|
jobs: asNumber6(totals["jobs"]),
|
|
@@ -2355,7 +2855,10 @@ var SmartEnrichmentEndpoint = class {
|
|
|
2355
2855
|
async parseJsonResponse(response, acceptedStatuses = [200]) {
|
|
2356
2856
|
const responseText = await response.text();
|
|
2357
2857
|
if (response.status === 422) {
|
|
2358
|
-
throw new ValidationException(
|
|
2858
|
+
throw new ValidationException(
|
|
2859
|
+
jsonErrorMessage(responseText) ?? "Validation failed",
|
|
2860
|
+
this.parseValidationErrors(responseText)
|
|
2861
|
+
);
|
|
2359
2862
|
}
|
|
2360
2863
|
if (!response.ok && !acceptedStatuses.includes(response.status)) {
|
|
2361
2864
|
throw new HttpException(
|
|
@@ -2389,7 +2892,10 @@ var SmartEnrichmentEndpoint = class {
|
|
|
2389
2892
|
async parseRawJson(response) {
|
|
2390
2893
|
const responseText = await response.text();
|
|
2391
2894
|
if (response.status === 422) {
|
|
2392
|
-
throw new ValidationException(
|
|
2895
|
+
throw new ValidationException(
|
|
2896
|
+
jsonErrorMessage(responseText) ?? "Validation failed",
|
|
2897
|
+
this.parseValidationErrors(responseText)
|
|
2898
|
+
);
|
|
2393
2899
|
}
|
|
2394
2900
|
if (!response.ok) {
|
|
2395
2901
|
throw new HttpException(
|
|
@@ -2418,7 +2924,10 @@ var SmartEnrichmentEndpoint = class {
|
|
|
2418
2924
|
async parseCsvResponse(response) {
|
|
2419
2925
|
const responseText = await response.text();
|
|
2420
2926
|
if (response.status === 422) {
|
|
2421
|
-
throw new ValidationException(
|
|
2927
|
+
throw new ValidationException(
|
|
2928
|
+
jsonErrorMessage(responseText) ?? "Validation failed",
|
|
2929
|
+
this.parseValidationErrors(responseText)
|
|
2930
|
+
);
|
|
2422
2931
|
}
|
|
2423
2932
|
if (!response.ok) {
|
|
2424
2933
|
throw new HttpException(
|
|
@@ -2464,14 +2973,14 @@ var VatState = {
|
|
|
2464
2973
|
function getFailedVatStates() {
|
|
2465
2974
|
return [VatState.INVALID, VatState.FRAUD];
|
|
2466
2975
|
}
|
|
2467
|
-
var
|
|
2976
|
+
var DESCRIPTIONS10 = {
|
|
2468
2977
|
[VatState.VALID]: "The VAT number is valid and active.",
|
|
2469
2978
|
[VatState.INVALID]: "The VAT number is invalid or not registered.",
|
|
2470
2979
|
[VatState.FRAUD]: "The VAT number has been flagged as potentially fraudulent.",
|
|
2471
2980
|
[VatState.UNKNOWN]: "The VAT number state could not be determined."
|
|
2472
2981
|
};
|
|
2473
2982
|
function describeVatState(state) {
|
|
2474
|
-
return
|
|
2983
|
+
return DESCRIPTIONS10[state];
|
|
2475
2984
|
}
|
|
2476
2985
|
|
|
2477
2986
|
// src/dto/CompanyAddress.ts
|
|
@@ -3203,7 +3712,7 @@ var AuthRetryHttpClient = class {
|
|
|
3203
3712
|
};
|
|
3204
3713
|
|
|
3205
3714
|
// src/version.ts
|
|
3206
|
-
var SDK_VERSION = "1.
|
|
3715
|
+
var SDK_VERSION = "1.3.0";
|
|
3207
3716
|
|
|
3208
3717
|
// src/http/SdkVersionHttpClient.ts
|
|
3209
3718
|
var SDK_VERSION_HEADER = "X-Taxora-SDK-Version";
|
|
@@ -3242,7 +3751,13 @@ var TaxoraClient = class {
|
|
|
3242
3751
|
const retryClient = new AuthRetryHttpClient(versionedClient, tokenStorage, () => this.auth.refresh());
|
|
3243
3752
|
this.vat = new VatEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient, retryPolicy);
|
|
3244
3753
|
this.company = new CompanyEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient, retryPolicy);
|
|
3245
|
-
this.smartEnrichment = new SmartEnrichmentEndpoint(
|
|
3754
|
+
this.smartEnrichment = new SmartEnrichmentEndpoint(
|
|
3755
|
+
this.baseUrl,
|
|
3756
|
+
options.apiKey,
|
|
3757
|
+
tokenStorage,
|
|
3758
|
+
retryClient,
|
|
3759
|
+
retryPolicy
|
|
3760
|
+
);
|
|
3246
3761
|
this.eReporting = new EReportingEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient, retryPolicy);
|
|
3247
3762
|
}
|
|
3248
3763
|
};
|
|
@@ -3264,6 +3779,125 @@ var Language = {
|
|
|
3264
3779
|
ENGLISH: "en",
|
|
3265
3780
|
GERMAN: "de"
|
|
3266
3781
|
};
|
|
3782
|
+
|
|
3783
|
+
// src/webhooks/WebhookSignature.ts
|
|
3784
|
+
var import_node_crypto = require("crypto");
|
|
3785
|
+
var WEBHOOK_SIGNATURE_HEADER = "Taxora-Signature";
|
|
3786
|
+
var WEBHOOK_ID_HEADER = "Taxora-Webhook-Id";
|
|
3787
|
+
var DEFAULT_WEBHOOK_TOLERANCE_SECONDS = 300;
|
|
3788
|
+
var SCHEME = "v1";
|
|
3789
|
+
var WebhookSignatureVerificationError = class extends TaxoraException {
|
|
3790
|
+
reason;
|
|
3791
|
+
constructor(message, reason, context = {}) {
|
|
3792
|
+
super(message, { ...context, reason });
|
|
3793
|
+
this.name = "WebhookSignatureVerificationError";
|
|
3794
|
+
this.reason = reason;
|
|
3795
|
+
}
|
|
3796
|
+
};
|
|
3797
|
+
function parseWebhookSignatureHeader(header) {
|
|
3798
|
+
const value = Array.isArray(header) ? header[0] : header;
|
|
3799
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
3800
|
+
throw new WebhookSignatureVerificationError(
|
|
3801
|
+
`Missing ${WEBHOOK_SIGNATURE_HEADER} header. Is signing enabled for this webhook endpoint?`,
|
|
3802
|
+
"missing_header"
|
|
3803
|
+
);
|
|
3804
|
+
}
|
|
3805
|
+
let timestamp = null;
|
|
3806
|
+
const signatures = [];
|
|
3807
|
+
for (const part of value.split(",")) {
|
|
3808
|
+
const separator = part.indexOf("=");
|
|
3809
|
+
if (separator === -1) continue;
|
|
3810
|
+
const key = part.slice(0, separator).trim();
|
|
3811
|
+
const val = part.slice(separator + 1).trim();
|
|
3812
|
+
if (key === "t" && /^\d+$/.test(val)) {
|
|
3813
|
+
timestamp = Number(val);
|
|
3814
|
+
} else if (key === SCHEME && /^[0-9a-f]{64}$/i.test(val)) {
|
|
3815
|
+
signatures.push(val.toLowerCase());
|
|
3816
|
+
}
|
|
3817
|
+
}
|
|
3818
|
+
if (timestamp === null || signatures.length === 0) {
|
|
3819
|
+
throw new WebhookSignatureVerificationError(
|
|
3820
|
+
`Malformed ${WEBHOOK_SIGNATURE_HEADER} header \u2014 expected "t=<unix>,v1=<hex>".`,
|
|
3821
|
+
"malformed_header"
|
|
3822
|
+
);
|
|
3823
|
+
}
|
|
3824
|
+
return { timestamp, signatures };
|
|
3825
|
+
}
|
|
3826
|
+
function computeWebhookSignature(rawBody, timestamp, secret) {
|
|
3827
|
+
return (0, import_node_crypto.createHmac)("sha256", secret).update(`${timestamp}.`).update(toBytes(rawBody)).digest("hex");
|
|
3828
|
+
}
|
|
3829
|
+
function generateWebhookSignatureHeader(rawBody, secret, timestamp = Math.floor(Date.now() / 1e3)) {
|
|
3830
|
+
const secrets = normalizeSecrets(secret);
|
|
3831
|
+
return [`t=${timestamp}`, ...secrets.map((s) => `${SCHEME}=${computeWebhookSignature(rawBody, timestamp, s)}`)].join(
|
|
3832
|
+
","
|
|
3833
|
+
);
|
|
3834
|
+
}
|
|
3835
|
+
function verifyWebhookSignature(rawBody, header, secret, options = {}) {
|
|
3836
|
+
const secrets = normalizeSecrets(secret);
|
|
3837
|
+
const bytes = toBytes(rawBody);
|
|
3838
|
+
const { timestamp, signatures } = parseWebhookSignatureHeader(header);
|
|
3839
|
+
const tolerance = options.tolerance ?? DEFAULT_WEBHOOK_TOLERANCE_SECONDS;
|
|
3840
|
+
const now = options.now ?? Math.floor(Date.now() / 1e3);
|
|
3841
|
+
if (tolerance > 0 && Math.abs(now - timestamp) > tolerance) {
|
|
3842
|
+
throw new WebhookSignatureVerificationError(
|
|
3843
|
+
`Timestamp outside the tolerance window (${tolerance}s). Possible replay \u2014 or check the server clock.`,
|
|
3844
|
+
"timestamp_outside_tolerance",
|
|
3845
|
+
{ timestamp, now, tolerance }
|
|
3846
|
+
);
|
|
3847
|
+
}
|
|
3848
|
+
const received = signatures.map((s) => Buffer.from(s, "hex"));
|
|
3849
|
+
for (const s of secrets) {
|
|
3850
|
+
const expected = Buffer.from(computeWebhookSignature(bytes, timestamp, s), "hex");
|
|
3851
|
+
let matched = false;
|
|
3852
|
+
for (const candidate of received) {
|
|
3853
|
+
if (candidate.length === expected.length && (0, import_node_crypto.timingSafeEqual)(candidate, expected)) {
|
|
3854
|
+
matched = true;
|
|
3855
|
+
}
|
|
3856
|
+
}
|
|
3857
|
+
if (matched) return true;
|
|
3858
|
+
}
|
|
3859
|
+
throw new WebhookSignatureVerificationError(
|
|
3860
|
+
'No signature matches the expected signature for this payload. Make sure you pass the raw request body (not re-serialised JSON) and the full secret including the "whsec_" prefix.',
|
|
3861
|
+
"no_matching_signature"
|
|
3862
|
+
);
|
|
3863
|
+
}
|
|
3864
|
+
function constructWebhookEvent(rawBody, header, secret, options = {}) {
|
|
3865
|
+
verifyWebhookSignature(rawBody, header, secret, options);
|
|
3866
|
+
let parsed;
|
|
3867
|
+
try {
|
|
3868
|
+
parsed = JSON.parse(Buffer.from(toBytes(rawBody)).toString("utf8"));
|
|
3869
|
+
} catch {
|
|
3870
|
+
throw new WebhookSignatureVerificationError("Webhook payload is not valid JSON.", "invalid_payload");
|
|
3871
|
+
}
|
|
3872
|
+
if (typeof parsed !== "object" || parsed === null || typeof parsed.id !== "string" || typeof parsed.event !== "string" || typeof parsed.data !== "object") {
|
|
3873
|
+
throw new WebhookSignatureVerificationError(
|
|
3874
|
+
"Webhook payload does not have the expected { id, event, timestamp, data } shape.",
|
|
3875
|
+
"invalid_payload"
|
|
3876
|
+
);
|
|
3877
|
+
}
|
|
3878
|
+
return parsed;
|
|
3879
|
+
}
|
|
3880
|
+
function normalizeSecrets(secret) {
|
|
3881
|
+
const list = (typeof secret === "string" ? [secret] : [...secret]).filter(
|
|
3882
|
+
(s) => typeof s === "string" && s !== ""
|
|
3883
|
+
);
|
|
3884
|
+
if (list.length === 0) {
|
|
3885
|
+
throw new WebhookSignatureVerificationError(
|
|
3886
|
+
"No webhook signing secret given. Copy it from the Taxora dashboard (Developer \u2192 Webhooks).",
|
|
3887
|
+
"missing_secret"
|
|
3888
|
+
);
|
|
3889
|
+
}
|
|
3890
|
+
return list;
|
|
3891
|
+
}
|
|
3892
|
+
function toBytes(rawBody) {
|
|
3893
|
+
if (typeof rawBody === "string") return Buffer.from(rawBody, "utf8");
|
|
3894
|
+
if (rawBody instanceof Uint8Array) return rawBody;
|
|
3895
|
+
if (rawBody instanceof ArrayBuffer) return new Uint8Array(rawBody);
|
|
3896
|
+
throw new WebhookSignatureVerificationError(
|
|
3897
|
+
"Webhook body must be the raw request body (string, Buffer or Uint8Array). It looks like it was already parsed as JSON \u2014 use express.raw() / request.text() instead of a JSON body parser.",
|
|
3898
|
+
"invalid_body"
|
|
3899
|
+
);
|
|
3900
|
+
}
|
|
3267
3901
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3268
3902
|
0 && (module.exports = {
|
|
3269
3903
|
ApiVersion,
|
|
@@ -3272,9 +3906,11 @@ var Language = {
|
|
|
3272
3906
|
AuthenticationException,
|
|
3273
3907
|
CompanyAddress,
|
|
3274
3908
|
CompanyEndpoint,
|
|
3909
|
+
ComplianceDocumentType,
|
|
3275
3910
|
ComplianceEnrollment,
|
|
3276
3911
|
ComplianceEnrollmentPage,
|
|
3277
3912
|
ComplianceEnrollmentStatus,
|
|
3913
|
+
ComplianceService,
|
|
3278
3914
|
ComplianceTaxReport,
|
|
3279
3915
|
ComplianceTaxReportPage,
|
|
3280
3916
|
ComplianceTaxReportState,
|
|
@@ -3282,6 +3918,7 @@ var Language = {
|
|
|
3282
3918
|
ComplianceTransactionPage,
|
|
3283
3919
|
ComplianceTransactionState,
|
|
3284
3920
|
ComplianceTransactionType,
|
|
3921
|
+
DEFAULT_WEBHOOK_TOLERANCE_SECONDS,
|
|
3285
3922
|
EReportingEndpoint,
|
|
3286
3923
|
Environment,
|
|
3287
3924
|
FetchHttpClient,
|
|
@@ -3290,8 +3927,12 @@ var Language = {
|
|
|
3290
3927
|
InMemoryTokenStorage,
|
|
3291
3928
|
Language,
|
|
3292
3929
|
LoginIdentifier,
|
|
3930
|
+
NorwegianOrgNumber,
|
|
3931
|
+
PeppolLookupResult,
|
|
3932
|
+
PeppolLookupStatus,
|
|
3293
3933
|
ProviderDocument,
|
|
3294
3934
|
ProviderDocumentLine,
|
|
3935
|
+
RegistryCompany,
|
|
3295
3936
|
RetryPolicy,
|
|
3296
3937
|
RevenueStatistics,
|
|
3297
3938
|
ScoreBreakdown,
|
|
@@ -3316,21 +3957,35 @@ var Language = {
|
|
|
3316
3957
|
VatResource,
|
|
3317
3958
|
VatState,
|
|
3318
3959
|
VatValidationAddressInput,
|
|
3960
|
+
WEBHOOK_ID_HEADER,
|
|
3961
|
+
WEBHOOK_SIGNATURE_HEADER,
|
|
3962
|
+
WebhookSignatureVerificationError,
|
|
3963
|
+
computeWebhookSignature,
|
|
3964
|
+
constructWebhookEvent,
|
|
3319
3965
|
describeApiError,
|
|
3966
|
+
describeComplianceDocumentType,
|
|
3320
3967
|
describeComplianceEnrollmentStatus,
|
|
3968
|
+
describeComplianceService,
|
|
3321
3969
|
describeComplianceTaxReportState,
|
|
3322
3970
|
describeComplianceTransactionState,
|
|
3323
3971
|
describeComplianceTransactionType,
|
|
3972
|
+
describePeppolLookupStatus,
|
|
3324
3973
|
describeSmartEnrichmentMode,
|
|
3325
3974
|
describeSmartEnrichmentStatus,
|
|
3326
3975
|
describeVatState,
|
|
3976
|
+
generateWebhookSignatureHeader,
|
|
3327
3977
|
getBaseUrl,
|
|
3328
3978
|
getFailedVatStates,
|
|
3979
|
+
parseWebhookSignatureHeader,
|
|
3980
|
+
toComplianceDocumentType,
|
|
3329
3981
|
toComplianceEnrollmentStatus,
|
|
3982
|
+
toComplianceService,
|
|
3330
3983
|
toComplianceTaxReportState,
|
|
3331
3984
|
toComplianceTransactionState,
|
|
3332
3985
|
toComplianceTransactionType,
|
|
3986
|
+
toPeppolLookupStatus,
|
|
3333
3987
|
toSmartEnrichmentMode,
|
|
3334
|
-
toSmartEnrichmentStatus
|
|
3988
|
+
toSmartEnrichmentStatus,
|
|
3989
|
+
verifyWebhookSignature
|
|
3335
3990
|
});
|
|
3336
3991
|
//# sourceMappingURL=index.cjs.map
|