@sixtyninecommerce/admin 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (179) hide show
  1. package/README.md +2739 -17
  2. package/dist/api-tokens/index.d.ts +15 -5
  3. package/dist/api-tokens/index.js +1 -0
  4. package/dist/apps/event-subscription.d.ts +59 -0
  5. package/dist/apps/event-subscription.js +32 -0
  6. package/dist/apps/hook-secret.d.ts +22 -0
  7. package/dist/apps/hook-secret.js +36 -0
  8. package/dist/apps/index.d.ts +54 -3
  9. package/dist/apps/index.js +17 -0
  10. package/dist/audit/index.d.ts +7 -0
  11. package/dist/auth/queries.d.ts +5 -1
  12. package/dist/auth/queries.js +6 -0
  13. package/dist/bulk/index.d.ts +323 -0
  14. package/dist/bulk/index.js +162 -0
  15. package/dist/catalog/assets.d.ts +147 -0
  16. package/dist/catalog/assets.js +164 -0
  17. package/dist/catalog/collections.d.ts +109 -0
  18. package/dist/catalog/collections.js +91 -0
  19. package/dist/catalog/facets.d.ts +103 -0
  20. package/dist/catalog/facets.js +100 -0
  21. package/dist/catalog/index.d.ts +115 -0
  22. package/dist/catalog/index.js +21 -0
  23. package/dist/catalog/options.d.ts +89 -0
  24. package/dist/catalog/options.js +88 -0
  25. package/dist/catalog/products-bulk.d.ts +21 -0
  26. package/dist/catalog/products-bulk.js +58 -0
  27. package/dist/catalog/products.d.ts +650 -0
  28. package/dist/catalog/products.js +458 -0
  29. package/dist/catalog/properties.d.ts +234 -0
  30. package/dist/catalog/properties.js +158 -0
  31. package/dist/catalog/types.d.ts +174 -0
  32. package/dist/catalog/types.js +141 -0
  33. package/dist/catalog/variants.d.ts +324 -0
  34. package/dist/catalog/variants.js +288 -0
  35. package/dist/catalog/visibility.d.ts +57 -0
  36. package/dist/catalog/visibility.js +59 -0
  37. package/dist/client.d.ts +192 -3
  38. package/dist/client.js +87 -12
  39. package/dist/compliance/index.d.ts +88 -0
  40. package/dist/compliance/index.js +88 -0
  41. package/dist/customer-data-redaction.d.ts +14 -0
  42. package/dist/customer-data-redaction.js +22 -0
  43. package/dist/customers/index.d.ts +428 -17
  44. package/dist/customers/index.js +322 -15
  45. package/dist/documents/index.d.ts +513 -16
  46. package/dist/documents/index.js +229 -3
  47. package/dist/events/index.d.ts +259 -0
  48. package/dist/events/index.js +147 -0
  49. package/dist/feeds/ai.d.ts +46 -0
  50. package/dist/feeds/ai.js +43 -0
  51. package/dist/feeds/categories.d.ts +50 -0
  52. package/dist/feeds/categories.js +56 -0
  53. package/dist/feeds/configs.d.ts +54 -0
  54. package/dist/feeds/configs.js +85 -0
  55. package/dist/feeds/identifier-fields.d.ts +25 -0
  56. package/dist/feeds/identifier-fields.js +29 -0
  57. package/dist/feeds/index.d.ts +54 -0
  58. package/dist/feeds/index.js +46 -0
  59. package/dist/feeds/preserve.d.ts +38 -0
  60. package/dist/feeds/preserve.js +74 -0
  61. package/dist/feeds/rules.d.ts +42 -0
  62. package/dist/feeds/rules.js +56 -0
  63. package/dist/feeds/types.d.ts +654 -0
  64. package/dist/feeds/types.js +135 -0
  65. package/dist/fulfillments/index.d.ts +437 -0
  66. package/dist/fulfillments/index.js +534 -0
  67. package/dist/heads/index.d.ts +60 -0
  68. package/dist/heads/index.js +45 -0
  69. package/dist/hooks/assignments.d.ts +90 -0
  70. package/dist/hooks/assignments.js +53 -0
  71. package/dist/hooks/index.d.ts +97 -0
  72. package/dist/hooks/index.js +76 -0
  73. package/dist/index.d.ts +95 -9
  74. package/dist/index.js +21 -1
  75. package/dist/integrations/index.d.ts +14 -0
  76. package/dist/integrations/index.js +9 -0
  77. package/dist/integrations/pipelines.d.ts +113 -0
  78. package/dist/integrations/pipelines.js +62 -0
  79. package/dist/integrations/types.d.ts +176 -0
  80. package/dist/integrations/types.js +8 -0
  81. package/dist/jobs/bulk-action-run.d.ts +74 -0
  82. package/dist/jobs/bulk-action-run.js +69 -0
  83. package/dist/locations/index.d.ts +6 -2
  84. package/dist/meta/index.d.ts +32 -0
  85. package/dist/orders/bulk.d.ts +75 -0
  86. package/dist/orders/bulk.js +150 -0
  87. package/dist/orders/commit-edit.d.ts +123 -0
  88. package/dist/orders/commit-edit.js +142 -0
  89. package/dist/orders/deposit-policy.d.ts +103 -0
  90. package/dist/orders/deposit-policy.js +202 -0
  91. package/dist/orders/get.d.ts +722 -0
  92. package/dist/orders/get.js +530 -0
  93. package/dist/orders/index.d.ts +186 -21
  94. package/dist/orders/index.js +57 -0
  95. package/dist/orders/line-price-preview.d.ts +297 -0
  96. package/dist/orders/line-price-preview.js +50 -0
  97. package/dist/orders/manual-discounts.d.ts +141 -0
  98. package/dist/orders/manual-discounts.js +97 -0
  99. package/dist/orders/manual-pricing.d.ts +192 -0
  100. package/dist/orders/manual-pricing.js +72 -0
  101. package/dist/orders/order-entry.d.ts +566 -0
  102. package/dist/orders/order-entry.js +129 -0
  103. package/dist/orders/parcel-charge.d.ts +45 -0
  104. package/dist/orders/parcel-charge.js +55 -0
  105. package/dist/orders/plan-edit.d.ts +489 -0
  106. package/dist/orders/plan-edit.js +93 -0
  107. package/dist/orders/status.d.ts +235 -0
  108. package/dist/orders/status.js +96 -0
  109. package/dist/orders/surcharges.d.ts +75 -2
  110. package/dist/orders/surcharges.js +110 -4
  111. package/dist/payments/account-credit.d.ts +171 -0
  112. package/dist/payments/account-credit.js +107 -0
  113. package/dist/payments/index.d.ts +241 -9
  114. package/dist/payments/index.js +92 -0
  115. package/dist/payments/methods.d.ts +37 -0
  116. package/dist/payments/methods.js +33 -0
  117. package/dist/platform/catalog.d.ts +148 -0
  118. package/dist/platform/catalog.js +74 -0
  119. package/dist/platform/entitlements.d.ts +111 -0
  120. package/dist/platform/entitlements.js +86 -0
  121. package/dist/platform/legal-entities.d.ts +139 -0
  122. package/dist/platform/legal-entities.js +126 -0
  123. package/dist/platform/legal-entity-numbering.d.ts +103 -0
  124. package/dist/platform/legal-entity-numbering.js +101 -0
  125. package/dist/platform/organization-membership.d.ts +80 -0
  126. package/dist/platform/organization-membership.js +71 -0
  127. package/dist/platform/organization-settings.d.ts +33 -0
  128. package/dist/platform/organization-settings.js +42 -0
  129. package/dist/platform/organization-sharing.d.ts +172 -0
  130. package/dist/platform/organization-sharing.js +120 -0
  131. package/dist/platform/organizations.d.ts +205 -0
  132. package/dist/platform/organizations.js +180 -0
  133. package/dist/platform/provision-store.d.ts +88 -8
  134. package/dist/platform/provision-store.js +12 -0
  135. package/dist/platform/reports.d.ts +46 -0
  136. package/dist/platform/reports.js +31 -0
  137. package/dist/platform/server-metrics.d.ts +58 -0
  138. package/dist/platform/server-metrics.js +11 -0
  139. package/dist/pos/index.d.ts +567 -0
  140. package/dist/pos/index.js +205 -0
  141. package/dist/pricing/index.d.ts +408 -0
  142. package/dist/pricing/index.js +353 -0
  143. package/dist/pricing/vouchers.d.ts +103 -0
  144. package/dist/pricing/vouchers.js +69 -0
  145. package/dist/provenance/index.d.ts +93 -0
  146. package/dist/provenance/index.js +53 -0
  147. package/dist/reports/index.d.ts +199 -0
  148. package/dist/reports/index.js +154 -0
  149. package/dist/returns/index.d.ts +225 -0
  150. package/dist/returns/index.js +160 -0
  151. package/dist/search/index.d.ts +99 -0
  152. package/dist/search/index.js +62 -0
  153. package/dist/shipping/parcel-count-suggestion.d.ts +52 -0
  154. package/dist/shipping/parcel-count-suggestion.js +73 -0
  155. package/dist/shipping/parcel-rule.d.ts +48 -0
  156. package/dist/shipping/parcel-rule.js +91 -0
  157. package/dist/stock/index.d.ts +166 -0
  158. package/dist/stock/index.js +115 -0
  159. package/dist/stock/transfers.d.ts +520 -0
  160. package/dist/stock/transfers.js +437 -0
  161. package/dist/stored-value/index.d.ts +154 -0
  162. package/dist/stored-value/index.js +130 -0
  163. package/dist/tenant/capabilities.d.ts +10 -0
  164. package/dist/tenant/entitlements.d.ts +35 -0
  165. package/dist/tenant/entitlements.js +15 -0
  166. package/dist/tenant/field-groups.d.ts +64 -0
  167. package/dist/tenant/field-groups.js +34 -0
  168. package/dist/tenant/legal-entity.d.ts +32 -0
  169. package/dist/tenant/legal-entity.js +41 -0
  170. package/dist/tenant/notifications.d.ts +148 -0
  171. package/dist/tenant/notifications.js +79 -0
  172. package/dist/tenant/retention.d.ts +10 -4
  173. package/dist/tenant/settings-sources.d.ts +103 -0
  174. package/dist/tenant/settings-sources.js +92 -0
  175. package/dist/types.d.ts +86 -11
  176. package/dist/uploads/index.d.ts +11 -7
  177. package/dist/users/index.d.ts +104 -0
  178. package/dist/users/index.js +80 -0
  179. package/package.json +3 -2
