@taxora/sdk 1.0.6 → 1.1.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/README.md +297 -0
- package/dist/index.cjs +1889 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +905 -2
- package/dist/index.d.ts +905 -2
- package/dist/index.js +1856 -23
- package/dist/index.js.map +1 -1
- package/package.json +10 -5
package/dist/index.cjs
CHANGED
|
@@ -26,15 +26,36 @@ __export(index_exports, {
|
|
|
26
26
|
AuthenticationException: () => AuthenticationException,
|
|
27
27
|
CompanyAddress: () => CompanyAddress,
|
|
28
28
|
CompanyEndpoint: () => CompanyEndpoint,
|
|
29
|
+
ComplianceEnrollment: () => ComplianceEnrollment,
|
|
30
|
+
ComplianceEnrollmentPage: () => ComplianceEnrollmentPage,
|
|
31
|
+
ComplianceEnrollmentStatus: () => ComplianceEnrollmentStatus,
|
|
32
|
+
ComplianceTaxReport: () => ComplianceTaxReport,
|
|
33
|
+
ComplianceTaxReportPage: () => ComplianceTaxReportPage,
|
|
34
|
+
ComplianceTaxReportState: () => ComplianceTaxReportState,
|
|
35
|
+
ComplianceTransaction: () => ComplianceTransaction,
|
|
36
|
+
ComplianceTransactionPage: () => ComplianceTransactionPage,
|
|
37
|
+
ComplianceTransactionState: () => ComplianceTransactionState,
|
|
38
|
+
ComplianceTransactionType: () => ComplianceTransactionType,
|
|
39
|
+
EReportingEndpoint: () => EReportingEndpoint,
|
|
29
40
|
Environment: () => Environment,
|
|
30
41
|
FetchHttpClient: () => FetchHttpClient,
|
|
31
42
|
HttpException: () => HttpException,
|
|
43
|
+
ImportResult: () => ImportResult,
|
|
32
44
|
InMemoryTokenStorage: () => InMemoryTokenStorage,
|
|
33
45
|
Language: () => Language,
|
|
34
46
|
LoginIdentifier: () => LoginIdentifier,
|
|
35
47
|
ProviderDocument: () => ProviderDocument,
|
|
36
48
|
ProviderDocumentLine: () => ProviderDocumentLine,
|
|
49
|
+
RevenueStatistics: () => RevenueStatistics,
|
|
37
50
|
ScoreBreakdown: () => ScoreBreakdown,
|
|
51
|
+
SireneLookupResult: () => SireneLookupResult,
|
|
52
|
+
SmartEnrichmentEndpoint: () => SmartEnrichmentEndpoint,
|
|
53
|
+
SmartEnrichmentHistoryPage: () => SmartEnrichmentHistoryPage,
|
|
54
|
+
SmartEnrichmentHistoryRow: () => SmartEnrichmentHistoryRow,
|
|
55
|
+
SmartEnrichmentJob: () => SmartEnrichmentJob,
|
|
56
|
+
SmartEnrichmentResource: () => SmartEnrichmentResource,
|
|
57
|
+
SmartEnrichmentStatistics: () => SmartEnrichmentStatistics,
|
|
58
|
+
SmartEnrichmentStatus: () => SmartEnrichmentStatus,
|
|
38
59
|
TaxoraClient: () => TaxoraClient,
|
|
39
60
|
TaxoraClientFactory: () => TaxoraClientFactory,
|
|
40
61
|
TaxoraException: () => TaxoraException,
|
|
@@ -43,12 +64,23 @@ __export(index_exports, {
|
|
|
43
64
|
VatCertificateExport: () => VatCertificateExport,
|
|
44
65
|
VatCollection: () => VatCollection,
|
|
45
66
|
VatEndpoint: () => VatEndpoint,
|
|
67
|
+
VatRates: () => VatRates,
|
|
46
68
|
VatResource: () => VatResource,
|
|
47
69
|
VatState: () => VatState,
|
|
48
70
|
VatValidationAddressInput: () => VatValidationAddressInput,
|
|
71
|
+
describeComplianceEnrollmentStatus: () => describeComplianceEnrollmentStatus,
|
|
72
|
+
describeComplianceTaxReportState: () => describeComplianceTaxReportState,
|
|
73
|
+
describeComplianceTransactionState: () => describeComplianceTransactionState,
|
|
74
|
+
describeComplianceTransactionType: () => describeComplianceTransactionType,
|
|
75
|
+
describeSmartEnrichmentStatus: () => describeSmartEnrichmentStatus,
|
|
49
76
|
describeVatState: () => describeVatState,
|
|
50
77
|
getBaseUrl: () => getBaseUrl,
|
|
51
|
-
getFailedVatStates: () => getFailedVatStates
|
|
78
|
+
getFailedVatStates: () => getFailedVatStates,
|
|
79
|
+
toComplianceEnrollmentStatus: () => toComplianceEnrollmentStatus,
|
|
80
|
+
toComplianceTaxReportState: () => toComplianceTaxReportState,
|
|
81
|
+
toComplianceTransactionState: () => toComplianceTransactionState,
|
|
82
|
+
toComplianceTransactionType: () => toComplianceTransactionType,
|
|
83
|
+
toSmartEnrichmentStatus: () => toSmartEnrichmentStatus
|
|
52
84
|
});
|
|
53
85
|
module.exports = __toCommonJS(index_exports);
|
|
54
86
|
|
|
@@ -277,6 +309,1779 @@ var CompanyEndpoint = class {
|
|
|
277
309
|
}
|
|
278
310
|
};
|
|
279
311
|
|
|
312
|
+
// src/enums/ComplianceEnrollmentStatus.ts
|
|
313
|
+
var ComplianceEnrollmentStatus = {
|
|
314
|
+
PENDING_DATA: "pending_data",
|
|
315
|
+
ACCOUNT_CREATED: "account_created",
|
|
316
|
+
REGIME_ACTIVATED: "regime_activated",
|
|
317
|
+
READY: "ready",
|
|
318
|
+
SUSPENDED: "suspended",
|
|
319
|
+
ERROR_ACCOUNT: "error_account",
|
|
320
|
+
ERROR_ACTIVATION: "error_activation",
|
|
321
|
+
UNKNOWN: "unknown"
|
|
322
|
+
};
|
|
323
|
+
var VALUES = Object.values(ComplianceEnrollmentStatus);
|
|
324
|
+
function toComplianceEnrollmentStatus(value) {
|
|
325
|
+
if (typeof value === "string") {
|
|
326
|
+
const normalized = value.trim().toLowerCase();
|
|
327
|
+
if (VALUES.includes(normalized)) {
|
|
328
|
+
return normalized;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return ComplianceEnrollmentStatus.UNKNOWN;
|
|
332
|
+
}
|
|
333
|
+
var DESCRIPTIONS = {
|
|
334
|
+
[ComplianceEnrollmentStatus.PENDING_DATA]: "Awaiting merchant data before provisioning can start.",
|
|
335
|
+
[ComplianceEnrollmentStatus.ACCOUNT_CREATED]: "Provider account exists. Regime not yet activated.",
|
|
336
|
+
[ComplianceEnrollmentStatus.REGIME_ACTIVATED]: "Compliance regime activated at provider. Ready to submit transactions.",
|
|
337
|
+
[ComplianceEnrollmentStatus.READY]: "Enrollment fully active and reporting.",
|
|
338
|
+
[ComplianceEnrollmentStatus.SUSPENDED]: "Enrollment temporarily suspended.",
|
|
339
|
+
[ComplianceEnrollmentStatus.ERROR_ACCOUNT]: "Provider account creation failed.",
|
|
340
|
+
[ComplianceEnrollmentStatus.ERROR_ACTIVATION]: "Regime activation at provider failed.",
|
|
341
|
+
[ComplianceEnrollmentStatus.UNKNOWN]: "Unknown status."
|
|
342
|
+
};
|
|
343
|
+
function describeComplianceEnrollmentStatus(status) {
|
|
344
|
+
return DESCRIPTIONS[status];
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// src/dto/ComplianceEnrollment.ts
|
|
348
|
+
function asString(value, fallback = "") {
|
|
349
|
+
return typeof value === "string" ? value : fallback;
|
|
350
|
+
}
|
|
351
|
+
function asNullableString(value) {
|
|
352
|
+
return typeof value === "string" ? value : null;
|
|
353
|
+
}
|
|
354
|
+
function asNumber(value) {
|
|
355
|
+
return typeof value === "number" ? value : Number(value ?? 0) || 0;
|
|
356
|
+
}
|
|
357
|
+
var ComplianceEnrollment = class _ComplianceEnrollment {
|
|
358
|
+
constructor(id, companyId, country, regime, provider, status, statusLabel, statusError, providerAccountId, taxId, companyRegisterId, companyRegisterScheme, regimeConfig, reportingStartDate, notificationEmail, autoSend, createdAt, updatedAt) {
|
|
359
|
+
this.id = id;
|
|
360
|
+
this.companyId = companyId;
|
|
361
|
+
this.country = country;
|
|
362
|
+
this.regime = regime;
|
|
363
|
+
this.provider = provider;
|
|
364
|
+
this.status = status;
|
|
365
|
+
this.statusLabel = statusLabel;
|
|
366
|
+
this.statusError = statusError;
|
|
367
|
+
this.providerAccountId = providerAccountId;
|
|
368
|
+
this.taxId = taxId;
|
|
369
|
+
this.companyRegisterId = companyRegisterId;
|
|
370
|
+
this.companyRegisterScheme = companyRegisterScheme;
|
|
371
|
+
this.regimeConfig = regimeConfig;
|
|
372
|
+
this.reportingStartDate = reportingStartDate;
|
|
373
|
+
this.notificationEmail = notificationEmail;
|
|
374
|
+
this.autoSend = autoSend;
|
|
375
|
+
this.createdAt = createdAt;
|
|
376
|
+
this.updatedAt = updatedAt;
|
|
377
|
+
}
|
|
378
|
+
id;
|
|
379
|
+
companyId;
|
|
380
|
+
country;
|
|
381
|
+
regime;
|
|
382
|
+
provider;
|
|
383
|
+
status;
|
|
384
|
+
statusLabel;
|
|
385
|
+
statusError;
|
|
386
|
+
providerAccountId;
|
|
387
|
+
taxId;
|
|
388
|
+
companyRegisterId;
|
|
389
|
+
companyRegisterScheme;
|
|
390
|
+
regimeConfig;
|
|
391
|
+
reportingStartDate;
|
|
392
|
+
notificationEmail;
|
|
393
|
+
autoSend;
|
|
394
|
+
createdAt;
|
|
395
|
+
updatedAt;
|
|
396
|
+
static fromArray(data) {
|
|
397
|
+
const regimeConfig = typeof data["regime_config"] === "object" && data["regime_config"] !== null && !Array.isArray(data["regime_config"]) ? data["regime_config"] : null;
|
|
398
|
+
return new _ComplianceEnrollment(
|
|
399
|
+
asNumber(data["id"]),
|
|
400
|
+
asNumber(data["company_id"]),
|
|
401
|
+
asString(data["country"]),
|
|
402
|
+
asString(data["regime"]),
|
|
403
|
+
asString(data["provider"]),
|
|
404
|
+
toComplianceEnrollmentStatus(data["status"]),
|
|
405
|
+
asString(data["status_label"]),
|
|
406
|
+
asNullableString(data["status_error"]),
|
|
407
|
+
asNullableString(data["provider_account_id"]),
|
|
408
|
+
asNullableString(data["tax_id"]),
|
|
409
|
+
asNullableString(data["company_register_id"]),
|
|
410
|
+
asNullableString(data["company_register_scheme"]),
|
|
411
|
+
regimeConfig,
|
|
412
|
+
asNullableString(data["reporting_start_date"]),
|
|
413
|
+
asNullableString(data["notification_email"]),
|
|
414
|
+
data["auto_send"] === true,
|
|
415
|
+
asNullableString(data["created_at"]),
|
|
416
|
+
asNullableString(data["updated_at"])
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
// src/dto/ComplianceEnrollmentPage.ts
|
|
422
|
+
var ComplianceEnrollmentPage = class _ComplianceEnrollmentPage {
|
|
423
|
+
constructor(rows, currentPage, perPage, total, lastPage) {
|
|
424
|
+
this.rows = rows;
|
|
425
|
+
this.currentPage = currentPage;
|
|
426
|
+
this.perPage = perPage;
|
|
427
|
+
this.total = total;
|
|
428
|
+
this.lastPage = lastPage;
|
|
429
|
+
}
|
|
430
|
+
rows;
|
|
431
|
+
currentPage;
|
|
432
|
+
perPage;
|
|
433
|
+
total;
|
|
434
|
+
lastPage;
|
|
435
|
+
static fromResponse(payload) {
|
|
436
|
+
const obj = payload !== null && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
437
|
+
const rows = Array.isArray(obj["data"]) ? obj["data"].filter((row) => typeof row === "object" && row !== null).map(ComplianceEnrollment.fromArray) : [];
|
|
438
|
+
const meta = obj["meta"] !== null && typeof obj["meta"] === "object" && !Array.isArray(obj["meta"]) ? obj["meta"] : {};
|
|
439
|
+
const num = (value, fallback) => typeof value === "number" ? value : fallback;
|
|
440
|
+
return new _ComplianceEnrollmentPage(
|
|
441
|
+
rows,
|
|
442
|
+
num(meta["current_page"], 1),
|
|
443
|
+
num(meta["per_page"], rows.length),
|
|
444
|
+
num(meta["total"], rows.length),
|
|
445
|
+
num(meta["last_page"], 1)
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
[Symbol.iterator]() {
|
|
449
|
+
return this.rows[Symbol.iterator]();
|
|
450
|
+
}
|
|
451
|
+
get length() {
|
|
452
|
+
return this.rows.length;
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
// src/enums/ComplianceTaxReportState.ts
|
|
457
|
+
var ComplianceTaxReportState = {
|
|
458
|
+
NEW: "new",
|
|
459
|
+
SENT: "sent",
|
|
460
|
+
ACKNOWLEDGED: "acknowledged",
|
|
461
|
+
REGISTERED: "registered",
|
|
462
|
+
REFUSED: "refused",
|
|
463
|
+
ERROR: "error",
|
|
464
|
+
UNKNOWN: "unknown"
|
|
465
|
+
};
|
|
466
|
+
var VALUES2 = Object.values(ComplianceTaxReportState);
|
|
467
|
+
function toComplianceTaxReportState(value) {
|
|
468
|
+
if (typeof value === "string") {
|
|
469
|
+
const normalized = value.trim().toLowerCase();
|
|
470
|
+
if (VALUES2.includes(normalized)) {
|
|
471
|
+
return normalized;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
return ComplianceTaxReportState.UNKNOWN;
|
|
475
|
+
}
|
|
476
|
+
var DESCRIPTIONS2 = {
|
|
477
|
+
[ComplianceTaxReportState.NEW]: "Created at provider, waiting for the daily ledger batch.",
|
|
478
|
+
[ComplianceTaxReportState.SENT]: "Ledger transmitted to PPF.",
|
|
479
|
+
[ComplianceTaxReportState.ACKNOWLEDGED]: "PPF acknowledged receipt of the ledger.",
|
|
480
|
+
[ComplianceTaxReportState.REGISTERED]: "Accepted by DGFiP (CDV 300).",
|
|
481
|
+
[ComplianceTaxReportState.REFUSED]: "Rejected by DGFiP (CDV 301).",
|
|
482
|
+
[ComplianceTaxReportState.ERROR]: "Transmission or PPF error.",
|
|
483
|
+
[ComplianceTaxReportState.UNKNOWN]: "Unknown state."
|
|
484
|
+
};
|
|
485
|
+
function describeComplianceTaxReportState(state) {
|
|
486
|
+
return DESCRIPTIONS2[state];
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// src/dto/ComplianceTaxReport.ts
|
|
490
|
+
function asString2(value, fallback = "") {
|
|
491
|
+
return typeof value === "string" ? value : fallback;
|
|
492
|
+
}
|
|
493
|
+
function asNullableString2(value) {
|
|
494
|
+
return typeof value === "string" ? value : null;
|
|
495
|
+
}
|
|
496
|
+
function asNumber2(value) {
|
|
497
|
+
return typeof value === "number" ? value : Number(value ?? 0) || 0;
|
|
498
|
+
}
|
|
499
|
+
function asNullableNumber(value) {
|
|
500
|
+
return typeof value === "number" ? value : null;
|
|
501
|
+
}
|
|
502
|
+
function asMoney(value) {
|
|
503
|
+
if (typeof value === "string") return value;
|
|
504
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
505
|
+
return "0.00";
|
|
506
|
+
}
|
|
507
|
+
var ComplianceTaxReport = class _ComplianceTaxReport {
|
|
508
|
+
constructor(id, companyId, complianceTransactionId, ledgerId, country, regime, state, stateLabel, isTerminal, providerTaxReportId, providerLedgerId, baseAmount, taxAmount, totalAmount, refusalReason, registeredAt, refusedAt, createdAt, updatedAt) {
|
|
509
|
+
this.id = id;
|
|
510
|
+
this.companyId = companyId;
|
|
511
|
+
this.complianceTransactionId = complianceTransactionId;
|
|
512
|
+
this.ledgerId = ledgerId;
|
|
513
|
+
this.country = country;
|
|
514
|
+
this.regime = regime;
|
|
515
|
+
this.state = state;
|
|
516
|
+
this.stateLabel = stateLabel;
|
|
517
|
+
this.isTerminal = isTerminal;
|
|
518
|
+
this.providerTaxReportId = providerTaxReportId;
|
|
519
|
+
this.providerLedgerId = providerLedgerId;
|
|
520
|
+
this.baseAmount = baseAmount;
|
|
521
|
+
this.taxAmount = taxAmount;
|
|
522
|
+
this.totalAmount = totalAmount;
|
|
523
|
+
this.refusalReason = refusalReason;
|
|
524
|
+
this.registeredAt = registeredAt;
|
|
525
|
+
this.refusedAt = refusedAt;
|
|
526
|
+
this.createdAt = createdAt;
|
|
527
|
+
this.updatedAt = updatedAt;
|
|
528
|
+
}
|
|
529
|
+
id;
|
|
530
|
+
companyId;
|
|
531
|
+
complianceTransactionId;
|
|
532
|
+
ledgerId;
|
|
533
|
+
country;
|
|
534
|
+
regime;
|
|
535
|
+
state;
|
|
536
|
+
stateLabel;
|
|
537
|
+
isTerminal;
|
|
538
|
+
providerTaxReportId;
|
|
539
|
+
providerLedgerId;
|
|
540
|
+
baseAmount;
|
|
541
|
+
taxAmount;
|
|
542
|
+
totalAmount;
|
|
543
|
+
refusalReason;
|
|
544
|
+
registeredAt;
|
|
545
|
+
refusedAt;
|
|
546
|
+
createdAt;
|
|
547
|
+
updatedAt;
|
|
548
|
+
static fromArray(data) {
|
|
549
|
+
return new _ComplianceTaxReport(
|
|
550
|
+
asNumber2(data["id"]),
|
|
551
|
+
asNumber2(data["company_id"]),
|
|
552
|
+
asNullableNumber(data["compliance_transaction_id"]),
|
|
553
|
+
asNullableNumber(data["ledger_id"]),
|
|
554
|
+
asString2(data["country"]),
|
|
555
|
+
asString2(data["regime"]),
|
|
556
|
+
toComplianceTaxReportState(data["state"]),
|
|
557
|
+
asString2(data["state_label"]),
|
|
558
|
+
data["is_terminal"] === true,
|
|
559
|
+
asNullableString2(data["provider_tax_report_id"]),
|
|
560
|
+
asNullableString2(data["provider_ledger_id"]),
|
|
561
|
+
asMoney(data["base_amount"]),
|
|
562
|
+
asMoney(data["tax_amount"]),
|
|
563
|
+
asMoney(data["total_amount"]),
|
|
564
|
+
asNullableString2(data["refusal_reason"]),
|
|
565
|
+
asNullableString2(data["registered_at"]),
|
|
566
|
+
asNullableString2(data["refused_at"]),
|
|
567
|
+
asNullableString2(data["created_at"]),
|
|
568
|
+
asNullableString2(data["updated_at"])
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
// src/dto/ComplianceTaxReportPage.ts
|
|
574
|
+
var ComplianceTaxReportPage = class _ComplianceTaxReportPage {
|
|
575
|
+
constructor(rows, currentPage, perPage, total, lastPage) {
|
|
576
|
+
this.rows = rows;
|
|
577
|
+
this.currentPage = currentPage;
|
|
578
|
+
this.perPage = perPage;
|
|
579
|
+
this.total = total;
|
|
580
|
+
this.lastPage = lastPage;
|
|
581
|
+
}
|
|
582
|
+
rows;
|
|
583
|
+
currentPage;
|
|
584
|
+
perPage;
|
|
585
|
+
total;
|
|
586
|
+
lastPage;
|
|
587
|
+
static fromResponse(payload) {
|
|
588
|
+
const obj = payload !== null && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
589
|
+
const rows = Array.isArray(obj["data"]) ? obj["data"].filter((row) => typeof row === "object" && row !== null).map(ComplianceTaxReport.fromArray) : [];
|
|
590
|
+
const meta = obj["meta"] !== null && typeof obj["meta"] === "object" && !Array.isArray(obj["meta"]) ? obj["meta"] : {};
|
|
591
|
+
const num = (value, fallback) => typeof value === "number" ? value : fallback;
|
|
592
|
+
return new _ComplianceTaxReportPage(
|
|
593
|
+
rows,
|
|
594
|
+
num(meta["current_page"], 1),
|
|
595
|
+
num(meta["per_page"], rows.length),
|
|
596
|
+
num(meta["total"], rows.length),
|
|
597
|
+
num(meta["last_page"], 1)
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
[Symbol.iterator]() {
|
|
601
|
+
return this.rows[Symbol.iterator]();
|
|
602
|
+
}
|
|
603
|
+
get length() {
|
|
604
|
+
return this.rows.length;
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
// src/enums/ComplianceTransactionState.ts
|
|
609
|
+
var ComplianceTransactionState = {
|
|
610
|
+
PENDING: "pending",
|
|
611
|
+
SENDING: "sending",
|
|
612
|
+
SUBMITTED: "submitted",
|
|
613
|
+
ERROR: "error",
|
|
614
|
+
UNKNOWN: "unknown"
|
|
615
|
+
};
|
|
616
|
+
var VALUES3 = Object.values(ComplianceTransactionState);
|
|
617
|
+
function toComplianceTransactionState(value) {
|
|
618
|
+
if (typeof value === "string") {
|
|
619
|
+
const normalized = value.trim().toLowerCase();
|
|
620
|
+
if (VALUES3.includes(normalized)) {
|
|
621
|
+
return normalized;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
return ComplianceTransactionState.UNKNOWN;
|
|
625
|
+
}
|
|
626
|
+
var DESCRIPTIONS3 = {
|
|
627
|
+
[ComplianceTransactionState.PENDING]: "Recorded locally, not yet submitted to the provider.",
|
|
628
|
+
[ComplianceTransactionState.SENDING]: "Submission to the provider in progress.",
|
|
629
|
+
[ComplianceTransactionState.SUBMITTED]: "Successfully submitted to the provider.",
|
|
630
|
+
[ComplianceTransactionState.ERROR]: "Submission failed. See submissionError.",
|
|
631
|
+
[ComplianceTransactionState.UNKNOWN]: "Unknown state."
|
|
632
|
+
};
|
|
633
|
+
function describeComplianceTransactionState(state) {
|
|
634
|
+
return DESCRIPTIONS3[state];
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// src/enums/ComplianceTransactionType.ts
|
|
638
|
+
var ComplianceTransactionType = {
|
|
639
|
+
B2C_OUTBOUND: "b2c_outbound",
|
|
640
|
+
B2B_DOMESTIC_OUTBOUND: "b2b_domestic_outbound",
|
|
641
|
+
B2B_DOMESTIC_INBOUND: "b2b_domestic_inbound",
|
|
642
|
+
CROSSBORDER_OUTBOUND: "crossborder_outbound",
|
|
643
|
+
CROSSBORDER_INBOUND: "crossborder_inbound",
|
|
644
|
+
UNKNOWN: "unknown"
|
|
645
|
+
};
|
|
646
|
+
var VALUES4 = Object.values(ComplianceTransactionType);
|
|
647
|
+
function toComplianceTransactionType(value) {
|
|
648
|
+
if (typeof value === "string") {
|
|
649
|
+
const normalized = value.trim().toLowerCase();
|
|
650
|
+
if (VALUES4.includes(normalized)) {
|
|
651
|
+
return normalized;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
return ComplianceTransactionType.UNKNOWN;
|
|
655
|
+
}
|
|
656
|
+
var DESCRIPTIONS4 = {
|
|
657
|
+
[ComplianceTransactionType.B2C_OUTBOUND]: "Sale to a private person in the merchant country (DGFiP Flux 10.3).",
|
|
658
|
+
[ComplianceTransactionType.B2B_DOMESTIC_OUTBOUND]: "Sale to a domestic business (DGFiP Flux 1, Phase 2).",
|
|
659
|
+
[ComplianceTransactionType.B2B_DOMESTIC_INBOUND]: "Purchase from a domestic business (DGFiP Flux 1, Phase 2).",
|
|
660
|
+
[ComplianceTransactionType.CROSSBORDER_OUTBOUND]: "Sale to a non-domestic business (DGFiP Flux 10.1).",
|
|
661
|
+
[ComplianceTransactionType.CROSSBORDER_INBOUND]: "Purchase from a non-domestic supplier (DGFiP Flux 10.1).",
|
|
662
|
+
[ComplianceTransactionType.UNKNOWN]: "Unknown transaction type."
|
|
663
|
+
};
|
|
664
|
+
function describeComplianceTransactionType(type) {
|
|
665
|
+
return DESCRIPTIONS4[type];
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// src/dto/ComplianceTransaction.ts
|
|
669
|
+
function asString3(value, fallback = "") {
|
|
670
|
+
return typeof value === "string" ? value : fallback;
|
|
671
|
+
}
|
|
672
|
+
function asNullableString3(value) {
|
|
673
|
+
return typeof value === "string" ? value : null;
|
|
674
|
+
}
|
|
675
|
+
function asNumber3(value) {
|
|
676
|
+
return typeof value === "number" ? value : Number(value ?? 0) || 0;
|
|
677
|
+
}
|
|
678
|
+
function asMoney2(value) {
|
|
679
|
+
if (typeof value === "string") return value;
|
|
680
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
681
|
+
return "0.00";
|
|
682
|
+
}
|
|
683
|
+
var ComplianceTransaction = class _ComplianceTransaction {
|
|
684
|
+
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) {
|
|
685
|
+
this.id = id;
|
|
686
|
+
this.companyId = companyId;
|
|
687
|
+
this.complianceEnrollmentId = complianceEnrollmentId;
|
|
688
|
+
this.country = country;
|
|
689
|
+
this.regime = regime;
|
|
690
|
+
this.transactionType = transactionType;
|
|
691
|
+
this.transactionTypeLabel = transactionTypeLabel;
|
|
692
|
+
this.state = state;
|
|
693
|
+
this.stateLabel = stateLabel;
|
|
694
|
+
this.invoiceNumber = invoiceNumber;
|
|
695
|
+
this.invoiceDate = invoiceDate;
|
|
696
|
+
this.dueDate = dueDate;
|
|
697
|
+
this.currency = currency;
|
|
698
|
+
this.subtotal = subtotal;
|
|
699
|
+
this.taxAmount = taxAmount;
|
|
700
|
+
this.total = total;
|
|
701
|
+
this.counterpartyName = counterpartyName;
|
|
702
|
+
this.counterpartyCountry = counterpartyCountry;
|
|
703
|
+
this.counterpartyVatNumber = counterpartyVatNumber;
|
|
704
|
+
this.isPaid = isPaid;
|
|
705
|
+
this.paidAt = paidAt;
|
|
706
|
+
this.providerInvoiceId = providerInvoiceId;
|
|
707
|
+
this.submissionError = submissionError;
|
|
708
|
+
this.reportedAt = reportedAt;
|
|
709
|
+
this.taxReport = taxReport;
|
|
710
|
+
this.createdAt = createdAt;
|
|
711
|
+
this.updatedAt = updatedAt;
|
|
712
|
+
}
|
|
713
|
+
id;
|
|
714
|
+
companyId;
|
|
715
|
+
complianceEnrollmentId;
|
|
716
|
+
country;
|
|
717
|
+
regime;
|
|
718
|
+
transactionType;
|
|
719
|
+
transactionTypeLabel;
|
|
720
|
+
state;
|
|
721
|
+
stateLabel;
|
|
722
|
+
invoiceNumber;
|
|
723
|
+
invoiceDate;
|
|
724
|
+
dueDate;
|
|
725
|
+
currency;
|
|
726
|
+
subtotal;
|
|
727
|
+
taxAmount;
|
|
728
|
+
total;
|
|
729
|
+
counterpartyName;
|
|
730
|
+
counterpartyCountry;
|
|
731
|
+
counterpartyVatNumber;
|
|
732
|
+
isPaid;
|
|
733
|
+
paidAt;
|
|
734
|
+
providerInvoiceId;
|
|
735
|
+
submissionError;
|
|
736
|
+
reportedAt;
|
|
737
|
+
taxReport;
|
|
738
|
+
createdAt;
|
|
739
|
+
updatedAt;
|
|
740
|
+
static fromArray(data) {
|
|
741
|
+
const taxReport = typeof data["tax_report"] === "object" && data["tax_report"] !== null && !Array.isArray(data["tax_report"]) ? ComplianceTaxReport.fromArray(data["tax_report"]) : void 0;
|
|
742
|
+
return new _ComplianceTransaction(
|
|
743
|
+
asNumber3(data["id"]),
|
|
744
|
+
asNumber3(data["company_id"]),
|
|
745
|
+
asNumber3(data["compliance_enrollment_id"]),
|
|
746
|
+
asString3(data["country"]),
|
|
747
|
+
asString3(data["regime"]),
|
|
748
|
+
toComplianceTransactionType(data["transaction_type"]),
|
|
749
|
+
asString3(data["transaction_type_label"]),
|
|
750
|
+
toComplianceTransactionState(data["state"]),
|
|
751
|
+
asString3(data["state_label"]),
|
|
752
|
+
asString3(data["invoice_number"]),
|
|
753
|
+
asNullableString3(data["invoice_date"]),
|
|
754
|
+
asNullableString3(data["due_date"]),
|
|
755
|
+
asString3(data["currency"], "EUR"),
|
|
756
|
+
asMoney2(data["subtotal"]),
|
|
757
|
+
asMoney2(data["tax_amount"]),
|
|
758
|
+
asMoney2(data["total"]),
|
|
759
|
+
asNullableString3(data["counterparty_name"]),
|
|
760
|
+
asNullableString3(data["counterparty_country"]),
|
|
761
|
+
asNullableString3(data["counterparty_vat_number"]),
|
|
762
|
+
data["is_paid"] === true,
|
|
763
|
+
asNullableString3(data["paid_at"]),
|
|
764
|
+
asNullableString3(data["provider_invoice_id"]),
|
|
765
|
+
asNullableString3(data["submission_error"]),
|
|
766
|
+
asNullableString3(data["reported_at"]),
|
|
767
|
+
taxReport,
|
|
768
|
+
asNullableString3(data["created_at"]),
|
|
769
|
+
asNullableString3(data["updated_at"])
|
|
770
|
+
);
|
|
771
|
+
}
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
// src/dto/ComplianceTransactionPage.ts
|
|
775
|
+
var ComplianceTransactionPage = class _ComplianceTransactionPage {
|
|
776
|
+
constructor(rows, currentPage, perPage, total, lastPage) {
|
|
777
|
+
this.rows = rows;
|
|
778
|
+
this.currentPage = currentPage;
|
|
779
|
+
this.perPage = perPage;
|
|
780
|
+
this.total = total;
|
|
781
|
+
this.lastPage = lastPage;
|
|
782
|
+
}
|
|
783
|
+
rows;
|
|
784
|
+
currentPage;
|
|
785
|
+
perPage;
|
|
786
|
+
total;
|
|
787
|
+
lastPage;
|
|
788
|
+
static fromResponse(payload) {
|
|
789
|
+
const obj = payload !== null && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
790
|
+
const rows = Array.isArray(obj["data"]) ? obj["data"].filter((row) => typeof row === "object" && row !== null).map(ComplianceTransaction.fromArray) : [];
|
|
791
|
+
const meta = obj["meta"] !== null && typeof obj["meta"] === "object" && !Array.isArray(obj["meta"]) ? obj["meta"] : {};
|
|
792
|
+
const num = (value, fallback) => typeof value === "number" ? value : fallback;
|
|
793
|
+
return new _ComplianceTransactionPage(
|
|
794
|
+
rows,
|
|
795
|
+
num(meta["current_page"], 1),
|
|
796
|
+
num(meta["per_page"], rows.length),
|
|
797
|
+
num(meta["total"], rows.length),
|
|
798
|
+
num(meta["last_page"], 1)
|
|
799
|
+
);
|
|
800
|
+
}
|
|
801
|
+
[Symbol.iterator]() {
|
|
802
|
+
return this.rows[Symbol.iterator]();
|
|
803
|
+
}
|
|
804
|
+
get length() {
|
|
805
|
+
return this.rows.length;
|
|
806
|
+
}
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
// src/dto/ImportResult.ts
|
|
810
|
+
var ImportResult = class _ImportResult {
|
|
811
|
+
constructor(created, skippedDuplicates, errors) {
|
|
812
|
+
this.created = created;
|
|
813
|
+
this.skippedDuplicates = skippedDuplicates;
|
|
814
|
+
this.errors = errors;
|
|
815
|
+
}
|
|
816
|
+
created;
|
|
817
|
+
skippedDuplicates;
|
|
818
|
+
errors;
|
|
819
|
+
static fromArray(data) {
|
|
820
|
+
const errors = (Array.isArray(data["errors"]) ? data["errors"] : []).filter(
|
|
821
|
+
(row) => typeof row === "string"
|
|
822
|
+
);
|
|
823
|
+
const num = (value) => typeof value === "number" ? value : 0;
|
|
824
|
+
return new _ImportResult(num(data["created"]), num(data["skipped_duplicates"]), errors);
|
|
825
|
+
}
|
|
826
|
+
};
|
|
827
|
+
|
|
828
|
+
// src/dto/RevenueStatistics.ts
|
|
829
|
+
function asString4(value, fallback = "") {
|
|
830
|
+
return typeof value === "string" ? value : fallback;
|
|
831
|
+
}
|
|
832
|
+
function asNumber4(value) {
|
|
833
|
+
return typeof value === "number" ? value : Number(value ?? 0) || 0;
|
|
834
|
+
}
|
|
835
|
+
function asMoney3(value) {
|
|
836
|
+
return typeof value === "string" ? value : "0.0000";
|
|
837
|
+
}
|
|
838
|
+
function asRecords(value) {
|
|
839
|
+
if (!Array.isArray(value)) return [];
|
|
840
|
+
return value.filter((row) => typeof row === "object" && row !== null);
|
|
841
|
+
}
|
|
842
|
+
function toTotals(data) {
|
|
843
|
+
return {
|
|
844
|
+
count: asNumber4(data["count"]),
|
|
845
|
+
subtotal: asMoney3(data["subtotal"]),
|
|
846
|
+
taxAmount: asMoney3(data["tax_amount"]),
|
|
847
|
+
total: asMoney3(data["total"])
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
var RevenueStatistics = class _RevenueStatistics {
|
|
851
|
+
constructor(dateFrom, dateTo, interval, primaryCurrency, isMultiCurrency, totals, timeSeries, byType, byCountry, byState, byCurrency) {
|
|
852
|
+
this.dateFrom = dateFrom;
|
|
853
|
+
this.dateTo = dateTo;
|
|
854
|
+
this.interval = interval;
|
|
855
|
+
this.primaryCurrency = primaryCurrency;
|
|
856
|
+
this.isMultiCurrency = isMultiCurrency;
|
|
857
|
+
this.totals = totals;
|
|
858
|
+
this.timeSeries = timeSeries;
|
|
859
|
+
this.byType = byType;
|
|
860
|
+
this.byCountry = byCountry;
|
|
861
|
+
this.byState = byState;
|
|
862
|
+
this.byCurrency = byCurrency;
|
|
863
|
+
}
|
|
864
|
+
dateFrom;
|
|
865
|
+
dateTo;
|
|
866
|
+
interval;
|
|
867
|
+
primaryCurrency;
|
|
868
|
+
isMultiCurrency;
|
|
869
|
+
totals;
|
|
870
|
+
timeSeries;
|
|
871
|
+
byType;
|
|
872
|
+
byCountry;
|
|
873
|
+
byState;
|
|
874
|
+
byCurrency;
|
|
875
|
+
static fromArray(data) {
|
|
876
|
+
const range = typeof data["range"] === "object" && data["range"] !== null ? data["range"] : {};
|
|
877
|
+
const totals = toTotals(
|
|
878
|
+
typeof data["totals"] === "object" && data["totals"] !== null ? data["totals"] : {}
|
|
879
|
+
);
|
|
880
|
+
const timeSeries = asRecords(data["time_series"]).map((row) => ({
|
|
881
|
+
bucket: asString4(row["bucket"]),
|
|
882
|
+
...toTotals(row)
|
|
883
|
+
}));
|
|
884
|
+
const byType = asRecords(data["by_type"]).map((row) => ({
|
|
885
|
+
type: asString4(row["type"]),
|
|
886
|
+
typeLabel: asString4(row["type_label"]),
|
|
887
|
+
count: asNumber4(row["count"]),
|
|
888
|
+
total: asMoney3(row["total"])
|
|
889
|
+
}));
|
|
890
|
+
const byCountry = asRecords(data["by_country"]).map((row) => ({
|
|
891
|
+
country: asString4(row["country"], "unknown"),
|
|
892
|
+
count: asNumber4(row["count"]),
|
|
893
|
+
total: asMoney3(row["total"])
|
|
894
|
+
}));
|
|
895
|
+
const byState = asRecords(data["by_state"]).map((row) => ({
|
|
896
|
+
state: asString4(row["state"]),
|
|
897
|
+
stateLabel: asString4(row["state_label"]),
|
|
898
|
+
count: asNumber4(row["count"]),
|
|
899
|
+
total: asMoney3(row["total"])
|
|
900
|
+
}));
|
|
901
|
+
const byCurrency = asRecords(data["by_currency"]).map((row) => ({
|
|
902
|
+
currency: asString4(row["currency"]),
|
|
903
|
+
...toTotals(row)
|
|
904
|
+
}));
|
|
905
|
+
return new _RevenueStatistics(
|
|
906
|
+
asString4(range["date_from"]) || void 0,
|
|
907
|
+
asString4(range["date_to"]) || void 0,
|
|
908
|
+
asString4(range["interval"]) || void 0,
|
|
909
|
+
asString4(data["primary_currency"], "EUR"),
|
|
910
|
+
data["is_multi_currency"] === true,
|
|
911
|
+
totals,
|
|
912
|
+
timeSeries,
|
|
913
|
+
byType,
|
|
914
|
+
byCountry,
|
|
915
|
+
byState,
|
|
916
|
+
byCurrency
|
|
917
|
+
);
|
|
918
|
+
}
|
|
919
|
+
};
|
|
920
|
+
|
|
921
|
+
// src/dto/SireneLookupResult.ts
|
|
922
|
+
function asString5(value, fallback = "") {
|
|
923
|
+
return typeof value === "string" ? value : fallback;
|
|
924
|
+
}
|
|
925
|
+
function asNullableString4(value) {
|
|
926
|
+
return typeof value === "string" ? value : null;
|
|
927
|
+
}
|
|
928
|
+
var SireneLookupResult = class _SireneLookupResult {
|
|
929
|
+
constructor(companyName, siren, siret, nafCode, nafFull, enterpriseSize, address, city, postalcode) {
|
|
930
|
+
this.companyName = companyName;
|
|
931
|
+
this.siren = siren;
|
|
932
|
+
this.siret = siret;
|
|
933
|
+
this.nafCode = nafCode;
|
|
934
|
+
this.nafFull = nafFull;
|
|
935
|
+
this.enterpriseSize = enterpriseSize;
|
|
936
|
+
this.address = address;
|
|
937
|
+
this.city = city;
|
|
938
|
+
this.postalcode = postalcode;
|
|
939
|
+
}
|
|
940
|
+
companyName;
|
|
941
|
+
siren;
|
|
942
|
+
siret;
|
|
943
|
+
nafCode;
|
|
944
|
+
nafFull;
|
|
945
|
+
enterpriseSize;
|
|
946
|
+
address;
|
|
947
|
+
city;
|
|
948
|
+
postalcode;
|
|
949
|
+
static fromArray(data) {
|
|
950
|
+
return new _SireneLookupResult(
|
|
951
|
+
asString5(data["company_name"]),
|
|
952
|
+
asString5(data["siren"]),
|
|
953
|
+
asNullableString4(data["siret"]),
|
|
954
|
+
asNullableString4(data["naf_code"]),
|
|
955
|
+
asNullableString4(data["naf_full"]),
|
|
956
|
+
asNullableString4(data["enterprise_size"]),
|
|
957
|
+
asNullableString4(data["address"]),
|
|
958
|
+
asNullableString4(data["city"]),
|
|
959
|
+
asNullableString4(data["postalcode"])
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
};
|
|
963
|
+
|
|
964
|
+
// src/dto/VatRates.ts
|
|
965
|
+
function asString6(value, fallback = "") {
|
|
966
|
+
return typeof value === "string" ? value : fallback;
|
|
967
|
+
}
|
|
968
|
+
function asNumber5(value) {
|
|
969
|
+
return typeof value === "number" ? value : Number(value ?? 0) || 0;
|
|
970
|
+
}
|
|
971
|
+
var VatRates = class _VatRates {
|
|
972
|
+
constructor(country, currency, rates) {
|
|
973
|
+
this.country = country;
|
|
974
|
+
this.currency = currency;
|
|
975
|
+
this.rates = rates;
|
|
976
|
+
}
|
|
977
|
+
country;
|
|
978
|
+
currency;
|
|
979
|
+
rates;
|
|
980
|
+
static fromArray(data) {
|
|
981
|
+
const rates = (Array.isArray(data["rates"]) ? data["rates"] : []).filter((row) => typeof row === "object" && row !== null).map((row) => ({
|
|
982
|
+
percent: asNumber5(row["percent"]),
|
|
983
|
+
category: asString6(row["category"]),
|
|
984
|
+
labelKey: asString6(row["label_key"]),
|
|
985
|
+
taxName: asString6(row["tax_name"]),
|
|
986
|
+
requiresVatex: row["requires_vatex"] === true
|
|
987
|
+
}));
|
|
988
|
+
return new _VatRates(asString6(data["country"]), asString6(data["currency"], "EUR"), rates);
|
|
989
|
+
}
|
|
990
|
+
};
|
|
991
|
+
|
|
992
|
+
// src/exceptions/ValidationException.ts
|
|
993
|
+
var ValidationException = class extends TaxoraException {
|
|
994
|
+
statusCode = 422;
|
|
995
|
+
errors;
|
|
996
|
+
constructor(message, errors, context = {}) {
|
|
997
|
+
super(message, context);
|
|
998
|
+
this.name = "ValidationException";
|
|
999
|
+
this.errors = errors;
|
|
1000
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
1001
|
+
}
|
|
1002
|
+
getErrors() {
|
|
1003
|
+
return this.errors;
|
|
1004
|
+
}
|
|
1005
|
+
};
|
|
1006
|
+
|
|
1007
|
+
// src/endpoints/EReportingEndpoint.ts
|
|
1008
|
+
var DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/;
|
|
1009
|
+
var NAF_CODE_REGEX = /^\d{2}$/;
|
|
1010
|
+
var INTERVALS = ["day", "week", "month"];
|
|
1011
|
+
var ENTERPRISE_SIZES = ["micro", "pme", "eti", "ge"];
|
|
1012
|
+
var TYPE_OPERATIONS = ["services", "goods", "mixed"];
|
|
1013
|
+
var TRANSACTION_TYPES = [
|
|
1014
|
+
"b2c_outbound",
|
|
1015
|
+
"b2b_domestic_outbound",
|
|
1016
|
+
"b2b_domestic_inbound",
|
|
1017
|
+
"crossborder_outbound",
|
|
1018
|
+
"crossborder_inbound"
|
|
1019
|
+
];
|
|
1020
|
+
var EReportingEndpoint = class {
|
|
1021
|
+
constructor(baseUrl, apiKey, tokenStorage, httpClient) {
|
|
1022
|
+
this.baseUrl = baseUrl;
|
|
1023
|
+
this.apiKey = apiKey;
|
|
1024
|
+
this.tokenStorage = tokenStorage;
|
|
1025
|
+
this.httpClient = httpClient;
|
|
1026
|
+
}
|
|
1027
|
+
baseUrl;
|
|
1028
|
+
apiKey;
|
|
1029
|
+
tokenStorage;
|
|
1030
|
+
httpClient;
|
|
1031
|
+
// ---------------------------------------------------------------------
|
|
1032
|
+
// Enrollments
|
|
1033
|
+
// ---------------------------------------------------------------------
|
|
1034
|
+
/**
|
|
1035
|
+
* Create a compliance enrollment and provision the provider account. By
|
|
1036
|
+
* default the DGFiP regime is activated right away; pass `autoActivate: false`
|
|
1037
|
+
* to only create the account.
|
|
1038
|
+
*
|
|
1039
|
+
* On provider failure the API responds 502 (mapped to an HttpException) and
|
|
1040
|
+
* the enrollment is persisted in `error_account`/`error_activation` state so
|
|
1041
|
+
* provisioning can be retried.
|
|
1042
|
+
*/
|
|
1043
|
+
async createEnrollment(input) {
|
|
1044
|
+
this.validateEnrollmentInput(input);
|
|
1045
|
+
const body = {
|
|
1046
|
+
email: input.email,
|
|
1047
|
+
naf_code: input.nafCode,
|
|
1048
|
+
enterprise_size: input.enterpriseSize,
|
|
1049
|
+
type_operation: input.typeOperation,
|
|
1050
|
+
reporting_start_date: this.formatDate(input.reportingStartDate)
|
|
1051
|
+
};
|
|
1052
|
+
if (input.country !== void 0) body["country"] = input.country;
|
|
1053
|
+
if (input.regime !== void 0) body["regime"] = input.regime;
|
|
1054
|
+
if (input.siret !== void 0) body["siret"] = input.siret;
|
|
1055
|
+
if (input.siren !== void 0) body["siren"] = input.siren;
|
|
1056
|
+
if (input.vatNumber !== void 0) body["vat_number"] = input.vatNumber;
|
|
1057
|
+
if (input.companyName !== void 0) body["company_name"] = input.companyName;
|
|
1058
|
+
if (input.address !== void 0) body["address"] = input.address;
|
|
1059
|
+
if (input.city !== void 0) body["city"] = input.city;
|
|
1060
|
+
if (input.postalcode !== void 0) body["postalcode"] = input.postalcode;
|
|
1061
|
+
if (input.province !== void 0) body["province"] = input.province;
|
|
1062
|
+
if (input.autoActivate !== void 0) body["auto_activate"] = input.autoActivate;
|
|
1063
|
+
const response = await this.sendRequest("POST", `${this.baseUrl}/compliance/enrollments`, body);
|
|
1064
|
+
const data = await this.parseJsonResponse(response);
|
|
1065
|
+
return ComplianceEnrollment.fromArray(data);
|
|
1066
|
+
}
|
|
1067
|
+
/** Paginated list of the company's enrollments (newest first). `perPage` is capped at 100 server-side. */
|
|
1068
|
+
async listEnrollments(page = 1, perPage = 25) {
|
|
1069
|
+
const params = new URLSearchParams();
|
|
1070
|
+
params.set("page", String(page));
|
|
1071
|
+
params.set("per_page", String(perPage));
|
|
1072
|
+
const response = await this.sendRequest("GET", `${this.baseUrl}/compliance/enrollments?${params.toString()}`);
|
|
1073
|
+
return ComplianceEnrollmentPage.fromResponse(await this.parseJsonResponse(response));
|
|
1074
|
+
}
|
|
1075
|
+
/** Get a single enrollment by id. */
|
|
1076
|
+
async getEnrollment(id) {
|
|
1077
|
+
this.validateId(id, "id");
|
|
1078
|
+
const response = await this.sendRequest("GET", `${this.baseUrl}/compliance/enrollments/${id}`);
|
|
1079
|
+
const data = await this.parseJsonResponse(response);
|
|
1080
|
+
return ComplianceEnrollment.fromArray(data);
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Look up company data by SIRET, SIREN or French VAT number via the French
|
|
1084
|
+
* SIRENE registry — ideal for prefilling createEnrollment().
|
|
1085
|
+
*
|
|
1086
|
+
* Rate-limited to 3 requests/minute per user (protects the external French
|
|
1087
|
+
* government API); exceeding it yields a 429 (mapped to an HttpException).
|
|
1088
|
+
*/
|
|
1089
|
+
async sireneLookup(q) {
|
|
1090
|
+
if (q.trim() === "") {
|
|
1091
|
+
throw new TaxoraException("q must not be empty.");
|
|
1092
|
+
}
|
|
1093
|
+
const params = new URLSearchParams();
|
|
1094
|
+
params.set("q", q);
|
|
1095
|
+
const response = await this.sendRequest("GET", `${this.baseUrl}/compliance/sirene-lookup?${params.toString()}`);
|
|
1096
|
+
const data = await this.parseJsonResponse(response);
|
|
1097
|
+
return SireneLookupResult.fromArray(data);
|
|
1098
|
+
}
|
|
1099
|
+
// ---------------------------------------------------------------------
|
|
1100
|
+
// Transactions
|
|
1101
|
+
// ---------------------------------------------------------------------
|
|
1102
|
+
/**
|
|
1103
|
+
* Record and (by default) submit a Flux 10 transaction. Pass `submitNow: false`
|
|
1104
|
+
* to only record it — submission can be triggered later via submitTransaction().
|
|
1105
|
+
*
|
|
1106
|
+
* Immediate per-invoice submission requires the e-invoicing feature on the
|
|
1107
|
+
* account; in pure e-reporting mode the transaction is only recorded and
|
|
1108
|
+
* reported via the aggregated daily ledgers.
|
|
1109
|
+
*
|
|
1110
|
+
* Creation is idempotent on the invoice's natural key (enrollment, type,
|
|
1111
|
+
* invoice number, invoice date, counterparty VAT): a re-sent create returns
|
|
1112
|
+
* the existing transaction with HTTP 200 instead of creating a duplicate.
|
|
1113
|
+
*
|
|
1114
|
+
* On provider failure the API responds 502 (mapped to an HttpException).
|
|
1115
|
+
*/
|
|
1116
|
+
async createTransaction(input) {
|
|
1117
|
+
this.validateId(input.complianceEnrollmentId, "complianceEnrollmentId");
|
|
1118
|
+
this.validateTransactionType(input.transactionType);
|
|
1119
|
+
this.validateInvoiceNumber(input.invoiceNumber);
|
|
1120
|
+
this.validateInvoiceLines(input.invoiceLines);
|
|
1121
|
+
this.validateOptionalCodes(input);
|
|
1122
|
+
const body = {
|
|
1123
|
+
compliance_enrollment_id: input.complianceEnrollmentId,
|
|
1124
|
+
transaction_type: input.transactionType,
|
|
1125
|
+
invoice_number: input.invoiceNumber,
|
|
1126
|
+
invoice_date: this.formatDate(input.invoiceDate),
|
|
1127
|
+
subtotal: input.subtotal,
|
|
1128
|
+
total: input.total,
|
|
1129
|
+
invoice_lines_attributes: this.buildInvoiceLines(input.invoiceLines)
|
|
1130
|
+
};
|
|
1131
|
+
this.applyOptionalTransactionFields(body, input);
|
|
1132
|
+
if (input.submitNow !== void 0) body["submit_now"] = input.submitNow;
|
|
1133
|
+
const response = await this.sendRequest("POST", `${this.baseUrl}/compliance/transactions`, body);
|
|
1134
|
+
const data = await this.parseJsonResponse(response);
|
|
1135
|
+
return ComplianceTransaction.fromArray(data);
|
|
1136
|
+
}
|
|
1137
|
+
/** Paginated list of the company's transactions (newest invoice date first), filterable by date / state / type. */
|
|
1138
|
+
async listTransactions(filters = {}) {
|
|
1139
|
+
const params = new URLSearchParams();
|
|
1140
|
+
if (filters.dateFrom !== void 0) params.set("date_from", this.formatDate(filters.dateFrom));
|
|
1141
|
+
if (filters.dateTo !== void 0) params.set("date_to", this.formatDate(filters.dateTo));
|
|
1142
|
+
if (filters.state !== void 0) params.set("state", filters.state);
|
|
1143
|
+
if (filters.transactionType !== void 0) params.set("transaction_type", filters.transactionType);
|
|
1144
|
+
if (filters.page !== void 0) params.set("page", String(filters.page));
|
|
1145
|
+
if (filters.perPage !== void 0) params.set("per_page", String(filters.perPage));
|
|
1146
|
+
const queryString = params.toString();
|
|
1147
|
+
const url = `${this.baseUrl}/compliance/transactions${queryString ? `?${queryString}` : ""}`;
|
|
1148
|
+
const response = await this.sendRequest("GET", url);
|
|
1149
|
+
return ComplianceTransactionPage.fromResponse(await this.parseJsonResponse(response));
|
|
1150
|
+
}
|
|
1151
|
+
/** Get a single transaction by id (includes its tax report when one exists). */
|
|
1152
|
+
async getTransaction(id) {
|
|
1153
|
+
this.validateId(id, "id");
|
|
1154
|
+
const response = await this.sendRequest("GET", `${this.baseUrl}/compliance/transactions/${id}`);
|
|
1155
|
+
const data = await this.parseJsonResponse(response);
|
|
1156
|
+
return ComplianceTransaction.fromArray(data);
|
|
1157
|
+
}
|
|
1158
|
+
/** Update a still-pending transaction. Only the provided fields are sent; already-submitted transactions are rejected with 422. */
|
|
1159
|
+
async updateTransaction(id, input) {
|
|
1160
|
+
this.validateId(id, "id");
|
|
1161
|
+
if (input.transactionType !== void 0) this.validateTransactionType(input.transactionType);
|
|
1162
|
+
if (input.invoiceNumber !== void 0) this.validateInvoiceNumber(input.invoiceNumber);
|
|
1163
|
+
if (input.invoiceLines !== void 0) this.validateInvoiceLines(input.invoiceLines);
|
|
1164
|
+
this.validateOptionalCodes(input);
|
|
1165
|
+
const body = {};
|
|
1166
|
+
if (input.transactionType !== void 0) body["transaction_type"] = input.transactionType;
|
|
1167
|
+
if (input.invoiceNumber !== void 0) body["invoice_number"] = input.invoiceNumber;
|
|
1168
|
+
if (input.invoiceDate !== void 0) body["invoice_date"] = this.formatDate(input.invoiceDate);
|
|
1169
|
+
if (input.subtotal !== void 0) body["subtotal"] = input.subtotal;
|
|
1170
|
+
if (input.total !== void 0) body["total"] = input.total;
|
|
1171
|
+
if (input.invoiceLines !== void 0) body["invoice_lines_attributes"] = this.buildInvoiceLines(input.invoiceLines);
|
|
1172
|
+
this.applyOptionalTransactionFields(body, input);
|
|
1173
|
+
const response = await this.sendRequest("PUT", `${this.baseUrl}/compliance/transactions/${id}`, body);
|
|
1174
|
+
const data = await this.parseJsonResponse(response);
|
|
1175
|
+
return ComplianceTransaction.fromArray(data);
|
|
1176
|
+
}
|
|
1177
|
+
/** Delete a still-pending transaction. Already-submitted transactions are rejected with 422. */
|
|
1178
|
+
async deleteTransaction(id) {
|
|
1179
|
+
this.validateId(id, "id");
|
|
1180
|
+
const response = await this.sendRequest("DELETE", `${this.baseUrl}/compliance/transactions/${id}`);
|
|
1181
|
+
await this.assertNoContentResponse(response);
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* Submit (or retry) an existing `pending`/`error` transaction to the provider.
|
|
1185
|
+
* Replays the invoice lines stored at creation, so they don't have to be re-sent.
|
|
1186
|
+
*
|
|
1187
|
+
* Requires the e-invoicing feature on the account — pure e-reporting customers
|
|
1188
|
+
* get a 422 (transactions are reported via the aggregated daily ledgers instead).
|
|
1189
|
+
*
|
|
1190
|
+
* On provider failure the API responds 502 (mapped to an HttpException);
|
|
1191
|
+
* already-submitted transactions are rejected with 422.
|
|
1192
|
+
*/
|
|
1193
|
+
async submitTransaction(id) {
|
|
1194
|
+
this.validateId(id, "id");
|
|
1195
|
+
const response = await this.sendRequest("POST", `${this.baseUrl}/compliance/transactions/${id}/submit`);
|
|
1196
|
+
const data = await this.parseJsonResponse(response);
|
|
1197
|
+
return ComplianceTransaction.fromArray(data);
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* Bulk-import transactions from a semicolon-separated CSV (one row per invoice
|
|
1201
|
+
* line; rows sharing an invoice_number are grouped into one transaction).
|
|
1202
|
+
* Required columns: invoice_number, invoice_date, transaction_type, subtotal,
|
|
1203
|
+
* total, line_description, line_quantity, line_price, tax_name, tax_percent,
|
|
1204
|
+
* tax_category.
|
|
1205
|
+
*
|
|
1206
|
+
* The import is idempotent: re-uploading the same file skips rows whose
|
|
1207
|
+
* invoice already exists (reported via `skippedDuplicates`).
|
|
1208
|
+
*/
|
|
1209
|
+
async importTransactions(enrollmentId, csvContent, filename = "transactions.csv") {
|
|
1210
|
+
this.validateId(enrollmentId, "enrollmentId");
|
|
1211
|
+
if (csvContent.trim() === "") {
|
|
1212
|
+
throw new TaxoraException("csvContent must not be empty.");
|
|
1213
|
+
}
|
|
1214
|
+
const form = new FormData();
|
|
1215
|
+
form.set("compliance_enrollment_id", String(enrollmentId));
|
|
1216
|
+
form.set("file", new Blob([csvContent], { type: "text/csv" }), filename);
|
|
1217
|
+
const response = await this.sendMultipartRequest("POST", `${this.baseUrl}/compliance/transactions/import`, form);
|
|
1218
|
+
const data = await this.parseJsonResponse(response);
|
|
1219
|
+
return ImportResult.fromArray(data);
|
|
1220
|
+
}
|
|
1221
|
+
// ---------------------------------------------------------------------
|
|
1222
|
+
// Analytics, configuration & reports
|
|
1223
|
+
// ---------------------------------------------------------------------
|
|
1224
|
+
/**
|
|
1225
|
+
* Aggregated turnover statistics for the authenticated company's e-reporting
|
|
1226
|
+
* transactions. All arguments are optional — the API defaults to the last 12
|
|
1227
|
+
* months and a monthly interval.
|
|
1228
|
+
*/
|
|
1229
|
+
async getRevenueStatistics(filters = {}) {
|
|
1230
|
+
if (filters.interval !== void 0 && !INTERVALS.includes(filters.interval)) {
|
|
1231
|
+
throw new TaxoraException(
|
|
1232
|
+
`Invalid statistics interval "${String(filters.interval)}". Expected one of: ${INTERVALS.join(", ")}.`
|
|
1233
|
+
);
|
|
1234
|
+
}
|
|
1235
|
+
const params = new URLSearchParams();
|
|
1236
|
+
if (filters.dateFrom !== void 0) params.set("date_from", this.formatDate(filters.dateFrom));
|
|
1237
|
+
if (filters.dateTo !== void 0) params.set("date_to", this.formatDate(filters.dateTo));
|
|
1238
|
+
if (filters.interval !== void 0) params.set("interval", filters.interval);
|
|
1239
|
+
if (filters.transactionType !== void 0) params.set("transaction_type", filters.transactionType);
|
|
1240
|
+
if (filters.state !== void 0) params.set("state", filters.state);
|
|
1241
|
+
const queryString = params.toString();
|
|
1242
|
+
const url = `${this.baseUrl}/compliance/revenue-statistics${queryString ? `?${queryString}` : ""}`;
|
|
1243
|
+
const response = await this.sendRequest("GET", url);
|
|
1244
|
+
const data = await this.parseJsonResponse(response);
|
|
1245
|
+
return RevenueStatistics.fromArray(data);
|
|
1246
|
+
}
|
|
1247
|
+
/**
|
|
1248
|
+
* The canonical VAT rates & DGFiP tax categories for a reporting country
|
|
1249
|
+
* (the seller's reporting-country rates, not the counterparty's). Falls back
|
|
1250
|
+
* to the configured default country (FR) when none/unknown is given.
|
|
1251
|
+
*/
|
|
1252
|
+
async getVatRates(country) {
|
|
1253
|
+
const params = new URLSearchParams();
|
|
1254
|
+
if (country !== void 0) params.set("country", country);
|
|
1255
|
+
const queryString = params.toString();
|
|
1256
|
+
const url = `${this.baseUrl}/compliance/vat-rates${queryString ? `?${queryString}` : ""}`;
|
|
1257
|
+
const response = await this.sendRequest("GET", url);
|
|
1258
|
+
const data = await this.parseJsonResponse(response);
|
|
1259
|
+
return VatRates.fromArray(data);
|
|
1260
|
+
}
|
|
1261
|
+
/** Paginated list of the company's tax reports (newest first), optionally filtered by state. */
|
|
1262
|
+
async listTaxReports(page = 1, perPage = 25, state) {
|
|
1263
|
+
const params = new URLSearchParams();
|
|
1264
|
+
params.set("page", String(page));
|
|
1265
|
+
params.set("per_page", String(perPage));
|
|
1266
|
+
if (state !== void 0) params.set("state", state);
|
|
1267
|
+
const response = await this.sendRequest("GET", `${this.baseUrl}/compliance/tax-reports?${params.toString()}`);
|
|
1268
|
+
return ComplianceTaxReportPage.fromResponse(await this.parseJsonResponse(response));
|
|
1269
|
+
}
|
|
1270
|
+
/** Get a single tax report by id. */
|
|
1271
|
+
async getTaxReport(id) {
|
|
1272
|
+
this.validateId(id, "id");
|
|
1273
|
+
const response = await this.sendRequest("GET", `${this.baseUrl}/compliance/tax-reports/${id}`);
|
|
1274
|
+
const data = await this.parseJsonResponse(response);
|
|
1275
|
+
return ComplianceTaxReport.fromArray(data);
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* Request activation of the E-Reporting feature for the account. This route
|
|
1279
|
+
* is deliberately NOT gated by compliance access — it exists precisely for
|
|
1280
|
+
* accounts that do not have the feature yet. The authenticated user's
|
|
1281
|
+
* name/email take precedence over the form values server-side.
|
|
1282
|
+
*
|
|
1283
|
+
* Note: unlike the other compliance routes, validation failures here are
|
|
1284
|
+
* returned as HTTP 400 (surfaced as HttpException), not 422.
|
|
1285
|
+
*/
|
|
1286
|
+
async requestEReportingAccess(input = {}) {
|
|
1287
|
+
const body = {};
|
|
1288
|
+
if (input.name !== void 0) body["name"] = input.name;
|
|
1289
|
+
if (input.email !== void 0) body["email"] = input.email;
|
|
1290
|
+
if (input.company !== void 0) body["company"] = input.company;
|
|
1291
|
+
if (input.phone !== void 0) body["phone"] = input.phone;
|
|
1292
|
+
if (input.message !== void 0) body["message"] = input.message;
|
|
1293
|
+
if (input.language !== void 0) body["language"] = input.language;
|
|
1294
|
+
const response = await this.sendRequest("POST", `${this.baseUrl}/compliance/e-reporting-request`, body);
|
|
1295
|
+
await this.parseJsonResponse(response);
|
|
1296
|
+
}
|
|
1297
|
+
// ---------------------------------------------------------------------
|
|
1298
|
+
// Input validation (fail fast, before any request is sent)
|
|
1299
|
+
// ---------------------------------------------------------------------
|
|
1300
|
+
validateEnrollmentInput(input) {
|
|
1301
|
+
if (input.siret === void 0 && input.siren === void 0) {
|
|
1302
|
+
throw new TaxoraException("Either siret or siren is required.");
|
|
1303
|
+
}
|
|
1304
|
+
if (input.siret !== void 0 && input.siret.length !== 14) {
|
|
1305
|
+
throw new TaxoraException("siret must be exactly 14 characters.");
|
|
1306
|
+
}
|
|
1307
|
+
if (input.siren !== void 0 && input.siren.length !== 9) {
|
|
1308
|
+
throw new TaxoraException("siren must be exactly 9 characters.");
|
|
1309
|
+
}
|
|
1310
|
+
if (input.email.trim() === "" || !input.email.includes("@")) {
|
|
1311
|
+
throw new TaxoraException("email must be a valid email address.");
|
|
1312
|
+
}
|
|
1313
|
+
if (!NAF_CODE_REGEX.test(input.nafCode)) {
|
|
1314
|
+
throw new TaxoraException('nafCode must be exactly 2 digits, e.g. "47".');
|
|
1315
|
+
}
|
|
1316
|
+
if (!ENTERPRISE_SIZES.includes(input.enterpriseSize)) {
|
|
1317
|
+
throw new TaxoraException(
|
|
1318
|
+
`Invalid enterpriseSize "${String(input.enterpriseSize)}". Expected one of: ${ENTERPRISE_SIZES.join(", ")}.`
|
|
1319
|
+
);
|
|
1320
|
+
}
|
|
1321
|
+
if (!TYPE_OPERATIONS.includes(input.typeOperation)) {
|
|
1322
|
+
throw new TaxoraException(
|
|
1323
|
+
`Invalid typeOperation "${String(input.typeOperation)}". Expected one of: ${TYPE_OPERATIONS.join(", ")}.`
|
|
1324
|
+
);
|
|
1325
|
+
}
|
|
1326
|
+
if (input.country !== void 0 && input.country.length !== 2) {
|
|
1327
|
+
throw new TaxoraException("country must be a 2-character ISO 3166-1 alpha-2 code.");
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
validateId(id, name) {
|
|
1331
|
+
if (!Number.isInteger(id) || id <= 0) {
|
|
1332
|
+
throw new TaxoraException(`${name} must be a positive integer.`);
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
validateTransactionType(type) {
|
|
1336
|
+
if (!TRANSACTION_TYPES.includes(type)) {
|
|
1337
|
+
throw new TaxoraException(
|
|
1338
|
+
`Invalid transactionType "${String(type)}". Expected one of: ${TRANSACTION_TYPES.join(", ")}.`
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
validateInvoiceNumber(invoiceNumber) {
|
|
1343
|
+
if (invoiceNumber.trim() === "") {
|
|
1344
|
+
throw new TaxoraException("invoiceNumber must not be empty.");
|
|
1345
|
+
}
|
|
1346
|
+
if (invoiceNumber.length > 50) {
|
|
1347
|
+
throw new TaxoraException("invoiceNumber must not exceed 50 characters.");
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
validateInvoiceLines(lines) {
|
|
1351
|
+
if (lines.length === 0) {
|
|
1352
|
+
throw new TaxoraException("invoiceLines must contain at least one line.");
|
|
1353
|
+
}
|
|
1354
|
+
lines.forEach((line, index) => {
|
|
1355
|
+
if (line.taxes.length === 0) {
|
|
1356
|
+
throw new TaxoraException(`invoiceLines[${index}].taxes must contain at least one tax.`);
|
|
1357
|
+
}
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
validateOptionalCodes(input) {
|
|
1361
|
+
if (input.currency !== void 0 && input.currency.length !== 3) {
|
|
1362
|
+
throw new TaxoraException("currency must be a 3-character ISO 4217 code.");
|
|
1363
|
+
}
|
|
1364
|
+
if (input.counterpartyCountry !== void 0 && input.counterpartyCountry.length !== 2) {
|
|
1365
|
+
throw new TaxoraException("counterpartyCountry must be a 2-character ISO 3166-1 alpha-2 code.");
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
// ---------------------------------------------------------------------
|
|
1369
|
+
// Body building (camelCase input → snake_case wire format)
|
|
1370
|
+
// ---------------------------------------------------------------------
|
|
1371
|
+
buildInvoiceLines(lines) {
|
|
1372
|
+
return lines.map((line) => {
|
|
1373
|
+
const built = {
|
|
1374
|
+
description: line.description,
|
|
1375
|
+
quantity: line.quantity,
|
|
1376
|
+
price: line.price,
|
|
1377
|
+
taxes_attributes: line.taxes.map((tax) => {
|
|
1378
|
+
const taxBuilt = {
|
|
1379
|
+
name: tax.name,
|
|
1380
|
+
percent: tax.percent,
|
|
1381
|
+
category: tax.category
|
|
1382
|
+
};
|
|
1383
|
+
if (tax.comment !== void 0) taxBuilt["comment"] = tax.comment;
|
|
1384
|
+
return taxBuilt;
|
|
1385
|
+
})
|
|
1386
|
+
};
|
|
1387
|
+
if (line.unit !== void 0) built["unit"] = line.unit;
|
|
1388
|
+
return built;
|
|
1389
|
+
});
|
|
1390
|
+
}
|
|
1391
|
+
/** Applies the optional scalar fields shared by create and update. */
|
|
1392
|
+
applyOptionalTransactionFields(body, input) {
|
|
1393
|
+
if (input.dueDate !== void 0) body["due_date"] = this.formatDate(input.dueDate);
|
|
1394
|
+
if (input.currency !== void 0) body["currency"] = input.currency;
|
|
1395
|
+
if (input.taxAmount !== void 0) body["tax_amount"] = input.taxAmount;
|
|
1396
|
+
if (input.counterpartyName !== void 0) body["counterparty_name"] = input.counterpartyName;
|
|
1397
|
+
if (input.counterpartyCountry !== void 0) body["counterparty_country"] = input.counterpartyCountry;
|
|
1398
|
+
if (input.counterpartyVatNumber !== void 0) body["counterparty_vat_number"] = input.counterpartyVatNumber;
|
|
1399
|
+
if (input.providerContactId !== void 0) body["provider_contact_id"] = input.providerContactId;
|
|
1400
|
+
if (input.paymentMethod !== void 0) body["payment_method"] = input.paymentMethod;
|
|
1401
|
+
if (input.remittanceInformation !== void 0) body["remittance_information"] = input.remittanceInformation;
|
|
1402
|
+
if (input.paymentMethodText !== void 0) body["payment_method_text"] = input.paymentMethodText;
|
|
1403
|
+
if (input.paymentTerms !== void 0) body["payment_terms"] = input.paymentTerms;
|
|
1404
|
+
}
|
|
1405
|
+
// ---------------------------------------------------------------------
|
|
1406
|
+
// HTTP plumbing (kept in sync with SmartEnrichmentEndpoint)
|
|
1407
|
+
// ---------------------------------------------------------------------
|
|
1408
|
+
buildHeaders(withJsonContentType = true) {
|
|
1409
|
+
const headers = {
|
|
1410
|
+
"x-api-key": this.apiKey
|
|
1411
|
+
};
|
|
1412
|
+
if (withJsonContentType) {
|
|
1413
|
+
headers["Content-Type"] = "application/json";
|
|
1414
|
+
}
|
|
1415
|
+
const token = this.tokenStorage.get();
|
|
1416
|
+
if (token) {
|
|
1417
|
+
headers["Authorization"] = `Bearer ${token.accessToken}`;
|
|
1418
|
+
}
|
|
1419
|
+
return headers;
|
|
1420
|
+
}
|
|
1421
|
+
async sendRequest(method, url, body) {
|
|
1422
|
+
const options = { headers: this.buildHeaders() };
|
|
1423
|
+
if (body) options.body = JSON.stringify(body);
|
|
1424
|
+
return this.httpClient.request(method, url, options);
|
|
1425
|
+
}
|
|
1426
|
+
/** Multipart upload: Content-Type is left to fetch so the boundary is set correctly. */
|
|
1427
|
+
async sendMultipartRequest(method, url, form) {
|
|
1428
|
+
return this.httpClient.request(method, url, { headers: this.buildHeaders(false), body: form });
|
|
1429
|
+
}
|
|
1430
|
+
/** Accepts any 2xx response (e.g. 201 on create, 200 on idempotent replay). */
|
|
1431
|
+
async parseJsonResponse(response) {
|
|
1432
|
+
const responseText = await response.text();
|
|
1433
|
+
if (response.status === 422) {
|
|
1434
|
+
throw this.buildValidationException(responseText);
|
|
1435
|
+
}
|
|
1436
|
+
if (!response.ok) {
|
|
1437
|
+
throw new HttpException(`HTTP error ${response.status}`, response.status, responseText);
|
|
1438
|
+
}
|
|
1439
|
+
let parsed;
|
|
1440
|
+
try {
|
|
1441
|
+
parsed = JSON.parse(responseText);
|
|
1442
|
+
} catch {
|
|
1443
|
+
throw new HttpException("Invalid JSON response", 0, responseText);
|
|
1444
|
+
}
|
|
1445
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
1446
|
+
throw new HttpException("Unexpected response format", 0, responseText);
|
|
1447
|
+
}
|
|
1448
|
+
const obj = parsed;
|
|
1449
|
+
if (obj["data"] !== void 0 && typeof obj["data"] === "object" && obj["data"] !== null) {
|
|
1450
|
+
return obj["data"];
|
|
1451
|
+
}
|
|
1452
|
+
return obj;
|
|
1453
|
+
}
|
|
1454
|
+
/** For the 204 delete: keeps the shared 422/HTTP error mapping but never parses a body. */
|
|
1455
|
+
async assertNoContentResponse(response) {
|
|
1456
|
+
if (response.status === 204) {
|
|
1457
|
+
return;
|
|
1458
|
+
}
|
|
1459
|
+
const responseText = await response.text();
|
|
1460
|
+
if (response.status === 422) {
|
|
1461
|
+
throw this.buildValidationException(responseText);
|
|
1462
|
+
}
|
|
1463
|
+
if (!response.ok) {
|
|
1464
|
+
throw new HttpException(`HTTP error ${response.status}`, response.status, responseText);
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
1467
|
+
/**
|
|
1468
|
+
* The backend emits two 422 shapes: Laravel FormRequest failures as
|
|
1469
|
+
* `{message, errors: {field: [...]}}` and state-guard errors via returnError()
|
|
1470
|
+
* as `{error: "reason"}`. Preserve the reason in both cases.
|
|
1471
|
+
*/
|
|
1472
|
+
buildValidationException(responseText) {
|
|
1473
|
+
let message = "Validation failed";
|
|
1474
|
+
let errors = {};
|
|
1475
|
+
try {
|
|
1476
|
+
const parsed = JSON.parse(responseText);
|
|
1477
|
+
if (parsed["errors"] !== null && typeof parsed["errors"] === "object" && !Array.isArray(parsed["errors"])) {
|
|
1478
|
+
errors = parsed["errors"];
|
|
1479
|
+
}
|
|
1480
|
+
if (typeof parsed["message"] === "string" && parsed["message"] !== "") {
|
|
1481
|
+
message = parsed["message"];
|
|
1482
|
+
} else if (typeof parsed["error"] === "string" && parsed["error"] !== "") {
|
|
1483
|
+
message = parsed["error"];
|
|
1484
|
+
}
|
|
1485
|
+
} catch {
|
|
1486
|
+
}
|
|
1487
|
+
return new ValidationException(message, errors, { responseBody: responseText });
|
|
1488
|
+
}
|
|
1489
|
+
/**
|
|
1490
|
+
* Date objects are serialized from their LOCAL date parts — construct them as
|
|
1491
|
+
* `new Date('2026-09-01T00:00:00')` (local midnight); a bare `new Date('2026-09-01')`
|
|
1492
|
+
* is UTC midnight and shifts a day back in UTC-negative timezones.
|
|
1493
|
+
*/
|
|
1494
|
+
formatDate(date) {
|
|
1495
|
+
if (date instanceof Date) {
|
|
1496
|
+
const year = date.getFullYear();
|
|
1497
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
1498
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
1499
|
+
return `${year}-${month}-${day}`;
|
|
1500
|
+
}
|
|
1501
|
+
if (!DATE_REGEX.test(date)) {
|
|
1502
|
+
throw new TaxoraException(`Invalid date format: "${date}". Expected YYYY-MM-DD.`);
|
|
1503
|
+
}
|
|
1504
|
+
return date;
|
|
1505
|
+
}
|
|
1506
|
+
};
|
|
1507
|
+
|
|
1508
|
+
// src/enums/SmartEnrichmentStatus.ts
|
|
1509
|
+
var SmartEnrichmentStatus = {
|
|
1510
|
+
FOUND: "found",
|
|
1511
|
+
NO_VAT_EXISTS: "no_vat_exists",
|
|
1512
|
+
NOT_FOUND: "not_found",
|
|
1513
|
+
PROCESSING: "processing",
|
|
1514
|
+
QUEUED: "queued",
|
|
1515
|
+
COMPLETED: "completed",
|
|
1516
|
+
FAILED: "failed",
|
|
1517
|
+
UNKNOWN: "unknown"
|
|
1518
|
+
};
|
|
1519
|
+
var VALUES5 = Object.values(SmartEnrichmentStatus);
|
|
1520
|
+
function toSmartEnrichmentStatus(value) {
|
|
1521
|
+
if (typeof value === "string") {
|
|
1522
|
+
const normalized = value.trim().toLowerCase();
|
|
1523
|
+
if (VALUES5.includes(normalized)) {
|
|
1524
|
+
return normalized;
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
return SmartEnrichmentStatus.UNKNOWN;
|
|
1528
|
+
}
|
|
1529
|
+
var DESCRIPTIONS5 = {
|
|
1530
|
+
[SmartEnrichmentStatus.FOUND]: "A VAT number was resolved and confirmed.",
|
|
1531
|
+
[SmartEnrichmentStatus.NO_VAT_EXISTS]: "The company was identified but has no VAT number.",
|
|
1532
|
+
[SmartEnrichmentStatus.NOT_FOUND]: "No sufficiently-confident match could be resolved.",
|
|
1533
|
+
[SmartEnrichmentStatus.PROCESSING]: "The lookup is still being processed.",
|
|
1534
|
+
[SmartEnrichmentStatus.QUEUED]: "The job is queued.",
|
|
1535
|
+
[SmartEnrichmentStatus.COMPLETED]: "The job has completed.",
|
|
1536
|
+
[SmartEnrichmentStatus.FAILED]: "The job failed.",
|
|
1537
|
+
[SmartEnrichmentStatus.UNKNOWN]: "Unknown status."
|
|
1538
|
+
};
|
|
1539
|
+
function describeSmartEnrichmentStatus(status) {
|
|
1540
|
+
return DESCRIPTIONS5[status];
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
// src/dto/SmartEnrichmentResource.ts
|
|
1544
|
+
var SmartEnrichmentResource = class _SmartEnrichmentResource {
|
|
1545
|
+
constructor(status, vatNumber, vatType, confidence, matchedCompanyName, matchedAddress, country, source) {
|
|
1546
|
+
this.status = status;
|
|
1547
|
+
this.vatNumber = vatNumber;
|
|
1548
|
+
this.vatType = vatType;
|
|
1549
|
+
this.confidence = confidence;
|
|
1550
|
+
this.matchedCompanyName = matchedCompanyName;
|
|
1551
|
+
this.matchedAddress = matchedAddress;
|
|
1552
|
+
this.country = country;
|
|
1553
|
+
this.source = source;
|
|
1554
|
+
}
|
|
1555
|
+
status;
|
|
1556
|
+
vatNumber;
|
|
1557
|
+
vatType;
|
|
1558
|
+
confidence;
|
|
1559
|
+
matchedCompanyName;
|
|
1560
|
+
matchedAddress;
|
|
1561
|
+
country;
|
|
1562
|
+
source;
|
|
1563
|
+
static fromArray(data) {
|
|
1564
|
+
const str = (key) => {
|
|
1565
|
+
const v = data[key];
|
|
1566
|
+
return typeof v === "string" ? v : void 0;
|
|
1567
|
+
};
|
|
1568
|
+
const num = (key) => {
|
|
1569
|
+
const v = data[key];
|
|
1570
|
+
return typeof v === "number" ? v : void 0;
|
|
1571
|
+
};
|
|
1572
|
+
return new _SmartEnrichmentResource(
|
|
1573
|
+
toSmartEnrichmentStatus(data["status"]),
|
|
1574
|
+
str("vatNumber"),
|
|
1575
|
+
str("vatType"),
|
|
1576
|
+
num("confidence"),
|
|
1577
|
+
str("matchedCompanyName"),
|
|
1578
|
+
str("matchedAddress"),
|
|
1579
|
+
str("country"),
|
|
1580
|
+
str("source")
|
|
1581
|
+
);
|
|
1582
|
+
}
|
|
1583
|
+
toArray() {
|
|
1584
|
+
return {
|
|
1585
|
+
status: this.status,
|
|
1586
|
+
vatNumber: this.vatNumber ?? null,
|
|
1587
|
+
vatType: this.vatType ?? null,
|
|
1588
|
+
confidence: this.confidence ?? null,
|
|
1589
|
+
matchedCompanyName: this.matchedCompanyName ?? null,
|
|
1590
|
+
matchedAddress: this.matchedAddress ?? null,
|
|
1591
|
+
country: this.country ?? null,
|
|
1592
|
+
source: this.source ?? null
|
|
1593
|
+
};
|
|
1594
|
+
}
|
|
1595
|
+
};
|
|
1596
|
+
|
|
1597
|
+
// src/dto/SmartEnrichmentJob.ts
|
|
1598
|
+
var SmartEnrichmentJob = class _SmartEnrichmentJob {
|
|
1599
|
+
constructor(jobId, status, itemCount, completedCount, foundCount, results) {
|
|
1600
|
+
this.jobId = jobId;
|
|
1601
|
+
this.status = status;
|
|
1602
|
+
this.itemCount = itemCount;
|
|
1603
|
+
this.completedCount = completedCount;
|
|
1604
|
+
this.foundCount = foundCount;
|
|
1605
|
+
this.results = results;
|
|
1606
|
+
}
|
|
1607
|
+
jobId;
|
|
1608
|
+
status;
|
|
1609
|
+
itemCount;
|
|
1610
|
+
completedCount;
|
|
1611
|
+
foundCount;
|
|
1612
|
+
results;
|
|
1613
|
+
static fromArray(data) {
|
|
1614
|
+
const num = (key) => {
|
|
1615
|
+
const v = data[key];
|
|
1616
|
+
return typeof v === "number" ? v : void 0;
|
|
1617
|
+
};
|
|
1618
|
+
let results = [];
|
|
1619
|
+
if (Array.isArray(data["results"])) {
|
|
1620
|
+
results = data["results"].filter((row) => typeof row === "object" && row !== null).map(SmartEnrichmentResource.fromArray);
|
|
1621
|
+
} else if (data["vatNumber"] !== void 0 || _SmartEnrichmentJob.looksLikeItem(data["status"])) {
|
|
1622
|
+
results = [SmartEnrichmentResource.fromArray(data)];
|
|
1623
|
+
}
|
|
1624
|
+
return new _SmartEnrichmentJob(
|
|
1625
|
+
typeof data["jobId"] === "string" ? data["jobId"] : "",
|
|
1626
|
+
toSmartEnrichmentStatus(data["status"]),
|
|
1627
|
+
num("itemCount"),
|
|
1628
|
+
num("completedCount"),
|
|
1629
|
+
num("foundCount"),
|
|
1630
|
+
results
|
|
1631
|
+
);
|
|
1632
|
+
}
|
|
1633
|
+
isProcessing() {
|
|
1634
|
+
return this.status === SmartEnrichmentStatus.PROCESSING || this.status === SmartEnrichmentStatus.QUEUED;
|
|
1635
|
+
}
|
|
1636
|
+
/** Convenience for single lookups: the first (or only) result, if any. */
|
|
1637
|
+
result() {
|
|
1638
|
+
return this.results[0];
|
|
1639
|
+
}
|
|
1640
|
+
static looksLikeItem(status) {
|
|
1641
|
+
const s = toSmartEnrichmentStatus(status);
|
|
1642
|
+
return s === SmartEnrichmentStatus.FOUND || s === SmartEnrichmentStatus.NO_VAT_EXISTS || s === SmartEnrichmentStatus.NOT_FOUND;
|
|
1643
|
+
}
|
|
1644
|
+
};
|
|
1645
|
+
|
|
1646
|
+
// src/dto/SmartEnrichmentHistoryRow.ts
|
|
1647
|
+
var SmartEnrichmentHistoryRow = class _SmartEnrichmentHistoryRow {
|
|
1648
|
+
constructor(jobId, status, isBulk, itemCount, foundCount, queryCompanyName, queryCountry, queryCity, input, result, createdAt, finishedAt) {
|
|
1649
|
+
this.jobId = jobId;
|
|
1650
|
+
this.status = status;
|
|
1651
|
+
this.isBulk = isBulk;
|
|
1652
|
+
this.itemCount = itemCount;
|
|
1653
|
+
this.foundCount = foundCount;
|
|
1654
|
+
this.queryCompanyName = queryCompanyName;
|
|
1655
|
+
this.queryCountry = queryCountry;
|
|
1656
|
+
this.queryCity = queryCity;
|
|
1657
|
+
this.input = input;
|
|
1658
|
+
this.result = result;
|
|
1659
|
+
this.createdAt = createdAt;
|
|
1660
|
+
this.finishedAt = finishedAt;
|
|
1661
|
+
}
|
|
1662
|
+
jobId;
|
|
1663
|
+
status;
|
|
1664
|
+
isBulk;
|
|
1665
|
+
itemCount;
|
|
1666
|
+
foundCount;
|
|
1667
|
+
queryCompanyName;
|
|
1668
|
+
queryCountry;
|
|
1669
|
+
queryCity;
|
|
1670
|
+
input;
|
|
1671
|
+
result;
|
|
1672
|
+
createdAt;
|
|
1673
|
+
finishedAt;
|
|
1674
|
+
static fromArray(data) {
|
|
1675
|
+
const str = (value) => typeof value === "string" ? value : void 0;
|
|
1676
|
+
const query = data["query"] !== null && typeof data["query"] === "object" && !Array.isArray(data["query"]) ? data["query"] : {};
|
|
1677
|
+
const inputRaw = data["input"] !== null && typeof data["input"] === "object" && !Array.isArray(data["input"]) ? data["input"] : void 0;
|
|
1678
|
+
const input = inputRaw ? {
|
|
1679
|
+
companyName: str(inputRaw["companyName"]),
|
|
1680
|
+
street: str(inputRaw["street"]),
|
|
1681
|
+
postalCode: str(inputRaw["postalCode"]),
|
|
1682
|
+
city: str(inputRaw["city"]),
|
|
1683
|
+
country: str(inputRaw["country"])
|
|
1684
|
+
} : void 0;
|
|
1685
|
+
const result = data["result"] !== null && typeof data["result"] === "object" && !Array.isArray(data["result"]) ? SmartEnrichmentResource.fromArray(data["result"]) : void 0;
|
|
1686
|
+
return new _SmartEnrichmentHistoryRow(
|
|
1687
|
+
str(data["jobId"]) ?? "",
|
|
1688
|
+
toSmartEnrichmentStatus(data["status"]),
|
|
1689
|
+
data["isBulk"] === true,
|
|
1690
|
+
typeof data["itemCount"] === "number" ? data["itemCount"] : 0,
|
|
1691
|
+
typeof data["foundCount"] === "number" ? data["foundCount"] : 0,
|
|
1692
|
+
str(query["companyName"]),
|
|
1693
|
+
str(query["country"]),
|
|
1694
|
+
str(query["city"]),
|
|
1695
|
+
input,
|
|
1696
|
+
result,
|
|
1697
|
+
str(data["createdAt"]),
|
|
1698
|
+
str(data["finishedAt"])
|
|
1699
|
+
);
|
|
1700
|
+
}
|
|
1701
|
+
};
|
|
1702
|
+
|
|
1703
|
+
// src/dto/SmartEnrichmentHistoryPage.ts
|
|
1704
|
+
var SmartEnrichmentHistoryPage = class _SmartEnrichmentHistoryPage {
|
|
1705
|
+
constructor(rows, currentPage, perPage, total, lastPage, stats) {
|
|
1706
|
+
this.rows = rows;
|
|
1707
|
+
this.currentPage = currentPage;
|
|
1708
|
+
this.perPage = perPage;
|
|
1709
|
+
this.total = total;
|
|
1710
|
+
this.lastPage = lastPage;
|
|
1711
|
+
this.stats = stats;
|
|
1712
|
+
}
|
|
1713
|
+
rows;
|
|
1714
|
+
currentPage;
|
|
1715
|
+
perPage;
|
|
1716
|
+
total;
|
|
1717
|
+
lastPage;
|
|
1718
|
+
stats;
|
|
1719
|
+
static fromResponse(payload) {
|
|
1720
|
+
const obj = payload !== null && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
1721
|
+
const rows = Array.isArray(obj["data"]) ? obj["data"].filter((row) => typeof row === "object" && row !== null).map(SmartEnrichmentHistoryRow.fromArray) : [];
|
|
1722
|
+
const meta = obj["meta"] !== null && typeof obj["meta"] === "object" && !Array.isArray(obj["meta"]) ? obj["meta"] : {};
|
|
1723
|
+
const num = (value, fallback) => typeof value === "number" ? value : fallback;
|
|
1724
|
+
const statsRaw = obj["stats"] !== null && typeof obj["stats"] === "object" && !Array.isArray(obj["stats"]) ? obj["stats"] : void 0;
|
|
1725
|
+
const stats = statsRaw ? { total: num(statsRaw["total"], 0), found: num(statsRaw["found"], 0) } : void 0;
|
|
1726
|
+
return new _SmartEnrichmentHistoryPage(
|
|
1727
|
+
rows,
|
|
1728
|
+
num(meta["currentPage"], 1),
|
|
1729
|
+
num(meta["perPage"], rows.length),
|
|
1730
|
+
num(meta["total"], rows.length),
|
|
1731
|
+
num(meta["lastPage"], 1),
|
|
1732
|
+
stats
|
|
1733
|
+
);
|
|
1734
|
+
}
|
|
1735
|
+
[Symbol.iterator]() {
|
|
1736
|
+
return this.rows[Symbol.iterator]();
|
|
1737
|
+
}
|
|
1738
|
+
get length() {
|
|
1739
|
+
return this.rows.length;
|
|
1740
|
+
}
|
|
1741
|
+
};
|
|
1742
|
+
|
|
1743
|
+
// src/dto/SmartEnrichmentStatistics.ts
|
|
1744
|
+
function asString7(value, fallback = "") {
|
|
1745
|
+
return typeof value === "string" ? value : fallback;
|
|
1746
|
+
}
|
|
1747
|
+
function asNumber6(value) {
|
|
1748
|
+
return typeof value === "number" ? value : Number(value ?? 0) || 0;
|
|
1749
|
+
}
|
|
1750
|
+
function asRecord(value) {
|
|
1751
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
1752
|
+
}
|
|
1753
|
+
function asRecords2(value) {
|
|
1754
|
+
if (!Array.isArray(value)) return [];
|
|
1755
|
+
return value.filter((row) => typeof row === "object" && row !== null);
|
|
1756
|
+
}
|
|
1757
|
+
var SmartEnrichmentStatistics = class _SmartEnrichmentStatistics {
|
|
1758
|
+
constructor(range, totals, timeSeries, bySource, byOutcome, confidenceBuckets) {
|
|
1759
|
+
this.range = range;
|
|
1760
|
+
this.totals = totals;
|
|
1761
|
+
this.timeSeries = timeSeries;
|
|
1762
|
+
this.bySource = bySource;
|
|
1763
|
+
this.byOutcome = byOutcome;
|
|
1764
|
+
this.confidenceBuckets = confidenceBuckets;
|
|
1765
|
+
}
|
|
1766
|
+
range;
|
|
1767
|
+
totals;
|
|
1768
|
+
timeSeries;
|
|
1769
|
+
bySource;
|
|
1770
|
+
byOutcome;
|
|
1771
|
+
confidenceBuckets;
|
|
1772
|
+
static fromArray(data) {
|
|
1773
|
+
const range = asRecord(data["range"]);
|
|
1774
|
+
const totals = asRecord(data["totals"]);
|
|
1775
|
+
const timeSeries = asRecords2(data["time_series"]).map((row) => ({
|
|
1776
|
+
bucket: asString7(row["bucket"]),
|
|
1777
|
+
jobs: asNumber6(row["jobs"]),
|
|
1778
|
+
items: asNumber6(row["items"]),
|
|
1779
|
+
found: asNumber6(row["found"])
|
|
1780
|
+
}));
|
|
1781
|
+
const bySource = asRecords2(data["by_source"]).map((row) => ({
|
|
1782
|
+
source: asString7(row["source"]),
|
|
1783
|
+
jobs: asNumber6(row["jobs"]),
|
|
1784
|
+
found: asNumber6(row["found"])
|
|
1785
|
+
}));
|
|
1786
|
+
const byOutcome = asRecords2(data["by_outcome"]).map((row) => ({
|
|
1787
|
+
outcome: asString7(row["outcome"]),
|
|
1788
|
+
count: asNumber6(row["count"])
|
|
1789
|
+
}));
|
|
1790
|
+
const confidenceBuckets = asRecords2(data["confidence_buckets"]).map((row) => ({
|
|
1791
|
+
bucket: asString7(row["bucket"]),
|
|
1792
|
+
count: asNumber6(row["count"])
|
|
1793
|
+
}));
|
|
1794
|
+
return new _SmartEnrichmentStatistics(
|
|
1795
|
+
{
|
|
1796
|
+
dateFrom: asString7(range["date_from"]),
|
|
1797
|
+
dateTo: asString7(range["date_to"]),
|
|
1798
|
+
interval: asString7(range["interval"])
|
|
1799
|
+
},
|
|
1800
|
+
{
|
|
1801
|
+
jobs: asNumber6(totals["jobs"]),
|
|
1802
|
+
items: asNumber6(totals["items"]),
|
|
1803
|
+
found: asNumber6(totals["found"]),
|
|
1804
|
+
foundRate: asNumber6(totals["found_rate"]),
|
|
1805
|
+
avgConfidence: asNumber6(totals["avg_confidence"])
|
|
1806
|
+
},
|
|
1807
|
+
timeSeries,
|
|
1808
|
+
bySource,
|
|
1809
|
+
byOutcome,
|
|
1810
|
+
confidenceBuckets
|
|
1811
|
+
);
|
|
1812
|
+
}
|
|
1813
|
+
};
|
|
1814
|
+
|
|
1815
|
+
// src/endpoints/SmartEnrichmentEndpoint.ts
|
|
1816
|
+
var STATISTICS_INTERVALS = ["day", "week", "month"];
|
|
1817
|
+
var DEFAULT_POLL_INTERVAL_MS = 2e3;
|
|
1818
|
+
var DEFAULT_POLL_TIMEOUT_MS = 12e4;
|
|
1819
|
+
var SmartEnrichmentEndpoint = class {
|
|
1820
|
+
constructor(baseUrl, apiKey, tokenStorage, httpClient) {
|
|
1821
|
+
this.baseUrl = baseUrl;
|
|
1822
|
+
this.apiKey = apiKey;
|
|
1823
|
+
this.tokenStorage = tokenStorage;
|
|
1824
|
+
this.httpClient = httpClient;
|
|
1825
|
+
}
|
|
1826
|
+
baseUrl;
|
|
1827
|
+
apiKey;
|
|
1828
|
+
tokenStorage;
|
|
1829
|
+
httpClient;
|
|
1830
|
+
/**
|
|
1831
|
+
* Single reverse lookup. Returns a confident result synchronously, or a `processing`
|
|
1832
|
+
* job (poll with get(job.jobId) or waitForCompletion(job.jobId)) when deeper resolution
|
|
1833
|
+
* is needed.
|
|
1834
|
+
*/
|
|
1835
|
+
async lookup(input) {
|
|
1836
|
+
this.validateInput(input);
|
|
1837
|
+
const body = {
|
|
1838
|
+
companyName: input.companyName,
|
|
1839
|
+
country: input.country
|
|
1840
|
+
};
|
|
1841
|
+
if (input.street !== void 0) body["street"] = input.street;
|
|
1842
|
+
if (input.postalCode !== void 0) body["postalCode"] = input.postalCode;
|
|
1843
|
+
if (input.city !== void 0) body["city"] = input.city;
|
|
1844
|
+
const response = await this.sendRequest("POST", `${this.baseUrl}/smart-enrichment`, body);
|
|
1845
|
+
const data = await this.parseJsonResponse(response, [200, 202]);
|
|
1846
|
+
return SmartEnrichmentJob.fromArray(data);
|
|
1847
|
+
}
|
|
1848
|
+
/**
|
|
1849
|
+
* Bulk batch — always async. Returns a `processing` job; results arrive via the
|
|
1850
|
+
* `enrichment.completed` webhook and are retrievable via get(job.jobId).
|
|
1851
|
+
*/
|
|
1852
|
+
async bulkLookup(items) {
|
|
1853
|
+
if (items.length === 0) {
|
|
1854
|
+
throw new TaxoraException("bulkLookup requires at least one item.");
|
|
1855
|
+
}
|
|
1856
|
+
items.forEach((item, index) => this.validateInput(item, `items[${index}]`));
|
|
1857
|
+
const response = await this.sendRequest("POST", `${this.baseUrl}/smart-enrichment/bulk`, { items });
|
|
1858
|
+
const data = await this.parseJsonResponse(response, [200, 202]);
|
|
1859
|
+
return SmartEnrichmentJob.fromArray(data);
|
|
1860
|
+
}
|
|
1861
|
+
/** Poll a job (single or bulk) by its id. */
|
|
1862
|
+
async get(jobId) {
|
|
1863
|
+
this.validateJobId(jobId);
|
|
1864
|
+
const response = await this.sendRequest("GET", `${this.baseUrl}/smart-enrichment/${encodeURIComponent(jobId)}`);
|
|
1865
|
+
const data = await this.parseJsonResponse(response);
|
|
1866
|
+
return SmartEnrichmentJob.fromArray(data);
|
|
1867
|
+
}
|
|
1868
|
+
/**
|
|
1869
|
+
* Poll get(jobId) until the job is no longer processing (completed, failed or resolved).
|
|
1870
|
+
* Throws a TaxoraException when the job does not finish within `timeoutMs`.
|
|
1871
|
+
*/
|
|
1872
|
+
async waitForCompletion(jobId, options = {}) {
|
|
1873
|
+
this.validateJobId(jobId);
|
|
1874
|
+
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
1875
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_POLL_TIMEOUT_MS;
|
|
1876
|
+
if (!Number.isFinite(pollIntervalMs) || pollIntervalMs <= 0) {
|
|
1877
|
+
throw new TaxoraException("pollIntervalMs must be greater than 0.");
|
|
1878
|
+
}
|
|
1879
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
1880
|
+
throw new TaxoraException("timeoutMs must be greater than 0.");
|
|
1881
|
+
}
|
|
1882
|
+
const deadline = Date.now() + timeoutMs;
|
|
1883
|
+
for (; ; ) {
|
|
1884
|
+
const job = await this.get(jobId);
|
|
1885
|
+
if (!job.isProcessing()) {
|
|
1886
|
+
return job;
|
|
1887
|
+
}
|
|
1888
|
+
if (Date.now() + pollIntervalMs > deadline) {
|
|
1889
|
+
throw new TaxoraException(`Smart Enrichment job "${jobId}" did not complete within ${timeoutMs}ms.`, {
|
|
1890
|
+
jobId,
|
|
1891
|
+
timeoutMs
|
|
1892
|
+
});
|
|
1893
|
+
}
|
|
1894
|
+
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
/**
|
|
1898
|
+
* Paginated lookup history (newest first). `perPage` is capped at 100 server-side.
|
|
1899
|
+
* `search` filters (free-text) over the queried company name and the resolved
|
|
1900
|
+
* VAT number / matched company name.
|
|
1901
|
+
*/
|
|
1902
|
+
async history(page = 1, perPage = 25, search) {
|
|
1903
|
+
const params = new URLSearchParams();
|
|
1904
|
+
params.set("page", String(page));
|
|
1905
|
+
params.set("perPage", String(perPage));
|
|
1906
|
+
if (search !== void 0) params.set("search", search);
|
|
1907
|
+
const response = await this.sendRequest("GET", `${this.baseUrl}/smart-enrichment/history?${params.toString()}`);
|
|
1908
|
+
return SmartEnrichmentHistoryPage.fromResponse(await this.parseRawJson(response));
|
|
1909
|
+
}
|
|
1910
|
+
/** Current billing-period quota usage, plus recent monthly billing entries. */
|
|
1911
|
+
async usage() {
|
|
1912
|
+
const response = await this.sendRequest("GET", `${this.baseUrl}/smart-enrichment/usage`);
|
|
1913
|
+
const data = await this.parseJsonResponse(response);
|
|
1914
|
+
return {
|
|
1915
|
+
period: typeof data["period"] === "string" ? data["period"] : "",
|
|
1916
|
+
used: typeof data["used"] === "number" ? data["used"] : 0,
|
|
1917
|
+
included: typeof data["included"] === "number" ? data["included"] : 0,
|
|
1918
|
+
remaining: typeof data["remaining"] === "number" ? data["remaining"] : 0,
|
|
1919
|
+
overageCount: typeof data["overageCount"] === "number" ? data["overageCount"] : 0,
|
|
1920
|
+
overagePrice: typeof data["overagePrice"] === "number" ? data["overagePrice"] : 0,
|
|
1921
|
+
overageAmount: typeof data["overageAmount"] === "number" ? data["overageAmount"] : 0,
|
|
1922
|
+
hardCap: typeof data["hardCap"] === "number" ? data["hardCap"] : null,
|
|
1923
|
+
history: this.parseUsageHistory(data["history"])
|
|
1924
|
+
};
|
|
1925
|
+
}
|
|
1926
|
+
/**
|
|
1927
|
+
* Export the company's lookups as CSV (bulk-input shape plus the resolved VAT columns;
|
|
1928
|
+
* bulk jobs are flattened to one line per input row). Returns the raw CSV text
|
|
1929
|
+
* (UTF-8, BOM included by the API so Excel opens umlauts correctly).
|
|
1930
|
+
*/
|
|
1931
|
+
async export(options = {}) {
|
|
1932
|
+
const params = new URLSearchParams();
|
|
1933
|
+
if (options.dateFrom !== void 0) params.set("date_from", options.dateFrom);
|
|
1934
|
+
if (options.dateTo !== void 0) params.set("date_to", options.dateTo);
|
|
1935
|
+
if (options.minConfidence !== void 0) params.set("min_confidence", String(options.minConfidence));
|
|
1936
|
+
for (const status of options.status ?? []) {
|
|
1937
|
+
params.append("status[]", status);
|
|
1938
|
+
}
|
|
1939
|
+
if (options.onlyFound !== void 0) params.set("only_found", options.onlyFound ? "1" : "0");
|
|
1940
|
+
const queryString = params.toString();
|
|
1941
|
+
const url = `${this.baseUrl}/smart-enrichment/export${queryString ? `?${queryString}` : ""}`;
|
|
1942
|
+
const response = await this.sendRequest("GET", url);
|
|
1943
|
+
return this.parseCsvResponse(response);
|
|
1944
|
+
}
|
|
1945
|
+
/**
|
|
1946
|
+
* Aggregated lookup statistics: headline totals, a time series and breakdowns by
|
|
1947
|
+
* source, outcome and confidence band. The API defaults to the last 12 months
|
|
1948
|
+
* and a monthly interval.
|
|
1949
|
+
*/
|
|
1950
|
+
async statistics(options = {}) {
|
|
1951
|
+
if (options.interval !== void 0 && !STATISTICS_INTERVALS.includes(options.interval)) {
|
|
1952
|
+
throw new TaxoraException(
|
|
1953
|
+
`Invalid statistics interval "${String(options.interval)}". Expected one of: ${STATISTICS_INTERVALS.join(", ")}.`
|
|
1954
|
+
);
|
|
1955
|
+
}
|
|
1956
|
+
const params = new URLSearchParams();
|
|
1957
|
+
if (options.dateFrom !== void 0) params.set("date_from", options.dateFrom);
|
|
1958
|
+
if (options.dateTo !== void 0) params.set("date_to", options.dateTo);
|
|
1959
|
+
if (options.interval !== void 0) params.set("interval", options.interval);
|
|
1960
|
+
const queryString = params.toString();
|
|
1961
|
+
const url = `${this.baseUrl}/smart-enrichment/statistics${queryString ? `?${queryString}` : ""}`;
|
|
1962
|
+
const response = await this.sendRequest("GET", url);
|
|
1963
|
+
return SmartEnrichmentStatistics.fromArray(await this.parseRawJson(response));
|
|
1964
|
+
}
|
|
1965
|
+
// ---------------------------------------------------------------------
|
|
1966
|
+
// Input validation (fail fast, before any request is sent)
|
|
1967
|
+
// ---------------------------------------------------------------------
|
|
1968
|
+
validateInput(input, context) {
|
|
1969
|
+
const where = context ? ` (${context})` : "";
|
|
1970
|
+
if (input.companyName.trim() === "") {
|
|
1971
|
+
throw new TaxoraException(`companyName must not be empty${where}.`);
|
|
1972
|
+
}
|
|
1973
|
+
if (input.country.length !== 2) {
|
|
1974
|
+
throw new TaxoraException(`country must be a 2-character ISO 3166-1 alpha-2 code${where}.`);
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
validateJobId(jobId) {
|
|
1978
|
+
if (jobId.trim() === "") {
|
|
1979
|
+
throw new TaxoraException("jobId must not be empty.");
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
// ---------------------------------------------------------------------
|
|
1983
|
+
// HTTP plumbing (kept in sync with VatEndpoint)
|
|
1984
|
+
// ---------------------------------------------------------------------
|
|
1985
|
+
buildHeaders() {
|
|
1986
|
+
const headers = {
|
|
1987
|
+
"Content-Type": "application/json",
|
|
1988
|
+
"x-api-key": this.apiKey
|
|
1989
|
+
};
|
|
1990
|
+
const token = this.tokenStorage.get();
|
|
1991
|
+
if (token) {
|
|
1992
|
+
headers["Authorization"] = `Bearer ${token.accessToken}`;
|
|
1993
|
+
}
|
|
1994
|
+
return headers;
|
|
1995
|
+
}
|
|
1996
|
+
async sendRequest(method, url, body) {
|
|
1997
|
+
const options = { headers: this.buildHeaders() };
|
|
1998
|
+
if (body) options.body = JSON.stringify(body);
|
|
1999
|
+
return this.httpClient.request(method, url, options);
|
|
2000
|
+
}
|
|
2001
|
+
async parseJsonResponse(response, acceptedStatuses = [200]) {
|
|
2002
|
+
const responseText = await response.text();
|
|
2003
|
+
if (response.status === 422) {
|
|
2004
|
+
throw new ValidationException("Validation failed", this.parseValidationErrors(responseText));
|
|
2005
|
+
}
|
|
2006
|
+
if (!response.ok && !acceptedStatuses.includes(response.status)) {
|
|
2007
|
+
throw new HttpException(`HTTP error ${response.status}`, response.status, responseText);
|
|
2008
|
+
}
|
|
2009
|
+
let parsed;
|
|
2010
|
+
try {
|
|
2011
|
+
parsed = JSON.parse(responseText);
|
|
2012
|
+
} catch {
|
|
2013
|
+
throw new HttpException("Invalid JSON response", 0, responseText);
|
|
2014
|
+
}
|
|
2015
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
2016
|
+
throw new HttpException("Unexpected response format", 0, responseText);
|
|
2017
|
+
}
|
|
2018
|
+
const obj = parsed;
|
|
2019
|
+
if (obj["data"] !== void 0 && (typeof obj["data"] === "object" || Array.isArray(obj["data"]))) {
|
|
2020
|
+
return obj["data"];
|
|
2021
|
+
}
|
|
2022
|
+
return obj;
|
|
2023
|
+
}
|
|
2024
|
+
/**
|
|
2025
|
+
* Like parseJsonResponse but returns the whole object WITHOUT unwrapping `data` — used for
|
|
2026
|
+
* the paginated history response (where `data` is the row array and `meta`/`stats` must be
|
|
2027
|
+
* preserved) and the statistics response.
|
|
2028
|
+
*/
|
|
2029
|
+
async parseRawJson(response) {
|
|
2030
|
+
const responseText = await response.text();
|
|
2031
|
+
if (response.status === 422) {
|
|
2032
|
+
throw new ValidationException("Validation failed", this.parseValidationErrors(responseText));
|
|
2033
|
+
}
|
|
2034
|
+
if (!response.ok) {
|
|
2035
|
+
throw new HttpException(`HTTP error ${response.status}`, response.status, responseText);
|
|
2036
|
+
}
|
|
2037
|
+
let parsed;
|
|
2038
|
+
try {
|
|
2039
|
+
parsed = JSON.parse(responseText);
|
|
2040
|
+
} catch {
|
|
2041
|
+
throw new HttpException("Invalid JSON response", 0, responseText);
|
|
2042
|
+
}
|
|
2043
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
2044
|
+
throw new HttpException("Unexpected response format", 0, responseText);
|
|
2045
|
+
}
|
|
2046
|
+
return parsed;
|
|
2047
|
+
}
|
|
2048
|
+
/**
|
|
2049
|
+
* For the CSV export: keeps the shared 422/HTTP error mapping but returns the body
|
|
2050
|
+
* verbatim (text/csv) instead of parsing JSON.
|
|
2051
|
+
*/
|
|
2052
|
+
async parseCsvResponse(response) {
|
|
2053
|
+
const responseText = await response.text();
|
|
2054
|
+
if (response.status === 422) {
|
|
2055
|
+
throw new ValidationException("Validation failed", this.parseValidationErrors(responseText));
|
|
2056
|
+
}
|
|
2057
|
+
if (!response.ok) {
|
|
2058
|
+
throw new HttpException(`HTTP error ${response.status}`, response.status, responseText);
|
|
2059
|
+
}
|
|
2060
|
+
return responseText;
|
|
2061
|
+
}
|
|
2062
|
+
parseValidationErrors(responseText) {
|
|
2063
|
+
try {
|
|
2064
|
+
const parsed = JSON.parse(responseText);
|
|
2065
|
+
if (parsed["errors"] !== null && typeof parsed["errors"] === "object" && !Array.isArray(parsed["errors"])) {
|
|
2066
|
+
return parsed["errors"];
|
|
2067
|
+
}
|
|
2068
|
+
} catch {
|
|
2069
|
+
}
|
|
2070
|
+
return {};
|
|
2071
|
+
}
|
|
2072
|
+
parseUsageHistory(value) {
|
|
2073
|
+
if (!Array.isArray(value)) return [];
|
|
2074
|
+
return value.filter((row) => typeof row === "object" && row !== null).map((row) => ({
|
|
2075
|
+
period: typeof row["period"] === "string" ? row["period"] : "",
|
|
2076
|
+
matches: typeof row["matches"] === "number" ? row["matches"] : 0,
|
|
2077
|
+
amount: typeof row["amount"] === "string" ? row["amount"] : "0.00",
|
|
2078
|
+
state: row["state"] === "billed" ? "billed" : "pending",
|
|
2079
|
+
billingType: typeof row["billingType"] === "string" ? row["billingType"] : null,
|
|
2080
|
+
manualReference: typeof row["manualReference"] === "string" ? row["manualReference"] : null
|
|
2081
|
+
}));
|
|
2082
|
+
}
|
|
2083
|
+
};
|
|
2084
|
+
|
|
280
2085
|
// src/enums/VatState.ts
|
|
281
2086
|
var VatState = {
|
|
282
2087
|
VALID: "valid",
|
|
@@ -287,14 +2092,14 @@ var VatState = {
|
|
|
287
2092
|
function getFailedVatStates() {
|
|
288
2093
|
return [VatState.INVALID, VatState.FRAUD];
|
|
289
2094
|
}
|
|
290
|
-
var
|
|
2095
|
+
var DESCRIPTIONS6 = {
|
|
291
2096
|
[VatState.VALID]: "The VAT number is valid and active.",
|
|
292
2097
|
[VatState.INVALID]: "The VAT number is invalid or not registered.",
|
|
293
2098
|
[VatState.FRAUD]: "The VAT number has been flagged as potentially fraudulent.",
|
|
294
2099
|
[VatState.UNKNOWN]: "The VAT number state could not be determined."
|
|
295
2100
|
};
|
|
296
2101
|
function describeVatState(state) {
|
|
297
|
-
return
|
|
2102
|
+
return DESCRIPTIONS6[state];
|
|
298
2103
|
}
|
|
299
2104
|
|
|
300
2105
|
// src/dto/CompanyAddress.ts
|
|
@@ -501,7 +2306,7 @@ var ProviderDocument = class _ProviderDocument {
|
|
|
501
2306
|
|
|
502
2307
|
// src/dto/VatResource.ts
|
|
503
2308
|
var VatResource = class _VatResource {
|
|
504
|
-
constructor(uuid, vatUid, state, countryCode, companyName, companyAddress, requestedCompanyName, requestedCompanyNameOriginal, requestedInputAddress, checkedAt, score, scoreSource, scoreAttempts, breakdown, environment, provider, usedProviders, providerVatState, providerNote, providerLastCheckedAt, hasApiError, errorMessage, nextApiRecheckAt, providerDocument) {
|
|
2309
|
+
constructor(uuid, vatUid, state, countryCode, companyName, companyAddress, requestedCompanyName, requestedCompanyNameOriginal, requestedInputAddress, checkedAt, score, scoreSource, scoreAttempts, breakdown, environment, provider, usedProviders, providerValid, providerVatState, providerNote, providerLastCheckedAt, hasApiError, errorMessage, nextApiRecheckAt, providerDocument) {
|
|
505
2310
|
this.uuid = uuid;
|
|
506
2311
|
this.vatUid = vatUid;
|
|
507
2312
|
this.state = state;
|
|
@@ -519,6 +2324,7 @@ var VatResource = class _VatResource {
|
|
|
519
2324
|
this.environment = environment;
|
|
520
2325
|
this.provider = provider;
|
|
521
2326
|
this.usedProviders = usedProviders;
|
|
2327
|
+
this.providerValid = providerValid;
|
|
522
2328
|
this.providerVatState = providerVatState;
|
|
523
2329
|
this.providerNote = providerNote;
|
|
524
2330
|
this.providerLastCheckedAt = providerLastCheckedAt;
|
|
@@ -544,6 +2350,7 @@ var VatResource = class _VatResource {
|
|
|
544
2350
|
environment;
|
|
545
2351
|
provider;
|
|
546
2352
|
usedProviders;
|
|
2353
|
+
providerValid;
|
|
547
2354
|
providerVatState;
|
|
548
2355
|
providerNote;
|
|
549
2356
|
providerLastCheckedAt;
|
|
@@ -563,6 +2370,7 @@ var VatResource = class _VatResource {
|
|
|
563
2370
|
const hasApiError = data["has_api_error"] === null ? null : typeof data["has_api_error"] === "boolean" ? data["has_api_error"] : void 0;
|
|
564
2371
|
const errorMessage = data["error_message"] === null ? null : typeof data["error_message"] === "string" ? data["error_message"] : void 0;
|
|
565
2372
|
const nextApiRecheckAt = data["next_api_recheck_at"] === null ? null : typeof data["next_api_recheck_at"] === "string" ? data["next_api_recheck_at"] : void 0;
|
|
2373
|
+
const providerValid = data["provider_valid"] === null ? null : typeof data["provider_valid"] === "boolean" ? data["provider_valid"] : void 0;
|
|
566
2374
|
const breakdown = Array.isArray(data["breakdown"]) ? data["breakdown"].map(ScoreBreakdown.fromArray) : void 0;
|
|
567
2375
|
const usedProviders = Array.isArray(data["used_providers"]) ? data["used_providers"].filter((v) => typeof v === "string") : void 0;
|
|
568
2376
|
const scoreAttempts = Array.isArray(data["score_attempts"]) ? data["score_attempts"] : void 0;
|
|
@@ -585,6 +2393,7 @@ var VatResource = class _VatResource {
|
|
|
585
2393
|
str("environment"),
|
|
586
2394
|
str("provider"),
|
|
587
2395
|
usedProviders,
|
|
2396
|
+
providerValid,
|
|
588
2397
|
str("provider_vat_state"),
|
|
589
2398
|
str("provider_note"),
|
|
590
2399
|
providerLastCheckedAt,
|
|
@@ -601,6 +2410,18 @@ var VatResource = class _VatResource {
|
|
|
601
2410
|
}
|
|
602
2411
|
return `https://app.sandbox.taxora.io/vat/history/${this.uuid}`;
|
|
603
2412
|
}
|
|
2413
|
+
isValid(useProviderState = false) {
|
|
2414
|
+
if (useProviderState) {
|
|
2415
|
+
return this.isProviderValid();
|
|
2416
|
+
}
|
|
2417
|
+
return this.state === VatState.VALID;
|
|
2418
|
+
}
|
|
2419
|
+
isProviderValid() {
|
|
2420
|
+
if (this.providerValid !== void 0 && this.providerValid !== null) {
|
|
2421
|
+
return this.providerValid;
|
|
2422
|
+
}
|
|
2423
|
+
return this.providerVatState === VatState.VALID;
|
|
2424
|
+
}
|
|
604
2425
|
toArray() {
|
|
605
2426
|
return {
|
|
606
2427
|
uuid: this.uuid,
|
|
@@ -620,6 +2441,7 @@ var VatResource = class _VatResource {
|
|
|
620
2441
|
environment: this.environment ?? null,
|
|
621
2442
|
provider: this.provider ?? null,
|
|
622
2443
|
used_providers: this.usedProviders ?? null,
|
|
2444
|
+
provider_valid: this.providerValid ?? null,
|
|
623
2445
|
provider_vat_state: this.providerVatState ?? null,
|
|
624
2446
|
provider_note: this.providerNote ?? null,
|
|
625
2447
|
provider_last_checked_at: this.providerLastCheckedAt?.toISOString() ?? null,
|
|
@@ -739,23 +2561,8 @@ var VatValidationAddressInput = class _VatValidationAddressInput {
|
|
|
739
2561
|
}
|
|
740
2562
|
};
|
|
741
2563
|
|
|
742
|
-
// src/exceptions/ValidationException.ts
|
|
743
|
-
var ValidationException = class extends TaxoraException {
|
|
744
|
-
statusCode = 422;
|
|
745
|
-
errors;
|
|
746
|
-
constructor(message, errors, context = {}) {
|
|
747
|
-
super(message, context);
|
|
748
|
-
this.name = "ValidationException";
|
|
749
|
-
this.errors = errors;
|
|
750
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
751
|
-
}
|
|
752
|
-
getErrors() {
|
|
753
|
-
return this.errors;
|
|
754
|
-
}
|
|
755
|
-
};
|
|
756
|
-
|
|
757
2564
|
// src/endpoints/VatEndpoint.ts
|
|
758
|
-
var
|
|
2565
|
+
var DATE_REGEX2 = /^\d{4}-\d{2}-\d{2}$/;
|
|
759
2566
|
var VatEndpoint = class {
|
|
760
2567
|
constructor(baseUrl, apiKey, tokenStorage, httpClient) {
|
|
761
2568
|
this.baseUrl = baseUrl;
|
|
@@ -920,7 +2727,7 @@ var VatEndpoint = class {
|
|
|
920
2727
|
const day = String(date.getDate()).padStart(2, "0");
|
|
921
2728
|
return `${year}-${month}-${day}`;
|
|
922
2729
|
}
|
|
923
|
-
if (!
|
|
2730
|
+
if (!DATE_REGEX2.test(date)) {
|
|
924
2731
|
throw new TaxoraException(`Invalid date format: "${date}". Expected YYYY-MM-DD.`);
|
|
925
2732
|
}
|
|
926
2733
|
return date;
|
|
@@ -1003,21 +2810,47 @@ var AuthRetryHttpClient = class {
|
|
|
1003
2810
|
}
|
|
1004
2811
|
};
|
|
1005
2812
|
|
|
2813
|
+
// src/version.ts
|
|
2814
|
+
var SDK_VERSION = "1.1.0";
|
|
2815
|
+
|
|
2816
|
+
// src/http/SdkVersionHttpClient.ts
|
|
2817
|
+
var SDK_VERSION_HEADER = "X-Taxora-SDK-Version";
|
|
2818
|
+
var SDK_VERSION_VALUE = `taxora-node/${SDK_VERSION}`;
|
|
2819
|
+
var SdkVersionHttpClient = class {
|
|
2820
|
+
constructor(inner) {
|
|
2821
|
+
this.inner = inner;
|
|
2822
|
+
}
|
|
2823
|
+
inner;
|
|
2824
|
+
async request(method, url, options) {
|
|
2825
|
+
const existing = options?.headers ?? {};
|
|
2826
|
+
const headers = {
|
|
2827
|
+
...existing,
|
|
2828
|
+
[SDK_VERSION_HEADER]: SDK_VERSION_VALUE
|
|
2829
|
+
};
|
|
2830
|
+
return this.inner.request(method, url, { ...options ?? {}, headers });
|
|
2831
|
+
}
|
|
2832
|
+
};
|
|
2833
|
+
|
|
1006
2834
|
// src/client/TaxoraClient.ts
|
|
1007
2835
|
var TaxoraClient = class {
|
|
1008
2836
|
auth;
|
|
1009
2837
|
vat;
|
|
1010
2838
|
company;
|
|
2839
|
+
smartEnrichment;
|
|
2840
|
+
eReporting;
|
|
1011
2841
|
baseUrl;
|
|
1012
2842
|
constructor(options) {
|
|
1013
2843
|
const environment = options.environment ?? Environment.SANDBOX;
|
|
1014
2844
|
const tokenStorage = options.tokenStorage ?? new InMemoryTokenStorage();
|
|
1015
2845
|
const httpClient = options.httpClient ?? new FetchHttpClient();
|
|
2846
|
+
const versionedClient = new SdkVersionHttpClient(httpClient);
|
|
1016
2847
|
this.baseUrl = getBaseUrl(environment);
|
|
1017
|
-
this.auth = new AuthEndpoint(this.baseUrl, options.apiKey, tokenStorage,
|
|
1018
|
-
const retryClient = new AuthRetryHttpClient(
|
|
2848
|
+
this.auth = new AuthEndpoint(this.baseUrl, options.apiKey, tokenStorage, versionedClient);
|
|
2849
|
+
const retryClient = new AuthRetryHttpClient(versionedClient, tokenStorage, () => this.auth.refresh());
|
|
1019
2850
|
this.vat = new VatEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient);
|
|
1020
2851
|
this.company = new CompanyEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient);
|
|
2852
|
+
this.smartEnrichment = new SmartEnrichmentEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient);
|
|
2853
|
+
this.eReporting = new EReportingEndpoint(this.baseUrl, options.apiKey, tokenStorage, retryClient);
|
|
1021
2854
|
}
|
|
1022
2855
|
};
|
|
1023
2856
|
|
|
@@ -1046,15 +2879,36 @@ var Language = {
|
|
|
1046
2879
|
AuthenticationException,
|
|
1047
2880
|
CompanyAddress,
|
|
1048
2881
|
CompanyEndpoint,
|
|
2882
|
+
ComplianceEnrollment,
|
|
2883
|
+
ComplianceEnrollmentPage,
|
|
2884
|
+
ComplianceEnrollmentStatus,
|
|
2885
|
+
ComplianceTaxReport,
|
|
2886
|
+
ComplianceTaxReportPage,
|
|
2887
|
+
ComplianceTaxReportState,
|
|
2888
|
+
ComplianceTransaction,
|
|
2889
|
+
ComplianceTransactionPage,
|
|
2890
|
+
ComplianceTransactionState,
|
|
2891
|
+
ComplianceTransactionType,
|
|
2892
|
+
EReportingEndpoint,
|
|
1049
2893
|
Environment,
|
|
1050
2894
|
FetchHttpClient,
|
|
1051
2895
|
HttpException,
|
|
2896
|
+
ImportResult,
|
|
1052
2897
|
InMemoryTokenStorage,
|
|
1053
2898
|
Language,
|
|
1054
2899
|
LoginIdentifier,
|
|
1055
2900
|
ProviderDocument,
|
|
1056
2901
|
ProviderDocumentLine,
|
|
2902
|
+
RevenueStatistics,
|
|
1057
2903
|
ScoreBreakdown,
|
|
2904
|
+
SireneLookupResult,
|
|
2905
|
+
SmartEnrichmentEndpoint,
|
|
2906
|
+
SmartEnrichmentHistoryPage,
|
|
2907
|
+
SmartEnrichmentHistoryRow,
|
|
2908
|
+
SmartEnrichmentJob,
|
|
2909
|
+
SmartEnrichmentResource,
|
|
2910
|
+
SmartEnrichmentStatistics,
|
|
2911
|
+
SmartEnrichmentStatus,
|
|
1058
2912
|
TaxoraClient,
|
|
1059
2913
|
TaxoraClientFactory,
|
|
1060
2914
|
TaxoraException,
|
|
@@ -1063,11 +2917,22 @@ var Language = {
|
|
|
1063
2917
|
VatCertificateExport,
|
|
1064
2918
|
VatCollection,
|
|
1065
2919
|
VatEndpoint,
|
|
2920
|
+
VatRates,
|
|
1066
2921
|
VatResource,
|
|
1067
2922
|
VatState,
|
|
1068
2923
|
VatValidationAddressInput,
|
|
2924
|
+
describeComplianceEnrollmentStatus,
|
|
2925
|
+
describeComplianceTaxReportState,
|
|
2926
|
+
describeComplianceTransactionState,
|
|
2927
|
+
describeComplianceTransactionType,
|
|
2928
|
+
describeSmartEnrichmentStatus,
|
|
1069
2929
|
describeVatState,
|
|
1070
2930
|
getBaseUrl,
|
|
1071
|
-
getFailedVatStates
|
|
2931
|
+
getFailedVatStates,
|
|
2932
|
+
toComplianceEnrollmentStatus,
|
|
2933
|
+
toComplianceTaxReportState,
|
|
2934
|
+
toComplianceTransactionState,
|
|
2935
|
+
toComplianceTransactionType,
|
|
2936
|
+
toSmartEnrichmentStatus
|
|
1072
2937
|
});
|
|
1073
2938
|
//# sourceMappingURL=index.cjs.map
|