@placeshakr/config 10.29.4 → 10.31.0-alpha.2

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.
Files changed (62) hide show
  1. package/dist/auth/policy.js +6 -0
  2. package/dist/auth/policy.js.map +1 -1
  3. package/dist/billing/index.js +9 -0
  4. package/dist/billing/index.js.map +1 -0
  5. package/dist/billing/pennylane.js +400 -0
  6. package/dist/billing/pennylane.js.map +1 -0
  7. package/dist/billing/permissions.js +27 -0
  8. package/dist/billing/permissions.js.map +1 -0
  9. package/dist/billing/prefill.js +208 -0
  10. package/dist/billing/prefill.js.map +1 -0
  11. package/dist/billing/types.js +3 -0
  12. package/dist/billing/types.js.map +1 -0
  13. package/dist/billing/validate.js +189 -0
  14. package/dist/billing/validate.js.map +1 -0
  15. package/dist/environment/base.js +28 -0
  16. package/dist/environment/base.js.map +1 -1
  17. package/dist/environment/decorators.js +2 -0
  18. package/dist/environment/decorators.js.map +1 -1
  19. package/dist/helpers/index.js +1 -0
  20. package/dist/helpers/index.js.map +1 -1
  21. package/dist/index.js +3 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/types/auth/policy.d.ts +2 -1
  24. package/dist/types/auth/policy.d.ts.map +1 -1
  25. package/dist/types/billing/index.d.ts +6 -0
  26. package/dist/types/billing/index.d.ts.map +1 -0
  27. package/dist/types/billing/pennylane.d.ts +191 -0
  28. package/dist/types/billing/pennylane.d.ts.map +1 -0
  29. package/dist/types/billing/permissions.d.ts +23 -0
  30. package/dist/types/billing/permissions.d.ts.map +1 -0
  31. package/dist/types/billing/prefill.d.ts +42 -0
  32. package/dist/types/billing/prefill.d.ts.map +1 -0
  33. package/dist/types/billing/types.d.ts +30 -0
  34. package/dist/types/billing/types.d.ts.map +1 -0
  35. package/dist/types/billing/validate.d.ts +48 -0
  36. package/dist/types/billing/validate.d.ts.map +1 -0
  37. package/dist/types/environment/base.d.ts.map +1 -1
  38. package/dist/types/environment/decorators.d.ts.map +1 -1
  39. package/dist/types/environment/types.d.ts +5 -0
  40. package/dist/types/environment/types.d.ts.map +1 -1
  41. package/dist/types/helpers/index.d.ts +1 -0
  42. package/dist/types/helpers/index.d.ts.map +1 -1
  43. package/dist/types/index.d.ts +2 -1
  44. package/dist/types/index.d.ts.map +1 -1
  45. package/dist/types/types.d.ts +491 -0
  46. package/dist/types/types.d.ts.map +1 -1
  47. package/dist/types.js +70 -1
  48. package/dist/types.js.map +1 -1
  49. package/package.json +2 -2
  50. package/src/auth/policy.ts +21 -1
  51. package/src/billing/index.ts +5 -0
  52. package/src/billing/pennylane.ts +530 -0
  53. package/src/billing/permissions.ts +25 -0
  54. package/src/billing/prefill.ts +309 -0
  55. package/src/billing/types.ts +32 -0
  56. package/src/billing/validate.ts +198 -0
  57. package/src/environment/base.ts +30 -0
  58. package/src/environment/decorators.ts +2 -0
  59. package/src/environment/types.ts +5 -0
  60. package/src/helpers/index.ts +2 -0
  61. package/src/index.ts +2 -0
  62. package/src/types.ts +524 -0
package/src/types.ts CHANGED
@@ -527,6 +527,8 @@ export interface Enterprise extends Resource {
527
527
  whatsapp?: boolean;
528
528
  marketplace?: boolean;
529
529
  multiProfessionals?: boolean;
530
+ /** PennyLane integration: enables the Bills listing and the sync. */
531
+ pennylane?: boolean;
530
532
  };
531
533
 