@@ -0,0 +1,139 @@
1
+ import { type Page, type Transport } from '@sixtyninecommerce/core';
2
+ import type { AdminClientConfig } from '../client.js';
3
+ import type { Call, ListOptions } from '../types.js';
4
+ import { type PlatformLegalEntityNumberingModule } from './legal-entity-numbering.js';
5
+ /**
6
+ * A company that issues a store's invoices (multi-region spec §7.1): its legal name, tax numbers,
7
+ * registered office and fiscal time zone. One or more stores trade under it. Its `id` is the
8
+ * engine's Seller id.
9
+ */
10
+ export interface LegalEntity {
11
+ id: string;
12
+ /** The Seller's name, set when it was created. Read-only: email store names fall back to it. */
13
+ name: string;
14
+ legalName: string | null;
15
+ vatNumber: string | null;
16
+ vatNumberUk: string | null;
17
+ eoriNumber: string | null;
18
+ registrationNumber: string | null;
19
+ registeredAddressLine1: string | null;
20
+ registeredAddressLine2: string | null;
21
+ registeredCity: string | null;
22
+ registeredPostalCode: string | null;
23
+ registeredProvince: string | null;
24
+ /** Upper-case ISO 3166-1 alpha-2. */
25
+ registeredCountry: string | null;
26
+ /** IANA time zone the fiscal year runs in (numbering resets), such as `Europe/Amsterdam`. */
27
+ timezone: string | null;
28
+ /** The entity's stores the caller may read; `storeCount` counts them all. */
29
+ stores: LegalEntityStore[];
30
+ storeCount: number;
31
+ /**
32
+ * Whether the caller may change it: a SuperAdmin, or a caller holding `UpdateSeller` on every one
33
+ * of its stores. Show the entity read-only when false.
34
+ */
35
+ editable: boolean;
36
+ /** ISO-8601 UTC. */
37
+ createdAt: string;
38
+ updatedAt: string;
39
+ }
40
+ export interface LegalEntityStore {
41
+ id: string;
42
+ code: string;
43
+ }
44
+ /**
45
+ * The legal fields of an entity. Values are trimmed by the engine. A field sent as `null` or `''`
46
+ * is cleared, the legal name aside; a field left out is kept.
47
+ */
48
+ export interface LegalEntityFields {
49
+ vatNumber?: string | null;
50
+ vatNumberUk?: string | null;
51
+ eoriNumber?: string | null;
52
+ registrationNumber?: string | null;
53
+ registeredAddressLine1?: string | null;
54
+ registeredAddressLine2?: string | null;
55
+ registeredCity?: string | null;
56
+ registeredPostalCode?: string | null;
57
+ registeredProvince?: string | null;
58
+ /** Upper-case ISO 3166-1 alpha-2, such as `NL`; anything else is `INVALID_COUNTRY_CODE`. */
59
+ registeredCountry?: string | null;
60
+ /** An IANA time zone; a fixed offset or an unknown name is `INVALID_TIMEZONE`. */
61
+ timezone?: string | null;
62
+ }
63
+ export interface CreateLegalEntityInput extends LegalEntityFields {
64
+ /** Required, and never empty: every invoice prints it. */
65
+ legalName: string;
66
+ /** Defaults to the legal name. */
67
+ name?: string;
68
+ }
69
+ export interface UpdateLegalEntityInput extends LegalEntityFields {
70
+ /** Changed when given; it can never be cleared (`LEGAL_ENTITY_FIELD_INVALID`). */
71
+ legalName?: string;
72
+ }
73
+ export interface LegalEntityListOptions extends ListOptions {
74
+ /** Matches the legal name, name, VAT or registration number, case-insensitively, as typed. */
75
+ term?: string;
76
+ }
77
+ /**
78
+ * `admin.platform.legalEntities` — the platform's legal entities (multi-region spec §7.1, decision
79
+ * 35 / Q9). Every method needs a human session: an API token or an app credential is refused with
80
+ * `PLATFORM_REQUIRES_SESSION` before anything is sent. A SuperAdmin needs no tenant on the client.
81
+ *
82
+ * - `list` and `create` are SuperAdmin-only (`FORBIDDEN` otherwise).
83
+ * - `get` answers the SuperAdmin any entity; anyone else only an entity whose every store they hold
84
+ * `ReadSettings` on, and `SHARED_SELLER_NOT_ALLOWED` (403) for one they hold it on only some
85
+ * stores of. Read the active store's entity with `admin.tenant.legalEntity` instead.
86
+ * - `update` needs `UpdateSeller` on every store of the entity (`SHARED_SELLER_NOT_ALLOWED`), and
87
+ * copies its legal name, VAT, EORI and registration numbers onto every one of them in the same
88
+ * transaction. The registered office and time zone are the entity's alone.
89
+ *
90
+ * An entity created with no store is not listed until a store is created under it, and only a
91
+ * SuperAdmin reads it by id. A store created under it, or moved onto it, takes its legal name and
92
+ * numbers.
93
+ *
94
+ * Neither write is deduplicated by an idempotency key (they are Admin API mutations). `update` is
95
+ * safe to repeat. `create` is not, and a lost answer cannot be recovered through this module: the
96
+ * new entity has no store yet, so `list` does not return it and its id went with the answer.
97
+ * Repeating the create makes a second entity, so confirm with the platform operator before you
98
+ * retry one whose outcome is unknown.
99
+ */
100
+ export interface PlatformLegalEntitiesModule {
101
+ /**
102
+ * Every legal entity with at least one store, by legal name. Pages default to 50; a `limit` above
103
+ * 100 is refused with `INVALID_LIMIT` (400), and walking on with `.next()` or `for await` reaches
104
+ * every one.
105
+ */
106
+ list(options?: LegalEntityListOptions): Promise<Page<LegalEntity>>;
107
+ /** Null when no legal entity has that id, or the caller may read none of its stores. */
108
+ get(id: string, call?: Call): Promise<LegalEntity | null>;
109
+ /**
110
+ * Creates a legal entity with no store yet. Refusals: `LEGAL_ENTITY_FIELD_INVALID`,
111
+ * `INVALID_COUNTRY_CODE`, `INVALID_TIMEZONE` (400).
112
+ */
113
+ create(input: CreateLegalEntityInput, call?: Call): Promise<LegalEntity>;
114
+ /**
115
+ * Changes the fields given. Refusals: `SHARED_SELLER_NOT_ALLOWED` (403), `ENTITY_NOT_FOUND`
116
+ * (404), `LEGAL_ENTITY_FIELD_INVALID`, `INVALID_COUNTRY_CODE`, `INVALID_TIMEZONE` (400).
117
+ */
118
+ update(id: string, input: UpdateLegalEntityInput, call?: Call): Promise<LegalEntity>;
119
+ /**
120
+ * The numbering series the entity's stores share (multi-region B6c): `get` needs `ReadSettings`
121
+ * and `update` `UpdateSettings`, on every store of the entity (`SHARED_SELLER_NOT_ALLOWED`).
122
+ */
123
+ numbering: PlatformLegalEntityNumberingModule;
124
+ }
125
+ export declare const LEGAL_ENTITY_FIELDS = "\n id\n name\n legalName\n vatNumber\n vatNumberUk\n eoriNumber\n registrationNumber\n registeredAddressLine1\n registeredAddressLine2\n registeredCity\n registeredPostalCode\n registeredProvince\n registeredCountry\n timezone\n stores {\n id\n code\n }\n storeCount\n editable\n createdAt\n updatedAt\n";
126
+ export declare const LEGAL_ENTITIES_QUERY = "\n query PlatformLegalEntities($options: LegalEntityListOptions) {\n legalEntities(options: $options) {\n totalItems\n items { \n id\n name\n legalName\n vatNumber\n vatNumberUk\n eoriNumber\n registrationNumber\n registeredAddressLine1\n registeredAddressLine2\n registeredCity\n registeredPostalCode\n registeredProvince\n registeredCountry\n timezone\n stores {\n id\n code\n }\n storeCount\n editable\n createdAt\n updatedAt\n }\n }\n }\n";
127
+ export declare const LEGAL_ENTITY_QUERY = "\n query PlatformLegalEntity($id: ID!) {\n legalEntity(id: $id) { \n id\n name\n legalName\n vatNumber\n vatNumberUk\n eoriNumber\n registrationNumber\n registeredAddressLine1\n registeredAddressLine2\n registeredCity\n registeredPostalCode\n registeredProvince\n registeredCountry\n timezone\n stores {\n id\n code\n }\n storeCount\n editable\n createdAt\n updatedAt\n }\n }\n";
128
+ export declare const CREATE_LEGAL_ENTITY_MUTATION = "\n mutation PlatformCreateLegalEntity($input: CreateLegalEntityInput!) {\n createLegalEntity(input: $input) { \n id\n name\n legalName\n vatNumber\n vatNumberUk\n eoriNumber\n registrationNumber\n registeredAddressLine1\n registeredAddressLine2\n registeredCity\n registeredPostalCode\n registeredProvince\n registeredCountry\n timezone\n stores {\n id\n code\n }\n storeCount\n editable\n createdAt\n updatedAt\n }\n }\n";
129
+ export declare const UPDATE_LEGAL_ENTITY_MUTATION = "\n mutation UpdateLegalEntity($id: ID!, $input: UpdateLegalEntityInput!) {\n updateLegalEntity(id: $id, input: $input) { \n id\n name\n legalName\n vatNumber\n vatNumberUk\n eoriNumber\n registrationNumber\n registeredAddressLine1\n registeredAddressLine2\n registeredCity\n registeredPostalCode\n registeredProvince\n registeredCountry\n timezone\n stores {\n id\n code\n }\n storeCount\n editable\n createdAt\n updatedAt\n }\n }\n";
130
+ /**
131
+ * The input as the engine declares it, field by field, so a caller spreading a wider object sends
132
+ * only what the input type has instead of failing validation. A field left out stays out (kept);
133
+ * `null` is sent as `null` (cleared).
134
+ */
135
+ export declare function legalEntityInputOf(input: LegalEntityFields & {
136
+ legalName?: string;
137
+ name?: string;
138
+ }): Record<string, string | null>;
139
+ export declare function createPlatformLegalEntitiesModule(transport: Transport, config: AdminClientConfig): PlatformLegalEntitiesModule;
@@ -0,0 +1,126 @@
1
+ import { pageFromVendureList, readOffsetCursor, } from '@sixtyninecommerce/core';
2
+ import { requireHumanSession } from './guard.js';
3
+ import { createPlatformLegalEntityNumberingModule, } from './legal-entity-numbering.js';
4
+ export const LEGAL_ENTITY_FIELDS = /* GraphQL */ `
5
+ id
6
+ name
7
+ legalName
8
+ vatNumber
9
+ vatNumberUk
10
+ eoriNumber
11
+ registrationNumber
12
+ registeredAddressLine1
13
+ registeredAddressLine2
14
+ registeredCity
15
+ registeredPostalCode
16
+ registeredProvince
17
+ registeredCountry
18
+ timezone
19
+ stores {
20
+ id
21
+ code
22
+ }
23
+ storeCount
24
+ editable
25
+ createdAt
26
+ updatedAt
27
+ `;
28
+ export const LEGAL_ENTITIES_QUERY = /* GraphQL */ `
29
+ query PlatformLegalEntities($options: LegalEntityListOptions) {
30
+ legalEntities(options: $options) {
31
+ totalItems
32
+ items { ${LEGAL_ENTITY_FIELDS} }
33
+ }
34
+ }
35
+ `;
36
+ export const LEGAL_ENTITY_QUERY = /* GraphQL */ `
37
+ query PlatformLegalEntity($id: ID!) {
38
+ legalEntity(id: $id) { ${LEGAL_ENTITY_FIELDS} }
39
+ }
40
+ `;
41
+ export const CREATE_LEGAL_ENTITY_MUTATION = /* GraphQL */ `
42
+ mutation PlatformCreateLegalEntity($input: CreateLegalEntityInput!) {
43
+ createLegalEntity(input: $input) { ${LEGAL_ENTITY_FIELDS} }
44
+ }
45
+ `;
46
+ export const UPDATE_LEGAL_ENTITY_MUTATION = /* GraphQL */ `
47
+ mutation UpdateLegalEntity($id: ID!, $input: UpdateLegalEntityInput!) {
48
+ updateLegalEntity(id: $id, input: $input) { ${LEGAL_ENTITY_FIELDS} }
49
+ }
50
+ `;
51
+ /** The engine's own default; it refuses a page above 100. */
52
+ const DEFAULT_PAGE_SIZE = 50;
53
+ const FIELD_NAMES = [
54
+ 'vatNumber',
55
+ 'vatNumberUk',
56
+ 'eoriNumber',
57
+ 'registrationNumber',
58
+ 'registeredAddressLine1',
59
+ 'registeredAddressLine2',
60
+ 'registeredCity',
61
+ 'registeredPostalCode',
62
+ 'registeredProvince',
63
+ 'registeredCountry',
64
+ 'timezone',
65
+ ];
66
+ /**
67
+ * The input as the engine declares it, field by field, so a caller spreading a wider object sends
68
+ * only what the input type has instead of failing validation. A field left out stays out (kept);
69
+ * `null` is sent as `null` (cleared).
70
+ */
71
+ export function legalEntityInputOf(input) {
72
+ const out = {};
73
+ for (const field of ['name', 'legalName', ...FIELD_NAMES]) {
74
+ const value = input[field];
75
+ if (value !== undefined)
76
+ out[field] = value;
77
+ }
78
+ return out;
79
+ }
80
+ export function createPlatformLegalEntitiesModule(transport, config) {
81
+ // Platform-wide, so a SuperAdmin must not need a tenant.
82
+ const unscoped = (call) => ({ ...call, allowUnscoped: true });
83
+ const listPage = async (skip, take, options) => {
84
+ requireHumanSession(config);
85
+ const variables = {
86
+ options: { skip, take, ...(options?.term === undefined ? {} : { term: options.term }) },
87
+ };
88
+ const data = await transport.graphql({ api: 'admin', query: LEGAL_ENTITIES_QUERY, variables }, unscoped(options));
89
+ return pageFromVendureList(data.legalEntities, skip, take, (cursor) => listPage(readOffsetCursor(cursor), take, options));
90
+ };
91
+ return {
92
+ numbering: createPlatformLegalEntityNumberingModule(transport, config),
93
+ async list(options) {
94
+ // Guarded here as well as per page: a bad cursor must not be reported ahead of the
95
+ // credential refusal.
96
+ requireHumanSession(config);
97
+ const take = options?.limit ?? DEFAULT_PAGE_SIZE;
98
+ const skip = options?.after === undefined ? 0 : readOffsetCursor(options.after);
99
+ return listPage(skip, take, options);
100
+ },
101
+ async get(id, call) {
102
+ requireHumanSession(config);
103
+ const data = await transport.graphql({ api: 'admin', query: LEGAL_ENTITY_QUERY, variables: { id } }, unscoped(call));
104
+ return data.legalEntity;
105
+ },
106
+ async create(input, call) {
107
+ requireHumanSession(config);
108
+ const data = await transport.graphql({
109
+ api: 'admin',
110
+ query: CREATE_LEGAL_ENTITY_MUTATION,
111
+ variables: { input: legalEntityInputOf(input) },
112
+ }, unscoped(call));
113
+ return data.createLegalEntity;
114
+ },
115
+ async update(id, input, call) {
116
+ requireHumanSession(config);
117
+ const { name: _ignored, ...fields } = input;
118
+ const data = await transport.graphql({
119
+ api: 'admin',
120
+ query: UPDATE_LEGAL_ENTITY_MUTATION,
121
+ variables: { id, input: legalEntityInputOf(fields) },
122
+ }, unscoped(call));
123
+ return data.updateLegalEntity;
124
+ },
125
+ };
126
+ }
@@ -0,0 +1,103 @@
1
+ import { type Transport } from '@sixtyninecommerce/core';
2
+ import type { AdminClientConfig } from '../client.js';
3
+ import type { Call } from '../types.js';
4
+ import type { LegalEntityStore } from './legal-entities.js';
5
+ /**
6
+ * A legal entity's numbering (multi-region B6c): the series its stores share. One store's invoice
7
+ * and credit-note numbers, and its AR credit notes where B2B credit is installed, are drawn from
8
+ * these, whichever store issues the document. A sandbox store numbers on its own rows and is not
9
+ * one of its stores here.
10
+ */
11
+ export interface LegalEntityNumbering {
12
+ /** The legal entity's id. */
13
+ legalEntityId: string;
14
+ series: LegalEntityNumberingSeries[];
15
+ /** The stores sharing the series that the caller may read; `storeCount` counts them all. */
16
+ stores: LegalEntityStore[];
17
+ storeCount: number;
18
+ /**
19
+ * Whether the caller may change it: a SuperAdmin, or a caller holding `UpdateSettings` on every
20
+ * store of the entity. Show the series read-only when false.
21
+ */
22
+ editable: boolean;
23
+ }
24
+ /** The series the engine numbers: `invoice`, `credit_note`, and `ar_credit_note` with B2B credit. */
25
+ export type LegalEntityNumberingSeriesName = 'invoice' | 'credit_note' | 'ar_credit_note';
26
+ export interface LegalEntityNumberingSeries {
27
+ series: LegalEntityNumberingSeriesName;
28
+ /**
29
+ * False while the entity has no shared series yet. A lone numbering store's first document then
30
+ * sets it up; with two or more (AR credit notes: two or more that issued), every store's
31
+ * documents are refused (`LEGAL_ENTITY_NUMBERING_UNSET`) until an `update` sets the series up,
32
+ * and any `update` does, even an empty one. Every field below is null then.
33
+ */
34
+ configured: boolean;
35
+ prefix: string | null;
36
+ suffix: string | null;
37
+ digits: number | null;
38
+ /** `none`, `short` (`26`) or `full` (`2026`). */
39
+ yearFormat: string | null;
40
+ /** Restart at 1 each fiscal year (in the entity's time zone); only with a year in the number. */
41
+ yearReset: boolean | null;
42
+ /** The next number the series issues. Read-only: only issuing a document moves it. */
43
+ nextNumber: number | null;
44
+ /** The fiscal year the series last restarted in. Read-only. */
45
+ lastResetYear: number | null;
46
+ /** `invoice` only: the provider that numbers it; null means each store's own setting. */
47
+ invoicingProvider: string | null;
48
+ }
49
+ /**
50
+ * A format change of one series. A field left out is kept; only the fields that differ from the
51
+ * entity's series count, so on a configured series sending back what was read changes nothing.
52
+ * On a series with `configured: false` any update, even an empty one, sets the series up.
53
+ */
54
+ export interface UpdateLegalEntityNumberingInput {
55
+ series: LegalEntityNumberingSeriesName;
56
+ /** At most 30 characters, never starting with `TEST-` (`NUMBER_PREFIX_RESERVED`). */
57
+ prefix?: string;
58
+ /** At most 30 characters. */
59
+ suffix?: string;
60
+ /** A whole number from 3 to 8 (`NUMBERING_DIGITS_INVALID`). */
61
+ digits?: number;
62
+ /** `none`, `short` or `full` (`NUMBERING_YEAR_FORMAT_INVALID`). */
63
+ yearFormat?: 'none' | 'short' | 'full';
64
+ /** Restart at 1 each fiscal year; it has no effect without a year in the number. */
65
+ yearReset?: boolean;
66
+ }
67
+ export declare const LEGAL_ENTITY_NUMBERING_FIELDS = "\n legalEntityId\n series {\n series\n configured\n prefix\n suffix\n digits\n yearFormat\n yearReset\n nextNumber\n lastResetYear\n invoicingProvider\n }\n stores {\n id\n code\n }\n storeCount\n editable\n";
68
+ export declare const LEGAL_ENTITY_NUMBERING_QUERY = "\n query LegalEntityNumbering($legalEntityId: ID) {\n legalEntityNumbering(legalEntityId: $legalEntityId) { \n legalEntityId\n series {\n series\n configured\n prefix\n suffix\n digits\n yearFormat\n yearReset\n nextNumber\n lastResetYear\n invoicingProvider\n }\n stores {\n id\n code\n }\n storeCount\n editable\n }\n }\n";
69
+ export declare const UPDATE_LEGAL_ENTITY_NUMBERING_MUTATION = "\n mutation UpdateLegalEntityNumbering($input: UpdateLegalEntityNumberingInput!) {\n updateLegalEntityNumbering(input: $input) { \n legalEntityId\n series {\n series\n configured\n prefix\n suffix\n digits\n yearFormat\n yearReset\n nextNumber\n lastResetYear\n invoicingProvider\n }\n stores {\n id\n code\n }\n storeCount\n editable\n }\n }\n";
70
+ /**
71
+ * The input as the engine declares it, field by field, so a caller spreading a series it read
72
+ * (which carries counters and `configured`) sends only the format, and a field left out stays out.
73
+ */
74
+ export declare function legalEntityNumberingInputOf(input: UpdateLegalEntityNumberingInput, legalEntityId?: string): Record<string, unknown>;
75
+ /**
76
+ * Refusals the engine answers on `update`: `SHARED_SELLER_NOT_ALLOWED` (403),
77
+ * `ENTITY_NOT_FOUND` (404), `NUMBERING_SERIES_INVALID`, `NUMBERING_YEAR_FORMAT_INVALID`,
78
+ * `NUMBERING_DIGITS_INVALID`, `NUMBERING_AFFIX_INVALID` (400), `NUMBER_PREFIX_RESERVED`,
79
+ * `LEGAL_ENTITY_NUMBERING_PROVIDERS_DIFFER`, `NUMBERING_RESTART_WOULD_REPEAT`,
80
+ * `NUMBERING_YEAR_FORMAT_UNKNOWN` (422).
81
+ */
82
+ export interface PlatformLegalEntityNumberingModule {
83
+ /**
84
+ * Null when no legal entity has that id, or the caller may read none of its stores;
85
+ * `SHARED_SELLER_NOT_ALLOWED` (403) when it may read only some of them.
86
+ */
87
+ get(legalEntityId: string, call?: Call): Promise<LegalEntityNumbering | null>;
88
+ /**
89
+ * Changes the format of one series, on the entity and on every store row of it, in one
90
+ * transaction, and sets the series up when it has none yet: it then continues past every number
91
+ * any store issued. Counters change only when an update sets a series up. Safe to repeat.
92
+ */
93
+ update(legalEntityId: string, input: UpdateLegalEntityNumberingInput, call?: Call): Promise<LegalEntityNumbering>;
94
+ }
95
+ /** The same, for the ACTIVE store's legal entity: one request each, no id needed. */
96
+ export interface TenantLegalEntityNumberingModule {
97
+ /** Null on a store with no legal entity, an organization's workspace and the root channel. */
98
+ get(call?: Call): Promise<LegalEntityNumbering | null>;
99
+ /** `ENTITY_NOT_FOUND` (404) on a store with no legal entity; otherwise as the platform's. */
100
+ update(input: UpdateLegalEntityNumberingInput, call?: Call): Promise<LegalEntityNumbering>;
101
+ }
102
+ export declare function createPlatformLegalEntityNumberingModule(transport: Transport, config: AdminClientConfig): PlatformLegalEntityNumberingModule;
103
+ export declare function createTenantLegalEntityNumberingModule(transport: Transport): TenantLegalEntityNumberingModule;
@@ -0,0 +1,101 @@
1
+ import { ValidationError } from '@sixtyninecommerce/core';
2
+ import { requireHumanSession } from './guard.js';
3
+ export const LEGAL_ENTITY_NUMBERING_FIELDS = /* GraphQL */ `
4
+ legalEntityId
5
+ series {
6
+ series
7
+ configured
8
+ prefix
9
+ suffix
10
+ digits
11
+ yearFormat
12
+ yearReset
13
+ nextNumber
14
+ lastResetYear
15
+ invoicingProvider
16
+ }
17
+ stores {
18
+ id
19
+ code
20
+ }
21
+ storeCount
22
+ editable
23
+ `;
24
+ export const LEGAL_ENTITY_NUMBERING_QUERY = /* GraphQL */ `
25
+ query LegalEntityNumbering($legalEntityId: ID) {
26
+ legalEntityNumbering(legalEntityId: $legalEntityId) { ${LEGAL_ENTITY_NUMBERING_FIELDS} }
27
+ }
28
+ `;
29
+ export const UPDATE_LEGAL_ENTITY_NUMBERING_MUTATION = /* GraphQL */ `
30
+ mutation UpdateLegalEntityNumbering($input: UpdateLegalEntityNumberingInput!) {
31
+ updateLegalEntityNumbering(input: $input) { ${LEGAL_ENTITY_NUMBERING_FIELDS} }
32
+ }
33
+ `;
34
+ const INPUT_FIELDS = ['series', 'prefix', 'suffix', 'digits', 'yearFormat', 'yearReset'];
35
+ /**
36
+ * The input as the engine declares it, field by field, so a caller spreading a series it read
37
+ * (which carries counters and `configured`) sends only the format, and a field left out stays out.
38
+ */
39
+ export function legalEntityNumberingInputOf(input, legalEntityId) {
40
+ const out = {};
41
+ if (legalEntityId !== undefined)
42
+ out.legalEntityId = legalEntityId;
43
+ for (const field of INPUT_FIELDS) {
44
+ const value = input[field];
45
+ if (value !== undefined && value !== null)
46
+ out[field] = value;
47
+ }
48
+ return out;
49
+ }
50
+ async function read(transport, legalEntityId, call) {
51
+ const data = await transport.graphql({
52
+ api: 'admin',
53
+ query: LEGAL_ENTITY_NUMBERING_QUERY,
54
+ variables: legalEntityId === undefined ? {} : { legalEntityId },
55
+ }, call);
56
+ return data.legalEntityNumbering;
57
+ }
58
+ async function write(transport, legalEntityId, input, call) {
59
+ const data = await transport.graphql({
60
+ api: 'admin',
61
+ query: UPDATE_LEGAL_ENTITY_NUMBERING_MUTATION,
62
+ variables: { input: legalEntityNumberingInputOf(input, legalEntityId) },
63
+ }, call);
64
+ return data.updateLegalEntityNumbering;
65
+ }
66
+ /**
67
+ * The platform methods name the entity: without an id the engine would answer for the ACTIVE
68
+ * store's entity instead, which on a tenant-scoped client is a different one than asked for.
69
+ */
70
+ function requireLegalEntityId(legalEntityId) {
71
+ if (typeof legalEntityId !== 'string' || legalEntityId.trim() === '') {
72
+ throw new ValidationError({
73
+ code: 'LEGAL_ENTITY_ID_REQUIRED',
74
+ message: 'platform.legalEntities.numbering needs the legal entity id. For the active store’s ' +
75
+ 'entity use tenant.legalEntity.numbering.',
76
+ status: 400,
77
+ service: 'vendure',
78
+ });
79
+ }
80
+ return legalEntityId;
81
+ }
82
+ export function createPlatformLegalEntityNumberingModule(transport, config) {
83
+ // Platform-wide, so a SuperAdmin must not need a tenant.
84
+ const unscoped = (call) => ({ ...call, allowUnscoped: true });
85
+ return {
86
+ async get(legalEntityId, call) {
87
+ requireHumanSession(config);
88
+ return read(transport, requireLegalEntityId(legalEntityId), unscoped(call));
89
+ },
90
+ async update(legalEntityId, input, call) {
91
+ requireHumanSession(config);
92
+ return write(transport, requireLegalEntityId(legalEntityId), input, unscoped(call));
93
+ },
94
+ };
95
+ }
96
+ export function createTenantLegalEntityNumberingModule(transport) {
97
+ return {
98
+ get: (call) => read(transport, undefined, call),
99
+ update: (input, call) => write(transport, undefined, input, call),
100
+ };
101
+ }
@@ -0,0 +1,80 @@
1
+ import { type Transport } from '@sixtyninecommerce/core';
2
+ import type { AdminClientConfig } from '../client.js';
3
+ import type { Call } from '../types.js';
4
+ /** A store's membership of an organization (multi-region spec §5.1, §7.10.3). */
5
+ export interface OrganizationMembership {
6
+ /** The member store's channel id. */
7
+ channelId: string;
8
+ /** The member store. Null once the store no longer exists. */
9
+ channel: {
10
+ id: string;
11
+ code: string;
12
+ } | null;
13
+ organizationId: string;
14
+ /** A free grouping label, such as `EMEA`. Null when none is set. */
15
+ region: string | null;
16
+ /** Whether the storefront region switcher lists this store. */
17
+ listedInRegionSwitcher: boolean;
18
+ /** ISO-8601 UTC. */
19
+ joinedAt: string;
20
+ }
21
+ export interface JoinOrganizationInput {
22
+ /** The organization code, not the `org-` workspace channel code. */
23
+ organizationCode: string;
24
+ /** The store's channel id. */
25
+ channelId: string;
26
+ /**
27
+ * A grouping label, at most 64 characters with no line breaks. Omitted keeps
28
+ * the region a re-join finds (a first join has none); `null` or `''` clears it.
29
+ */
30
+ region?: string | null;
31
+ /**
32
+ * `true`: the store keeps its own values for every settings group instead of
33
+ * inheriting the organization's; each group can be switched to inherit later.
34
+ * On a re-join, a group the store inherits unlocked at that moment starts
35
+ * from a copy of the organization's values.
36
+ * Omitted or `false`: it inherits whatever the organization shares, and on a
37
+ * re-join nothing it already keeps changes. Needs an engine that knows the
38
+ * field (a `true` sent to an older one is a GraphQL validation error).
39
+ */
40
+ keepOwnSettings?: boolean;
41
+ }
42
+ /** The membership half of `admin.platform.organizations`. */
43
+ export interface OrganizationMembershipMethods {
44
+ /**
45
+ * Makes a store a member of an organization and answers the membership: the
46
+ * organization's roles are granted on the store, and the workspace takes on
47
+ * the store's currencies and languages. Joining the organization the store
48
+ * is already in answers the same membership (`joinedAt` unchanged), changing
49
+ * only the region when one is given — so a join whose answer was lost is
50
+ * safe to repeat. `keepOwnSettings: true` makes the store keep its own
51
+ * settings (only the groups it does not keep yet are added on a re-join).
52
+ * There is no way to leave yet. SuperAdmin only.
53
+ *
54
+ * Refusals: `ORGANIZATION_MEMBERSHIP_CONFLICT` (409 `ConflictError`: the store
55
+ * belongs to another organization); `ORGANIZATION_NOT_FOUND` (no organization
56
+ * has that code) and `ORGANIZATION_MEMBER_STORE_NOT_FOUND` (no store has that
57
+ * id) (404 `NotFoundError`); `ORGANIZATION_MEMBER_NOT_A_STORE` (the platform's
58
+ * root channel or an organization's workspace) and
59
+ * `ORGANIZATION_MEMBER_STORE_CLOSED` (restore the store first) and
60
+ * `ORGANIZATION_TAX_MODE_MISMATCH` (the store's `pricesIncludeTax` differs
61
+ * from the organization's: every store of an organization enters prices the
62
+ * same way; judged on a first join only) (422
63
+ * `BusinessRuleError`); `ORGANIZATION_MEMBER_REGION_INVALID` (400
64
+ * `ValidationError`); `FORBIDDEN` (403) for a caller who is not a SuperAdmin.
65
+ */
66
+ join(input: JoinOrganizationInput, call?: Call): Promise<OrganizationMembership>;
67
+ /**
68
+ * The organization's member stores, oldest member first. A store that no
69
+ * longer exists is left out. A SuperAdmin reads any organization's with no
70
+ * tenant; an organization admin reads its own with the workspace channel
71
+ * (`org-<code>`) as the tenant, and is refused elsewhere with a 403
72
+ * `PermissionDeniedError` (`FORBIDDEN`, or `ORGANIZATION_ACCESS_DENIED` for
73
+ * another organization). An unknown id is `ORGANIZATION_NOT_FOUND` (404
74
+ * `NotFoundError`), not an empty list.
75
+ */
76
+ members(organizationId: string, call?: Call): Promise<OrganizationMembership[]>;
77
+ }
78
+ export declare const JOIN_ORGANIZATION_MUTATION = "\n mutation PlatformJoinOrganization($channelId: ID!, $input: JoinOrganizationInput!) {\n joinOrganization(channelId: $channelId, input: $input) { \n channelId\n channel {\n id\n code\n }\n organizationId\n region\n listedInRegionSwitcher\n joinedAt\n }\n }\n";
79
+ export declare const ORGANIZATION_MEMBERS_QUERY = "\n query PlatformOrganizationMembers($id: ID!) {\n organization(id: $id) {\n id\n members { \n channelId\n channel {\n id\n code\n }\n organizationId\n region\n listedInRegionSwitcher\n joinedAt\n }\n }\n }\n";
80
+ export declare function createOrganizationMembershipMethods(transport: Transport, config: AdminClientConfig): OrganizationMembershipMethods;
@@ -0,0 +1,71 @@
1
+ import { NotFoundError } from '@sixtyninecommerce/core';
2
+ import { requireHumanSession } from './guard.js';
3
+ const MEMBERSHIP_FIELDS = /* GraphQL */ `
4
+ channelId
5
+ channel {
6
+ id
7
+ code
8
+ }
9
+ organizationId
10
+ region
11
+ listedInRegionSwitcher
12
+ joinedAt
13
+ `;
14
+ export const JOIN_ORGANIZATION_MUTATION = /* GraphQL */ `
15
+ mutation PlatformJoinOrganization($channelId: ID!, $input: JoinOrganizationInput!) {
16
+ joinOrganization(channelId: $channelId, input: $input) { ${MEMBERSHIP_FIELDS} }
17
+ }
18
+ `;
19
+ // Through `organization(id)` rather than a query of its own: the engine
20
+ // applies the organization reads' access rule there (a SuperAdmin, or the
21
+ // organization admin in its own workspace), and answers null for an unknown id.
22
+ export const ORGANIZATION_MEMBERS_QUERY = /* GraphQL */ `
23
+ query PlatformOrganizationMembers($id: ID!) {
24
+ organization(id: $id) {
25
+ id
26
+ members { ${MEMBERSHIP_FIELDS} }
27
+ }
28
+ }
29
+ `;
30
+ export function createOrganizationMembershipMethods(transport, config) {
31
+ // Platform-wide, as in `createPlatformOrganizationsModule`: the opt-in only
32
+ // matters when the scope is `none`, so an organization admin's workspace
33
+ // tenant still goes out.
34
+ const unscoped = (call) => ({ ...call, allowUnscoped: true });
35
+ return {
36
+ async join(input, call) {
37
+ requireHumanSession(config);
38
+ // The engine reads an ABSENT region as "keep the current one" and null as
39
+ // "clear it", so an omitted region must stay absent on the wire, never
40
+ // become null.
41
+ const joinInput = {
42
+ organizationCode: input.organizationCode,
43
+ };
44
+ if (input.region !== undefined)
45
+ joinInput.region = input.region;
46
+ // Only `true` goes on the wire: `false` means what an absent field means, and an engine
47
+ // older than the field refuses the whole document when it sees one it does not know.
48
+ if (input.keepOwnSettings === true)
49
+ joinInput.keepOwnSettings = true;
50
+ const data = await transport.graphql({
51
+ api: 'admin',
52
+ query: JOIN_ORGANIZATION_MUTATION,
53
+ variables: { channelId: input.channelId, input: joinInput },
54
+ }, unscoped(call));
55
+ return data.joinOrganization;
56
+ },
57
+ async members(organizationId, call) {
58
+ requireHumanSession(config);
59
+ const data = await transport.graphql({ api: 'admin', query: ORGANIZATION_MEMBERS_QUERY, variables: { id: organizationId } }, unscoped(call));
60
+ if (!data.organization) {
61
+ throw new NotFoundError({
62
+ code: 'ORGANIZATION_NOT_FOUND',
63
+ message: `No organization has the id ${organizationId}.`,
64
+ status: 404,
65
+ service: 'vendure',
66
+ });
67
+ }
68
+ return data.organization.members;
69
+ },
70
+ };
71
+ }
@@ -0,0 +1,33 @@
1
+ import { type Transport } from '@sixtyninecommerce/core';
2
+ import type { AdminClientConfig } from '../client.js';
3
+ import type { SettingsGroup } from '../tenant/settings-sources.js';
4
+ import type { Call } from '../types.js';
5
+ /** A member store that keeps its own values for one settings group. */
6
+ export interface OrganizationSettingsOverride {
7
+ /** The member store's channel id. */
8
+ channelId: string;
9
+ channelCode: string;
10
+ group: SettingsGroup | (string & {});
11
+ /**
12
+ * When the store started keeping its own values: ISO-8601 in UTC (`…Z`), exactly as the engine
13
+ * answers it. Compare instants with `Date.parse`; format it in the viewer's time zone only for
14
+ * display.
15
+ */
16
+ overriddenAt: string;
17
+ }
18
+ /** The settings half of `admin.platform.organizations`. */
19
+ export interface OrganizationSettingsMethods {
20
+ /**
21
+ * The member stores keeping their own values, one entry per store and group, whether or not
22
+ * the organization shares that group today — what "Lock for all stores" would take away from
23
+ * them. Ordered by store code, then by group in catalog order; a store that no longer exists
24
+ * is left out. A SuperAdmin reads any organization's with no tenant; an organization admin
25
+ * reads its own with the workspace channel (`org-<code>`) as the tenant and is refused
26
+ * elsewhere with a 403 `PermissionDeniedError` (`FORBIDDEN`, or `ORGANIZATION_ACCESS_DENIED` for
27
+ * another organization). A caller who may read the organization but not manage it gets an
28
+ * empty list. An unknown id is `ORGANIZATION_NOT_FOUND` (404 `NotFoundError`).
29
+ */
30
+ settingsOverrides(organizationId: string, call?: Call): Promise<OrganizationSettingsOverride[]>;
31
+ }
32
+ export declare const ORGANIZATION_SETTINGS_OVERRIDES_QUERY = "\n query PlatformOrganizationSettingsOverrides($id: ID!) {\n organization(id: $id) {\n id\n settingsOverrides {\n channelId\n channelCode\n group\n overriddenAt\n }\n }\n }\n";
33
+ export declare function createOrganizationSettingsMethods(transport: Transport, config: AdminClientConfig): OrganizationSettingsMethods;