@sixtyninecommerce/admin 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/README.md +2445 -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 +489 -0
  28. package/dist/catalog/products.js +365 -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 +274 -0
  34. package/dist/catalog/variants.js +258 -0
  35. package/dist/catalog/visibility.d.ts +57 -0
  36. package/dist/catalog/visibility.js +59 -0
  37. package/dist/client.d.ts +171 -3
  38. package/dist/client.js +81 -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 +360 -0
  66. package/dist/fulfillments/index.js +425 -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 +84 -9
  74. package/dist/index.js +16 -1
  75. package/dist/jobs/bulk-action-run.d.ts +65 -0
  76. package/dist/jobs/bulk-action-run.js +70 -0
  77. package/dist/locations/index.d.ts +6 -2
  78. package/dist/meta/index.d.ts +32 -0
  79. package/dist/orders/commit-edit.d.ts +123 -0
  80. package/dist/orders/commit-edit.js +142 -0
  81. package/dist/orders/get.d.ts +722 -0
  82. package/dist/orders/get.js +530 -0
  83. package/dist/orders/index.d.ts +105 -20
  84. package/dist/orders/index.js +44 -0
  85. package/dist/orders/line-price-preview.d.ts +297 -0
  86. package/dist/orders/line-price-preview.js +50 -0
  87. package/dist/orders/manual-discounts.d.ts +132 -0
  88. package/dist/orders/manual-discounts.js +95 -0
  89. package/dist/orders/manual-pricing.d.ts +192 -0
  90. package/dist/orders/manual-pricing.js +72 -0
  91. package/dist/orders/order-entry.d.ts +566 -0
  92. package/dist/orders/order-entry.js +129 -0
  93. package/dist/orders/parcel-charge.d.ts +45 -0
  94. package/dist/orders/parcel-charge.js +55 -0
  95. package/dist/orders/plan-edit.d.ts +489 -0
  96. package/dist/orders/plan-edit.js +93 -0
  97. package/dist/orders/status.d.ts +235 -0
  98. package/dist/orders/status.js +96 -0
  99. package/dist/orders/surcharges.d.ts +75 -2
  100. package/dist/orders/surcharges.js +110 -4
  101. package/dist/payments/account-credit.d.ts +171 -0
  102. package/dist/payments/account-credit.js +107 -0
  103. package/dist/payments/index.d.ts +234 -9
  104. package/dist/payments/index.js +90 -0
  105. package/dist/platform/catalog.d.ts +148 -0
  106. package/dist/platform/catalog.js +74 -0
  107. package/dist/platform/entitlements.d.ts +111 -0
  108. package/dist/platform/entitlements.js +86 -0
  109. package/dist/platform/legal-entities.d.ts +139 -0
  110. package/dist/platform/legal-entities.js +126 -0
  111. package/dist/platform/legal-entity-numbering.d.ts +103 -0
  112. package/dist/platform/legal-entity-numbering.js +101 -0
  113. package/dist/platform/organization-membership.d.ts +80 -0
  114. package/dist/platform/organization-membership.js +71 -0
  115. package/dist/platform/organization-settings.d.ts +33 -0
  116. package/dist/platform/organization-settings.js +42 -0
  117. package/dist/platform/organization-sharing.d.ts +172 -0
  118. package/dist/platform/organization-sharing.js +120 -0
  119. package/dist/platform/organizations.d.ts +205 -0
  120. package/dist/platform/organizations.js +180 -0
  121. package/dist/platform/provision-store.d.ts +88 -8
  122. package/dist/platform/provision-store.js +12 -0
  123. package/dist/platform/reports.d.ts +46 -0
  124. package/dist/platform/reports.js +31 -0
  125. package/dist/platform/server-metrics.d.ts +58 -0
  126. package/dist/platform/server-metrics.js +11 -0
  127. package/dist/pos/index.d.ts +567 -0
  128. package/dist/pos/index.js +205 -0
  129. package/dist/pricing/index.d.ts +405 -0
  130. package/dist/pricing/index.js +351 -0
  131. package/dist/provenance/index.d.ts +93 -0
  132. package/dist/provenance/index.js +53 -0
  133. package/dist/reports/index.d.ts +199 -0
  134. package/dist/reports/index.js +154 -0
  135. package/dist/shipping/parcel-count-suggestion.d.ts +52 -0
  136. package/dist/shipping/parcel-count-suggestion.js +73 -0
  137. package/dist/shipping/parcel-rule.d.ts +48 -0
  138. package/dist/shipping/parcel-rule.js +91 -0
  139. package/dist/stock/index.d.ts +166 -0
  140. package/dist/stock/index.js +115 -0
  141. package/dist/stock/transfers.d.ts +520 -0
  142. package/dist/stock/transfers.js +437 -0
  143. package/dist/stored-value/index.d.ts +154 -0
  144. package/dist/stored-value/index.js +130 -0
  145. package/dist/tenant/capabilities.d.ts +10 -0
  146. package/dist/tenant/entitlements.d.ts +35 -0
  147. package/dist/tenant/entitlements.js +15 -0
  148. package/dist/tenant/field-groups.d.ts +64 -0
  149. package/dist/tenant/field-groups.js +34 -0
  150. package/dist/tenant/legal-entity.d.ts +32 -0
  151. package/dist/tenant/legal-entity.js +41 -0
  152. package/dist/tenant/notifications.d.ts +148 -0
  153. package/dist/tenant/notifications.js +79 -0
  154. package/dist/tenant/retention.d.ts +10 -4
  155. package/dist/tenant/settings-sources.d.ts +103 -0
  156. package/dist/tenant/settings-sources.js +92 -0
  157. package/dist/types.d.ts +86 -11
  158. package/dist/uploads/index.d.ts +11 -7
  159. package/dist/users/index.d.ts +104 -0
  160. package/dist/users/index.js +80 -0
  161. package/package.json +3 -2
