@sixtyninecommerce/admin 0.10.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5772 -118
- package/dist/auth/index.d.ts +7 -1
- package/dist/auth/index.js +8 -1
- package/dist/catalog/assets.d.ts +120 -8
- package/dist/catalog/assets.js +98 -12
- package/dist/catalog/collections.d.ts +279 -14
- package/dist/catalog/collections.js +246 -15
- package/dist/catalog/documents.d.ts +142 -0
- package/dist/catalog/documents.js +114 -0
- package/dist/catalog/index.d.ts +54 -6
- package/dist/catalog/index.js +10 -1
- package/dist/catalog/metadata.d.ts +244 -0
- package/dist/catalog/metadata.js +220 -0
- package/dist/catalog/products.d.ts +159 -19
- package/dist/catalog/products.js +88 -13
- package/dist/catalog/properties.d.ts +140 -14
- package/dist/catalog/properties.js +65 -1
- package/dist/catalog/recommendations.d.ts +288 -0
- package/dist/catalog/recommendations.js +237 -0
- package/dist/catalog/reviews.d.ts +381 -0
- package/dist/catalog/reviews.js +325 -0
- package/dist/catalog/types.d.ts +17 -1
- package/dist/catalog/types.js +10 -0
- package/dist/catalog/variant-find.d.ts +136 -0
- package/dist/catalog/variant-find.js +239 -0
- package/dist/catalog/variants.d.ts +293 -26
- package/dist/catalog/variants.js +164 -7
- package/dist/catalog/visibility.d.ts +38 -7
- package/dist/catalog/visibility.js +19 -1
- package/dist/client.d.ts +121 -9
- package/dist/client.js +53 -14
- package/dist/content/assets.d.ts +285 -0
- package/dist/content/assets.js +181 -0
- package/dist/content/forms.d.ts +332 -1
- package/dist/content/forms.js +140 -4
- package/dist/content/items.d.ts +292 -0
- package/dist/content/items.js +170 -0
- package/dist/content/menus.d.ts +254 -0
- package/dist/content/menus.js +70 -0
- package/dist/content/strings.d.ts +137 -0
- package/dist/content/strings.js +82 -0
- package/dist/content/types.d.ts +282 -0
- package/dist/content/types.js +100 -0
- package/dist/customers/age-verification.d.ts +66 -0
- package/dist/customers/age-verification.js +79 -0
- package/dist/customers/credit.d.ts +263 -0
- package/dist/customers/credit.js +244 -0
- package/dist/customers/delivery-preferences.d.ts +120 -0
- package/dist/customers/delivery-preferences.js +97 -0
- package/dist/customers/delivery-terms.d.ts +44 -0
- package/dist/customers/delivery-terms.js +32 -0
- package/dist/customers/groups.d.ts +207 -0
- package/dist/customers/groups.js +438 -0
- package/dist/customers/index.d.ts +462 -37
- package/dist/customers/index.js +317 -40
- package/dist/customers/invitation-status.d.ts +57 -0
- package/dist/customers/invitation-status.js +21 -0
- package/dist/customers/notes.d.ts +67 -0
- package/dist/customers/notes.js +51 -0
- package/dist/customers/notification-recipients.d.ts +97 -0
- package/dist/customers/notification-recipients.js +84 -0
- package/dist/customers/saved-lists.d.ts +42 -0
- package/dist/customers/saved-lists.js +61 -0
- package/dist/customers/vat.d.ts +83 -0
- package/dist/customers/vat.js +46 -0
- package/dist/customers/wire.d.ts +20 -0
- package/dist/customers/wire.js +35 -0
- package/dist/documents/ar.d.ts +307 -0
- package/dist/documents/ar.js +254 -0
- package/dist/documents/emails.d.ts +150 -0
- package/dist/documents/emails.js +220 -0
- package/dist/documents/index.d.ts +744 -21
- package/dist/documents/index.js +438 -24
- package/dist/documents/pdf.d.ts +2 -0
- package/dist/documents/pdf.js +11 -0
- package/dist/fulfillments/create.d.ts +167 -0
- package/dist/fulfillments/create.js +216 -0
- package/dist/fulfillments/index.d.ts +163 -11
- package/dist/fulfillments/index.js +135 -6
- package/dist/fulfillments/payment-policy.d.ts +64 -0
- package/dist/fulfillments/payment-policy.js +140 -0
- package/dist/fulfillments/warehouse.d.ts +724 -0
- package/dist/fulfillments/warehouse.js +914 -0
- package/dist/geo/index.d.ts +119 -0
- package/dist/geo/index.js +107 -0
- package/dist/index.d.ts +147 -39
- package/dist/index.js +51 -12
- package/dist/integrations/afas-actions.d.ts +234 -0
- package/dist/integrations/afas-actions.js +310 -0
- package/dist/integrations/afas-types.d.ts +483 -0
- package/dist/integrations/afas-types.js +5 -0
- package/dist/integrations/afas.d.ts +234 -0
- package/dist/integrations/afas.js +290 -0
- package/dist/integrations/connections.d.ts +103 -0
- package/dist/integrations/connections.js +55 -0
- package/dist/integrations/esp.d.ts +313 -0
- package/dist/integrations/esp.js +169 -0
- package/dist/integrations/exact-online-types.d.ts +965 -0
- package/dist/integrations/exact-online-types.js +6 -0
- package/dist/integrations/exact-online.d.ts +784 -0
- package/dist/integrations/exact-online.js +1089 -0
- package/dist/integrations/index.d.ts +44 -3
- package/dist/integrations/index.js +23 -3
- package/dist/integrations/pipeline-discoveries.d.ts +65 -0
- package/dist/integrations/pipeline-discoveries.js +65 -0
- package/dist/integrations/pipeline-keys.d.ts +13 -0
- package/dist/integrations/pipeline-keys.js +22 -0
- package/dist/integrations/pipeline-runs.d.ts +119 -0
- package/dist/integrations/pipeline-runs.js +87 -0
- package/dist/integrations/pipelines.d.ts +87 -15
- package/dist/integrations/pipelines.js +41 -22
- package/dist/integrations/price-import.d.ts +223 -0
- package/dist/integrations/price-import.js +124 -0
- package/dist/integrations/types.d.ts +367 -3
- package/dist/integrations/types.js +4 -3
- package/dist/locations/index.d.ts +66 -0
- package/dist/locations/index.js +31 -0
- package/dist/meta/index.d.ts +172 -0
- package/dist/metafields/index.d.ts +8 -1
- package/dist/metafields/index.js +10 -0
- package/dist/orders/cancel-with-money.d.ts +237 -0
- package/dist/orders/cancel-with-money.js +155 -0
- package/dist/orders/commit-edit.d.ts +23 -1
- package/dist/orders/commit-edit.js +19 -2
- package/dist/orders/deposit-policy.d.ts +3 -1
- package/dist/orders/drafts.d.ts +800 -0
- package/dist/orders/drafts.js +771 -0
- package/dist/orders/fields.d.ts +245 -0
- package/dist/orders/fields.js +188 -0
- package/dist/orders/get.d.ts +29 -19
- package/dist/orders/get.js +17 -8
- package/dist/orders/index.d.ts +66 -15
- package/dist/orders/index.js +25 -2
- package/dist/orders/lifecycle.d.ts +128 -0
- package/dist/orders/lifecycle.js +158 -0
- package/dist/orders/line-price-preview.d.ts +7 -2
- package/dist/orders/list.d.ts +243 -0
- package/dist/orders/list.js +487 -0
- package/dist/orders/manual-discounts.d.ts +13 -5
- package/dist/orders/manual-pricing.d.ts +5 -0
- package/dist/orders/money-view.d.ts +149 -0
- package/dist/orders/money-view.js +99 -0
- package/dist/orders/order-entry.d.ts +20 -7
- package/dist/orders/plan-edit.d.ts +34 -2
- package/dist/orders/plan-edit.js +112 -11
- package/dist/orders/settings.d.ts +201 -0
- package/dist/orders/settings.js +325 -0
- package/dist/orders/status.d.ts +159 -13
- package/dist/orders/status.js +21 -0
- package/dist/orders/surcharges.d.ts +20 -1
- package/dist/orders/surcharges.js +37 -11
- package/dist/payments/account-credit.d.ts +46 -0
- package/dist/payments/account-credit.js +42 -0
- package/dist/payments/ar.d.ts +292 -0
- package/dist/payments/ar.js +223 -0
- package/dist/payments/connected-account.d.ts +47 -0
- package/dist/payments/connected-account.js +61 -0
- package/dist/payments/credit-noted-fields.d.ts +19 -0
- package/dist/payments/credit-noted-fields.js +69 -0
- package/dist/payments/customer-consent.d.ts +30 -0
- package/dist/payments/customer-consent.js +49 -0
- package/dist/payments/index.d.ts +340 -19
- package/dist/payments/index.js +151 -1
- package/dist/payments/methods.d.ts +303 -8
- package/dist/payments/methods.js +337 -7
- package/dist/payments/mollie-methods.d.ts +159 -0
- package/dist/payments/mollie-methods.js +141 -0
- package/dist/payments/payment-links.d.ts +180 -0
- package/dist/payments/payment-links.js +97 -0
- package/dist/payments/provider-keys.d.ts +150 -0
- package/dist/payments/provider-keys.js +118 -0
- package/dist/payments/providers.d.ts +86 -11
- package/dist/payments/providers.js +29 -0
- package/dist/payments/requests.d.ts +147 -0
- package/dist/payments/requests.js +93 -0
- package/dist/payments/store-credit-fields.d.ts +15 -0
- package/dist/payments/store-credit-fields.js +51 -0
- package/dist/pickups/index.d.ts +106 -0
- package/dist/pickups/index.js +108 -0
- package/dist/platform/channels.d.ts +132 -0
- package/dist/platform/channels.js +128 -0
- package/dist/platform/email-gateways.d.ts +165 -0
- package/dist/platform/email-gateways.js +78 -0
- package/dist/platform/geo.d.ts +123 -0
- package/dist/platform/geo.js +144 -0
- package/dist/platform/tax.d.ts +162 -0
- package/dist/platform/tax.js +169 -0
- package/dist/pos/anomalies.d.ts +158 -0
- package/dist/pos/anomalies.js +64 -0
- package/dist/pos/assisted-selling.d.ts +79 -0
- package/dist/pos/assisted-selling.js +38 -0
- package/dist/pos/exchanges.d.ts +108 -0
- package/dist/pos/exchanges.js +22 -0
- package/dist/pos/gift-cards.d.ts +135 -0
- package/dist/pos/gift-cards.js +47 -0
- package/dist/pos/index.d.ts +2370 -58
- package/dist/pos/index.js +854 -7
- package/dist/pos/no-receipt.d.ts +94 -0
- package/dist/pos/no-receipt.js +25 -0
- package/dist/pos/offline-sales.d.ts +228 -0
- package/dist/pos/offline-sales.js +170 -0
- package/dist/pos/pay-by-link.d.ts +143 -0
- package/dist/pos/pay-by-link.js +57 -0
- package/dist/pos/quick-keys.d.ts +103 -0
- package/dist/pos/quick-keys.js +45 -0
- package/dist/pos/reports.d.ts +360 -0
- package/dist/pos/reports.js +62 -0
- package/dist/pos/returns.d.ts +244 -0
- package/dist/pos/returns.js +83 -0
- package/dist/pricing/bulk-coupons.d.ts +139 -0
- package/dist/pricing/bulk-coupons.js +112 -0
- package/dist/pricing/index.d.ts +174 -4
- package/dist/pricing/index.js +174 -1
- package/dist/pricing/price-lists.d.ts +606 -0
- package/dist/pricing/price-lists.js +600 -0
- package/dist/purchasing/alerts.d.ts +104 -0
- package/dist/purchasing/alerts.js +88 -0
- package/dist/purchasing/backorders.d.ts +61 -0
- package/dist/purchasing/backorders.js +92 -0
- package/dist/purchasing/cost.d.ts +110 -0
- package/dist/purchasing/cost.js +86 -0
- package/dist/purchasing/index.d.ts +54 -0
- package/dist/purchasing/index.js +24 -0
- package/dist/purchasing/links.d.ts +263 -0
- package/dist/purchasing/links.js +192 -0
- package/dist/purchasing/purchase-orders.d.ts +551 -0
- package/dist/purchasing/purchase-orders.js +491 -0
- package/dist/purchasing/receipts.d.ts +396 -0
- package/dist/purchasing/receipts.js +287 -0
- package/dist/purchasing/replenishment.d.ts +281 -0
- package/dist/purchasing/replenishment.js +240 -0
- package/dist/purchasing/returns.d.ts +273 -0
- package/dist/purchasing/returns.js +229 -0
- package/dist/purchasing/settings.d.ts +152 -0
- package/dist/purchasing/settings.js +181 -0
- package/dist/purchasing/suppliers.d.ts +476 -0
- package/dist/purchasing/suppliers.js +438 -0
- package/dist/quotes/index.d.ts +518 -0
- package/dist/quotes/index.js +439 -0
- package/dist/reports/index.d.ts +71 -8
- package/dist/reports/index.js +74 -11
- package/dist/returns/index.d.ts +675 -21
- package/dist/returns/index.js +756 -11
- package/dist/search/index.d.ts +76 -1
- package/dist/search/index.js +63 -0
- package/dist/seo/config.d.ts +128 -0
- package/dist/seo/config.js +95 -0
- package/dist/seo/redirects.d.ts +125 -0
- package/dist/seo/redirects.js +60 -1
- package/dist/seo/settings.d.ts +147 -0
- package/dist/seo/settings.js +209 -0
- package/dist/shipping/definitions.d.ts +29 -0
- package/dist/shipping/definitions.js +47 -0
- package/dist/shipping/fulfillment-profiles.d.ts +174 -0
- package/dist/shipping/fulfillment-profiles.js +104 -0
- package/dist/shipping/hendriks.d.ts +97 -0
- package/dist/shipping/hendriks.js +50 -0
- package/dist/shipping/index.d.ts +54 -0
- package/dist/shipping/index.js +27 -0
- package/dist/shipping/methods.d.ts +205 -0
- package/dist/shipping/methods.js +240 -0
- package/dist/shipping/myparcel.d.ts +668 -0
- package/dist/shipping/myparcel.js +466 -0
- package/dist/shipping/parcel-count-suggestion.d.ts +2 -0
- package/dist/shipping/parcel-rule.d.ts +6 -5
- package/dist/shipping/parcel-rule.js +21 -23
- package/dist/shipping/rate-tables.d.ts +324 -0
- package/dist/shipping/rate-tables.js +390 -0
- package/dist/shipping/ship-to-countries.d.ts +75 -0
- package/dist/shipping/ship-to-countries.js +47 -0
- package/dist/stock/by-location.d.ts +86 -0
- package/dist/stock/by-location.js +94 -0
- package/dist/stock/index.d.ts +18 -4
- package/dist/stock/index.js +7 -0
- package/dist/stock/locations.d.ts +144 -0
- package/dist/stock/locations.js +168 -0
- package/dist/stock/settings.d.ts +106 -0
- package/dist/stock/settings.js +103 -0
- package/dist/stock/transfers.d.ts +386 -52
- package/dist/stock/transfers.js +222 -17
- package/dist/stored-value/index.d.ts +312 -11
- package/dist/stored-value/index.js +223 -4
- package/dist/subscriptions/index.d.ts +682 -0
- package/dist/subscriptions/index.js +815 -0
- package/dist/tax/display-policy.d.ts +105 -0
- package/dist/tax/display-policy.js +84 -0
- package/dist/tax/index.d.ts +79 -1
- package/dist/tax/index.js +52 -0
- package/dist/tenant/email-style.d.ts +102 -0
- package/dist/tenant/email-style.js +72 -0
- package/dist/tenant/email-templates.d.ts +287 -0
- package/dist/tenant/email-templates.js +271 -0
- package/dist/tenant/notifications.d.ts +23 -17
- package/dist/tenant/settings-sources.d.ts +1 -1
- package/dist/tenant/time-zone.d.ts +17 -0
- package/dist/tenant/time-zone.js +11 -0
- package/dist/types.d.ts +50 -3
- package/dist/users/index.d.ts +3 -0
- package/dist/users/index.js +2 -0
- package/dist/users/warehouses.d.ts +50 -0
- package/dist/users/warehouses.js +51 -0
- package/package.json +2 -2
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { type Transport } from '@sixtyninecommerce/core';
|
|
2
|
+
import type { AdminClientConfig } from '../client.js';
|
|
3
|
+
import { type Country, type ZoneWithMembers } from '../geo/index.js';
|
|
4
|
+
import type { Call } from '../types.js';
|
|
5
|
+
/** A new zone, as {@link PlatformZonesModule.create} takes it. */
|
|
6
|
+
export interface CreateZoneInput {
|
|
7
|
+
name: string;
|
|
8
|
+
/** The countries in it (`geo.countries.list` ids). None when left out. */
|
|
9
|
+
memberIds?: string[];
|
|
10
|
+
}
|
|
11
|
+
/** A change to a zone. A field left out keeps what the zone has; members have their own calls. */
|
|
12
|
+
export interface UpdateZoneInput {
|
|
13
|
+
name?: string;
|
|
14
|
+
}
|
|
15
|
+
/** A country's name in one language. */
|
|
16
|
+
export interface CountryTranslationInput {
|
|
17
|
+
/** As the engine spells it: `en`, `nl`, `pt_BR`. */
|
|
18
|
+
languageCode: string;
|
|
19
|
+
name: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A change to a country. A field left out keeps what the country has.
|
|
23
|
+
*
|
|
24
|
+
* The ISO code is not changeable here: tax class mappings, a store's ship-to list and every
|
|
25
|
+
* address carry it, so a changed code would silently re-route them.
|
|
26
|
+
*/
|
|
27
|
+
export interface UpdateCountryInput {
|
|
28
|
+
/**
|
|
29
|
+
* A disabled country is kept for history; checkout and address forms refuse it, in every
|
|
30
|
+
* store.
|
|
31
|
+
*/
|
|
32
|
+
enabled?: boolean;
|
|
33
|
+
/** Writing a language the country has replaces that name; another language is added. */
|
|
34
|
+
translations?: CountryTranslationInput[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* `admin.platform.geo.zones` — the SuperAdmin writes of the platform's zones: the named sets
|
|
38
|
+
* of countries every store's tax rates and default zones point at (spec §9.2 `platform`, ruling
|
|
39
|
+
* G128). Reads are `geo.zones.list()` / `geo.zones.get()`. Every write answers the zone with its
|
|
40
|
+
* members, as `geo.zones.get()` reads it.
|
|
41
|
+
*
|
|
42
|
+
* Every method needs a human SuperAdmin session: an API token or an app credential is refused
|
|
43
|
+
* with `PLATFORM_REQUIRES_SESSION` (`PermissionDeniedError`, 403) BEFORE anything is sent, and a
|
|
44
|
+
* store administrator is refused by the engine with `PLATFORM_SETTINGS_NOT_ALLOWED`
|
|
45
|
+
* (`PermissionDeniedError`, 403) before anything is read or written. No tenant is needed on the
|
|
46
|
+
* client.
|
|
47
|
+
*/
|
|
48
|
+
export interface PlatformZonesModule {
|
|
49
|
+
/**
|
|
50
|
+
* Create a zone. A member id that names no country is skipped by the engine, so read the
|
|
51
|
+
* answer's `members` for what the zone holds.
|
|
52
|
+
*
|
|
53
|
+
* `INVALID_ZONE_INPUT` (`ValidationError`, 400): a missing or blank name, or `memberIds` that
|
|
54
|
+
* is not a list of ids, refused here before anything is sent.
|
|
55
|
+
*
|
|
56
|
+
* @effect write
|
|
57
|
+
*/
|
|
58
|
+
create(input: CreateZoneInput, options?: Call): Promise<ZoneWithMembers>;
|
|
59
|
+
/**
|
|
60
|
+
* Rename a zone. `ENTITY_NOT_FOUND` (`NotFoundError`, 404): no zone has that id.
|
|
61
|
+
*
|
|
62
|
+
* @effect write
|
|
63
|
+
*/
|
|
64
|
+
update(id: string, patch: UpdateZoneInput, options?: Call): Promise<ZoneWithMembers>;
|
|
65
|
+
/**
|
|
66
|
+
* Delete a zone.
|
|
67
|
+
*
|
|
68
|
+
* - `ZONE_NOT_DELETED` (`ConflictError`, 409): a store uses it as its default tax or shipping
|
|
69
|
+
* zone, or a tax rate prices in it; the engine's reason names the store codes or the rates.
|
|
70
|
+
* Nothing is deleted.
|
|
71
|
+
* - `ENTITY_NOT_FOUND` (`NotFoundError`, 404): no zone has that id.
|
|
72
|
+
*
|
|
73
|
+
* @effect destructive
|
|
74
|
+
*/
|
|
75
|
+
delete(id: string, options?: Call): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Add countries to a zone. A country already in it stays once, and an id that names no
|
|
78
|
+
* country is skipped by the engine: read the answer's `members` for what the zone holds.
|
|
79
|
+
*
|
|
80
|
+
* `INVALID_ZONE_INPUT` (`ValidationError`, 400): no ids, refused here. `ENTITY_NOT_FOUND`
|
|
81
|
+
* (`NotFoundError`, 404): no zone has that id.
|
|
82
|
+
*
|
|
83
|
+
* @effect write
|
|
84
|
+
*/
|
|
85
|
+
addMembers(zoneId: string, memberIds: string[], options?: Call): Promise<ZoneWithMembers>;
|
|
86
|
+
/**
|
|
87
|
+
* Take countries out of a zone. An id that is not a member is ignored.
|
|
88
|
+
*
|
|
89
|
+
* `INVALID_ZONE_INPUT` (`ValidationError`, 400): no ids, refused here. `ENTITY_NOT_FOUND`
|
|
90
|
+
* (`NotFoundError`, 404): no zone has that id.
|
|
91
|
+
*
|
|
92
|
+
* @effect write
|
|
93
|
+
*/
|
|
94
|
+
removeMembers(zoneId: string, memberIds: string[], options?: Call): Promise<ZoneWithMembers>;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* `admin.platform.geo.countries` — the SuperAdmin write of the platform's countries (G128).
|
|
98
|
+
* Reads are `geo.countries.list()`. The same session rules as {@link PlatformZonesModule}.
|
|
99
|
+
*/
|
|
100
|
+
export interface PlatformCountriesModule {
|
|
101
|
+
/**
|
|
102
|
+
* Switch a country on or off, or rename it in a language, and answer it as read.
|
|
103
|
+
*
|
|
104
|
+
* `INVALID_COUNTRY_INPUT` (`ValidationError`, 400): an `enabled` that is not a boolean, a
|
|
105
|
+
* translation without a language or a name, or a `code` (not changeable here), refused before
|
|
106
|
+
* anything is sent. `ENTITY_NOT_FOUND` (`NotFoundError`, 404): no country has that id.
|
|
107
|
+
*
|
|
108
|
+
* @effect write
|
|
109
|
+
*/
|
|
110
|
+
update(id: string, patch: UpdateCountryInput, options?: Call): Promise<Country>;
|
|
111
|
+
}
|
|
112
|
+
/** `admin.platform.geo`: SuperAdmin writes of the platform's zones and countries (G128). */
|
|
113
|
+
export interface PlatformGeoModule {
|
|
114
|
+
zones: PlatformZonesModule;
|
|
115
|
+
countries: PlatformCountriesModule;
|
|
116
|
+
}
|
|
117
|
+
export declare const CREATE_ZONE_MUTATION = "\n mutation PlatformCreateZone($input: CreateZoneInput!) {\n createZone(input: $input) { \n id\n name\n createdAt\n updatedAt\n \n members {\n id\n name\n code\n enabled\n type\n }\n }\n }\n";
|
|
118
|
+
export declare const UPDATE_ZONE_MUTATION = "\n mutation PlatformUpdateZone($input: UpdateZoneInput!) {\n updateZone(input: $input) { \n id\n name\n createdAt\n updatedAt\n \n members {\n id\n name\n code\n enabled\n type\n }\n }\n }\n";
|
|
119
|
+
export declare const DELETE_ZONE_MUTATION = "\n mutation PlatformDeleteZone($id: ID!) {\n deleteZone(id: $id) { \n result\n message\n }\n }\n";
|
|
120
|
+
export declare const ADD_MEMBERS_TO_ZONE_MUTATION = "\n mutation PlatformAddMembersToZone($zoneId: ID!, $memberIds: [ID!]!) {\n addMembersToZone(zoneId: $zoneId, memberIds: $memberIds) { \n id\n name\n createdAt\n updatedAt\n \n members {\n id\n name\n code\n enabled\n type\n }\n }\n }\n";
|
|
121
|
+
export declare const REMOVE_MEMBERS_FROM_ZONE_MUTATION = "\n mutation PlatformRemoveMembersFromZone($zoneId: ID!, $memberIds: [ID!]!) {\n removeMembersFromZone(zoneId: $zoneId, memberIds: $memberIds) { \n id\n name\n createdAt\n updatedAt\n \n members {\n id\n name\n code\n enabled\n type\n }\n }\n }\n";
|
|
122
|
+
export declare const UPDATE_COUNTRY_MUTATION = "\n mutation PlatformUpdateCountry($input: UpdateCountryInput!) {\n updateCountry(input: $input) { \n id\n name\n code\n enabled\n createdAt\n updatedAt\n }\n }\n";
|
|
123
|
+
export declare function createPlatformGeoModule(transport: Transport, config: AdminClientConfig): PlatformGeoModule;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { ValidationError } from '@sixtyninecommerce/core';
|
|
2
|
+
import { assertDeleted, DELETION_FIELDS, fieldOf, } from '../catalog/types.js';
|
|
3
|
+
import { COUNTRY_FIELDS, ZONE_FIELDS, ZONE_MEMBER_FIELDS, } from '../geo/index.js';
|
|
4
|
+
import { requireHumanSession } from './guard.js';
|
|
5
|
+
const ZONE_ANSWER = `${ZONE_FIELDS} ${ZONE_MEMBER_FIELDS}`;
|
|
6
|
+
export const CREATE_ZONE_MUTATION = /* GraphQL */ `
|
|
7
|
+
mutation PlatformCreateZone($input: CreateZoneInput!) {
|
|
8
|
+
createZone(input: $input) { ${ZONE_ANSWER} }
|
|
9
|
+
}
|
|
10
|
+
`;
|
|
11
|
+
export const UPDATE_ZONE_MUTATION = /* GraphQL */ `
|
|
12
|
+
mutation PlatformUpdateZone($input: UpdateZoneInput!) {
|
|
13
|
+
updateZone(input: $input) { ${ZONE_ANSWER} }
|
|
14
|
+
}
|
|
15
|
+
`;
|
|
16
|
+
export const DELETE_ZONE_MUTATION = /* GraphQL */ `
|
|
17
|
+
mutation PlatformDeleteZone($id: ID!) {
|
|
18
|
+
deleteZone(id: $id) { ${DELETION_FIELDS} }
|
|
19
|
+
}
|
|
20
|
+
`;
|
|
21
|
+
export const ADD_MEMBERS_TO_ZONE_MUTATION = /* GraphQL */ `
|
|
22
|
+
mutation PlatformAddMembersToZone($zoneId: ID!, $memberIds: [ID!]!) {
|
|
23
|
+
addMembersToZone(zoneId: $zoneId, memberIds: $memberIds) { ${ZONE_ANSWER} }
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
export const REMOVE_MEMBERS_FROM_ZONE_MUTATION = /* GraphQL */ `
|
|
27
|
+
mutation PlatformRemoveMembersFromZone($zoneId: ID!, $memberIds: [ID!]!) {
|
|
28
|
+
removeMembersFromZone(zoneId: $zoneId, memberIds: $memberIds) { ${ZONE_ANSWER} }
|
|
29
|
+
}
|
|
30
|
+
`;
|
|
31
|
+
export const UPDATE_COUNTRY_MUTATION = /* GraphQL */ `
|
|
32
|
+
mutation PlatformUpdateCountry($input: UpdateCountryInput!) {
|
|
33
|
+
updateCountry(input: $input) { ${COUNTRY_FIELDS} }
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
36
|
+
const isObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
37
|
+
const refusal = (code) => (message) => new ValidationError({ code, message, status: 400, service: 'vendure' });
|
|
38
|
+
const zoneRefusal = refusal('INVALID_ZONE_INPUT');
|
|
39
|
+
const countryRefusal = refusal('INVALID_COUNTRY_INPUT');
|
|
40
|
+
const isId = (value) => typeof value === 'string' && value.trim() !== '';
|
|
41
|
+
function requireId(id, what, refuse) {
|
|
42
|
+
if (!isId(id))
|
|
43
|
+
throw refuse(`${what} must be an id.`);
|
|
44
|
+
return id;
|
|
45
|
+
}
|
|
46
|
+
function memberIdsInput(value, allowEmpty) {
|
|
47
|
+
if (!Array.isArray(value) || !value.every(isId)) {
|
|
48
|
+
throw zoneRefusal('memberIds must be a list of country ids.');
|
|
49
|
+
}
|
|
50
|
+
if (!allowEmpty && value.length === 0) {
|
|
51
|
+
throw zoneRefusal('Name at least one country.');
|
|
52
|
+
}
|
|
53
|
+
return [...value];
|
|
54
|
+
}
|
|
55
|
+
function zoneInput(input, creating) {
|
|
56
|
+
if (!isObject(input))
|
|
57
|
+
throw zoneRefusal('A zone input must be an object.');
|
|
58
|
+
const out = {};
|
|
59
|
+
if (input.name !== undefined || creating) {
|
|
60
|
+
if (typeof input.name !== 'string' || input.name.trim() === '') {
|
|
61
|
+
throw zoneRefusal('A zone needs a name.');
|
|
62
|
+
}
|
|
63
|
+
out.name = input.name;
|
|
64
|
+
}
|
|
65
|
+
if (creating && input.memberIds !== undefined) {
|
|
66
|
+
out.memberIds = memberIdsInput(input.memberIds, true);
|
|
67
|
+
}
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
function countryInput(input) {
|
|
71
|
+
if (!isObject(input))
|
|
72
|
+
throw countryRefusal('A country change must be an object.');
|
|
73
|
+
if (input.code !== undefined) {
|
|
74
|
+
throw countryRefusal('A country keeps its ISO code: tax class mappings, ship-to lists and addresses carry it.');
|
|
75
|
+
}
|
|
76
|
+
const out = {};
|
|
77
|
+
if (input.enabled !== undefined) {
|
|
78
|
+
if (typeof input.enabled !== 'boolean')
|
|
79
|
+
throw countryRefusal('enabled must be a boolean.');
|
|
80
|
+
out.enabled = input.enabled;
|
|
81
|
+
}
|
|
82
|
+
if (input.translations !== undefined) {
|
|
83
|
+
const rows = input.translations;
|
|
84
|
+
if (!Array.isArray(rows) ||
|
|
85
|
+
!rows.every((row) => isObject(row) &&
|
|
86
|
+
typeof row.languageCode === 'string' &&
|
|
87
|
+
row.languageCode !== '' &&
|
|
88
|
+
typeof row.name === 'string' &&
|
|
89
|
+
row.name.trim() !== '')) {
|
|
90
|
+
throw countryRefusal('translations must be a list of { languageCode, name } with strings.');
|
|
91
|
+
}
|
|
92
|
+
out.translations = rows.map((row) => ({
|
|
93
|
+
languageCode: row.languageCode,
|
|
94
|
+
name: row.name,
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
return out;
|
|
98
|
+
}
|
|
99
|
+
export function createPlatformGeoModule(transport, config) {
|
|
100
|
+
// Platform-wide rows: no store is involved, so no tenant is needed. Scoped to a store instead,
|
|
101
|
+
// the transport would first resolve it through the CMS channel mirror and fail on one missing
|
|
102
|
+
// there.
|
|
103
|
+
const unscoped = (call) => ({ ...call, allowUnscoped: true });
|
|
104
|
+
return {
|
|
105
|
+
zones: {
|
|
106
|
+
async create(input, options) {
|
|
107
|
+
requireHumanSession(config);
|
|
108
|
+
return fieldOf(transport, CREATE_ZONE_MUTATION, 'createZone', { input: zoneInput(input, true) }, unscoped(options));
|
|
109
|
+
},
|
|
110
|
+
async update(id, patch, options) {
|
|
111
|
+
requireHumanSession(config);
|
|
112
|
+
const zoneId = requireId(id, 'id', zoneRefusal);
|
|
113
|
+
return fieldOf(transport, UPDATE_ZONE_MUTATION, 'updateZone', { input: { ...zoneInput(patch, false), id: zoneId } }, unscoped(options));
|
|
114
|
+
},
|
|
115
|
+
async delete(id, options) {
|
|
116
|
+
requireHumanSession(config);
|
|
117
|
+
assertDeleted('ZONE_NOT_DELETED', [
|
|
118
|
+
await fieldOf(transport, DELETE_ZONE_MUTATION, 'deleteZone', { id: requireId(id, 'id', zoneRefusal) }, unscoped(options)),
|
|
119
|
+
]);
|
|
120
|
+
},
|
|
121
|
+
async addMembers(zoneId, memberIds, options) {
|
|
122
|
+
requireHumanSession(config);
|
|
123
|
+
return fieldOf(transport, ADD_MEMBERS_TO_ZONE_MUTATION, 'addMembersToZone', {
|
|
124
|
+
zoneId: requireId(zoneId, 'zoneId', zoneRefusal),
|
|
125
|
+
memberIds: memberIdsInput(memberIds, false),
|
|
126
|
+
}, unscoped(options));
|
|
127
|
+
},
|
|
128
|
+
async removeMembers(zoneId, memberIds, options) {
|
|
129
|
+
requireHumanSession(config);
|
|
130
|
+
return fieldOf(transport, REMOVE_MEMBERS_FROM_ZONE_MUTATION, 'removeMembersFromZone', {
|
|
131
|
+
zoneId: requireId(zoneId, 'zoneId', zoneRefusal),
|
|
132
|
+
memberIds: memberIdsInput(memberIds, false),
|
|
133
|
+
}, unscoped(options));
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
countries: {
|
|
137
|
+
async update(id, patch, options) {
|
|
138
|
+
requireHumanSession(config);
|
|
139
|
+
const countryId = requireId(id, 'id', countryRefusal);
|
|
140
|
+
return fieldOf(transport, UPDATE_COUNTRY_MUTATION, 'updateCountry', { input: { ...countryInput(patch), id: countryId } }, unscoped(options));
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { type Transport } from '@sixtyninecommerce/core';
|
|
2
|
+
import type { AdminClientConfig } from '../client.js';
|
|
3
|
+
import { type TaxCategory, type TaxRate } from '../tax/index.js';
|
|
4
|
+
import type { Call } from '../types.js';
|
|
5
|
+
/** A new platform-wide tax category, as {@link PlatformTaxCategoriesModule.create} takes it. */
|
|
6
|
+
export interface CreateTaxCategoryInput {
|
|
7
|
+
name: string;
|
|
8
|
+
/**
|
|
9
|
+
* Make it the platform's default category. Only one category is the default: setting it here
|
|
10
|
+
* takes the mark off the one that had it. Not the default when left out.
|
|
11
|
+
*/
|
|
12
|
+
isDefault?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/** A change to a tax category. A field left out keeps what the category has. */
|
|
15
|
+
export interface UpdateTaxCategoryInput {
|
|
16
|
+
name?: string;
|
|
17
|
+
/** `true` moves the default mark here (off the category that had it). */
|
|
18
|
+
isDefault?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** A new platform-wide tax rate, as {@link PlatformTaxRatesModule.create} takes it. */
|
|
21
|
+
export interface CreateTaxRateInput {
|
|
22
|
+
name: string;
|
|
23
|
+
/**
|
|
24
|
+
* A percentage from 0 to 100, both included: `21` is 21 %. Not money. The engine keeps two
|
|
25
|
+
* decimals (`5.5`, `20.75`), so a third one is rounded when it is stored; the answer carries
|
|
26
|
+
* the stored value. A value outside 0–100 is refused as sent, before any rounding
|
|
27
|
+
* (`TAX_RATE_VALUE_INVALID`).
|
|
28
|
+
*/
|
|
29
|
+
value: number;
|
|
30
|
+
/** A disabled rate is never applied. Required: a rate is applied from the moment it exists. */
|
|
31
|
+
enabled: boolean;
|
|
32
|
+
/** The tax category it prices (`tax.categories.list`). */
|
|
33
|
+
categoryId: string;
|
|
34
|
+
/** The zone it prices that category in (`geo.zones.list`). */
|
|
35
|
+
zoneId: string;
|
|
36
|
+
/** Only for customers of this group. Left out, the rate applies to every customer. */
|
|
37
|
+
customerGroupId?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* A change to a tax rate. A field left out keeps what the rate has.
|
|
41
|
+
*
|
|
42
|
+
* There is no way to take the customer group OFF a rate: the engine ignores a null group and
|
|
43
|
+
* keeps the one stored, so `customerGroupId: null` is refused here rather than silently
|
|
44
|
+
* dropped. To widen a group-limited rate to every customer, create a rate without a group and
|
|
45
|
+
* delete the old one.
|
|
46
|
+
*/
|
|
47
|
+
export interface UpdateTaxRateInput {
|
|
48
|
+
name?: string;
|
|
49
|
+
/** See {@link CreateTaxRateInput.value}. */
|
|
50
|
+
value?: number;
|
|
51
|
+
enabled?: boolean;
|
|
52
|
+
categoryId?: string;
|
|
53
|
+
zoneId?: string;
|
|
54
|
+
/** Move the rate to another customer group. */
|
|
55
|
+
customerGroupId?: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* `admin.platform.tax.categories` — the SuperAdmin writes of the platform-wide tax categories
|
|
59
|
+
* every store shares (spec §9.2 `platform`, ruling G128). Reads are `tax.categories.list()`.
|
|
60
|
+
*
|
|
61
|
+
* Every method needs a human SuperAdmin session: an API token or an app credential is refused
|
|
62
|
+
* with `PLATFORM_REQUIRES_SESSION` (`PermissionDeniedError`, 403) BEFORE anything is sent, and a
|
|
63
|
+
* store administrator is refused by the engine with `PLATFORM_SETTINGS_NOT_ALLOWED`
|
|
64
|
+
* (`PermissionDeniedError`, 403) before anything is read or written. No tenant is needed on the
|
|
65
|
+
* client.
|
|
66
|
+
*/
|
|
67
|
+
export interface PlatformTaxCategoriesModule {
|
|
68
|
+
/**
|
|
69
|
+
* Create a tax category, and answer it as `tax.categories.list()` reads it.
|
|
70
|
+
*
|
|
71
|
+
* `INVALID_TAX_CATEGORY_INPUT` (`ValidationError`, 400): a missing or blank name, or an
|
|
72
|
+
* `isDefault` that is not a boolean, refused here before anything is sent.
|
|
73
|
+
*
|
|
74
|
+
* @effect write
|
|
75
|
+
*/
|
|
76
|
+
create(input: CreateTaxCategoryInput, options?: Call): Promise<TaxCategory>;
|
|
77
|
+
/**
|
|
78
|
+
* Rename a tax category or move the default mark to it, and answer it as read. Every store
|
|
79
|
+
* mapping a tax class onto it, and every rate pricing it, keeps pointing at it.
|
|
80
|
+
*
|
|
81
|
+
* `ENTITY_NOT_FOUND` (`NotFoundError`, 404): no category has that id.
|
|
82
|
+
*
|
|
83
|
+
* @effect write
|
|
84
|
+
*/
|
|
85
|
+
update(id: string, patch: UpdateTaxCategoryInput, options?: Call): Promise<TaxCategory>;
|
|
86
|
+
/**
|
|
87
|
+
* Delete a tax category nothing uses any more.
|
|
88
|
+
*
|
|
89
|
+
* - `TAX_CATEGORY_IN_USE` (`ConflictError`, 409): something still prices or carries it. The
|
|
90
|
+
* message names what: the tax rates pricing it, each store's tax class mapped to it (by key
|
|
91
|
+
* and store code), how many product variants carry it, and whether deleted variants or
|
|
92
|
+
* orders were taxed with it. Rates, classes and live variants can be moved to another
|
|
93
|
+
* category; deleted variants and orders keep it for good, so such a category can never be
|
|
94
|
+
* deleted. Nothing is deleted.
|
|
95
|
+
* - `TAX_CATEGORY_NOT_DELETED` (`ConflictError`, 409): the engine refused it for a reason it
|
|
96
|
+
* answered as a result rather than an error, with that reason.
|
|
97
|
+
* - `ENTITY_NOT_FOUND` (`NotFoundError`, 404): no category has that id.
|
|
98
|
+
*
|
|
99
|
+
* @effect destructive
|
|
100
|
+
*/
|
|
101
|
+
delete(id: string, options?: Call): Promise<void>;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* `admin.platform.tax.rates` — the SuperAdmin writes of the platform-wide tax rates: what a tax
|
|
105
|
+
* category costs in a zone. One rate serves every store, so a change reaches every store selling
|
|
106
|
+
* into that zone. Reads are `tax.rates.list()`.
|
|
107
|
+
*
|
|
108
|
+
* Every method needs a human SuperAdmin session (`PLATFORM_REQUIRES_SESSION` before anything is
|
|
109
|
+
* sent; `PLATFORM_SETTINGS_NOT_ALLOWED` from the engine for a store administrator, both
|
|
110
|
+
* `PermissionDeniedError`, 403). No tenant is needed on the client.
|
|
111
|
+
*/
|
|
112
|
+
export interface PlatformTaxRatesModule {
|
|
113
|
+
/**
|
|
114
|
+
* Create a tax rate, and answer it as `tax.rates.list()` reads it.
|
|
115
|
+
*
|
|
116
|
+
* - `INVALID_TAX_RATE_INPUT` (`ValidationError`, 400): a missing name, category, zone or
|
|
117
|
+
* `enabled`, or a value that is not a finite number, refused here before anything is sent.
|
|
118
|
+
* - `TAX_RATE_VALUE_INVALID` (`ValidationError`, 400): a value below 0 or above 100. Refused
|
|
119
|
+
* here before anything is sent, and by the engine for any other caller, with the same code
|
|
120
|
+
* and `details[0].field` `/input/value` (`code` `minimum` or `maximum`), so a form can put
|
|
121
|
+
* the sentence on the rate field whichever side refused it.
|
|
122
|
+
* - `ENTITY_NOT_FOUND` (`NotFoundError`, 404): the category, zone or customer group does not
|
|
123
|
+
* exist.
|
|
124
|
+
*
|
|
125
|
+
* Tagged `money`: a rate decides the tax every store selling into its zone charges from the
|
|
126
|
+
* moment it exists.
|
|
127
|
+
*
|
|
128
|
+
* @effect money
|
|
129
|
+
*/
|
|
130
|
+
create(input: CreateTaxRateInput, options?: Call): Promise<TaxRate>;
|
|
131
|
+
/**
|
|
132
|
+
* Change a tax rate, and answer it as read. Refused as {@link create} is, plus
|
|
133
|
+
* `INVALID_TAX_RATE_INPUT` for `customerGroupId: null` (see {@link UpdateTaxRateInput}) and
|
|
134
|
+
* `ENTITY_NOT_FOUND` for an unknown rate. Only a value the patch SENDS is held to 0–100: a
|
|
135
|
+
* rate stored outside it before the bound existed can still be renamed or switched off
|
|
136
|
+
* without one.
|
|
137
|
+
*
|
|
138
|
+
* @effect money
|
|
139
|
+
*/
|
|
140
|
+
update(id: string, patch: UpdateTaxRateInput, options?: Call): Promise<TaxRate>;
|
|
141
|
+
/**
|
|
142
|
+
* Delete a tax rate, for every store.
|
|
143
|
+
*
|
|
144
|
+
* - `TAX_RATE_NOT_DELETED` (`ConflictError`, 409): the engine refused it, with its reason.
|
|
145
|
+
* - `ENTITY_NOT_FOUND` (`NotFoundError`, 404): no rate has that id.
|
|
146
|
+
*
|
|
147
|
+
* @effect destructive
|
|
148
|
+
*/
|
|
149
|
+
delete(id: string, options?: Call): Promise<void>;
|
|
150
|
+
}
|
|
151
|
+
/** `admin.platform.tax`: SuperAdmin writes of the platform-wide tax tables (G128). */
|
|
152
|
+
export interface PlatformTaxModule {
|
|
153
|
+
categories: PlatformTaxCategoriesModule;
|
|
154
|
+
rates: PlatformTaxRatesModule;
|
|
155
|
+
}
|
|
156
|
+
export declare const CREATE_TAX_CATEGORY_MUTATION = "\n mutation PlatformCreateTaxCategory($input: CreateTaxCategoryInput!) {\n createTaxCategory(input: $input) { \n id\n name\n isDefault\n createdAt\n updatedAt\n }\n }\n";
|
|
157
|
+
export declare const UPDATE_TAX_CATEGORY_MUTATION = "\n mutation PlatformUpdateTaxCategory($input: UpdateTaxCategoryInput!) {\n updateTaxCategory(input: $input) { \n id\n name\n isDefault\n createdAt\n updatedAt\n }\n }\n";
|
|
158
|
+
export declare const DELETE_TAX_CATEGORY_MUTATION = "\n mutation PlatformDeleteTaxCategory($id: ID!) {\n deleteTaxCategory(id: $id) { \n result\n message\n }\n }\n";
|
|
159
|
+
export declare const CREATE_TAX_RATE_MUTATION = "\n mutation PlatformCreateTaxRate($input: CreateTaxRateInput!) {\n createTaxRate(input: $input) { \n id\n name\n value\n enabled\n category { id name }\n zone { id name }\n customerGroup { id name }\n createdAt\n updatedAt\n }\n }\n";
|
|
160
|
+
export declare const UPDATE_TAX_RATE_MUTATION = "\n mutation PlatformUpdateTaxRate($input: UpdateTaxRateInput!) {\n updateTaxRate(input: $input) { \n id\n name\n value\n enabled\n category { id name }\n zone { id name }\n customerGroup { id name }\n createdAt\n updatedAt\n }\n }\n";
|
|
161
|
+
export declare const DELETE_TAX_RATE_MUTATION = "\n mutation PlatformDeleteTaxRate($id: ID!) {\n deleteTaxRate(id: $id) { \n result\n message\n }\n }\n";
|
|
162
|
+
export declare function createPlatformTaxModule(transport: Transport, config: AdminClientConfig): PlatformTaxModule;
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { ValidationError } from '@sixtyninecommerce/core';
|
|
2
|
+
import { assertDeleted, DELETION_FIELDS, fieldOf, } from '../catalog/types.js';
|
|
3
|
+
import { TAX_CATEGORY_FIELDS, TAX_RATE_FIELDS, } from '../tax/index.js';
|
|
4
|
+
import { requireHumanSession } from './guard.js';
|
|
5
|
+
export const CREATE_TAX_CATEGORY_MUTATION = /* GraphQL */ `
|
|
6
|
+
mutation PlatformCreateTaxCategory($input: CreateTaxCategoryInput!) {
|
|
7
|
+
createTaxCategory(input: $input) { ${TAX_CATEGORY_FIELDS} }
|
|
8
|
+
}
|
|
9
|
+
`;
|
|
10
|
+
export const UPDATE_TAX_CATEGORY_MUTATION = /* GraphQL */ `
|
|
11
|
+
mutation PlatformUpdateTaxCategory($input: UpdateTaxCategoryInput!) {
|
|
12
|
+
updateTaxCategory(input: $input) { ${TAX_CATEGORY_FIELDS} }
|
|
13
|
+
}
|
|
14
|
+
`;
|
|
15
|
+
export const DELETE_TAX_CATEGORY_MUTATION = /* GraphQL */ `
|
|
16
|
+
mutation PlatformDeleteTaxCategory($id: ID!) {
|
|
17
|
+
deleteTaxCategory(id: $id) { ${DELETION_FIELDS} }
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
20
|
+
export const CREATE_TAX_RATE_MUTATION = /* GraphQL */ `
|
|
21
|
+
mutation PlatformCreateTaxRate($input: CreateTaxRateInput!) {
|
|
22
|
+
createTaxRate(input: $input) { ${TAX_RATE_FIELDS} }
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
export const UPDATE_TAX_RATE_MUTATION = /* GraphQL */ `
|
|
26
|
+
mutation PlatformUpdateTaxRate($input: UpdateTaxRateInput!) {
|
|
27
|
+
updateTaxRate(input: $input) { ${TAX_RATE_FIELDS} }
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
export const DELETE_TAX_RATE_MUTATION = /* GraphQL */ `
|
|
31
|
+
mutation PlatformDeleteTaxRate($id: ID!) {
|
|
32
|
+
deleteTaxRate(id: $id) { ${DELETION_FIELDS} }
|
|
33
|
+
}
|
|
34
|
+
`;
|
|
35
|
+
const isObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
36
|
+
const refusal = (code) => (message) => new ValidationError({ code, message, status: 400, service: 'vendure' });
|
|
37
|
+
const categoryRefusal = refusal('INVALID_TAX_CATEGORY_INPUT');
|
|
38
|
+
const rateRefusal = refusal('INVALID_TAX_RATE_INPUT');
|
|
39
|
+
/** The bounds of a rate's percentage; the engine holds every caller to the same ones. */
|
|
40
|
+
const TAX_RATE_MIN_PERCENT = 0;
|
|
41
|
+
const TAX_RATE_MAX_PERCENT = 100;
|
|
42
|
+
/**
|
|
43
|
+
* The engine's own refusal of a value outside 0–100 % (`TAX_RATE_VALUE_INVALID`), word for word,
|
|
44
|
+
* with the detail on `/input/value` the engine answers, so a caller cannot tell which side
|
|
45
|
+
* refused it.
|
|
46
|
+
*/
|
|
47
|
+
function rateValueOutOfRange(value) {
|
|
48
|
+
const below = value < TAX_RATE_MIN_PERCENT;
|
|
49
|
+
const range = `from ${String(TAX_RATE_MIN_PERCENT)} to ${String(TAX_RATE_MAX_PERCENT)}`;
|
|
50
|
+
return new ValidationError({
|
|
51
|
+
code: 'TAX_RATE_VALUE_INVALID',
|
|
52
|
+
message: below
|
|
53
|
+
? `A tax rate cannot be below ${String(TAX_RATE_MIN_PERCENT)} %: ${String(value)} % was sent. Enter a percentage ${range}.`
|
|
54
|
+
: `A tax rate cannot be above ${String(TAX_RATE_MAX_PERCENT)} %: ${String(value)} % was sent. Enter a percentage ${range}.`,
|
|
55
|
+
status: 400,
|
|
56
|
+
service: 'vendure',
|
|
57
|
+
details: [
|
|
58
|
+
{
|
|
59
|
+
field: '/input/value',
|
|
60
|
+
code: below ? 'minimum' : 'maximum',
|
|
61
|
+
message: `Enter a rate ${range}.`,
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function requireId(id, what, refuse) {
|
|
67
|
+
if (typeof id !== 'string' || id.trim() === '')
|
|
68
|
+
throw refuse(`${what} must be an id.`);
|
|
69
|
+
return id;
|
|
70
|
+
}
|
|
71
|
+
function categoryInput(input, creating) {
|
|
72
|
+
if (!isObject(input))
|
|
73
|
+
throw categoryRefusal('A tax category input must be an object.');
|
|
74
|
+
const out = {};
|
|
75
|
+
if (input.name !== undefined || creating) {
|
|
76
|
+
if (typeof input.name !== 'string' || input.name.trim() === '') {
|
|
77
|
+
throw categoryRefusal('A tax category needs a name.');
|
|
78
|
+
}
|
|
79
|
+
out.name = input.name;
|
|
80
|
+
}
|
|
81
|
+
if (input.isDefault !== undefined) {
|
|
82
|
+
if (typeof input.isDefault !== 'boolean')
|
|
83
|
+
throw categoryRefusal('isDefault must be a boolean.');
|
|
84
|
+
out.isDefault = input.isDefault;
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
function rateInput(input, creating) {
|
|
89
|
+
if (!isObject(input))
|
|
90
|
+
throw rateRefusal('A tax rate input must be an object.');
|
|
91
|
+
const out = {};
|
|
92
|
+
if (input.name !== undefined || creating) {
|
|
93
|
+
if (typeof input.name !== 'string' || input.name.trim() === '') {
|
|
94
|
+
throw rateRefusal('A tax rate needs a name.');
|
|
95
|
+
}
|
|
96
|
+
out.name = input.name;
|
|
97
|
+
}
|
|
98
|
+
if (input.value !== undefined || creating) {
|
|
99
|
+
if (typeof input.value !== 'number' || !Number.isFinite(input.value)) {
|
|
100
|
+
throw rateRefusal('value must be a finite number: the percentage, 21 for 21 %.');
|
|
101
|
+
}
|
|
102
|
+
if (input.value < TAX_RATE_MIN_PERCENT || input.value > TAX_RATE_MAX_PERCENT) {
|
|
103
|
+
throw rateValueOutOfRange(input.value);
|
|
104
|
+
}
|
|
105
|
+
out.value = input.value;
|
|
106
|
+
}
|
|
107
|
+
if (input.enabled !== undefined || creating) {
|
|
108
|
+
if (typeof input.enabled !== 'boolean')
|
|
109
|
+
throw rateRefusal('enabled must be a boolean.');
|
|
110
|
+
out.enabled = input.enabled;
|
|
111
|
+
}
|
|
112
|
+
if (input.categoryId !== undefined || creating) {
|
|
113
|
+
out.categoryId = requireId(input.categoryId, 'categoryId', rateRefusal);
|
|
114
|
+
}
|
|
115
|
+
if (input.zoneId !== undefined || creating) {
|
|
116
|
+
out.zoneId = requireId(input.zoneId, 'zoneId', rateRefusal);
|
|
117
|
+
}
|
|
118
|
+
if (input.customerGroupId === null && !creating) {
|
|
119
|
+
// The engine reads a null group as "keep the stored one": a request that seems to widen a
|
|
120
|
+
// group-limited rate to every customer would answer success and change nothing.
|
|
121
|
+
throw rateRefusal('A tax rate cannot lose its customer group: create a rate without one and delete this one.');
|
|
122
|
+
}
|
|
123
|
+
if (input.customerGroupId !== undefined && input.customerGroupId !== null) {
|
|
124
|
+
out.customerGroupId = requireId(input.customerGroupId, 'customerGroupId', rateRefusal);
|
|
125
|
+
}
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
export function createPlatformTaxModule(transport, config) {
|
|
129
|
+
// Platform-wide rows: no store is involved, so no tenant is needed. Scoped to a store instead,
|
|
130
|
+
// the transport would first resolve it through the CMS channel mirror and fail on one missing
|
|
131
|
+
// there.
|
|
132
|
+
const unscoped = (call) => ({ ...call, allowUnscoped: true });
|
|
133
|
+
return {
|
|
134
|
+
categories: {
|
|
135
|
+
async create(input, options) {
|
|
136
|
+
requireHumanSession(config);
|
|
137
|
+
return fieldOf(transport, CREATE_TAX_CATEGORY_MUTATION, 'createTaxCategory', { input: categoryInput(input, true) }, unscoped(options));
|
|
138
|
+
},
|
|
139
|
+
async update(id, patch, options) {
|
|
140
|
+
requireHumanSession(config);
|
|
141
|
+
const categoryId = requireId(id, 'id', categoryRefusal);
|
|
142
|
+
return fieldOf(transport, UPDATE_TAX_CATEGORY_MUTATION, 'updateTaxCategory', { input: { ...categoryInput(patch, false), id: categoryId } }, unscoped(options));
|
|
143
|
+
},
|
|
144
|
+
async delete(id, options) {
|
|
145
|
+
requireHumanSession(config);
|
|
146
|
+
assertDeleted('TAX_CATEGORY_NOT_DELETED', [
|
|
147
|
+
await fieldOf(transport, DELETE_TAX_CATEGORY_MUTATION, 'deleteTaxCategory', { id: requireId(id, 'id', categoryRefusal) }, unscoped(options)),
|
|
148
|
+
]);
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
rates: {
|
|
152
|
+
async create(input, options) {
|
|
153
|
+
requireHumanSession(config);
|
|
154
|
+
return fieldOf(transport, CREATE_TAX_RATE_MUTATION, 'createTaxRate', { input: rateInput(input, true) }, unscoped(options));
|
|
155
|
+
},
|
|
156
|
+
async update(id, patch, options) {
|
|
157
|
+
requireHumanSession(config);
|
|
158
|
+
const rateId = requireId(id, 'id', rateRefusal);
|
|
159
|
+
return fieldOf(transport, UPDATE_TAX_RATE_MUTATION, 'updateTaxRate', { input: { ...rateInput(patch, false), id: rateId } }, unscoped(options));
|
|
160
|
+
},
|
|
161
|
+
async delete(id, options) {
|
|
162
|
+
requireHumanSession(config);
|
|
163
|
+
assertDeleted('TAX_RATE_NOT_DELETED', [
|
|
164
|
+
await fieldOf(transport, DELETE_TAX_RATE_MUTATION, 'deleteTaxRate', { id: requireId(id, 'id', rateRefusal) }, unscoped(options)),
|
|
165
|
+
]);
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|