532
534
  /**
@@ -690,6 +692,13 @@ export interface User extends Resource {
690
692
  type Permissions = Record<string, boolean>;
691
693
 
692
694
  export interface Profile extends Resource {
695
+ /**
696
+ * The third party's billing data. It lives on Profile — and not on Client,
697
+ * Pro and Seller separately — because all three inherit from it and the SDK
698
+ * writes against this type. See [[BillingIdentity]] and `config/src/billing`.
699
+ */
700
+ billing?: BillingIdentity;
701
+
693
702
  /**
694
703
  *
695
704
  */
@@ -1105,6 +1114,12 @@ export interface Commissions {
1105
1114
  * Represents an provider
1106
1115
  */
1107
1116
  export interface Provider extends Resource {
1117
+ /**
1118
+ * Datos de facturacion. Se completa de forma incremental al facturar.
1119
+ * Ver [[BillingIdentity]] y `config/src/billing`.
1120
+ */
1121
+ billing?: BillingIdentity;
1122
+
1108
1123
  /**
1109
1124
  * The provider name
1110
1125
  */
@@ -2493,9 +2508,33 @@ export type Bill = Resource & {
2493
2508
  // used to save information related with any possible external system
2494
2509
  metadata?: {
2495
2510
  sentToIpaidthat?: boolean;
2511
+ /** @deprecated use metadata.pennylane. Kept until email delivery is retired. */
2496
2512
  sentToPennyLane?: boolean;
2513
+ /** @deprecated usar metadata.pennylane.lastSyncAt */
2497
2514
  sentToPennyLaneDate?: number;
2515
+ /**
2516
+ * PennyLane sync state. Replaces the two booleans above: it holds the
2517
+ * accounting id, the hash of the last payload sent (idempotency) and the
2518
+ * error, so a retry never duplicates.
2519
+ */
2520
+ pennylane?: PennylaneBillSync;
2498
2521
  };
2522
+
2523
+ /**
2524
+ * Where the document came from when it was not created in Articho. Bills
2525
+ * whose source is not undefined are neither edited nor deleted from the app:
2526
+ * the authority on that is firestore.rules.
2527
+ */
2528
+ source?: 'pennylane';
2529
+ imported?: boolean;
2530
+
2531
+ /**
2532
+ * Billing data of the recipient when they have no record of their own
2533
+ * (fournisseur de matériaux, de services and personnalisé). For CLIENT, PRO
2534
+ * and PROVIDER it lives on the third party's record. See
2535
+ * `config/src/billing`.
2536
+ */
2537
+ billing?: BillingIdentity;
2499
2538
  };
2500
2539
 
2501
2540
  export type BillReceived = Bill & {
@@ -2656,6 +2695,12 @@ export type Price = {
2656
2695
  * Represents a materials provider
2657
2696
  */
2658
2697
  export interface MaterialsProvider extends Resource {
2698
+ /**
2699
+ * Datos de facturacion. Se completa de forma incremental al facturar.
2700
+ * Ver [[BillingIdentity]] y `config/src/billing`.
2701
+ */
2702
+ billing?: BillingIdentity;
2703
+
2659
2704
  /**
2660
2705
  * The material provider name
2661
2706
  */
@@ -4563,3 +4608,482 @@ export enum EmailEventsEnum {
4563
4608
  RESET_USER_PASSWORD = 'RESET_USER_PASSWORD',
4564
4609
  DOCUMENTS_ISSUES = 'DOCUMENTS_ISSUES',
4565
4610
  }
4611
+
4612
+ /* -------------------------------------------------------------------------- */
4613
+ /* PennyLane */
4614
+ /* -------------------------------------------------------------------------- */
4615
+
4616
+ /** Sync state of one specific bill against PennyLane. */
4617
+ export type PennylaneBillSync = {
4618
+ status: 'PENDING' | 'SYNCED' | 'FAILED' | 'SKIPPED';
4619
+ /** Invoice id in PennyLane. */
4620
+ invoiceId?: string;
4621
+ /** Id of the credited invoice in PennyLane (for credit notes). */
4622
+ creditedInvoiceId?: string;
4623
+ /** Id of the PennyLane credit note that cancels this invoice. */
4624
+ creditNoteId?: string;
4625
+ creditNoteNumber?: string;
4626
+ creditNoteStatus?: 'PENDING' | 'SYNCED' | 'FAILED' | 'SKIPPED';
4627
+ creditNoteError?: string;
4628
+ /** Mirror document under enterprises/{id}/importedBills. */
4629
+ importedBillId?: string;
4630
+ fileAttachmentId?: string;
4631
+ /**
4632
+ * Hash of the payload sent. PennyLane offers no Idempotency-Key, so
4633
+ * deduplication is ours: same hash as the last SYNCED, nothing is resent.
4634
+ */
4635
+ payloadHash?: string;
4636
+ attempts?: number;
4637
+ lastAttemptAt?: number;
4638
+ lastSyncAt?: number;
4639
+ syncedAt?: number;
4640
+ error?: { code: string; message: string; status?: number };
4641
+ };
4642
+
4643
+ /** Which field of the PennyLane invoice each reference is read from. */
4644
+ export type PennylaneReferenceConfig = {
4645
+ /** Field where the supplier writes the chantier reference. */
4646
+ projectField: 'label' | 'invoice_number' | 'lines';
4647
+ /** Field where the supplier writes the devis reference. */
4648
+ devisField: 'label' | 'invoice_number' | 'lines';
4649
+ /** Regular expression with a single capture group. */
4650
+ projectPattern?: string;
4651
+ devisPattern?: string;
4652
+ };
4653
+
4654
+ export type PennylaneIgnoredSupplier = {
4655
+ name: string;
4656
+ regNo?: string | null;
4657
+ pennylaneId?: string | null;
4658
+ ignoredAt: number;
4659
+ ignoredBy?: string | null;
4660
+ };
4661
+
4662
+ /** Per-enterprise PennyLane configuration: enterprises/{id}/configurations/pennylane */
4663
+ export type PennylaneConfiguration = {
4664
+ enabled: boolean;
4665
+ /** Numeric id of the company in PennyLane (e.g. '156553'). */
4666
+ companyId?: string;
4667
+ push: { issued: boolean; received: boolean };
4668
+ pull: { supplierInvoices: boolean };
4669
+ /** false = send aggregate amounts + PDF only. */
4670
+ sendLineItems: boolean;
4671
+ /** true while the accounting mapping is not settled with the accountant. */
4672
+ importAsIncomplete: boolean;
4673
+ references: PennylaneReferenceConfig;
4674
+ /** PennyLane states that are not pulled (drafts and initial noise). */
4675
+ excludedStates?: string[];
4676
+ /** Days to look back on the initial load or a full resync. */
4677
+ lookbackDays?: number;
4678
+ defaultLedgerAccountId?: string;
4679
+ ledgerAccountByCategory?: Record<string, string>;
4680
+ /** Analytical breakdown per chantier. See [[PennylaneCategoryConfig]]. */
4681
+ categories?: PennylaneCategoryConfig;
4682
+ /** Suppliers whose invoices are ignored automatically on sync. */
4683
+ ignoredSuppliers?: PennylaneIgnoredSupplier[];
4684
+ /** Sync state. Written by the Cloud Functions only. */
4685
+ sync?: {
4686
+ supplierInvoices?: PennylaneSyncState;
4687
+ customerInvoices?: PennylaneSyncState;
4688
+ };
4689
+ };
4690
+
4691
+ /**
4692
+ * Analytical breakdown per chantier: one PennyLane category per Articho
4693
+ * project, the same one for that project's issued and received invoices.
4694
+ *
4695
+ * The category GROUP cannot be created through the API: a person creates it in
4696
+ * PennyLane and its id is pasted here. And categories, once created, can NOT
4697
+ * be deleted through the API — only renamed — so they are created lazily: the
4698
+ * first time a project receives or issues an invoice, never when the project
4699
+ * is created. A project that never invoices does not pollute the chart.
4700
+ */
4701
+ export type PennylaneCategoryConfig = {
4702
+ /** Master switch. Without it the sync never touches categories. */
4703
+ enabled: boolean;
4704
+ /**
4705
+ * Id of the group created by hand in PennyLane (e.g. "Chantiers Articho").
4706
+ * It differs per enterprise: they are separate PennyLane workspaces.
4707
+ */
4708
+ groupId: number;
4709
+ /** Also categorise the invoices Articho issues. */
4710
+ includeCustomerInvoices?: boolean;
4711
+ };
4712
+
4713
+ export type PennylaneSyncState = {
4714
+ /**
4715
+ * Timestamp of the last change processed. PennyLane's changelog only retains
4716
+ * 4 weeks: if this falls behind, data is lost.
4717
+ */
4718
+ checkpoint: number;
4719
+ lastRunAt: number;
4720
+ lastError?: string | null;
4721
+ /**
4722
+ * Invoices that failed and must be retried on the next run.
4723
+ *
4724
+ * It exists so the checkpoint can advance even when an invoice fails. The
4725
+ * alternative — holding the checkpoint back whenever there are errors —
4726
+ * looks safer and is not: a single invoice that always fails (a corrupt PDF,
4727
+ * a supplier that never resolves) would freeze the whole enterprise's sync,
4728
+ * reprocessing an ever-growing window until the function times out.
4729
+ */
4730
+ pending?: PennylanePendingInvoice[];
4731
+ };
4732
+
4733
+ /** An invoice awaiting retry, with its attempt count. */
4734
+ export type PennylanePendingInvoice = {
4735
+ /** Invoice id in PennyLane. */
4736
+ id: string;
4737
+ /** Attempts used. On reaching [[PENNYLANE_MAX_RETRIES]] it is abandoned. */
4738
+ attempts: number;
4739
+ /** Last error, so the reason is visible without opening the logs. */
4740
+ lastError: string;
4741
+ /** When it last failed. */
4742
+ lastAttemptAt: number;
4743
+ };
4744
+
4745
+ export enum ImportedBillStatus {
4746
+ /** Arrived from PennyLane; project or devis could not be resolved. */
4747
+ PENDING_ASSIGNMENT = 'PENDING_ASSIGNMENT',
4748
+ /** Project and devis resolved: waiting for an administrator to confirm. */
4749
+ READY_TO_ASSIGN = 'READY_TO_ASSIGN',
4750
+ /** Already has a bill created inside a project. */
4751
+ ASSIGNED = 'ASSIGNED',
4752
+ /** Discarded by hand. */
4753
+ IGNORED = 'IGNORED',
4754
+ /** Duplicate of another imported invoice. */
4755
+ DUPLICATE = 'DUPLICATE',
4756
+ }
4757
+
4758
+ export enum PennylaneSyncEventType {
4759
+ IMPORTED = 'IMPORTED',
4760
+ EXTERNAL_STATUS_CHANGE = 'EXTERNAL_STATUS_CHANGE',
4761
+ BILL_STATUS_UPDATED = 'BILL_STATUS_UPDATED',
4762
+ ASSIGNED = 'ASSIGNED',
4763
+ IGNORED = 'IGNORED',
4764
+ ERROR = 'ERROR',
4765
+ }
4766
+
4767
+ /**
4768
+ * One event per thing that happens to an imported invoice. Without this, an
4769
+ * invoice that changes status on its own is indistinguishable from a bug.
4770
+ */
4771
+ export type PennylaneSyncEvent = {
4772
+ id: string;
4773
+ date: number;
4774
+ type: PennylaneSyncEventType;
4775
+ message: string;
4776
+ before?: Record<string, unknown>;
4777
+ after?: Record<string, unknown>;
4778
+ payload?: Record<string, unknown>;
4779
+ };
4780
+
4781
+ /**
4782
+ * Mirror of a PennyLane invoice inside Articho.
4783
+ *
4784
+ * It deliberately lives at enterprise level and not inside a project: an
4785
+ * invoice arriving electronically does not know which project it belongs to.
4786
+ * It is also the source of the "Bills" listing in the administrator menu.
4787
+ */
4788
+ export type ImportedBill = {
4789
+ id: string;
4790
+ source: 'pennylane';
4791
+ direction: 'supplier' | 'customer';
4792
+ /** Id in PennyLane. The deduplication key. */
4793
+ externalId: string;
4794
+ enterpriseId: string;
4795
+ status: ImportedBillStatus;
4796
+
4797
+ invoice: {
4798
+ reference: string;
4799
+ label?: string;
4800
+ date: number;
4801
+ dueDate?: number | null;
4802
+ currency: string;
4803
+ amountHT: number;
4804
+ amountTVA: number;
4805
+ amountTTC: number;
4806
+ isPaid: boolean;
4807
+ paidAt?: number | null;
4808
+ externalStatus?: string | null;
4809
+ /** How it got into PennyLane: Email, API, PA/PDP… */
4810
+ externalSource?: string | null;
4811
+ fileUrl?: string | null;
4812
+ };
4813
+
4814
+ counterparty: {
4815
+ name: string;
4816
+ regNo?: string | null;
4817
+ pennylaneId?: string | null;
4818
+ };
4819
+
4820
+ /** References exactly as they came on the invoice, and which field they came from. */
4821
+ references: {
4822
+ projectRef?: string | null;
4823
+ devisRef?: string | null;
4824
+ sources?: { project?: string; devis?: string };
4825
+ };
4826
+
4827
+ /** Automatic resolution. It never creates the bill on its own. */
4828
+ suggestion?: {
4829
+ projectId?: string | null;
4830
+ devisId?: string | null;
4831
+ reasons: string[];
4832
+ };
4833
+
4834
+ /** Association confirmed by an administrator. */
4835
+ assignment?: {
4836
+ projectId: string;
4837
+ devisId: string;
4838
+ billId: string;
4839
+ projectName?: string | null;
4840
+ projectReference?: string | null;
4841
+ devisName?: string | null;
4842
+ assignedBy: string;
4843
+ assignedAt: number;
4844
+ } | null;
4845
+
4846
+ lastSyncAt: number;
4847
+ createdAt: number;
4848
+ };
4849
+
4850
+ /* -------------------------------------------------------------------------- */
4851
+ /* Billing identity */
4852
+ /* -------------------------------------------------------------------------- */
4853
+
4854
+ /**
4855
+ * Postal address, broken down.
4856
+ *
4857
+ * The loose `address` field several entities already carry is not usable for
4858
+ * invoicing: PennyLane — and e-invoicing in general — requires street, postal
4859
+ * code, city and country as separate fields. And `GeoLocation` only stores
4860
+ * lat/lng, so there is nothing to derive them from.
4861
+ */
4862
+ export type PostalAddress = {
4863
+ address: string;
4864
+ postalCode: string;
4865
+ city: string;
4866
+ /** Two-letter ISO code: FR, ES, BE… */
4867
+ countryAlpha2: string;
4868
+ };
4869
+
4870
+ export enum BillingPaymentConditions {
4871
+ UPON_RECEIPT = 'upon_receipt',
4872
+ DAYS_7 = '7_days',
4873
+ DAYS_15 = '15_days',
4874
+ DAYS_30 = '30_days',
4875
+ DAYS_30_EOM = '30_days_end_of_month',
4876
+ DAYS_45 = '45_days',
4877
+ DAYS_45_EOM = '45_days_end_of_month',
4878
+ DAYS_60 = '60_days',
4879
+ }
4880
+
4881
+ export enum BillingLanguage {
4882
+ FR = 'fr_FR',
4883
+ EN = 'en_GB',
4884
+ DE = 'de_DE',
4885
+ ES = 'es_ES',
4886
+ }
4887
+
4888
+ /**
4889
+ * Everything needed to issue an invoice to this entity.
4890
+ *
4891
+ * It is deliberately the same object for the five billable entities (Client,
4892
+ * Pro, Seller, Provider, MaterialsProvider): one type, one validator and one
4893
+ * form, instead of five variants that drift apart.
4894
+ *
4895
+ * It is filled in incrementally: the PennyLane sending modal asks for whatever
4896
+ * is missing right before invoicing and saves it here, so it only ever gets
4897
+ * completed for the entities that actually get invoiced.
4898
+ */
4899
+ /**
4900
+ * Legal person or natural person.
4901
+ *
4902
+ * Not a cosmetic detail: it decides what the law requires and which PennyLane
4903
+ * endpoint is used. An invoice to a company falls under e-invoicing — SIREN
4904
+ * mandatory, transmitted over the network; one to a private individual is out
4905
+ * of scope and only produces e-reporting, with no client identity.
4906
+ *
4907
+ * `undefined` means "we do not know yet", which is different from the other
4908
+ * two: the form has to ask, not assume.
4909
+ */
4910
+ export type BillingLegalType = 'company' | 'individual';
4911
+
4912
+ export type BillingIdentity = {
4913
+ /** Company or private individual. See [[BillingLegalType]]. */
4914
+ legalType?: BillingLegalType;
4915
+
4916
+ /**
4917
+ * Legal name. Mandatory for companies.
4918
+ *
4919
+ * It is not asked of an individual: it is composed from first and last name
4920
+ * by [[billingDisplayName]], so the same fact does not live in two places
4921
+ * and end up saying different things.
4922
+ */
4923
+ legalName: string;
4924
+
4925
+ /** First name. Mandatory for individuals; PennyLane wants it separate. */
4926
+ firstName?: string;
4927
+ /** Last name. Mandatory for individuals. */
4928
+ lastName?: string;
4929
+ /** Billing address. Mandatory. */
4930
+ address: PostalAddress;
4931
+ /** Delivery address, when it differs from the billing one. */
4932
+ deliveryAddress?: PostalAddress;
4933
+ /** SIREN (9 digits) or SIRET (14). */
4934
+ registrationNumber?: string;
4935
+ /** Intra-community VAT number. Not to be confused with the VAT rate. */
4936
+ vatNumber?: string;
4937
+ /** Addresses the invoice is sent to. */
4938
+ emails?: string[];
4939
+ phone?: string;
4940
+ /** Recipient person or department inside the company. */
4941
+ recipient?: string;
4942
+ paymentConditions?: BillingPaymentConditions;
4943
+ language?: BillingLanguage;
4944
+ /** Notes attached to the third party's record. */
4945
+ notes?: string;
4946
+ /**
4947
+ * The third party's id in PennyLane, cached after the first invoice. It
4948
+ * avoids looking it up again and, above all, avoids duplicating the record.
4949
+ */
4950
+ pennylaneCustomerId?: string;
4951
+
4952
+ /**
4953
+ * What the public register says about the company, exactly as it was last
4954
+ * read. It is not printed on the invoice: it is the provenance of what is
4955
+ * above. See [[BillingInseeData]].
4956
+ */
4957
+ insee?: BillingInseeData;
4958
+
4959
+ /**
4960
+ * What went wrong the last time this record was completed from the public
4961
+ * registers. Meant to be rendered as a tooltip. See [[BillingEnrichment]].
4962
+ */
4963
+ enrichment?: BillingEnrichment;
4964
+
4965
+ updatedAt?: number;
4966
+ updatedBy?: string;
4967
+ };
4968
+
4969
+ /**
4970
+ * What the public register says about a third party's company.
4971
+ *
4972
+ * Written by `scripts/enrich-billing-from-insee.js`. It hangs off
4973
+ * [[BillingIdentity]] alongside the rest of what invoicing needs, but in its
4974
+ * own block: the fields above are what gets printed on the invoice and a human
4975
+ * may correct them; this is what the register says and it is rewritten on
4976
+ * every pass.
4977
+ */
4978
+ export interface BillingInseeData {
4979
+ /** SIREN, 9 digits. */
4980
+ siren?: string;
4981
+ /** SIRET of the establishment queried, 14 digits. */
4982
+ siret?: string;
4983
+ /** Whether the establishment queried is the registered office. */
4984
+ siege?: boolean;
4985
+ /** Legal form (`categorieJuridiqueUniteLegale`). */
4986
+ legalForm?: string | null;
4987
+ /** APE/NAF code (`activitePrincipaleUniteLegale`). */
4988
+ nafCode?: string | null;
4989
+ /** Legal unit state: `A` active, `C` ceased. */
4990
+ state?: string | null;
4991
+ /** Establishment state: `A` open, `F` closed. */
4992
+ establishmentState?: string | null;
4993
+ /** Trade name, when it differs from the legal name. */
4994
+ tradeName?: string | null;
4995
+ /** How it was resolved: `siret`, `siege` or `siege-fallback`. */
4996
+ matchedBy?: string;
4997
+ /**
4998
+ * Set only when the SIREN was absent from the record and was deduced by
4999
+ * searching on the legal name. It keeps a supplied fact distinguishable from
5000
+ * an inferred one.
5001
+ */
5002
+ sirenFoundBy?: string;
5003
+ /** Result of checking the VAT number against VIES. */
5004
+ vatCheck?: BillingVatCheck;
5005
+ /** When the register was last queried. */
5006
+ checkedAt?: number;
5007
+ }
5008
+
5009
+ /**
5010
+ * Validation of the intra-community VAT number against the VIES register.
5011
+ *
5012
+ * INSEE does not publish the number: it is computed from the SIREN, and the
5013
+ * formula always returns something well-formed, including for someone under
5014
+ * franchise en base who has no real number. `valid: false` means the number
5015
+ * does not exist, not that it is malformed.
5016
+ */
5017
+ export interface BillingVatCheck {
5018
+ /** The number that was checked. */
5019
+ number: string;
5020
+ status: 'VALID' | 'INVALID' | 'UNAVAILABLE';
5021
+ /** `null` when VIES did not answer: unknown, which is not the same as no. */
5022
+ valid: boolean | null;
5023
+ reason?: string | null;
5024
+ source: string;
5025
+ checkedAt: number;
5026
+ }
5027
+
5028
+ /**
5029
+ * Severity of an enrichment issue.
5030
+ *
5031
+ * - `ok` the record was completed with nothing worth flagging.
5032
+ * - `warning` it was completed, but something is worth a look.
5033
+ * - `error` it could not be completed: the identifier is missing, it is not
5034
+ * in the register, or the lookup failed.
5035
+ */
5036
+ export type BillingEnrichmentLevel = 'ok' | 'warning' | 'error';
5037
+
5038
+ /**
5039
+ * Code for each issue. It exists so they can be filtered and counted without
5040
+ * parsing the text, which is written to be read and may be reworded.
5041
+ */
5042
+ export enum BillingEnrichmentCode {
5043
+ /** The record carries neither SIREN nor SIRET. */
5044
+ NO_IDENTIFIER = 'NO_IDENTIFIER',
5045
+ /** Several companies share that legal name: a human must choose. */
5046
+ SIREN_AMBIGUOUS = 'SIREN_AMBIGUOUS',
5047
+ /** The identifier does not appear in the register. */
5048
+ NOT_FOUND = 'NOT_FOUND',
5049
+ /** The legal unit is recorded as ceased. */
5050
+ COMPANY_CLOSED = 'COMPANY_CLOSED',
5051
+ /** The establishment is closed; the company may still be alive. */
5052
+ ESTABLISHMENT_CLOSED = 'ESTABLISHMENT_CLOSED',
5053
+ /** The VAT number is unknown to VIES. Likely franchise en base. */
5054
+ VAT_NOT_REGISTERED = 'VAT_NOT_REGISTERED',
5055
+ /** VIES did not answer: the number was stored unverified. */
5056
+ VAT_UNVERIFIED = 'VAT_UNVERIFIED',
5057
+ /** VIES returns a legal name different from INSEE's. */
5058
+ VAT_NAME_MISMATCH = 'VAT_NAME_MISMATCH',
5059
+ /** Establishment outside France: the country must be filled in by hand. */
5060
+ FOREIGN_ADDRESS = 'FOREIGN_ADDRESS',
5061
+ MISSING_POSTAL_CODE = 'MISSING_POSTAL_CODE',
5062
+ MISSING_STREET = 'MISSING_STREET',
5063
+ /** The register lookup failed (network, quota, credentials). */
5064
+ LOOKUP_ERROR = 'LOOKUP_ERROR',
5065
+ }
5066
+
5067
+ /**
5068
+ * What happened the last time this record's billing data was completed from
5069
+ * the public registers.
5070
+ *
5071
+ * `text` is the field meant to be displayed: plain text, one message per line,
5072
+ * ready for a `title` or a tooltip. `messages` and `codes` are there for
5073
+ * whoever prefers to render them separately or filter by issue type.
5074
+ *
5075
+ * The whole block is rewritten on every pass. Its absence means the record was
5076
+ * never reviewed; `level` being `ok` means it was reviewed and there was
5077
+ * nothing to flag.
5078
+ */
5079
+ export interface BillingEnrichment {
5080
+ /** One message per line, separated by `\n`. Empty when `level` is `ok`. */
5081
+ text: string;
5082
+ /** The same messages, unjoined. */
5083
+ messages: string[];
5084
+ codes: BillingEnrichmentCode[];
5085
+ level: BillingEnrichmentLevel;
5086
+ /** Who wrote it, e.g. `insee-script`. */
5087
+ source: string;
5088
+ checkedAt: number;
5089
+ }