@@ -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;
@@ -0,0 +1,42 @@
1
+ import { NotFoundError } from '@sixtyninecommerce/core';
2
+ import { requireHumanSession } from './guard.js';
3
+ // Through `organization(id)`, like `members`: the engine applies the organization reads' access
4
+ // rule there and answers null for an unknown id. A separate document rather than a field of every
5
+ // organization read, so `get`/`list` keep working against an engine older than the field.
6
+ export const ORGANIZATION_SETTINGS_OVERRIDES_QUERY = /* GraphQL */ `
7
+ query PlatformOrganizationSettingsOverrides($id: ID!) {
8
+ organization(id: $id) {
9
+ id
10
+ settingsOverrides {
11
+ channelId
12
+ channelCode
13
+ group
14
+ overriddenAt
15
+ }
16
+ }
17
+ }
18
+ `;
19
+ export function createOrganizationSettingsMethods(transport, config) {
20
+ // As in `organizations.ts`: a SuperAdmin needs no tenant, and an organization admin's
21
+ // workspace tenant is left alone.
22
+ const unscoped = (call) => ({ ...call, allowUnscoped: true });
23
+ return {
24
+ async settingsOverrides(organizationId, call) {
25
+ requireHumanSession(config);
26
+ const data = await transport.graphql({
27
+ api: 'admin',
28
+ query: ORGANIZATION_SETTINGS_OVERRIDES_QUERY,
29
+ variables: { id: organizationId },
30
+ }, unscoped(call));
31
+ if (!data.organization) {
32
+ throw new NotFoundError({
33
+ code: 'ORGANIZATION_NOT_FOUND',
34
+ message: `No organization has the id ${organizationId}.`,
35
+ status: 404,
36
+ service: 'vendure',
37
+ });
38
+ }
39
+ return data.organization.settingsOverrides;
40
+ },
41
+ };
42
+ }