@taxora/sdk 1.7.1 → 1.9.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 +84 -0
- package/README.md +205 -4
- package/dist/index.cjs +985 -184
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +564 -16
- package/dist/index.d.ts +564 -16
- package/dist/index.js +978 -184
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -440,6 +440,213 @@ var AuthEndpoint = class {
|
|
|
440
440
|
}
|
|
441
441
|
};
|
|
442
442
|
|
|
443
|
+
// src/dto/UsageSummary.ts
|
|
444
|
+
function asRecord(value) {
|
|
445
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
446
|
+
}
|
|
447
|
+
function asRecordList(value) {
|
|
448
|
+
return Array.isArray(value) ? value.filter((row) => asRecord(row) !== null) : [];
|
|
449
|
+
}
|
|
450
|
+
function asString(value, fallback = "") {
|
|
451
|
+
return typeof value === "string" ? value : fallback;
|
|
452
|
+
}
|
|
453
|
+
function asNullableString(value) {
|
|
454
|
+
return typeof value === "string" ? value : null;
|
|
455
|
+
}
|
|
456
|
+
function asNumber(value) {
|
|
457
|
+
return typeof value === "number" ? value : Number(value ?? 0) || 0;
|
|
458
|
+
}
|
|
459
|
+
function asNullableNumber(value) {
|
|
460
|
+
if (value === null || value === void 0 || value === "") return null;
|
|
461
|
+
const num = Number(value);
|
|
462
|
+
return Number.isFinite(num) ? num : null;
|
|
463
|
+
}
|
|
464
|
+
var UsageSummary = class _UsageSummary {
|
|
465
|
+
constructor(id, companyId, feature, country, regime, billingPeriod, eventCount, billableAmount, state, stateLabel, periodClosedAt, billingTriggeredAt, billedAt, stripeInvoiceId, stripeSubscriptionItemId, billingNotes, events, createdAt, updatedAt) {
|
|
466
|
+
this.id = id;
|
|
467
|
+
this.companyId = companyId;
|
|
468
|
+
this.feature = feature;
|
|
469
|
+
this.country = country;
|
|
470
|
+
this.regime = regime;
|
|
471
|
+
this.billingPeriod = billingPeriod;
|
|
472
|
+
this.eventCount = eventCount;
|
|
473
|
+
this.billableAmount = billableAmount;
|
|
474
|
+
this.state = state;
|
|
475
|
+
this.stateLabel = stateLabel;
|
|
476
|
+
this.periodClosedAt = periodClosedAt;
|
|
477
|
+
this.billingTriggeredAt = billingTriggeredAt;
|
|
478
|
+
this.billedAt = billedAt;
|
|
479
|
+
this.stripeInvoiceId = stripeInvoiceId;
|
|
480
|
+
this.stripeSubscriptionItemId = stripeSubscriptionItemId;
|
|
481
|
+
this.billingNotes = billingNotes;
|
|
482
|
+
this.events = events;
|
|
483
|
+
this.createdAt = createdAt;
|
|
484
|
+
this.updatedAt = updatedAt;
|
|
485
|
+
}
|
|
486
|
+
id;
|
|
487
|
+
companyId;
|
|
488
|
+
feature;
|
|
489
|
+
country;
|
|
490
|
+
regime;
|
|
491
|
+
billingPeriod;
|
|
492
|
+
eventCount;
|
|
493
|
+
billableAmount;
|
|
494
|
+
state;
|
|
495
|
+
stateLabel;
|
|
496
|
+
periodClosedAt;
|
|
497
|
+
billingTriggeredAt;
|
|
498
|
+
billedAt;
|
|
499
|
+
stripeInvoiceId;
|
|
500
|
+
stripeSubscriptionItemId;
|
|
501
|
+
billingNotes;
|
|
502
|
+
events;
|
|
503
|
+
createdAt;
|
|
504
|
+
updatedAt;
|
|
505
|
+
static fromArray(data) {
|
|
506
|
+
const amount = data["billable_amount"];
|
|
507
|
+
return new _UsageSummary(
|
|
508
|
+
asNumber(data["id"]),
|
|
509
|
+
asNumber(data["company_id"]),
|
|
510
|
+
asString(data["feature"]),
|
|
511
|
+
asNullableString(data["country"]),
|
|
512
|
+
asNullableString(data["regime"]),
|
|
513
|
+
asString(data["billing_period"]),
|
|
514
|
+
asNumber(data["event_count"]),
|
|
515
|
+
typeof amount === "string" ? amount : typeof amount === "number" ? String(amount) : null,
|
|
516
|
+
asNullableString(data["state"]),
|
|
517
|
+
asNullableString(data["state_label"]),
|
|
518
|
+
asNullableString(data["period_closed_at"]),
|
|
519
|
+
asNullableString(data["billing_triggered_at"]),
|
|
520
|
+
asNullableString(data["billed_at"]),
|
|
521
|
+
asNullableString(data["stripe_invoice_id"]),
|
|
522
|
+
asNullableString(data["stripe_subscription_item_id"]),
|
|
523
|
+
asNullableString(data["billing_notes"]),
|
|
524
|
+
asRecordList(data["events"]).map((event) => ({
|
|
525
|
+
id: asNumber(event["id"]),
|
|
526
|
+
usageSummaryId: asNullableNumber(event["usage_summary_id"]),
|
|
527
|
+
feature: asString(event["feature"]),
|
|
528
|
+
country: asNullableString(event["country"]),
|
|
529
|
+
regime: asNullableString(event["regime"]),
|
|
530
|
+
billingPeriod: asString(event["billing_period"]),
|
|
531
|
+
resourceType: asNullableString(event["resource_type"]),
|
|
532
|
+
resourceId: asNullableNumber(event["resource_id"]),
|
|
533
|
+
stripeUsageRecordId: asNullableString(event["stripe_usage_record_id"]),
|
|
534
|
+
stripeReportedAt: asNullableString(event["stripe_reported_at"]),
|
|
535
|
+
createdAt: asNullableString(event["created_at"])
|
|
536
|
+
})),
|
|
537
|
+
asNullableString(data["created_at"]),
|
|
538
|
+
asNullableString(data["updated_at"])
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
var UsageSummaryPage = class _UsageSummaryPage {
|
|
543
|
+
constructor(rows, currentPage, perPage, total, lastPage) {
|
|
544
|
+
this.rows = rows;
|
|
545
|
+
this.currentPage = currentPage;
|
|
546
|
+
this.perPage = perPage;
|
|
547
|
+
this.total = total;
|
|
548
|
+
this.lastPage = lastPage;
|
|
549
|
+
}
|
|
550
|
+
rows;
|
|
551
|
+
currentPage;
|
|
552
|
+
perPage;
|
|
553
|
+
total;
|
|
554
|
+
lastPage;
|
|
555
|
+
static fromResponse(payload) {
|
|
556
|
+
const obj = asRecord(payload) ?? {};
|
|
557
|
+
const rows = asRecordList(obj["data"]).map(UsageSummary.fromArray);
|
|
558
|
+
const meta = asRecord(obj["meta"]) ?? {};
|
|
559
|
+
const num = (value, fallback) => typeof value === "number" ? value : fallback;
|
|
560
|
+
return new _UsageSummaryPage(
|
|
561
|
+
rows,
|
|
562
|
+
num(meta["current_page"], 1),
|
|
563
|
+
num(meta["per_page"], rows.length),
|
|
564
|
+
num(meta["total"], rows.length),
|
|
565
|
+
num(meta["last_page"], 1)
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
[Symbol.iterator]() {
|
|
569
|
+
return this.rows[Symbol.iterator]();
|
|
570
|
+
}
|
|
571
|
+
get length() {
|
|
572
|
+
return this.rows.length;
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
// src/endpoints/BillingEndpoint.ts
|
|
577
|
+
var PERIOD_REGEX = /^\d{4}-(0[1-9]|1[0-2])$/;
|
|
578
|
+
var BillingEndpoint = class {
|
|
579
|
+
constructor(baseUrl, apiKey, tokenStorage, httpClient, retryPolicy = new RetryPolicy()) {
|
|
580
|
+
this.baseUrl = baseUrl;
|
|
581
|
+
this.apiKey = apiKey;
|
|
582
|
+
this.tokenStorage = tokenStorage;
|
|
583
|
+
this.httpClient = httpClient;
|
|
584
|
+
this.retryPolicy = retryPolicy;
|
|
585
|
+
}
|
|
586
|
+
baseUrl;
|
|
587
|
+
apiKey;
|
|
588
|
+
tokenStorage;
|
|
589
|
+
httpClient;
|
|
590
|
+
retryPolicy;
|
|
591
|
+
/** Paginated usage summaries, newest billing period first. `perPage` is clamped to 1-100 server-side. */
|
|
592
|
+
async listUsageSummaries(page = 1, perPage = 25) {
|
|
593
|
+
const params = new URLSearchParams();
|
|
594
|
+
params.set("page", String(page));
|
|
595
|
+
params.set("per_page", String(perPage));
|
|
596
|
+
const data = await this.getJson(`${this.baseUrl}/billing/usage-summaries?${params.toString()}`);
|
|
597
|
+
return UsageSummaryPage.fromResponse(data);
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* The usage summaries of one billing period (YYYY-MM), one per feature,
|
|
601
|
+
* each with its usage events. A period without usage yields a 404 (HttpException).
|
|
602
|
+
*/
|
|
603
|
+
async getUsageSummaries(period) {
|
|
604
|
+
if (!PERIOD_REGEX.test(period)) {
|
|
605
|
+
throw new TaxoraException(`Invalid billing period "${period}". Expected YYYY-MM, e.g. "2026-09".`);
|
|
606
|
+
}
|
|
607
|
+
const data = await this.getJson(`${this.baseUrl}/billing/usage-summaries/${period}`);
|
|
608
|
+
return Array.isArray(data) ? data.filter((row) => typeof row === "object" && row !== null).map(UsageSummary.fromArray) : [];
|
|
609
|
+
}
|
|
610
|
+
buildHeaders() {
|
|
611
|
+
const headers = {
|
|
612
|
+
"Content-Type": "application/json",
|
|
613
|
+
"x-api-key": this.apiKey
|
|
614
|
+
};
|
|
615
|
+
const token = this.tokenStorage.get();
|
|
616
|
+
if (token) {
|
|
617
|
+
headers["Authorization"] = `Bearer ${token.accessToken}`;
|
|
618
|
+
}
|
|
619
|
+
return headers;
|
|
620
|
+
}
|
|
621
|
+
/** GET + envelope unwrap (`{success, data}` → data, which may be an object or an array). */
|
|
622
|
+
async getJson(url) {
|
|
623
|
+
return withRetries(this.retryPolicy, "billing request", async () => {
|
|
624
|
+
const response = await this.httpClient.request("GET", url, { headers: this.buildHeaders() });
|
|
625
|
+
const responseText = await response.text();
|
|
626
|
+
if (!response.ok) {
|
|
627
|
+
throw new HttpException(
|
|
628
|
+
describeApiError(responseText, response.status),
|
|
629
|
+
response.status,
|
|
630
|
+
responseText,
|
|
631
|
+
{},
|
|
632
|
+
response.headers.get("retry-after")
|
|
633
|
+
);
|
|
634
|
+
}
|
|
635
|
+
let parsed;
|
|
636
|
+
try {
|
|
637
|
+
parsed = JSON.parse(responseText);
|
|
638
|
+
} catch {
|
|
639
|
+
throw new HttpException("Invalid JSON response", response.status, responseText);
|
|
640
|
+
}
|
|
641
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
642
|
+
throw new HttpException("Unexpected response format", response.status, responseText);
|
|
643
|
+
}
|
|
644
|
+
const obj = parsed;
|
|
645
|
+
return obj["data"] !== void 0 && obj["data"] !== null ? obj["data"] : obj;
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
|
|
443
650
|
// src/dto/CompanyResource.ts
|
|
444
651
|
function normalizeCompanyResource(data) {
|
|
445
652
|
const apiRateLimit = typeof data["api_rate_limit"] === "number" ? data["api_rate_limit"] : void 0;
|
|
@@ -566,13 +773,13 @@ function describeComplianceService(service) {
|
|
|
566
773
|
}
|
|
567
774
|
|
|
568
775
|
// src/dto/ComplianceEnrollment.ts
|
|
569
|
-
function
|
|
776
|
+
function asString2(value, fallback = "") {
|
|
570
777
|
return typeof value === "string" ? value : fallback;
|
|
571
778
|
}
|
|
572
|
-
function
|
|
779
|
+
function asNullableString2(value) {
|
|
573
780
|
return typeof value === "string" ? value : null;
|
|
574
781
|
}
|
|
575
|
-
function
|
|
782
|
+
function asNumber2(value) {
|
|
576
783
|
return typeof value === "number" ? value : Number(value ?? 0) || 0;
|
|
577
784
|
}
|
|
578
785
|
var ComplianceEnrollment = class _ComplianceEnrollment {
|
|
@@ -619,29 +826,114 @@ var ComplianceEnrollment = class _ComplianceEnrollment {
|
|
|
619
826
|
static fromArray(data) {
|
|
620
827
|
const regimeConfig = typeof data["regime_config"] === "object" && data["regime_config"] !== null && !Array.isArray(data["regime_config"]) ? data["regime_config"] : null;
|
|
621
828
|
return new _ComplianceEnrollment(
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
829
|
+
asNumber2(data["id"]),
|
|
830
|
+
asNumber2(data["company_id"]),
|
|
831
|
+
asString2(data["country"]),
|
|
832
|
+
asString2(data["regime"]),
|
|
833
|
+
asString2(data["provider"]),
|
|
627
834
|
toComplianceEnrollmentStatus(data["status"]),
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
835
|
+
asString2(data["status_label"]),
|
|
836
|
+
asNullableString2(data["status_error"]),
|
|
837
|
+
asNullableString2(data["provider_account_id"]),
|
|
838
|
+
asNullableString2(data["tax_id"]),
|
|
839
|
+
asNullableString2(data["company_register_id"]),
|
|
840
|
+
asNullableString2(data["company_register_scheme"]),
|
|
634
841
|
regimeConfig,
|
|
635
|
-
|
|
636
|
-
|
|
842
|
+
asNullableString2(data["reporting_start_date"]),
|
|
843
|
+
asNullableString2(data["notification_email"]),
|
|
637
844
|
data["auto_send"] === true,
|
|
638
|
-
|
|
639
|
-
|
|
845
|
+
asNullableString2(data["created_at"]),
|
|
846
|
+
asNullableString2(data["updated_at"]),
|
|
640
847
|
toComplianceService(data["service"])
|
|
641
848
|
);
|
|
642
849
|
}
|
|
643
850
|
};
|
|
644
851
|
|
|
852
|
+
// src/dto/ComplianceOfferings.ts
|
|
853
|
+
function asRecord2(value) {
|
|
854
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
855
|
+
}
|
|
856
|
+
function asRecordList2(value) {
|
|
857
|
+
return Array.isArray(value) ? value.filter((row) => asRecord2(row) !== null) : [];
|
|
858
|
+
}
|
|
859
|
+
function asString3(value, fallback = "") {
|
|
860
|
+
return typeof value === "string" ? value : fallback;
|
|
861
|
+
}
|
|
862
|
+
function asNullableString3(value) {
|
|
863
|
+
return typeof value === "string" ? value : null;
|
|
864
|
+
}
|
|
865
|
+
function asNullableNumber2(value) {
|
|
866
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
867
|
+
if (typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value))) return Number(value);
|
|
868
|
+
return null;
|
|
869
|
+
}
|
|
870
|
+
function asStringList(value) {
|
|
871
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
872
|
+
}
|
|
873
|
+
function toRequires(value) {
|
|
874
|
+
const record = asRecord2(value);
|
|
875
|
+
return record === null ? null : { country: asString3(record["country"]), service: asString3(record["service"]) };
|
|
876
|
+
}
|
|
877
|
+
var ComplianceOfferings = class _ComplianceOfferings {
|
|
878
|
+
constructor(offerings, coverage, access, accessByCountry) {
|
|
879
|
+
this.offerings = offerings;
|
|
880
|
+
this.coverage = coverage;
|
|
881
|
+
this.access = access;
|
|
882
|
+
this.accessByCountry = accessByCountry;
|
|
883
|
+
}
|
|
884
|
+
offerings;
|
|
885
|
+
coverage;
|
|
886
|
+
access;
|
|
887
|
+
accessByCountry;
|
|
888
|
+
static fromArray(data) {
|
|
889
|
+
const offerings = asRecordList2(data["data"]).map((row) => ({
|
|
890
|
+
country: asString3(row["country"]),
|
|
891
|
+
service: asString3(row["service"]),
|
|
892
|
+
currency: asString3(row["currency"], "EUR"),
|
|
893
|
+
active: row["active"] === true,
|
|
894
|
+
viaStripe: row["via_stripe"] === true,
|
|
895
|
+
plan: asNullableString3(row["plan"]),
|
|
896
|
+
status: asNullableString3(row["status"]),
|
|
897
|
+
enrolled: row["enrolled"] === true,
|
|
898
|
+
plans: asRecordList2(row["plans"]).map((plan) => ({
|
|
899
|
+
key: asString3(plan["key"]),
|
|
900
|
+
monthlyFee: asNullableNumber2(plan["monthly_fee"]),
|
|
901
|
+
setupFee: asNullableNumber2(plan["setup_fee"]),
|
|
902
|
+
usageTiers: Array.isArray(plan["usage_tiers"]) ? plan["usage_tiers"] : [],
|
|
903
|
+
volumeLimit: plan["volume_limit"] ?? null,
|
|
904
|
+
contactOnly: plan["contact_only"] === true,
|
|
905
|
+
checkoutAvailable: plan["checkout_available"] === true,
|
|
906
|
+
requires: toRequires(plan["requires"]),
|
|
907
|
+
eligible: plan["eligible"] === true
|
|
908
|
+
}))
|
|
909
|
+
}));
|
|
910
|
+
const coverage = asRecordList2(data["coverage"]).map((row) => ({
|
|
911
|
+
country: asString3(row["country"]),
|
|
912
|
+
availability: asString3(row["availability"]),
|
|
913
|
+
services: asStringList(row["services"]),
|
|
914
|
+
network: asNullableString3(row["network"]),
|
|
915
|
+
format: asNullableString3(row["format"]),
|
|
916
|
+
mandate: asNullableString3(row["mandate"]),
|
|
917
|
+
support: asString3(row["support"], "yes")
|
|
918
|
+
}));
|
|
919
|
+
const access = asRecord2(data["access"]) ?? {};
|
|
920
|
+
const accessByCountry = {};
|
|
921
|
+
for (const [country, services] of Object.entries(asRecord2(data["access_by_country"]) ?? {})) {
|
|
922
|
+
const flags = {};
|
|
923
|
+
for (const [service, value] of Object.entries(asRecord2(services) ?? {})) {
|
|
924
|
+
flags[service] = value === true;
|
|
925
|
+
}
|
|
926
|
+
accessByCountry[country] = flags;
|
|
927
|
+
}
|
|
928
|
+
return new _ComplianceOfferings(
|
|
929
|
+
offerings,
|
|
930
|
+
coverage,
|
|
931
|
+
{ eReporting: access["e_reporting"] === true, eInvoicing: access["e_invoicing"] === true },
|
|
932
|
+
accessByCountry
|
|
933
|
+
);
|
|
934
|
+
}
|
|
935
|
+
};
|
|
936
|
+
|
|
645
937
|
// src/dto/ComplianceEnrollmentPage.ts
|
|
646
938
|
var ComplianceEnrollmentPage = class _ComplianceEnrollmentPage {
|
|
647
939
|
constructor(rows, currentPage, perPage, total, lastPage) {
|
|
@@ -711,16 +1003,16 @@ function describeComplianceTaxReportState(state) {
|
|
|
711
1003
|
}
|
|
712
1004
|
|
|
713
1005
|
// src/dto/ComplianceTaxReport.ts
|
|
714
|
-
function
|
|
1006
|
+
function asString4(value, fallback = "") {
|
|
715
1007
|
return typeof value === "string" ? value : fallback;
|
|
716
1008
|
}
|
|
717
|
-
function
|
|
1009
|
+
function asNullableString4(value) {
|
|
718
1010
|
return typeof value === "string" ? value : null;
|
|
719
1011
|
}
|
|
720
|
-
function
|
|
1012
|
+
function asNumber3(value) {
|
|
721
1013
|
return typeof value === "number" ? value : Number(value ?? 0) || 0;
|
|
722
1014
|
}
|
|
723
|
-
function
|
|
1015
|
+
function asNullableNumber3(value) {
|
|
724
1016
|
return typeof value === "number" ? value : null;
|
|
725
1017
|
}
|
|
726
1018
|
function asMoney(value) {
|
|
@@ -771,25 +1063,25 @@ var ComplianceTaxReport = class _ComplianceTaxReport {
|
|
|
771
1063
|
updatedAt;
|
|
772
1064
|
static fromArray(data) {
|
|
773
1065
|
return new _ComplianceTaxReport(
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
1066
|
+
asNumber3(data["id"]),
|
|
1067
|
+
asNumber3(data["company_id"]),
|
|
1068
|
+
asNullableNumber3(data["compliance_transaction_id"]),
|
|
1069
|
+
asNullableNumber3(data["ledger_id"]),
|
|
1070
|
+
asString4(data["country"]),
|
|
1071
|
+
asString4(data["regime"]),
|
|
780
1072
|
toComplianceTaxReportState(data["state"]),
|
|
781
|
-
|
|
1073
|
+
asString4(data["state_label"]),
|
|
782
1074
|
data["is_terminal"] === true,
|
|
783
|
-
|
|
784
|
-
|
|
1075
|
+
asNullableString4(data["provider_tax_report_id"]),
|
|
1076
|
+
asNullableString4(data["provider_ledger_id"]),
|
|
785
1077
|
asMoney(data["base_amount"]),
|
|
786
1078
|
asMoney(data["tax_amount"]),
|
|
787
1079
|
asMoney(data["total_amount"]),
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
1080
|
+
asNullableString4(data["refusal_reason"]),
|
|
1081
|
+
asNullableString4(data["registered_at"]),
|
|
1082
|
+
asNullableString4(data["refused_at"]),
|
|
1083
|
+
asNullableString4(data["created_at"]),
|
|
1084
|
+
asNullableString4(data["updated_at"])
|
|
793
1085
|
);
|
|
794
1086
|
}
|
|
795
1087
|
};
|
|
@@ -860,6 +1152,8 @@ var ComplianceTransactionState = {
|
|
|
860
1152
|
SENDING: "sending",
|
|
861
1153
|
SUBMITTED: "submitted",
|
|
862
1154
|
ERROR: "error",
|
|
1155
|
+
/** E-invoicing only: the buyer cannot receive e-invoices — nothing was sent or billed; send your regular invoice. */
|
|
1156
|
+
NOT_REQUIRED: "not_required",
|
|
863
1157
|
UNKNOWN: "unknown"
|
|
864
1158
|
};
|
|
865
1159
|
var VALUES5 = Object.values(ComplianceTransactionState);
|
|
@@ -877,6 +1171,7 @@ var DESCRIPTIONS5 = {
|
|
|
877
1171
|
[ComplianceTransactionState.SENDING]: "Submission to the provider in progress.",
|
|
878
1172
|
[ComplianceTransactionState.SUBMITTED]: "Successfully submitted to the provider.",
|
|
879
1173
|
[ComplianceTransactionState.ERROR]: "Submission failed. See submissionError.",
|
|
1174
|
+
[ComplianceTransactionState.NOT_REQUIRED]: "The buyer cannot receive e-invoices, so none was sent or billed. Send your regular invoice instead.",
|
|
880
1175
|
[ComplianceTransactionState.UNKNOWN]: "Unknown state."
|
|
881
1176
|
};
|
|
882
1177
|
function describeComplianceTransactionState(state) {
|
|
@@ -915,13 +1210,13 @@ function describeComplianceTransactionType(type) {
|
|
|
915
1210
|
}
|
|
916
1211
|
|
|
917
1212
|
// src/dto/ComplianceTransaction.ts
|
|
918
|
-
function
|
|
1213
|
+
function asString5(value, fallback = "") {
|
|
919
1214
|
return typeof value === "string" ? value : fallback;
|
|
920
1215
|
}
|
|
921
|
-
function
|
|
1216
|
+
function asNullableString5(value) {
|
|
922
1217
|
return typeof value === "string" ? value : null;
|
|
923
1218
|
}
|
|
924
|
-
function
|
|
1219
|
+
function asNumber4(value) {
|
|
925
1220
|
return typeof value === "number" ? value : Number(value ?? 0) || 0;
|
|
926
1221
|
}
|
|
927
1222
|
function asMoney2(value) {
|
|
@@ -929,34 +1224,55 @@ function asMoney2(value) {
|
|
|
929
1224
|
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
930
1225
|
return "0.00";
|
|
931
1226
|
}
|
|
932
|
-
function
|
|
1227
|
+
function asNullableNumber4(value) {
|
|
933
1228
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
934
1229
|
if (typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value))) return Number(value);
|
|
935
1230
|
return null;
|
|
936
1231
|
}
|
|
937
|
-
function
|
|
1232
|
+
function asRecord3(value) {
|
|
938
1233
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
939
1234
|
}
|
|
940
|
-
function
|
|
941
|
-
return Array.isArray(value) ? value.filter((row) =>
|
|
1235
|
+
function asRecordList3(value) {
|
|
1236
|
+
return Array.isArray(value) ? value.filter((row) => asRecord3(row) !== null) : [];
|
|
1237
|
+
}
|
|
1238
|
+
function toInvoicePdf(value) {
|
|
1239
|
+
const pdf = asRecord3(value);
|
|
1240
|
+
if (pdf === null) return null;
|
|
1241
|
+
return {
|
|
1242
|
+
filename: asNullableString5(pdf["filename"]),
|
|
1243
|
+
size: asNullableNumber4(pdf["size"]),
|
|
1244
|
+
attached: pdf["attached"] === true
|
|
1245
|
+
};
|
|
1246
|
+
}
|
|
1247
|
+
function toEurEquivalent(value) {
|
|
1248
|
+
const eur = asRecord3(value);
|
|
1249
|
+
if (eur === null) return null;
|
|
1250
|
+
return {
|
|
1251
|
+
subtotal: asMoney2(eur["subtotal"]),
|
|
1252
|
+
taxAmount: asMoney2(eur["tax_amount"]),
|
|
1253
|
+
total: asMoney2(eur["total"]),
|
|
1254
|
+
rate: asString5(eur["rate"]),
|
|
1255
|
+
rateDate: asNullableString5(eur["rate_date"]),
|
|
1256
|
+
source: asString5(eur["source"], "ECB")
|
|
1257
|
+
};
|
|
942
1258
|
}
|
|
943
1259
|
function toInvoiceLines(providerPayload) {
|
|
944
|
-
const invoice =
|
|
945
|
-
return
|
|
946
|
-
description:
|
|
947
|
-
quantity:
|
|
1260
|
+
const invoice = asRecord3(asRecord3(providerPayload)?.["invoice"]);
|
|
1261
|
+
return asRecordList3(invoice?.["invoice_lines_attributes"]).map((line) => ({
|
|
1262
|
+
description: asString5(line["description"]),
|
|
1263
|
+
quantity: asNullableNumber4(line["quantity"]),
|
|
948
1264
|
price: asMoney2(line["price"]),
|
|
949
|
-
unit:
|
|
950
|
-
taxes:
|
|
951
|
-
name:
|
|
952
|
-
percent:
|
|
953
|
-
category:
|
|
954
|
-
comment:
|
|
1265
|
+
unit: asNullableNumber4(line["unit"]),
|
|
1266
|
+
taxes: asRecordList3(line["taxes_attributes"]).map((tax) => ({
|
|
1267
|
+
name: asString5(tax["name"]),
|
|
1268
|
+
percent: asNullableNumber4(tax["percent"]),
|
|
1269
|
+
category: asNullableString5(tax["category"]),
|
|
1270
|
+
comment: asNullableString5(tax["comment"])
|
|
955
1271
|
}))
|
|
956
1272
|
}));
|
|
957
1273
|
}
|
|
958
1274
|
var ComplianceTransaction = class _ComplianceTransaction {
|
|
959
|
-
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 = []) {
|
|
1275
|
+
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 = [], documentUrl = null, deliveryCheck = null, invoicePdf = null, internalReference = null, pdfUrl = null, buyerRejected = false, rejectionReason = null, eurEquivalent = null) {
|
|
960
1276
|
this.id = id;
|
|
961
1277
|
this.companyId = companyId;
|
|
962
1278
|
this.complianceEnrollmentId = complianceEnrollmentId;
|
|
@@ -995,6 +1311,14 @@ var ComplianceTransaction = class _ComplianceTransaction {
|
|
|
995
1311
|
this.amendedDate = amendedDate;
|
|
996
1312
|
this.providerState = providerState;
|
|
997
1313
|
this.invoiceLines = invoiceLines;
|
|
1314
|
+
this.documentUrl = documentUrl;
|
|
1315
|
+
this.deliveryCheck = deliveryCheck;
|
|
1316
|
+
this.invoicePdf = invoicePdf;
|
|
1317
|
+
this.internalReference = internalReference;
|
|
1318
|
+
this.pdfUrl = pdfUrl;
|
|
1319
|
+
this.buyerRejected = buyerRejected;
|
|
1320
|
+
this.rejectionReason = rejectionReason;
|
|
1321
|
+
this.eurEquivalent = eurEquivalent;
|
|
998
1322
|
}
|
|
999
1323
|
id;
|
|
1000
1324
|
companyId;
|
|
@@ -1034,50 +1358,66 @@ var ComplianceTransaction = class _ComplianceTransaction {
|
|
|
1034
1358
|
amendedDate;
|
|
1035
1359
|
providerState;
|
|
1036
1360
|
invoiceLines;
|
|
1361
|
+
documentUrl;
|
|
1362
|
+
deliveryCheck;
|
|
1363
|
+
invoicePdf;
|
|
1364
|
+
internalReference;
|
|
1365
|
+
pdfUrl;
|
|
1366
|
+
buyerRejected;
|
|
1367
|
+
rejectionReason;
|
|
1368
|
+
eurEquivalent;
|
|
1037
1369
|
get isCreditNote() {
|
|
1038
1370
|
return this.documentType === ComplianceDocumentType.CREDIT_NOTE;
|
|
1039
1371
|
}
|
|
1040
1372
|
static fromArray(data) {
|
|
1041
1373
|
const taxReport = typeof data["tax_report"] === "object" && data["tax_report"] !== null && !Array.isArray(data["tax_report"]) ? ComplianceTaxReport.fromArray(data["tax_report"]) : void 0;
|
|
1042
1374
|
return new _ComplianceTransaction(
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1375
|
+
asNumber4(data["id"]),
|
|
1376
|
+
asNumber4(data["company_id"]),
|
|
1377
|
+
asNumber4(data["compliance_enrollment_id"]),
|
|
1378
|
+
asString5(data["country"]),
|
|
1379
|
+
asString5(data["regime"]),
|
|
1048
1380
|
toComplianceTransactionType(data["transaction_type"]),
|
|
1049
|
-
|
|
1381
|
+
asString5(data["transaction_type_label"]),
|
|
1050
1382
|
toComplianceTransactionState(data["state"]),
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1383
|
+
asString5(data["state_label"]),
|
|
1384
|
+
asString5(data["invoice_number"]),
|
|
1385
|
+
asNullableString5(data["invoice_date"]),
|
|
1386
|
+
asNullableString5(data["due_date"]),
|
|
1387
|
+
asString5(data["currency"], "EUR"),
|
|
1056
1388
|
asMoney2(data["subtotal"]),
|
|
1057
1389
|
asMoney2(data["tax_amount"]),
|
|
1058
1390
|
asMoney2(data["total"]),
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1391
|
+
asNullableString5(data["counterparty_name"]),
|
|
1392
|
+
asNullableString5(data["counterparty_country"]),
|
|
1393
|
+
asNullableString5(data["counterparty_vat_number"]),
|
|
1062
1394
|
data["is_paid"] === true,
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1395
|
+
asNullableString5(data["paid_at"]),
|
|
1396
|
+
asNullableString5(data["provider_invoice_id"]),
|
|
1397
|
+
asNullableString5(data["submission_error"]),
|
|
1398
|
+
asNullableString5(data["reported_at"]),
|
|
1067
1399
|
taxReport,
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1400
|
+
asNullableString5(data["created_at"]),
|
|
1401
|
+
asNullableString5(data["updated_at"]),
|
|
1402
|
+
asNullableString5(data["counterparty_register_id"]),
|
|
1403
|
+
asNullableString5(data["counterparty_address"]),
|
|
1404
|
+
asNullableString5(data["counterparty_city"]),
|
|
1405
|
+
asNullableString5(data["counterparty_postalcode"]),
|
|
1406
|
+
asNullableString5(data["counterparty_email"]),
|
|
1407
|
+
asNullableString5(data["buyer_reference"]),
|
|
1076
1408
|
data["document_type"] === void 0 || data["document_type"] === null ? ComplianceDocumentType.INVOICE : toComplianceDocumentType(data["document_type"]),
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
toInvoiceLines(data["provider_payload"])
|
|
1409
|
+
asNullableString5(data["amended_number"]),
|
|
1410
|
+
asNullableString5(data["amended_date"]),
|
|
1411
|
+
asNullableString5(data["provider_state"]),
|
|
1412
|
+
toInvoiceLines(data["provider_payload"]),
|
|
1413
|
+
asNullableString5(data["document_url"]),
|
|
1414
|
+
asRecord3(data["delivery_check"]),
|
|
1415
|
+
toInvoicePdf(data["invoice_pdf"]),
|
|
1416
|
+
asNullableString5(data["internal_reference"]),
|
|
1417
|
+
asNullableString5(data["pdf_url"]),
|
|
1418
|
+
data["buyer_rejected"] === true,
|
|
1419
|
+
asNullableString5(data["rejection_reason"]),
|
|
1420
|
+
toEurEquivalent(data["eur_equivalent"])
|
|
1081
1421
|
);
|
|
1082
1422
|
}
|
|
1083
1423
|
};
|
|
@@ -1164,10 +1504,10 @@ function describePeppolLookupStatus(status) {
|
|
|
1164
1504
|
}
|
|
1165
1505
|
|
|
1166
1506
|
// src/dto/PeppolLookupResult.ts
|
|
1167
|
-
function
|
|
1507
|
+
function asString6(value, fallback = "") {
|
|
1168
1508
|
return typeof value === "string" ? value : fallback;
|
|
1169
1509
|
}
|
|
1170
|
-
function
|
|
1510
|
+
function asNullableString6(value) {
|
|
1171
1511
|
return typeof value === "string" ? value : null;
|
|
1172
1512
|
}
|
|
1173
1513
|
var PeppolLookupResult = class _PeppolLookupResult {
|
|
@@ -1198,21 +1538,21 @@ var PeppolLookupResult = class _PeppolLookupResult {
|
|
|
1198
1538
|
return new _PeppolLookupResult(
|
|
1199
1539
|
toPeppolLookupStatus(data["status"]),
|
|
1200
1540
|
typeof data["reachable"] === "boolean" ? data["reachable"] : null,
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1541
|
+
asString6(data["country"]),
|
|
1542
|
+
asString6(data["scheme"]),
|
|
1543
|
+
asString6(data["id"]),
|
|
1204
1544
|
documentTypes,
|
|
1205
|
-
|
|
1206
|
-
|
|
1545
|
+
asNullableString6(data["transport_type_code"]),
|
|
1546
|
+
asNullableString6(data["checked_at"])
|
|
1207
1547
|
);
|
|
1208
1548
|
}
|
|
1209
1549
|
};
|
|
1210
1550
|
|
|
1211
1551
|
// src/dto/RegistryCompany.ts
|
|
1212
|
-
function
|
|
1552
|
+
function asString7(value, fallback = "") {
|
|
1213
1553
|
return typeof value === "string" ? value : fallback;
|
|
1214
1554
|
}
|
|
1215
|
-
function
|
|
1555
|
+
function asNullableString7(value) {
|
|
1216
1556
|
return typeof value === "string" ? value : null;
|
|
1217
1557
|
}
|
|
1218
1558
|
var RegistryCompany = class _RegistryCompany {
|
|
@@ -1244,27 +1584,27 @@ var RegistryCompany = class _RegistryCompany {
|
|
|
1244
1584
|
country;
|
|
1245
1585
|
static fromArray(data) {
|
|
1246
1586
|
return new _RegistryCompany(
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1587
|
+
asString7(data["org_number"]),
|
|
1588
|
+
asString7(data["company_name"]),
|
|
1589
|
+
asNullableString7(data["organisation_form"]),
|
|
1250
1590
|
data["vat_registered"] === true,
|
|
1251
|
-
|
|
1591
|
+
asNullableString7(data["vat_number"]),
|
|
1252
1592
|
data["enterprise_register"] === true,
|
|
1253
1593
|
data["bankrupt"] === true,
|
|
1254
1594
|
data["under_liquidation"] === true,
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1595
|
+
asNullableString7(data["address"]),
|
|
1596
|
+
asNullableString7(data["postalcode"]),
|
|
1597
|
+
asNullableString7(data["city"]),
|
|
1598
|
+
asString7(data["country"])
|
|
1259
1599
|
);
|
|
1260
1600
|
}
|
|
1261
1601
|
};
|
|
1262
1602
|
|
|
1263
1603
|
// src/dto/RevenueStatistics.ts
|
|
1264
|
-
function
|
|
1604
|
+
function asString8(value, fallback = "") {
|
|
1265
1605
|
return typeof value === "string" ? value : fallback;
|
|
1266
1606
|
}
|
|
1267
|
-
function
|
|
1607
|
+
function asNumber5(value) {
|
|
1268
1608
|
return typeof value === "number" ? value : Number(value ?? 0) || 0;
|
|
1269
1609
|
}
|
|
1270
1610
|
function asMoney3(value) {
|
|
@@ -1276,7 +1616,7 @@ function asRecords(value) {
|
|
|
1276
1616
|
}
|
|
1277
1617
|
function toTotals(data) {
|
|
1278
1618
|
return {
|
|
1279
|
-
count:
|
|
1619
|
+
count: asNumber5(data["count"]),
|
|
1280
1620
|
subtotal: asMoney3(data["subtotal"]),
|
|
1281
1621
|
taxAmount: asMoney3(data["tax_amount"]),
|
|
1282
1622
|
total: asMoney3(data["total"])
|
|
@@ -1313,35 +1653,35 @@ var RevenueStatistics = class _RevenueStatistics {
|
|
|
1313
1653
|
typeof data["totals"] === "object" && data["totals"] !== null ? data["totals"] : {}
|
|
1314
1654
|
);
|
|
1315
1655
|
const timeSeries = asRecords(data["time_series"]).map((row) => ({
|
|
1316
|
-
bucket:
|
|
1656
|
+
bucket: asString8(row["bucket"]),
|
|
1317
1657
|
...toTotals(row)
|
|
1318
1658
|
}));
|
|
1319
1659
|
const byType = asRecords(data["by_type"]).map((row) => ({
|
|
1320
|
-
type:
|
|
1321
|
-
typeLabel:
|
|
1322
|
-
count:
|
|
1660
|
+
type: asString8(row["type"]),
|
|
1661
|
+
typeLabel: asString8(row["type_label"]),
|
|
1662
|
+
count: asNumber5(row["count"]),
|
|
1323
1663
|
total: asMoney3(row["total"])
|
|
1324
1664
|
}));
|
|
1325
1665
|
const byCountry = asRecords(data["by_country"]).map((row) => ({
|
|
1326
|
-
country:
|
|
1327
|
-
count:
|
|
1666
|
+
country: asString8(row["country"], "unknown"),
|
|
1667
|
+
count: asNumber5(row["count"]),
|
|
1328
1668
|
total: asMoney3(row["total"])
|
|
1329
1669
|
}));
|
|
1330
1670
|
const byState = asRecords(data["by_state"]).map((row) => ({
|
|
1331
|
-
state:
|
|
1332
|
-
stateLabel:
|
|
1333
|
-
count:
|
|
1671
|
+
state: asString8(row["state"]),
|
|
1672
|
+
stateLabel: asString8(row["state_label"]),
|
|
1673
|
+
count: asNumber5(row["count"]),
|
|
1334
1674
|
total: asMoney3(row["total"])
|
|
1335
1675
|
}));
|
|
1336
1676
|
const byCurrency = asRecords(data["by_currency"]).map((row) => ({
|
|
1337
|
-
currency:
|
|
1677
|
+
currency: asString8(row["currency"]),
|
|
1338
1678
|
...toTotals(row)
|
|
1339
1679
|
}));
|
|
1340
1680
|
return new _RevenueStatistics(
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1681
|
+
asString8(range["date_from"]) || void 0,
|
|
1682
|
+
asString8(range["date_to"]) || void 0,
|
|
1683
|
+
asString8(range["interval"]) || void 0,
|
|
1684
|
+
asString8(data["primary_currency"], "EUR"),
|
|
1345
1685
|
data["is_multi_currency"] === true,
|
|
1346
1686
|
totals,
|
|
1347
1687
|
timeSeries,
|
|
@@ -1354,10 +1694,10 @@ var RevenueStatistics = class _RevenueStatistics {
|
|
|
1354
1694
|
};
|
|
1355
1695
|
|
|
1356
1696
|
// src/dto/SireneLookupResult.ts
|
|
1357
|
-
function
|
|
1697
|
+
function asString9(value, fallback = "") {
|
|
1358
1698
|
return typeof value === "string" ? value : fallback;
|
|
1359
1699
|
}
|
|
1360
|
-
function
|
|
1700
|
+
function asNullableString8(value) {
|
|
1361
1701
|
return typeof value === "string" ? value : null;
|
|
1362
1702
|
}
|
|
1363
1703
|
var SireneLookupResult = class _SireneLookupResult {
|
|
@@ -1383,24 +1723,24 @@ var SireneLookupResult = class _SireneLookupResult {
|
|
|
1383
1723
|
postalcode;
|
|
1384
1724
|
static fromArray(data) {
|
|
1385
1725
|
return new _SireneLookupResult(
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1726
|
+
asString9(data["company_name"]),
|
|
1727
|
+
asString9(data["siren"]),
|
|
1728
|
+
asNullableString8(data["siret"]),
|
|
1729
|
+
asNullableString8(data["naf_code"]),
|
|
1730
|
+
asNullableString8(data["naf_full"]),
|
|
1731
|
+
asNullableString8(data["enterprise_size"]),
|
|
1732
|
+
asNullableString8(data["address"]),
|
|
1733
|
+
asNullableString8(data["city"]),
|
|
1734
|
+
asNullableString8(data["postalcode"])
|
|
1395
1735
|
);
|
|
1396
1736
|
}
|
|
1397
1737
|
};
|
|
1398
1738
|
|
|
1399
1739
|
// src/dto/VatRates.ts
|
|
1400
|
-
function
|
|
1740
|
+
function asString10(value, fallback = "") {
|
|
1401
1741
|
return typeof value === "string" ? value : fallback;
|
|
1402
1742
|
}
|
|
1403
|
-
function
|
|
1743
|
+
function asNumber6(value) {
|
|
1404
1744
|
return typeof value === "number" ? value : Number(value ?? 0) || 0;
|
|
1405
1745
|
}
|
|
1406
1746
|
var VatRates = class _VatRates {
|
|
@@ -1414,13 +1754,13 @@ var VatRates = class _VatRates {
|
|
|
1414
1754
|
rates;
|
|
1415
1755
|
static fromArray(data) {
|
|
1416
1756
|
const rates = (Array.isArray(data["rates"]) ? data["rates"] : []).filter((row) => typeof row === "object" && row !== null).map((row) => ({
|
|
1417
|
-
percent:
|
|
1418
|
-
category:
|
|
1419
|
-
labelKey:
|
|
1420
|
-
taxName:
|
|
1757
|
+
percent: asNumber6(row["percent"]),
|
|
1758
|
+
category: asString10(row["category"]),
|
|
1759
|
+
labelKey: asString10(row["label_key"]),
|
|
1760
|
+
taxName: asString10(row["tax_name"]),
|
|
1421
1761
|
requiresVatex: row["requires_vatex"] === true
|
|
1422
1762
|
}));
|
|
1423
|
-
return new _VatRates(
|
|
1763
|
+
return new _VatRates(asString10(data["country"]), asString10(data["currency"], "EUR"), rates);
|
|
1424
1764
|
}
|
|
1425
1765
|
};
|
|
1426
1766
|
|
|
@@ -1479,10 +1819,15 @@ var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
|
1479
1819
|
var NAF_CODE_REGEX = /^\d{2}$/;
|
|
1480
1820
|
var COUNTRY_REGEX = /^[A-Za-z]{2}$/;
|
|
1481
1821
|
var PEPPOL_SCHEME_REGEX = /^\d{4}$/;
|
|
1822
|
+
var INVOICE_PDF_MAX_BYTES = 10 * 1024 * 1024;
|
|
1823
|
+
var INVOICE_PDF_MAGIC = [37, 80, 68, 70, 45];
|
|
1482
1824
|
var INTERVALS = ["day", "week", "month"];
|
|
1483
1825
|
var SERVICES = ["e_reporting", "e_invoicing"];
|
|
1484
1826
|
var ENTERPRISE_SIZES = ["micro", "pme", "eti", "ge"];
|
|
1485
1827
|
var TYPE_OPERATIONS = ["services", "goods", "mixed"];
|
|
1828
|
+
var NOTIFICATION_LANGUAGES = ["de", "en"];
|
|
1829
|
+
var NOTIFICATION_DIGESTS = ["off", "daily", "weekly"];
|
|
1830
|
+
var NOTIFICATION_MAX_RECIPIENTS = 5;
|
|
1486
1831
|
var TRANSACTION_TYPES = [
|
|
1487
1832
|
"b2c_outbound",
|
|
1488
1833
|
"b2b_domestic_outbound",
|
|
@@ -1677,6 +2022,8 @@ var EReportingEndpoint = class {
|
|
|
1677
2022
|
this.validateInvoiceLines(input.invoiceLines);
|
|
1678
2023
|
this.validateOptionalCodes(input);
|
|
1679
2024
|
this.validateBuyerFields(input);
|
|
2025
|
+
this.validateInternalReference(input.internalReference);
|
|
2026
|
+
this.validateInvoicePdfFilename(input);
|
|
1680
2027
|
const body = {
|
|
1681
2028
|
compliance_enrollment_id: input.complianceEnrollmentId,
|
|
1682
2029
|
transaction_type: input.transactionType,
|
|
@@ -1692,23 +2039,9 @@ var EReportingEndpoint = class {
|
|
|
1692
2039
|
const data = await this.parseJsonResponse(response);
|
|
1693
2040
|
return ComplianceTransaction.fromArray(data);
|
|
1694
2041
|
}
|
|
1695
|
-
/** Paginated list of the company's transactions (newest invoice date first), filterable by date / state / type / enrollment / country. */
|
|
2042
|
+
/** Paginated list of the company's transactions (newest invoice date first), filterable by date / state / type / enrollment / country / search / internal reference / provider state. */
|
|
1696
2043
|
async listTransactions(filters = {}) {
|
|
1697
|
-
|
|
1698
|
-
this.validateId(filters.complianceEnrollmentId, "complianceEnrollmentId");
|
|
1699
|
-
}
|
|
1700
|
-
if (filters.country !== void 0 && !COUNTRY_REGEX.test(filters.country)) {
|
|
1701
|
-
throw new TaxoraException("country must be a 2-character ISO 3166-1 alpha-2 code.");
|
|
1702
|
-
}
|
|
1703
|
-
const params = new URLSearchParams();
|
|
1704
|
-
if (filters.dateFrom !== void 0) params.set("date_from", this.formatDate(filters.dateFrom));
|
|
1705
|
-
if (filters.dateTo !== void 0) params.set("date_to", this.formatDate(filters.dateTo));
|
|
1706
|
-
if (filters.state !== void 0) params.set("state", filters.state);
|
|
1707
|
-
if (filters.transactionType !== void 0) params.set("transaction_type", filters.transactionType);
|
|
1708
|
-
if (filters.complianceEnrollmentId !== void 0) {
|
|
1709
|
-
params.set("compliance_enrollment_id", String(filters.complianceEnrollmentId));
|
|
1710
|
-
}
|
|
1711
|
-
if (filters.country !== void 0) params.set("country", filters.country.toUpperCase());
|
|
2044
|
+
const params = this.buildTransactionFilterParams(filters);
|
|
1712
2045
|
if (filters.page !== void 0) params.set("page", String(filters.page));
|
|
1713
2046
|
if (filters.perPage !== void 0) params.set("per_page", String(filters.perPage));
|
|
1714
2047
|
const queryString = params.toString();
|
|
@@ -1716,6 +2049,27 @@ var EReportingEndpoint = class {
|
|
|
1716
2049
|
const response = await this.sendRequest("GET", url);
|
|
1717
2050
|
return ComplianceTransactionPage.fromResponse(await this.parseJsonResponse(response));
|
|
1718
2051
|
}
|
|
2052
|
+
/**
|
|
2053
|
+
* All transactions matching the filters as raw CSV for bookkeeping
|
|
2054
|
+
* (semicolon-separated) — the same filters as listTransactions() without
|
|
2055
|
+
* pagination. Columns: invoice_number, internal_reference, invoice_date,
|
|
2056
|
+
* due_date, country, transaction_type, document_type, state, delivery_state,
|
|
2057
|
+
* buyer_rejected, rejection_reason, counterparty_name, counterparty_country,
|
|
2058
|
+
* counterparty_vat_number, currency, subtotal, tax_amount, total, eur_rate,
|
|
2059
|
+
* eur_rate_date, eur_subtotal, eur_tax_amount, eur_total, provider_invoice_id,
|
|
2060
|
+
* created_at. The eur_* columns hold the ECB reference conversion for non-EUR
|
|
2061
|
+
* invoices (empty for EUR). Max 50,000 rows server-side. The body is returned
|
|
2062
|
+
* verbatim, a UTF-8 BOM included when the API sends one.
|
|
2063
|
+
*/
|
|
2064
|
+
async exportTransactionsCsv(filters = {}) {
|
|
2065
|
+
const queryString = this.buildTransactionFilterParams(filters).toString();
|
|
2066
|
+
const url = `${this.baseUrl}/compliance/transactions/export.csv${queryString ? `?${queryString}` : ""}`;
|
|
2067
|
+
const response = await this.sendDownloadRequest(url, "text/csv, application/json");
|
|
2068
|
+
if (!response.ok) {
|
|
2069
|
+
await this.parseJsonResponse(response);
|
|
2070
|
+
}
|
|
2071
|
+
return new TextDecoder("utf-8", { ignoreBOM: true }).decode(await response.arrayBuffer());
|
|
2072
|
+
}
|
|
1719
2073
|
/** Get a single transaction by id (includes its tax report when one exists). */
|
|
1720
2074
|
async getTransaction(id) {
|
|
1721
2075
|
this.validateId(id, "id");
|
|
@@ -1731,6 +2085,8 @@ var EReportingEndpoint = class {
|
|
|
1731
2085
|
if (input.invoiceLines !== void 0) this.validateInvoiceLines(input.invoiceLines);
|
|
1732
2086
|
this.validateOptionalCodes(input);
|
|
1733
2087
|
this.validateBuyerFields(input);
|
|
2088
|
+
this.validateInternalReference(input.internalReference);
|
|
2089
|
+
this.validateInvoicePdfFilename(input);
|
|
1734
2090
|
const body = {};
|
|
1735
2091
|
if (input.transactionType !== void 0) body["transaction_type"] = input.transactionType;
|
|
1736
2092
|
if (input.invoiceNumber !== void 0) body["invoice_number"] = input.invoiceNumber;
|
|
@@ -1765,6 +2121,47 @@ var EReportingEndpoint = class {
|
|
|
1765
2121
|
const data = await this.parseJsonResponse(response);
|
|
1766
2122
|
return ComplianceTransaction.fromArray(data);
|
|
1767
2123
|
}
|
|
2124
|
+
/**
|
|
2125
|
+
* Download the legal e-invoice document of a sent transaction (e-invoicing,
|
|
2126
|
+
* e.g. the EHF/UBL XML for Norway). Available once `documentUrl` on the
|
|
2127
|
+
* transaction is set.
|
|
2128
|
+
*
|
|
2129
|
+
* Errors: 404 (HttpException) for an unknown transaction; 409 (HttpException)
|
|
2130
|
+
* when no document exists (yet) — e.g. e-reporting, not sent, or the network
|
|
2131
|
+
* has not produced it yet (try again in a few minutes); 502 on provider failure.
|
|
2132
|
+
*/
|
|
2133
|
+
async getTransactionDocument(id) {
|
|
2134
|
+
this.validateId(id, "id");
|
|
2135
|
+
const response = await this.sendDownloadRequest(`${this.baseUrl}/compliance/transactions/${id}/document`, "*/*");
|
|
2136
|
+
if (!response.ok) {
|
|
2137
|
+
await this.parseJsonResponse(response);
|
|
2138
|
+
}
|
|
2139
|
+
return {
|
|
2140
|
+
content: new Uint8Array(await response.arrayBuffer()),
|
|
2141
|
+
contentType: response.headers.get("content-type") ?? "application/octet-stream",
|
|
2142
|
+
filename: this.filenameFromDisposition(response.headers.get("content-disposition"))
|
|
2143
|
+
};
|
|
2144
|
+
}
|
|
2145
|
+
/**
|
|
2146
|
+
* Download the invoice as a readable PDF — the seller's attached PDF, or the
|
|
2147
|
+
* provider's rendering of the e-invoice. Available once `pdfUrl` on the
|
|
2148
|
+
* transaction is set.
|
|
2149
|
+
*
|
|
2150
|
+
* Errors: 404 (HttpException) for an unknown transaction; 409 (HttpException)
|
|
2151
|
+
* when no PDF exists (yet); 502 on provider failure.
|
|
2152
|
+
*/
|
|
2153
|
+
async getTransactionPdf(id) {
|
|
2154
|
+
this.validateId(id, "id");
|
|
2155
|
+
const response = await this.sendDownloadRequest(`${this.baseUrl}/compliance/transactions/${id}/pdf`, "*/*");
|
|
2156
|
+
if (!response.ok) {
|
|
2157
|
+
await this.parseJsonResponse(response);
|
|
2158
|
+
}
|
|
2159
|
+
return {
|
|
2160
|
+
content: new Uint8Array(await response.arrayBuffer()),
|
|
2161
|
+
contentType: response.headers.get("content-type") ?? "application/octet-stream",
|
|
2162
|
+
filename: this.filenameFromDisposition(response.headers.get("content-disposition"))
|
|
2163
|
+
};
|
|
2164
|
+
}
|
|
1768
2165
|
/**
|
|
1769
2166
|
* Bulk-import transactions from a semicolon-separated CSV (one row per invoice
|
|
1770
2167
|
* line; rows sharing an invoice_number are grouped into one transaction).
|
|
@@ -1796,6 +2193,9 @@ var EReportingEndpoint = class {
|
|
|
1796
2193
|
* months and a monthly interval.
|
|
1797
2194
|
*/
|
|
1798
2195
|
async getRevenueStatistics(filters = {}) {
|
|
2196
|
+
if (filters.complianceEnrollmentId !== void 0) {
|
|
2197
|
+
this.validateId(filters.complianceEnrollmentId, "complianceEnrollmentId");
|
|
2198
|
+
}
|
|
1799
2199
|
if (filters.interval !== void 0 && !INTERVALS.includes(filters.interval)) {
|
|
1800
2200
|
throw new TaxoraException(
|
|
1801
2201
|
`Invalid statistics interval "${String(filters.interval)}". Expected one of: ${INTERVALS.join(", ")}.`
|
|
@@ -1807,12 +2207,42 @@ var EReportingEndpoint = class {
|
|
|
1807
2207
|
if (filters.interval !== void 0) params.set("interval", filters.interval);
|
|
1808
2208
|
if (filters.transactionType !== void 0) params.set("transaction_type", filters.transactionType);
|
|
1809
2209
|
if (filters.state !== void 0) params.set("state", filters.state);
|
|
2210
|
+
if (filters.complianceEnrollmentId !== void 0) {
|
|
2211
|
+
params.set("compliance_enrollment_id", String(filters.complianceEnrollmentId));
|
|
2212
|
+
}
|
|
1810
2213
|
const queryString = params.toString();
|
|
1811
2214
|
const url = `${this.baseUrl}/compliance/revenue-statistics${queryString ? `?${queryString}` : ""}`;
|
|
1812
2215
|
const response = await this.sendRequest("GET", url);
|
|
1813
2216
|
const data = await this.parseJsonResponse(response);
|
|
1814
2217
|
return RevenueStatistics.fromArray(data);
|
|
1815
2218
|
}
|
|
2219
|
+
/**
|
|
2220
|
+
* Net and VAT per month, currency and tax rate as raw CSV (semicolon-separated,
|
|
2221
|
+
* computed from the invoice lines) — for reconciling the reported figures with
|
|
2222
|
+
* your VAT return. Same filters as getRevenueStatistics() (without
|
|
2223
|
+
* `interval`); defaults to the last 12 months. The body is returned verbatim,
|
|
2224
|
+
* a UTF-8 BOM included when the API sends one.
|
|
2225
|
+
*/
|
|
2226
|
+
async exportRevenueTaxRatesCsv(filters = {}) {
|
|
2227
|
+
if (filters.complianceEnrollmentId !== void 0) {
|
|
2228
|
+
this.validateId(filters.complianceEnrollmentId, "complianceEnrollmentId");
|
|
2229
|
+
}
|
|
2230
|
+
const params = new URLSearchParams();
|
|
2231
|
+
if (filters.dateFrom !== void 0) params.set("date_from", this.formatDate(filters.dateFrom));
|
|
2232
|
+
if (filters.dateTo !== void 0) params.set("date_to", this.formatDate(filters.dateTo));
|
|
2233
|
+
if (filters.transactionType !== void 0) params.set("transaction_type", filters.transactionType);
|
|
2234
|
+
if (filters.state !== void 0) params.set("state", filters.state);
|
|
2235
|
+
if (filters.complianceEnrollmentId !== void 0) {
|
|
2236
|
+
params.set("compliance_enrollment_id", String(filters.complianceEnrollmentId));
|
|
2237
|
+
}
|
|
2238
|
+
const queryString = params.toString();
|
|
2239
|
+
const url = `${this.baseUrl}/compliance/revenue-statistics/tax-rates.csv${queryString ? `?${queryString}` : ""}`;
|
|
2240
|
+
const response = await this.sendDownloadRequest(url, "text/csv, application/json");
|
|
2241
|
+
if (!response.ok) {
|
|
2242
|
+
await this.parseJsonResponse(response);
|
|
2243
|
+
}
|
|
2244
|
+
return new TextDecoder("utf-8", { ignoreBOM: true }).decode(await response.arrayBuffer());
|
|
2245
|
+
}
|
|
1816
2246
|
/**
|
|
1817
2247
|
* The canonical VAT rates & DGFiP tax categories for a reporting country
|
|
1818
2248
|
* (the seller's reporting-country rates, not the counterparty's). Falls back
|
|
@@ -1827,12 +2257,19 @@ var EReportingEndpoint = class {
|
|
|
1827
2257
|
const data = await this.parseJsonResponse(response);
|
|
1828
2258
|
return VatRates.fromArray(data);
|
|
1829
2259
|
}
|
|
1830
|
-
/**
|
|
1831
|
-
|
|
2260
|
+
/**
|
|
2261
|
+
* Paginated list of the company's tax reports (newest first), optionally
|
|
2262
|
+
* filtered by state and by country (2-letter ISO code, case-insensitive).
|
|
2263
|
+
*/
|
|
2264
|
+
async listTaxReports(page = 1, perPage = 25, state, country) {
|
|
2265
|
+
if (country !== void 0 && !COUNTRY_REGEX.test(country)) {
|
|
2266
|
+
throw new TaxoraException("country must be a 2-character ISO 3166-1 alpha-2 code.");
|
|
2267
|
+
}
|
|
1832
2268
|
const params = new URLSearchParams();
|
|
1833
2269
|
params.set("page", String(page));
|
|
1834
2270
|
params.set("per_page", String(perPage));
|
|
1835
2271
|
if (state !== void 0) params.set("state", state);
|
|
2272
|
+
if (country !== void 0) params.set("country", country.toUpperCase());
|
|
1836
2273
|
const response = await this.sendRequest("GET", `${this.baseUrl}/compliance/tax-reports?${params.toString()}`);
|
|
1837
2274
|
return ComplianceTaxReportPage.fromResponse(await this.parseJsonResponse(response));
|
|
1838
2275
|
}
|
|
@@ -1874,8 +2311,177 @@ var EReportingEndpoint = class {
|
|
|
1874
2311
|
await this.parseJsonResponse(response);
|
|
1875
2312
|
}
|
|
1876
2313
|
// ---------------------------------------------------------------------
|
|
2314
|
+
// Self-service plans (Stripe) — not gated by compliance access
|
|
2315
|
+
// ---------------------------------------------------------------------
|
|
2316
|
+
/**
|
|
2317
|
+
* Bookable compliance plans per country (net EUR prices), every country
|
|
2318
|
+
* Taxora reaches, and which services the company has unlocked. Works for
|
|
2319
|
+
* companies without compliance access.
|
|
2320
|
+
*/
|
|
2321
|
+
async getOfferings() {
|
|
2322
|
+
const response = await this.sendRequest("GET", `${this.baseUrl}/compliance/offerings`);
|
|
2323
|
+
return ComplianceOfferings.fromArray(await this.parseJsonResponse(response));
|
|
2324
|
+
}
|
|
2325
|
+
/**
|
|
2326
|
+
* Start a Stripe Checkout for a plan (see getOfferings() — `checkoutAvailable`).
|
|
2327
|
+
* Open the returned `url` in the browser. After payment Stripe redirects to
|
|
2328
|
+
* the Taxora portal, which activates the plan; call confirmCheckout() with the
|
|
2329
|
+
* session id to activate it from your side (idempotent).
|
|
2330
|
+
*
|
|
2331
|
+
* Errors: 422 (ValidationException) for an unknown or contact-only plan or a
|
|
2332
|
+
* plan that is already active; 502 (HttpException) on a Stripe error.
|
|
2333
|
+
*/
|
|
2334
|
+
async createCheckout(country, plan) {
|
|
2335
|
+
if (!COUNTRY_REGEX.test(country)) {
|
|
2336
|
+
throw new TaxoraException("country must be a 2-character ISO 3166-1 alpha-2 code.");
|
|
2337
|
+
}
|
|
2338
|
+
if (plan.trim() === "" || plan.length > 30) {
|
|
2339
|
+
throw new TaxoraException("plan must be a non-empty plan key of at most 30 characters.");
|
|
2340
|
+
}
|
|
2341
|
+
const response = await this.sendRequest("POST", `${this.baseUrl}/compliance/checkout`, {
|
|
2342
|
+
country: country.toUpperCase(),
|
|
2343
|
+
plan
|
|
2344
|
+
});
|
|
2345
|
+
const data = await this.parseJsonResponse(response);
|
|
2346
|
+
return { id: String(data["id"] ?? ""), url: String(data["url"] ?? "") };
|
|
2347
|
+
}
|
|
2348
|
+
/** Confirm a finished Stripe Checkout and activate its plan. Idempotent. */
|
|
2349
|
+
async confirmCheckout(sessionId) {
|
|
2350
|
+
if (sessionId.trim() === "" || sessionId.length > 255) {
|
|
2351
|
+
throw new TaxoraException("sessionId must be a non-empty string of at most 255 characters.");
|
|
2352
|
+
}
|
|
2353
|
+
const response = await this.sendRequest("POST", `${this.baseUrl}/compliance/checkout/confirm`, {
|
|
2354
|
+
session_id: sessionId
|
|
2355
|
+
});
|
|
2356
|
+
const data = await this.parseJsonResponse(response);
|
|
2357
|
+
const str = (value) => typeof value === "string" ? value : null;
|
|
2358
|
+
return {
|
|
2359
|
+
active: data["active"] === true,
|
|
2360
|
+
country: str(data["country"]),
|
|
2361
|
+
service: str(data["service"]),
|
|
2362
|
+
plan: str(data["plan"]),
|
|
2363
|
+
status: str(data["status"])
|
|
2364
|
+
};
|
|
2365
|
+
}
|
|
2366
|
+
/**
|
|
2367
|
+
* URL of the Stripe billing portal for the company's compliance plans
|
|
2368
|
+
* (invoices, payment method, cancellation). The portal returns to the Taxora
|
|
2369
|
+
* portal. 404 (HttpException) when no plan was bought via Stripe.
|
|
2370
|
+
*/
|
|
2371
|
+
async createBillingPortalSession() {
|
|
2372
|
+
const response = await this.sendRequest("POST", `${this.baseUrl}/compliance/billing-portal`);
|
|
2373
|
+
const data = await this.parseJsonResponse(response);
|
|
2374
|
+
return String(data["url"] ?? "");
|
|
2375
|
+
}
|
|
2376
|
+
// ---------------------------------------------------------------------
|
|
2377
|
+
// Notification emails
|
|
2378
|
+
// ---------------------------------------------------------------------
|
|
2379
|
+
/**
|
|
2380
|
+
* The company's opt-in e-reporting / e-invoicing emails: recipients, language,
|
|
2381
|
+
* the "buyer not on Peppol" email and the digest. Readable by every member.
|
|
2382
|
+
*/
|
|
2383
|
+
async getNotificationSettings() {
|
|
2384
|
+
const response = await this.sendRequest("GET", `${this.baseUrl}/compliance/notification-settings`);
|
|
2385
|
+
return this.toNotificationSettings(await this.parseJsonResponse(response));
|
|
2386
|
+
}
|
|
2387
|
+
/**
|
|
2388
|
+
* Change the company's e-reporting / e-invoicing emails; only the provided
|
|
2389
|
+
* fields change. `notOnPeppol` only reports invoices held back after it was
|
|
2390
|
+
* switched on.
|
|
2391
|
+
*
|
|
2392
|
+
* Errors: 422 (ValidationException) when an email is switched on without any
|
|
2393
|
+
* recipient; 403 (HttpException, body code `admin_only` or `read_only_role`)
|
|
2394
|
+
* for users who are not company admins.
|
|
2395
|
+
*/
|
|
2396
|
+
async updateNotificationSettings(input) {
|
|
2397
|
+
const body = {};
|
|
2398
|
+
if (input.recipients !== void 0) {
|
|
2399
|
+
if (!Array.isArray(input.recipients)) {
|
|
2400
|
+
throw new TaxoraException("recipients must be an array of email addresses.");
|
|
2401
|
+
}
|
|
2402
|
+
if (input.recipients.length > NOTIFICATION_MAX_RECIPIENTS) {
|
|
2403
|
+
throw new TaxoraException(`recipients must not contain more than ${NOTIFICATION_MAX_RECIPIENTS} entries.`);
|
|
2404
|
+
}
|
|
2405
|
+
body["recipients"] = input.recipients.map((recipient, index) => {
|
|
2406
|
+
const email = typeof recipient === "string" ? recipient.trim() : recipient;
|
|
2407
|
+
this.validateEmail(email, `recipients[${index}]`);
|
|
2408
|
+
if (email.length > 191) {
|
|
2409
|
+
throw new TaxoraException(`recipients[${index}] must not exceed 191 characters.`);
|
|
2410
|
+
}
|
|
2411
|
+
return email;
|
|
2412
|
+
});
|
|
2413
|
+
}
|
|
2414
|
+
if (input.language !== void 0) {
|
|
2415
|
+
if (!NOTIFICATION_LANGUAGES.includes(input.language)) {
|
|
2416
|
+
throw new TaxoraException(
|
|
2417
|
+
`Invalid language "${String(input.language)}". Expected one of: ${NOTIFICATION_LANGUAGES.join(", ")}.`
|
|
2418
|
+
);
|
|
2419
|
+
}
|
|
2420
|
+
body["language"] = input.language;
|
|
2421
|
+
}
|
|
2422
|
+
if (input.notOnPeppol !== void 0) {
|
|
2423
|
+
if (typeof input.notOnPeppol !== "boolean") {
|
|
2424
|
+
throw new TaxoraException("notOnPeppol must be a boolean.");
|
|
2425
|
+
}
|
|
2426
|
+
body["not_on_peppol"] = input.notOnPeppol;
|
|
2427
|
+
}
|
|
2428
|
+
if (input.digest !== void 0) {
|
|
2429
|
+
if (!NOTIFICATION_DIGESTS.includes(input.digest)) {
|
|
2430
|
+
throw new TaxoraException(
|
|
2431
|
+
`Invalid digest "${String(input.digest)}". Expected one of: ${NOTIFICATION_DIGESTS.join(", ")}.`
|
|
2432
|
+
);
|
|
2433
|
+
}
|
|
2434
|
+
body["digest"] = input.digest;
|
|
2435
|
+
}
|
|
2436
|
+
if (Object.keys(body).length === 0) {
|
|
2437
|
+
throw new TaxoraException("updateNotificationSettings requires at least one field to update.");
|
|
2438
|
+
}
|
|
2439
|
+
const response = await this.sendRequest("PUT", `${this.baseUrl}/compliance/notification-settings`, body);
|
|
2440
|
+
return this.toNotificationSettings(await this.parseJsonResponse(response));
|
|
2441
|
+
}
|
|
2442
|
+
toNotificationSettings(data) {
|
|
2443
|
+
const recipients = Array.isArray(data["recipients"]) ? data["recipients"].filter((r) => typeof r === "string" && r !== "") : [];
|
|
2444
|
+
const digest = data["digest"];
|
|
2445
|
+
return {
|
|
2446
|
+
recipients,
|
|
2447
|
+
language: data["language"] === "en" ? "en" : "de",
|
|
2448
|
+
notOnPeppol: data["not_on_peppol"] === true,
|
|
2449
|
+
digest: digest === "daily" || digest === "weekly" ? digest : "off",
|
|
2450
|
+
digestSentAt: typeof data["digest_sent_at"] === "string" ? data["digest_sent_at"] : null
|
|
2451
|
+
};
|
|
2452
|
+
}
|
|
2453
|
+
// ---------------------------------------------------------------------
|
|
1877
2454
|
// Input validation (fail fast, before any request is sent)
|
|
1878
2455
|
// ---------------------------------------------------------------------
|
|
2456
|
+
/** Validated transaction-list filters as query params (shared by listTransactions and exportTransactionsCsv). */
|
|
2457
|
+
buildTransactionFilterParams(filters) {
|
|
2458
|
+
if (filters.complianceEnrollmentId !== void 0) {
|
|
2459
|
+
this.validateId(filters.complianceEnrollmentId, "complianceEnrollmentId");
|
|
2460
|
+
}
|
|
2461
|
+
if (filters.country !== void 0 && !COUNTRY_REGEX.test(filters.country)) {
|
|
2462
|
+
throw new TaxoraException("country must be a 2-character ISO 3166-1 alpha-2 code.");
|
|
2463
|
+
}
|
|
2464
|
+
if (filters.search !== void 0 && filters.search.length > 100) {
|
|
2465
|
+
throw new TaxoraException("search must not exceed 100 characters.");
|
|
2466
|
+
}
|
|
2467
|
+
this.validateInternalReference(filters.internalReference);
|
|
2468
|
+
if (filters.providerState !== void 0 && !/^[a-z_]{1,30}$/.test(filters.providerState)) {
|
|
2469
|
+
throw new TaxoraException('providerState must be 1-30 lowercase letters or underscores (e.g. "refused").');
|
|
2470
|
+
}
|
|
2471
|
+
const params = new URLSearchParams();
|
|
2472
|
+
if (filters.dateFrom !== void 0) params.set("date_from", this.formatDate(filters.dateFrom));
|
|
2473
|
+
if (filters.dateTo !== void 0) params.set("date_to", this.formatDate(filters.dateTo));
|
|
2474
|
+
if (filters.state !== void 0) params.set("state", filters.state);
|
|
2475
|
+
if (filters.transactionType !== void 0) params.set("transaction_type", filters.transactionType);
|
|
2476
|
+
if (filters.complianceEnrollmentId !== void 0) {
|
|
2477
|
+
params.set("compliance_enrollment_id", String(filters.complianceEnrollmentId));
|
|
2478
|
+
}
|
|
2479
|
+
if (filters.country !== void 0) params.set("country", filters.country.toUpperCase());
|
|
2480
|
+
if (filters.search !== void 0) params.set("search", filters.search);
|
|
2481
|
+
if (filters.internalReference !== void 0) params.set("internal_reference", filters.internalReference);
|
|
2482
|
+
if (filters.providerState !== void 0) params.set("provider_state", filters.providerState);
|
|
2483
|
+
return params;
|
|
2484
|
+
}
|
|
1879
2485
|
validateEnrollmentInput(input) {
|
|
1880
2486
|
if (input.siret === void 0 && input.siren === void 0) {
|
|
1881
2487
|
throw new TaxoraException("Either siret or siren is required.");
|
|
@@ -2003,6 +2609,20 @@ var EReportingEndpoint = class {
|
|
|
2003
2609
|
}
|
|
2004
2610
|
});
|
|
2005
2611
|
}
|
|
2612
|
+
validateInvoicePdfFilename(input) {
|
|
2613
|
+
if (input.invoicePdfFilename === void 0) return;
|
|
2614
|
+
if (input.invoicePdfFilename.length > 120) {
|
|
2615
|
+
throw new TaxoraException("invoicePdfFilename must not exceed 120 characters.");
|
|
2616
|
+
}
|
|
2617
|
+
if (input.invoicePdf === void 0) {
|
|
2618
|
+
throw new TaxoraException("invoicePdfFilename requires invoicePdf.");
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
validateInternalReference(internalReference) {
|
|
2622
|
+
if (internalReference !== void 0 && internalReference.length > 100) {
|
|
2623
|
+
throw new TaxoraException("internalReference must not exceed 100 characters.");
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2006
2626
|
validateOptionalCodes(input) {
|
|
2007
2627
|
if (input.currency !== void 0 && input.currency.length !== 3) {
|
|
2008
2628
|
throw new TaxoraException("currency must be a 3-character ISO 4217 code.");
|
|
@@ -2084,6 +2704,29 @@ var EReportingEndpoint = class {
|
|
|
2084
2704
|
if (input.amendedNumber !== void 0) body["amended_number"] = input.amendedNumber;
|
|
2085
2705
|
if (input.amendedDate !== void 0) body["amended_date"] = this.formatDate(input.amendedDate);
|
|
2086
2706
|
if (input.extraInfo !== void 0) body["extra_info"] = input.extraInfo;
|
|
2707
|
+
if (input.internalReference !== void 0) body["internal_reference"] = input.internalReference;
|
|
2708
|
+
if (input.invoicePdf !== void 0) body["invoice_pdf"] = this.encodeInvoicePdf(input.invoicePdf);
|
|
2709
|
+
if (input.invoicePdfFilename !== void 0) body["invoice_pdf_filename"] = input.invoicePdfFilename;
|
|
2710
|
+
}
|
|
2711
|
+
/** Bytes → base64 (validated as a PDF of at most 10 MB); strings are taken as already base64. */
|
|
2712
|
+
encodeInvoicePdf(pdf) {
|
|
2713
|
+
if (typeof pdf === "string") {
|
|
2714
|
+
if (pdf.trim() === "") {
|
|
2715
|
+
throw new TaxoraException("invoicePdf must not be empty.");
|
|
2716
|
+
}
|
|
2717
|
+
return pdf;
|
|
2718
|
+
}
|
|
2719
|
+
const bytes = pdf instanceof Uint8Array ? pdf : new Uint8Array(pdf);
|
|
2720
|
+
if (bytes.byteLength === 0) {
|
|
2721
|
+
throw new TaxoraException("invoicePdf must not be empty.");
|
|
2722
|
+
}
|
|
2723
|
+
if (bytes.byteLength > INVOICE_PDF_MAX_BYTES) {
|
|
2724
|
+
throw new TaxoraException("invoicePdf must not exceed 10 MB.");
|
|
2725
|
+
}
|
|
2726
|
+
if (!INVOICE_PDF_MAGIC.every((byte, index) => bytes[index] === byte)) {
|
|
2727
|
+
throw new TaxoraException('invoicePdf must be a PDF file (content must start with "%PDF-").');
|
|
2728
|
+
}
|
|
2729
|
+
return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString("base64");
|
|
2087
2730
|
}
|
|
2088
2731
|
// ---------------------------------------------------------------------
|
|
2089
2732
|
// HTTP plumbing (kept in sync with SmartEnrichmentEndpoint)
|
|
@@ -2107,6 +2750,30 @@ var EReportingEndpoint = class {
|
|
|
2107
2750
|
const send = () => this.httpClient.request(method, url, options);
|
|
2108
2751
|
return method === "GET" ? withResponseRetries(this.retryPolicy, "e-reporting request", send) : send();
|
|
2109
2752
|
}
|
|
2753
|
+
/** GET for a non-JSON download (CSV / document): no JSON Content-Type, retried like other GETs. */
|
|
2754
|
+
async sendDownloadRequest(url, accept) {
|
|
2755
|
+
const headers = this.buildHeaders(false);
|
|
2756
|
+
headers["Accept"] = accept;
|
|
2757
|
+
return withResponseRetries(
|
|
2758
|
+
this.retryPolicy,
|
|
2759
|
+
"e-reporting download",
|
|
2760
|
+
() => this.httpClient.request("GET", url, { headers })
|
|
2761
|
+
);
|
|
2762
|
+
}
|
|
2763
|
+
/** `attachment; filename="x.xml"` (or RFC 5987 `filename*=UTF-8''x.xml`) → "x.xml". */
|
|
2764
|
+
filenameFromDisposition(header) {
|
|
2765
|
+
if (header === null) return null;
|
|
2766
|
+
const extended = /filename\*\s*=\s*(?:UTF-8|utf-8)''([^;]+)/.exec(header);
|
|
2767
|
+
if (extended?.[1] !== void 0) {
|
|
2768
|
+
try {
|
|
2769
|
+
return decodeURIComponent(extended[1].trim());
|
|
2770
|
+
} catch {
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2773
|
+
const plain = /filename\s*=\s*"([^"]*)"|filename\s*=\s*([^;]+)/.exec(header);
|
|
2774
|
+
const name = (plain?.[1] ?? plain?.[2])?.trim();
|
|
2775
|
+
return name !== void 0 && name !== "" ? name : null;
|
|
2776
|
+
}
|
|
2110
2777
|
/** Multipart upload: Content-Type is left to fetch so the boundary is set correctly. */
|
|
2111
2778
|
async sendMultipartRequest(method, url, form) {
|
|
2112
2779
|
return this.httpClient.request(method, url, { headers: this.buildHeaders(false), body: form });
|
|
@@ -2201,6 +2868,73 @@ var EReportingEndpoint = class {
|
|
|
2201
2868
|
}
|
|
2202
2869
|
};
|
|
2203
2870
|
|
|
2871
|
+
// src/dto/SmartEnrichmentRecheck.ts
|
|
2872
|
+
var toIndexes = (value) => Array.isArray(value) ? value.filter((v) => typeof v === "number" && Number.isInteger(v)) : [];
|
|
2873
|
+
var SmartEnrichmentRecheck = class _SmartEnrichmentRecheck {
|
|
2874
|
+
constructor(jobId, rows, checks, skipped, dryRun) {
|
|
2875
|
+
this.jobId = jobId;
|
|
2876
|
+
this.rows = rows;
|
|
2877
|
+
this.checks = checks;
|
|
2878
|
+
this.skipped = skipped;
|
|
2879
|
+
this.dryRun = dryRun;
|
|
2880
|
+
}
|
|
2881
|
+
jobId;
|
|
2882
|
+
rows;
|
|
2883
|
+
checks;
|
|
2884
|
+
skipped;
|
|
2885
|
+
dryRun;
|
|
2886
|
+
static fromArray(data) {
|
|
2887
|
+
const skipped = {};
|
|
2888
|
+
const rawSkipped = data["skipped"];
|
|
2889
|
+
if (typeof rawSkipped === "object" && rawSkipped !== null && !Array.isArray(rawSkipped)) {
|
|
2890
|
+
for (const [reason, count] of Object.entries(rawSkipped)) {
|
|
2891
|
+
if (typeof count === "number") skipped[reason] = count;
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
return new _SmartEnrichmentRecheck(
|
|
2895
|
+
typeof data["jobId"] === "string" ? data["jobId"] : "",
|
|
2896
|
+
toIndexes(data["rows"]),
|
|
2897
|
+
typeof data["checks"] === "number" ? data["checks"] : 0,
|
|
2898
|
+
skipped,
|
|
2899
|
+
data["dryRun"] === true
|
|
2900
|
+
);
|
|
2901
|
+
}
|
|
2902
|
+
};
|
|
2903
|
+
var SmartEnrichmentRecheckState = class _SmartEnrichmentRecheckState {
|
|
2904
|
+
constructor(eligible, runs, maxPerRow, cooldownDays) {
|
|
2905
|
+
this.eligible = eligible;
|
|
2906
|
+
this.runs = runs;
|
|
2907
|
+
this.maxPerRow = maxPerRow;
|
|
2908
|
+
this.cooldownDays = cooldownDays;
|
|
2909
|
+
}
|
|
2910
|
+
eligible;
|
|
2911
|
+
runs;
|
|
2912
|
+
maxPerRow;
|
|
2913
|
+
cooldownDays;
|
|
2914
|
+
static fromArray(data) {
|
|
2915
|
+
const runs = {};
|
|
2916
|
+
const rawRuns = data["runs"];
|
|
2917
|
+
if (typeof rawRuns === "object" && rawRuns !== null && !Array.isArray(rawRuns)) {
|
|
2918
|
+
for (const [index, run] of Object.entries(rawRuns)) {
|
|
2919
|
+
if (!/^\d+$/.test(index) || typeof run !== "object" || run === null) continue;
|
|
2920
|
+
const { state, resolved } = run;
|
|
2921
|
+
if (state !== "queued" && state !== "running" && state !== "finished" && state !== "failed") continue;
|
|
2922
|
+
runs[Number(index)] = typeof resolved === "boolean" ? { state, resolved } : { state };
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
return new _SmartEnrichmentRecheckState(
|
|
2926
|
+
toIndexes(data["eligible"]),
|
|
2927
|
+
runs,
|
|
2928
|
+
typeof data["maxPerRow"] === "number" ? data["maxPerRow"] : 3,
|
|
2929
|
+
typeof data["cooldownDays"] === "number" ? data["cooldownDays"] : 7
|
|
2930
|
+
);
|
|
2931
|
+
}
|
|
2932
|
+
/** True while any recheck of this lookup is queued or running. */
|
|
2933
|
+
isActive() {
|
|
2934
|
+
return Object.values(this.runs).some((run) => run.state === "queued" || run.state === "running");
|
|
2935
|
+
}
|
|
2936
|
+
};
|
|
2937
|
+
|
|
2204
2938
|
// src/enums/SmartEnrichmentMode.ts
|
|
2205
2939
|
var SmartEnrichmentMode = {
|
|
2206
2940
|
DEFAULT: "default",
|
|
@@ -2330,7 +3064,7 @@ function toOfficialAddress(value) {
|
|
|
2330
3064
|
return Object.keys(address).length > 0 ? address : void 0;
|
|
2331
3065
|
}
|
|
2332
3066
|
var SmartEnrichmentResource = class _SmartEnrichmentResource {
|
|
2333
|
-
constructor(status, vatNumber, vatType, confidence, matchedCompanyName, matchedAddress, country, source, mode = void 0, providerVerdicts = [], addressQuality = void 0, rejectedCandidates = [], sourceUrl = void 0, registeredOwner = void 0, sourceUrls = [], taxNumber = void 0, vatValid = void 0, aiScore = void 0, nameMatch = void 0, officialName = void 0, officialAddress = void 0, taxNumberType = void 0, taxNumberLabel = void 0, taxNumberSource = void 0) {
|
|
3067
|
+
constructor(status, vatNumber, vatType, confidence, matchedCompanyName, matchedAddress, country, source, mode = void 0, providerVerdicts = [], addressQuality = void 0, rejectedCandidates = [], sourceUrl = void 0, registeredOwner = void 0, sourceUrls = [], taxNumber = void 0, vatValid = void 0, aiScore = void 0, nameMatch = void 0, officialName = void 0, officialAddress = void 0, taxNumberType = void 0, taxNumberLabel = void 0, taxNumberSource = void 0, recheckCount = void 0, lastRecheckedAt = void 0) {
|
|
2334
3068
|
this.status = status;
|
|
2335
3069
|
this.vatNumber = vatNumber;
|
|
2336
3070
|
this.vatType = vatType;
|
|
@@ -2355,6 +3089,8 @@ var SmartEnrichmentResource = class _SmartEnrichmentResource {
|
|
|
2355
3089
|
this.taxNumberType = taxNumberType;
|
|
2356
3090
|
this.taxNumberLabel = taxNumberLabel;
|
|
2357
3091
|
this.taxNumberSource = taxNumberSource;
|
|
3092
|
+
this.recheckCount = recheckCount;
|
|
3093
|
+
this.lastRecheckedAt = lastRecheckedAt;
|
|
2358
3094
|
}
|
|
2359
3095
|
status;
|
|
2360
3096
|
vatNumber;
|
|
@@ -2380,6 +3116,8 @@ var SmartEnrichmentResource = class _SmartEnrichmentResource {
|
|
|
2380
3116
|
taxNumberType;
|
|
2381
3117
|
taxNumberLabel;
|
|
2382
3118
|
taxNumberSource;
|
|
3119
|
+
recheckCount;
|
|
3120
|
+
lastRecheckedAt;
|
|
2383
3121
|
/** True when the register knows the number under a different name than the one requested. */
|
|
2384
3122
|
nameMismatch() {
|
|
2385
3123
|
return this.nameMatch === "mismatch";
|
|
@@ -2430,7 +3168,9 @@ var SmartEnrichmentResource = class _SmartEnrichmentResource {
|
|
|
2430
3168
|
toOfficialAddress(data["officialAddress"]),
|
|
2431
3169
|
text("taxNumberType"),
|
|
2432
3170
|
text("taxNumberLabel"),
|
|
2433
|
-
data["taxNumberSource"] === "vat_id" || data["taxNumberSource"] === "company_website" ? data["taxNumberSource"] : void 0
|
|
3171
|
+
data["taxNumberSource"] === "vat_id" || data["taxNumberSource"] === "company_website" ? data["taxNumberSource"] : void 0,
|
|
3172
|
+
num("recheckCount"),
|
|
3173
|
+
text("lastRecheckedAt")
|
|
2434
3174
|
);
|
|
2435
3175
|
}
|
|
2436
3176
|
toArray() {
|
|
@@ -2458,20 +3198,23 @@ var SmartEnrichmentResource = class _SmartEnrichmentResource {
|
|
|
2458
3198
|
officialAddress: this.officialAddress ?? null,
|
|
2459
3199
|
taxNumberType: this.taxNumberType ?? null,
|
|
2460
3200
|
taxNumberLabel: this.taxNumberLabel ?? null,
|
|
2461
|
-
taxNumberSource: this.taxNumberSource ?? null
|
|
3201
|
+
taxNumberSource: this.taxNumberSource ?? null,
|
|
3202
|
+
recheckCount: this.recheckCount ?? null,
|
|
3203
|
+
lastRecheckedAt: this.lastRecheckedAt ?? null
|
|
2462
3204
|
};
|
|
2463
3205
|
}
|
|
2464
3206
|
};
|
|
2465
3207
|
|
|
2466
3208
|
// src/dto/SmartEnrichmentJob.ts
|
|
2467
3209
|
var SmartEnrichmentJob = class _SmartEnrichmentJob {
|
|
2468
|
-
constructor(jobId, status, itemCount, completedCount, foundCount, results) {
|
|
3210
|
+
constructor(jobId, status, itemCount, completedCount, foundCount, results, recheck = void 0) {
|
|
2469
3211
|
this.jobId = jobId;
|
|
2470
3212
|
this.status = status;
|
|
2471
3213
|
this.itemCount = itemCount;
|
|
2472
3214
|
this.completedCount = completedCount;
|
|
2473
3215
|
this.foundCount = foundCount;
|
|
2474
3216
|
this.results = results;
|
|
3217
|
+
this.recheck = recheck;
|
|
2475
3218
|
}
|
|
2476
3219
|
jobId;
|
|
2477
3220
|
status;
|
|
@@ -2479,6 +3222,7 @@ var SmartEnrichmentJob = class _SmartEnrichmentJob {
|
|
|
2479
3222
|
completedCount;
|
|
2480
3223
|
foundCount;
|
|
2481
3224
|
results;
|
|
3225
|
+
recheck;
|
|
2482
3226
|
static fromArray(data) {
|
|
2483
3227
|
const num = (key) => {
|
|
2484
3228
|
const v = data[key];
|
|
@@ -2496,7 +3240,8 @@ var SmartEnrichmentJob = class _SmartEnrichmentJob {
|
|
|
2496
3240
|
num("itemCount"),
|
|
2497
3241
|
num("completedCount"),
|
|
2498
3242
|
num("foundCount"),
|
|
2499
|
-
results
|
|
3243
|
+
results,
|
|
3244
|
+
typeof data["recheck"] === "object" && data["recheck"] !== null && !Array.isArray(data["recheck"]) ? SmartEnrichmentRecheckState.fromArray(data["recheck"]) : void 0
|
|
2500
3245
|
);
|
|
2501
3246
|
}
|
|
2502
3247
|
isProcessing() {
|
|
@@ -2610,13 +3355,13 @@ var SmartEnrichmentHistoryPage = class _SmartEnrichmentHistoryPage {
|
|
|
2610
3355
|
};
|
|
2611
3356
|
|
|
2612
3357
|
// src/dto/SmartEnrichmentStatistics.ts
|
|
2613
|
-
function
|
|
3358
|
+
function asString11(value, fallback = "") {
|
|
2614
3359
|
return typeof value === "string" ? value : fallback;
|
|
2615
3360
|
}
|
|
2616
|
-
function
|
|
3361
|
+
function asNumber7(value) {
|
|
2617
3362
|
return typeof value === "number" ? value : Number(value ?? 0) || 0;
|
|
2618
3363
|
}
|
|
2619
|
-
function
|
|
3364
|
+
function asRecord4(value) {
|
|
2620
3365
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
2621
3366
|
}
|
|
2622
3367
|
function asRecords2(value) {
|
|
@@ -2639,39 +3384,39 @@ var SmartEnrichmentStatistics = class _SmartEnrichmentStatistics {
|
|
|
2639
3384
|
byOutcome;
|
|
2640
3385
|
confidenceBuckets;
|
|
2641
3386
|
static fromArray(data) {
|
|
2642
|
-
const range =
|
|
2643
|
-
const totals =
|
|
3387
|
+
const range = asRecord4(data["range"]);
|
|
3388
|
+
const totals = asRecord4(data["totals"]);
|
|
2644
3389
|
const timeSeries = asRecords2(data["time_series"]).map((row) => ({
|
|
2645
|
-
bucket:
|
|
2646
|
-
jobs:
|
|
2647
|
-
items:
|
|
2648
|
-
found:
|
|
3390
|
+
bucket: asString11(row["bucket"]),
|
|
3391
|
+
jobs: asNumber7(row["jobs"]),
|
|
3392
|
+
items: asNumber7(row["items"]),
|
|
3393
|
+
found: asNumber7(row["found"])
|
|
2649
3394
|
}));
|
|
2650
3395
|
const bySource = asRecords2(data["by_source"]).map((row) => ({
|
|
2651
|
-
source:
|
|
2652
|
-
jobs:
|
|
2653
|
-
found:
|
|
3396
|
+
source: asString11(row["source"]),
|
|
3397
|
+
jobs: asNumber7(row["jobs"]),
|
|
3398
|
+
found: asNumber7(row["found"])
|
|
2654
3399
|
}));
|
|
2655
3400
|
const byOutcome = asRecords2(data["by_outcome"]).map((row) => ({
|
|
2656
|
-
outcome:
|
|
2657
|
-
count:
|
|
3401
|
+
outcome: asString11(row["outcome"]),
|
|
3402
|
+
count: asNumber7(row["count"])
|
|
2658
3403
|
}));
|
|
2659
3404
|
const confidenceBuckets = asRecords2(data["confidence_buckets"]).map((row) => ({
|
|
2660
|
-
bucket:
|
|
2661
|
-
count:
|
|
3405
|
+
bucket: asString11(row["bucket"]),
|
|
3406
|
+
count: asNumber7(row["count"])
|
|
2662
3407
|
}));
|
|
2663
3408
|
return new _SmartEnrichmentStatistics(
|
|
2664
3409
|
{
|
|
2665
|
-
dateFrom:
|
|
2666
|
-
dateTo:
|
|
2667
|
-
interval:
|
|
3410
|
+
dateFrom: asString11(range["date_from"]),
|
|
3411
|
+
dateTo: asString11(range["date_to"]),
|
|
3412
|
+
interval: asString11(range["interval"])
|
|
2668
3413
|
},
|
|
2669
3414
|
{
|
|
2670
|
-
jobs:
|
|
2671
|
-
items:
|
|
2672
|
-
found:
|
|
2673
|
-
foundRate:
|
|
2674
|
-
avgConfidence:
|
|
3415
|
+
jobs: asNumber7(totals["jobs"]),
|
|
3416
|
+
items: asNumber7(totals["items"]),
|
|
3417
|
+
found: asNumber7(totals["found"]),
|
|
3418
|
+
foundRate: asNumber7(totals["found_rate"]),
|
|
3419
|
+
avgConfidence: asNumber7(totals["avg_confidence"])
|
|
2675
3420
|
},
|
|
2676
3421
|
timeSeries,
|
|
2677
3422
|
bySource,
|
|
@@ -2742,6 +3487,41 @@ var SmartEnrichmentEndpoint = class {
|
|
|
2742
3487
|
const data = await this.parseJsonResponse(response);
|
|
2743
3488
|
return SmartEnrichmentJob.fromArray(data);
|
|
2744
3489
|
}
|
|
3490
|
+
/**
|
|
3491
|
+
* Search again for rows of a finished lookup that have no usable answer (`not_found`, or a
|
|
3492
|
+
* number registered to another company). Without `rows` every row that qualifies is rechecked.
|
|
3493
|
+
*
|
|
3494
|
+
* Every recheck counts as a check like a new lookup (Deep Verify ×2), whether a VAT number is
|
|
3495
|
+
* found or not. A row can be rechecked up to 3 times, with 7 days between two rechecks;
|
|
3496
|
+
* `no_vat_exists` and found rows are never rechecked. Pass `dryRun` to see which rows would run
|
|
3497
|
+
* and what they cost without starting anything. Improved rows arrive via the
|
|
3498
|
+
* `enrichment.updated` webhook; `get(jobId).recheck` shows the progress.
|
|
3499
|
+
*
|
|
3500
|
+
* Throws a ValidationException when nothing can be rechecked, the lookup is still running, or
|
|
3501
|
+
* rechecks are not available (sandbox, flat-fee import), and an HttpException (429) when the
|
|
3502
|
+
* start credit or monthly hard cap does not cover it.
|
|
3503
|
+
*/
|
|
3504
|
+
async recheck(jobId, options = {}) {
|
|
3505
|
+
this.validateJobId(jobId);
|
|
3506
|
+
const body = {};
|
|
3507
|
+
if (options.rows !== void 0) {
|
|
3508
|
+
if (options.rows.length === 0) {
|
|
3509
|
+
throw new TaxoraException("rows must not be empty; omit it to recheck every row that qualifies.");
|
|
3510
|
+
}
|
|
3511
|
+
if (options.rows.some((index) => !Number.isInteger(index) || index < 0)) {
|
|
3512
|
+
throw new TaxoraException("rows must contain 0-based row indexes (integers >= 0).");
|
|
3513
|
+
}
|
|
3514
|
+
body["rows"] = [...new Set(options.rows)];
|
|
3515
|
+
}
|
|
3516
|
+
if (options.dryRun) body["dryRun"] = true;
|
|
3517
|
+
const response = await this.sendRequest(
|
|
3518
|
+
"POST",
|
|
3519
|
+
`${this.baseUrl}/smart-enrichment/${encodeURIComponent(jobId)}/recheck`,
|
|
3520
|
+
body
|
|
3521
|
+
);
|
|
3522
|
+
const data = await this.parseJsonResponse(response, [200, 202]);
|
|
3523
|
+
return SmartEnrichmentRecheck.fromArray(data);
|
|
3524
|
+
}
|
|
2745
3525
|
/**
|
|
2746
3526
|
* Poll get(jobId) until the job is no longer processing (completed, failed or resolved).
|
|
2747
3527
|
* Throws a TaxoraException when the job does not finish within `timeoutMs`.
|
|
@@ -3916,7 +4696,7 @@ var AuthRetryHttpClient = class {
|
|
|
3916
4696
|
};
|
|
3917
4697
|
|
|
3918
4698
|
// src/version.ts
|
|
3919
|
-
var SDK_VERSION = "1.
|
|
4699
|
+
var SDK_VERSION = "1.9.0";
|
|
3920
4700
|
|
|
3921
4701
|
// src/http/SdkVersionHttpClient.ts
|
|
3922
4702
|
var SDK_VERSION_HEADER = "X-Taxora-SDK-Version";
|
|
@@ -3943,6 +4723,7 @@ var TaxoraClient = class {
|
|
|
3943
4723
|
company;
|
|
3944
4724
|
smartEnrichment;
|
|
3945
4725
|
eReporting;
|
|
4726
|
+
billing;
|
|
3946
4727
|
baseUrl;
|
|
3947
4728
|
constructor(options) {
|
|
3948
4729
|
const environment = options.environment ?? Environment.SANDBOX;
|
|
@@ -3963,6 +4744,7 @@ var TaxoraClient = class {
|
|
|
3963
4744
|
retryPolicy
|
|
3964
4745
|
);
|
|
3965
4746
|
this.eReporting = new EReportingEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient, retryPolicy);
|
|
4747
|
+
this.billing = new BillingEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient, retryPolicy);
|
|
3966
4748
|
}
|
|
3967
4749
|
};
|
|
3968
4750
|
|
|
@@ -4102,17 +4884,24 @@ function toBytes(rawBody) {
|
|
|
4102
4884
|
"invalid_body"
|
|
4103
4885
|
);
|
|
4104
4886
|
}
|
|
4887
|
+
|
|
4888
|
+
// src/webhooks/WebhookEvent.ts
|
|
4889
|
+
function isTransactionBuyerRejected(object) {
|
|
4890
|
+
return object.buyer_rejected === true;
|
|
4891
|
+
}
|
|
4105
4892
|
export {
|
|
4106
4893
|
ApiVersion,
|
|
4107
4894
|
AuthEndpoint,
|
|
4108
4895
|
AuthRetryHttpClient,
|
|
4109
4896
|
AuthenticationException,
|
|
4897
|
+
BillingEndpoint,
|
|
4110
4898
|
CompanyAddress,
|
|
4111
4899
|
CompanyEndpoint,
|
|
4112
4900
|
ComplianceDocumentType,
|
|
4113
4901
|
ComplianceEnrollment,
|
|
4114
4902
|
ComplianceEnrollmentPage,
|
|
4115
4903
|
ComplianceEnrollmentStatus,
|
|
4904
|
+
ComplianceOfferings,
|
|
4116
4905
|
ComplianceService,
|
|
4117
4906
|
ComplianceTaxReport,
|
|
4118
4907
|
ComplianceTaxReportPage,
|
|
@@ -4146,6 +4935,8 @@ export {
|
|
|
4146
4935
|
SmartEnrichmentHistoryRow,
|
|
4147
4936
|
SmartEnrichmentJob,
|
|
4148
4937
|
SmartEnrichmentMode,
|
|
4938
|
+
SmartEnrichmentRecheck,
|
|
4939
|
+
SmartEnrichmentRecheckState,
|
|
4149
4940
|
SmartEnrichmentRejectionReason,
|
|
4150
4941
|
SmartEnrichmentResource,
|
|
4151
4942
|
SmartEnrichmentStatistics,
|
|
@@ -4154,6 +4945,8 @@ export {
|
|
|
4154
4945
|
TaxoraClientFactory,
|
|
4155
4946
|
TaxoraException,
|
|
4156
4947
|
Token,
|
|
4948
|
+
UsageSummary,
|
|
4949
|
+
UsageSummaryPage,
|
|
4157
4950
|
ValidationException,
|
|
4158
4951
|
VatCertificateExport,
|
|
4159
4952
|
VatCollection,
|
|
@@ -4182,6 +4975,7 @@ export {
|
|
|
4182
4975
|
generateWebhookSignatureHeader,
|
|
4183
4976
|
getBaseUrl,
|
|
4184
4977
|
getFailedVatStates,
|
|
4978
|
+
isTransactionBuyerRejected,
|
|
4185
4979
|
parseLocalTaxNumbersCsv,
|
|
4186
4980
|
parseWebhookSignatureHeader,
|
|
4187
4981
|
toComplianceDocumentType,
|