@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,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A customer's additional notification recipients (headless spec §9.2 `customers` "notification
|
|
3
|
+
* recipients"; W10-33): extra addresses (accounting, purchasing, a warehouse) the store's order
|
|
4
|
+
* emails to the customer also go to. Who an order's document email goes to with them applied is
|
|
5
|
+
* `documents.emailRecipients`.
|
|
6
|
+
*/
|
|
7
|
+
import type { Transport } from '@sixtyninecommerce/core';
|
|
8
|
+
import type { Call } from '../types.js';
|
|
9
|
+
export interface CustomerNotificationRecipient {
|
|
10
|
+
id: string;
|
|
11
|
+
/** ISO-8601 with offset. */
|
|
12
|
+
createdAt: string;
|
|
13
|
+
/** ISO-8601 with offset. */
|
|
14
|
+
updatedAt: string;
|
|
15
|
+
email: string;
|
|
16
|
+
label: string | null;
|
|
17
|
+
/**
|
|
18
|
+
* The notification event codes the recipient receives (`order_placed`, `order_shipped`,
|
|
19
|
+
* `invoice_generated`, …). Empty means every event a customer's contacts may receive; a
|
|
20
|
+
* security email (password reset, verification) never goes to a recipient.
|
|
21
|
+
*/
|
|
22
|
+
events: string[];
|
|
23
|
+
enabled: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* "Send only to this address": for its events the address takes the customer's own place
|
|
26
|
+
* instead of being copied beside it.
|
|
27
|
+
*/
|
|
28
|
+
replaceCustomerEmail: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Set when the caller's customer-data level blanked `email` or `label` (an app installation
|
|
31
|
+
* below `identity`): "" or null then means "not granted". Never write such a recipient back.
|
|
32
|
+
*/
|
|
33
|
+
redacted?: true;
|
|
34
|
+
}
|
|
35
|
+
export interface CreateNotificationRecipientInput {
|
|
36
|
+
customerId: string;
|
|
37
|
+
email: string;
|
|
38
|
+
label?: string | null;
|
|
39
|
+
/** Empty or left out: every event a customer's contacts may receive. */
|
|
40
|
+
events?: string[];
|
|
41
|
+
/** Default true. */
|
|
42
|
+
enabled?: boolean;
|
|
43
|
+
/** Default false. */
|
|
44
|
+
replaceCustomerEmail?: boolean;
|
|
45
|
+
}
|
|
46
|
+
export interface UpdateNotificationRecipientInput {
|
|
47
|
+
email?: string;
|
|
48
|
+
/** `null` clears the label. */
|
|
49
|
+
label?: string | null;
|
|
50
|
+
events?: string[];
|
|
51
|
+
enabled?: boolean;
|
|
52
|
+
replaceCustomerEmail?: boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface CustomerNotificationRecipientsModule {
|
|
55
|
+
/**
|
|
56
|
+
* The customer's notification recipients in this store, oldest first; `[]` for a customer
|
|
57
|
+
* with none, and for one the store does not hold. Needs `ReadCustomer`.
|
|
58
|
+
*
|
|
59
|
+
* @effect read
|
|
60
|
+
*/
|
|
61
|
+
list(customerId: string, options?: Call): Promise<CustomerNotificationRecipient[]>;
|
|
62
|
+
/**
|
|
63
|
+
* Add a recipient to a customer. Needs `UpdateCustomer`.
|
|
64
|
+
*
|
|
65
|
+
* Refused with the engine's sentence (`ValidationError`, `USER_INPUT_ERROR`, 400): a value
|
|
66
|
+
* that is not an email address, an address the customer already has as a recipient, an event
|
|
67
|
+
* code a customer's contacts may not receive, a label over 100 characters, or a customer that
|
|
68
|
+
* already has 20. A customer this store does not hold is a `NotFoundError`
|
|
69
|
+
* (`ENTITY_NOT_FOUND`); an engine older than that check saved the recipient under any id,
|
|
70
|
+
* where no read ever showed it.
|
|
71
|
+
*
|
|
72
|
+
* @effect write
|
|
73
|
+
*/
|
|
74
|
+
create(input: CreateNotificationRecipientInput, options?: Call): Promise<CustomerNotificationRecipient>;
|
|
75
|
+
/**
|
|
76
|
+
* Change a recipient; what is left out is kept. Needs `UpdateCustomer`. Refused like
|
|
77
|
+
* {@link create}, and for an id that is not a recipient of this store.
|
|
78
|
+
*
|
|
79
|
+
* @effect write
|
|
80
|
+
*/
|
|
81
|
+
update(id: string, input: UpdateNotificationRecipientInput, options?: Call): Promise<CustomerNotificationRecipient>;
|
|
82
|
+
/**
|
|
83
|
+
* Remove a recipient: the store's emails stop going to the address. Needs `UpdateCustomer`.
|
|
84
|
+
*
|
|
85
|
+
* Refused `CUSTOMER_NOTIFICATION_RECIPIENT_NOT_DELETED` (`ConflictError`, 409) with the
|
|
86
|
+
* engine's own reason when this store has no such recipient.
|
|
87
|
+
*
|
|
88
|
+
* @effect destructive
|
|
89
|
+
*/
|
|
90
|
+
delete(id: string, options?: Call): Promise<void>;
|
|
91
|
+
}
|
|
92
|
+
export declare const NOTIFICATION_RECIPIENT_FIELDS = "\n id\n createdAt\n updatedAt\n email\n label\n events\n enabled\n replaceCustomerEmail\n";
|
|
93
|
+
export declare const NOTIFICATION_RECIPIENTS_QUERY = "\n query CustomerNotificationRecipients($id: ID!) {\n customer(id: $id) {\n id\n notificationRecipients {\n \n id\n createdAt\n updatedAt\n email\n label\n events\n enabled\n replaceCustomerEmail\n\n }\n }\n }\n";
|
|
94
|
+
export declare const CREATE_NOTIFICATION_RECIPIENT_MUTATION = "\n mutation CreateCustomerNotificationRecipient($input: CreateCustomerNotificationRecipientInput!) {\n createCustomerNotificationRecipient(input: $input) {\n \n id\n createdAt\n updatedAt\n email\n label\n events\n enabled\n replaceCustomerEmail\n\n }\n }\n";
|
|
95
|
+
export declare const UPDATE_NOTIFICATION_RECIPIENT_MUTATION = "\n mutation UpdateCustomerNotificationRecipient($input: UpdateCustomerNotificationRecipientInput!) {\n updateCustomerNotificationRecipient(input: $input) {\n \n id\n createdAt\n updatedAt\n email\n label\n events\n enabled\n replaceCustomerEmail\n\n }\n }\n";
|
|
96
|
+
export declare const DELETE_NOTIFICATION_RECIPIENT_MUTATION = "\n mutation DeleteCustomerNotificationRecipient($id: ID!) {\n deleteCustomerNotificationRecipient(id: $id) {\n result\n message\n }\n }\n";
|
|
97
|
+
export declare function createCustomerNotificationRecipientsModule(transport: Transport): CustomerNotificationRecipientsModule;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { assertDeleted, fieldOf } from '../catalog/types.js';
|
|
2
|
+
import { customerDataField } from './wire.js';
|
|
3
|
+
export const NOTIFICATION_RECIPIENT_FIELDS = /* GraphQL */ `
|
|
4
|
+
id
|
|
5
|
+
createdAt
|
|
6
|
+
updatedAt
|
|
7
|
+
email
|
|
8
|
+
label
|
|
9
|
+
events
|
|
10
|
+
enabled
|
|
11
|
+
replaceCustomerEmail
|
|
12
|
+
`;
|
|
13
|
+
export const NOTIFICATION_RECIPIENTS_QUERY = /* GraphQL */ `
|
|
14
|
+
query CustomerNotificationRecipients($id: ID!) {
|
|
15
|
+
customer(id: $id) {
|
|
16
|
+
id
|
|
17
|
+
notificationRecipients {
|
|
18
|
+
${NOTIFICATION_RECIPIENT_FIELDS}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
`;
|
|
23
|
+
export const CREATE_NOTIFICATION_RECIPIENT_MUTATION = /* GraphQL */ `
|
|
24
|
+
mutation CreateCustomerNotificationRecipient($input: CreateCustomerNotificationRecipientInput!) {
|
|
25
|
+
createCustomerNotificationRecipient(input: $input) {
|
|
26
|
+
${NOTIFICATION_RECIPIENT_FIELDS}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
export const UPDATE_NOTIFICATION_RECIPIENT_MUTATION = /* GraphQL */ `
|
|
31
|
+
mutation UpdateCustomerNotificationRecipient($input: UpdateCustomerNotificationRecipientInput!) {
|
|
32
|
+
updateCustomerNotificationRecipient(input: $input) {
|
|
33
|
+
${NOTIFICATION_RECIPIENT_FIELDS}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
`;
|
|
37
|
+
export const DELETE_NOTIFICATION_RECIPIENT_MUTATION = /* GraphQL */ `
|
|
38
|
+
mutation DeleteCustomerNotificationRecipient($id: ID!) {
|
|
39
|
+
deleteCustomerNotificationRecipient(id: $id) {
|
|
40
|
+
result
|
|
41
|
+
message
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
`;
|
|
45
|
+
export function createCustomerNotificationRecipientsModule(transport) {
|
|
46
|
+
return {
|
|
47
|
+
async list(customerId, options) {
|
|
48
|
+
const { value: customer, mark } = await customerDataField(transport, NOTIFICATION_RECIPIENTS_QUERY, 'customer', { id: customerId }, options);
|
|
49
|
+
return (customer?.notificationRecipients ?? []).map(mark);
|
|
50
|
+
},
|
|
51
|
+
async create(input, options) {
|
|
52
|
+
const { value, mark } = await customerDataField(transport, CREATE_NOTIFICATION_RECIPIENT_MUTATION, 'createCustomerNotificationRecipient', {
|
|
53
|
+
input: {
|
|
54
|
+
customerId: input.customerId,
|
|
55
|
+
email: input.email,
|
|
56
|
+
label: input.label,
|
|
57
|
+
events: input.events,
|
|
58
|
+
enabled: input.enabled,
|
|
59
|
+
replaceCustomerEmail: input.replaceCustomerEmail,
|
|
60
|
+
},
|
|
61
|
+
}, options);
|
|
62
|
+
return mark(value);
|
|
63
|
+
},
|
|
64
|
+
async update(id, input, options) {
|
|
65
|
+
const { value, mark } = await customerDataField(transport, UPDATE_NOTIFICATION_RECIPIENT_MUTATION, 'updateCustomerNotificationRecipient', {
|
|
66
|
+
// `label: null` clears it and is sent; everything left out stays off the wire, and kept.
|
|
67
|
+
input: {
|
|
68
|
+
id,
|
|
69
|
+
email: input.email,
|
|
70
|
+
label: input.label,
|
|
71
|
+
events: input.events,
|
|
72
|
+
enabled: input.enabled,
|
|
73
|
+
replaceCustomerEmail: input.replaceCustomerEmail,
|
|
74
|
+
},
|
|
75
|
+
}, options);
|
|
76
|
+
return mark(value);
|
|
77
|
+
},
|
|
78
|
+
async delete(id, options) {
|
|
79
|
+
assertDeleted('CUSTOMER_NOTIFICATION_RECIPIENT_NOT_DELETED', [
|
|
80
|
+
await fieldOf(transport, DELETE_NOTIFICATION_RECIPIENT_MUTATION, 'deleteCustomerNotificationRecipient', { id }, options),
|
|
81
|
+
]);
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A customer's saved lists (headless W10-15, spec §9.2 `customers`): the named lists of products
|
|
3
|
+
* and quantities a shopper keeps on the storefront to order again. Read-only here: the shopper
|
|
4
|
+
* writes them through the Shop API, and the back office reads them on the customer's page.
|
|
5
|
+
*/
|
|
6
|
+
import { type Transport } from '@sixtyninecommerce/core';
|
|
7
|
+
import type { Call } from '../types.js';
|
|
8
|
+
export interface CustomerSavedListItem {
|
|
9
|
+
id: string;
|
|
10
|
+
productVariantId: string;
|
|
11
|
+
quantity: number;
|
|
12
|
+
/** The shopper's order of the items, lowest first; the items are answered in it. */
|
|
13
|
+
position: number;
|
|
14
|
+
/**
|
|
15
|
+
* The variant as the store holds it now, or `null` when it no longer does. A variant of a
|
|
16
|
+
* DISABLED product is still answered here: the Shop API hides it from the shopper's own list
|
|
17
|
+
* (multi-region decision 87), the back office still sees what the list holds.
|
|
18
|
+
*/
|
|
19
|
+
productVariant: {
|
|
20
|
+
id: string;
|
|
21
|
+
name: string;
|
|
22
|
+
sku: string;
|
|
23
|
+
} | null;
|
|
24
|
+
}
|
|
25
|
+
export interface CustomerSavedList {
|
|
26
|
+
id: string;
|
|
27
|
+
/** What the shopper called the list: customer data, withheld below `customerData: full`. */
|
|
28
|
+
name: string;
|
|
29
|
+
createdAt: string;
|
|
30
|
+
updatedAt: string;
|
|
31
|
+
items: CustomerSavedListItem[];
|
|
32
|
+
/** Set when the caller's customer-data level withheld the name (an app below `full`). */
|
|
33
|
+
redacted?: true;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The customer's own read (`customer(id) { id }`) beside the lists: the lists' door answers `[]`
|
|
37
|
+
* for an id the store does not hold, and only the customer read tells a customer with no lists
|
|
38
|
+
* apart from a customer the store does not hold.
|
|
39
|
+
*/
|
|
40
|
+
export declare const CUSTOMER_SAVED_LISTS_QUERY = "\n query CustomerSavedLists($customerId: ID!) {\n customer(id: $customerId) {\n id\n }\n savedListsForCustomer(customerId: $customerId) {\n id\n name\n createdAt\n updatedAt\n items {\n id\n productVariantId\n quantity\n position\n productVariant {\n id\n name\n sku\n }\n }\n }\n }\n";
|
|
41
|
+
/** `customers.savedLists`: see `CustomersModule.savedLists`. */
|
|
42
|
+
export declare function readCustomerSavedLists(transport: Transport, customerId: string, options: Call | undefined): Promise<CustomerSavedList[] | null>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A customer's saved lists (headless W10-15, spec §9.2 `customers`): the named lists of products
|
|
3
|
+
* and quantities a shopper keeps on the storefront to order again. Read-only here: the shopper
|
|
4
|
+
* writes them through the Shop API, and the back office reads them on the customer's page.
|
|
5
|
+
*/
|
|
6
|
+
import { UpstreamError } from '@sixtyninecommerce/core';
|
|
7
|
+
import { redactionWatcher } from '../customer-data-redaction.js';
|
|
8
|
+
/**
|
|
9
|
+
* The customer's own read (`customer(id) { id }`) beside the lists: the lists' door answers `[]`
|
|
10
|
+
* for an id the store does not hold, and only the customer read tells a customer with no lists
|
|
11
|
+
* apart from a customer the store does not hold.
|
|
12
|
+
*/
|
|
13
|
+
export const CUSTOMER_SAVED_LISTS_QUERY = /* GraphQL */ `
|
|
14
|
+
query CustomerSavedLists($customerId: ID!) {
|
|
15
|
+
customer(id: $customerId) {
|
|
16
|
+
id
|
|
17
|
+
}
|
|
18
|
+
savedListsForCustomer(customerId: $customerId) {
|
|
19
|
+
id
|
|
20
|
+
name
|
|
21
|
+
createdAt
|
|
22
|
+
updatedAt
|
|
23
|
+
items {
|
|
24
|
+
id
|
|
25
|
+
productVariantId
|
|
26
|
+
quantity
|
|
27
|
+
position
|
|
28
|
+
productVariant {
|
|
29
|
+
id
|
|
30
|
+
name
|
|
31
|
+
sku
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
`;
|
|
37
|
+
/** `customers.savedLists`: see `CustomersModule.savedLists`. */
|
|
38
|
+
export async function readCustomerSavedLists(transport, customerId, options) {
|
|
39
|
+
const redaction = redactionWatcher();
|
|
40
|
+
const data = await transport.graphql({
|
|
41
|
+
api: 'admin',
|
|
42
|
+
query: CUSTOMER_SAVED_LISTS_QUERY,
|
|
43
|
+
variables: { customerId },
|
|
44
|
+
onExtensions: redaction.onExtensions,
|
|
45
|
+
}, options);
|
|
46
|
+
if (data === null || typeof data !== 'object' || !Array.isArray(data.savedListsForCustomer)) {
|
|
47
|
+
throw new UpstreamError({
|
|
48
|
+
code: 'UNEXPECTED_RESPONSE',
|
|
49
|
+
message: 'The engine answered without "savedListsForCustomer".',
|
|
50
|
+
status: 502,
|
|
51
|
+
service: 'vendure',
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
if (!data.customer)
|
|
55
|
+
return null;
|
|
56
|
+
return data.savedListsForCustomer.map((list) => redaction.mark({
|
|
57
|
+
...list,
|
|
58
|
+
// The engine keeps no order on the items; the shopper's is `position`, then the id.
|
|
59
|
+
items: [...list.items].sort((a, b) => a.position - b.position || a.id.localeCompare(b.id)),
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A customer's VAT number, checked against the EU's VIES service (headless spec §9.2
|
|
3
|
+
* `customers` "VAT validation"; W10-33). The stored number and its standing verdict are on
|
|
4
|
+
* `customers.get(id, { include: ['customFields'] })`.
|
|
5
|
+
*/
|
|
6
|
+
import type { Transport } from '@sixtyninecommerce/core';
|
|
7
|
+
import type { Call } from '../types.js';
|
|
8
|
+
/**
|
|
9
|
+
* How long {@link CustomerVatModule.validate} waits for the engine, which asks VIES up to three
|
|
10
|
+
* times (a 5 s limit each, with a pause between) before it answers.
|
|
11
|
+
*/
|
|
12
|
+
export declare const VAT_VALIDATION_TIMEOUT_MS = 25000;
|
|
13
|
+
/**
|
|
14
|
+
* What a check of a VAT number found. Only `valid` and `invalid` say something about the
|
|
15
|
+
* number:
|
|
16
|
+
*
|
|
17
|
+
* - `valid`: VIES confirmed the number is registered.
|
|
18
|
+
* - `invalid`: VIES confirmed it is not, or the number failed a check before VIES was asked
|
|
19
|
+
* (too short, no EU member state's prefix); `error` then says which.
|
|
20
|
+
* - `pending`: VIES could not be reached or kept failing. The number was not checked: try
|
|
21
|
+
* again later.
|
|
22
|
+
* - `error`: VIES refused the lookup for a reason that will not pass by itself (`error`
|
|
23
|
+
* carries it). The number was not checked.
|
|
24
|
+
* - `none`: no verdict (never answered by a check).
|
|
25
|
+
*/
|
|
26
|
+
export type VatValidationStatus = 'valid' | 'invalid' | 'pending' | 'error' | 'none';
|
|
27
|
+
export interface CustomerVatValidation {
|
|
28
|
+
status: VatValidationStatus | (string & {});
|
|
29
|
+
/** The number as checked, normalised (upper case, no spaces). */
|
|
30
|
+
vatNumber: string;
|
|
31
|
+
/**
|
|
32
|
+
* The country the number's two-letter prefix names (Greece's `EL` reads `GR`), whether or not
|
|
33
|
+
* it is an EU member state; "" for a number too short to have one.
|
|
34
|
+
*/
|
|
35
|
+
countryCode: string;
|
|
36
|
+
/** The registered name VIES answered, when it shares one. */
|
|
37
|
+
companyName: string | null;
|
|
38
|
+
/** The registered address VIES answered, when it shares one. */
|
|
39
|
+
companyAddress: string | null;
|
|
40
|
+
/** ISO-8601 with offset; when VIES confirmed the number. */
|
|
41
|
+
validatedAt: string | null;
|
|
42
|
+
/** Why the number is `invalid`, or what stopped the check. */
|
|
43
|
+
error: string | null;
|
|
44
|
+
/**
|
|
45
|
+
* Set when the caller's customer-data level blanked the number, the name and the address (an
|
|
46
|
+
* app installation below `full`): "" or null then means "not granted".
|
|
47
|
+
*/
|
|
48
|
+
redacted?: true;
|
|
49
|
+
}
|
|
50
|
+
export interface CustomerVatModule {
|
|
51
|
+
/**
|
|
52
|
+
* Check a VAT number with the EU's VIES service and store it on the customer with the
|
|
53
|
+
* verdict. Needs `UpdateCustomer`.
|
|
54
|
+
*
|
|
55
|
+
* **The verdict is `status`, never an error.** A number VIES does not know resolves
|
|
56
|
+
* `invalid`; a VIES that cannot be reached resolves `pending`, and one that refuses the lookup
|
|
57
|
+
* `error`, neither of which says anything about the number. The number and the verdict are
|
|
58
|
+
* stored either way, with one exception: `pending` or `error` for the number the customer
|
|
59
|
+
* already has as `valid` changes nothing, so an outage never downgrades a checked number.
|
|
60
|
+
*
|
|
61
|
+
* The call can take up to {@link VAT_VALIDATION_TIMEOUT_MS} (it waits that long instead of
|
|
62
|
+
* the client's own limit); pass `signal` to give up earlier.
|
|
63
|
+
*
|
|
64
|
+
* While an app or API token owns Customer details on the store, a number that differs from
|
|
65
|
+
* the stored one is refused `FIELD_GROUP_LOCKED` (`BusinessRuleError`); checking the stored
|
|
66
|
+
* number again passes. A customer this store does not hold is a `NotFoundError`
|
|
67
|
+
* (`ENTITY_NOT_FOUND`).
|
|
68
|
+
*
|
|
69
|
+
* @effect write
|
|
70
|
+
*/
|
|
71
|
+
validate(customerId: string, vatNumber: string, options?: Call): Promise<CustomerVatValidation>;
|
|
72
|
+
/**
|
|
73
|
+
* Remove the customer's VAT number and its verdict. Needs `UpdateCustomer`. Refused
|
|
74
|
+
* `FIELD_GROUP_LOCKED` like {@link validate} while the customer has a number; a customer this
|
|
75
|
+
* store does not hold is a `NotFoundError` (`ENTITY_NOT_FOUND`).
|
|
76
|
+
*
|
|
77
|
+
* @effect write
|
|
78
|
+
*/
|
|
79
|
+
clear(customerId: string, options?: Call): Promise<void>;
|
|
80
|
+
}
|
|
81
|
+
export declare const VALIDATE_VAT_MUTATION = "\n mutation ValidateCustomerVatNumber($customerId: ID!, $vatNumber: String!) {\n validateCustomerVatNumber(customerId: $customerId, vatNumber: $vatNumber) {\n status\n vatNumber\n countryCode\n companyName\n companyAddress\n validatedAt\n error\n }\n }\n";
|
|
82
|
+
export declare const CLEAR_VAT_MUTATION = "\n mutation ClearCustomerVatNumber($customerId: ID!) {\n clearCustomerVatNumber(customerId: $customerId)\n }\n";
|
|
83
|
+
export declare function createCustomerVatModule(transport: Transport): CustomerVatModule;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { fieldOf } from '../catalog/types.js';
|
|
2
|
+
import { customerDataField } from './wire.js';
|
|
3
|
+
/**
|
|
4
|
+
* How long {@link CustomerVatModule.validate} waits for the engine, which asks VIES up to three
|
|
5
|
+
* times (a 5 s limit each, with a pause between) before it answers.
|
|
6
|
+
*/
|
|
7
|
+
export const VAT_VALIDATION_TIMEOUT_MS = 25_000;
|
|
8
|
+
export const VALIDATE_VAT_MUTATION = /* GraphQL */ `
|
|
9
|
+
mutation ValidateCustomerVatNumber($customerId: ID!, $vatNumber: String!) {
|
|
10
|
+
validateCustomerVatNumber(customerId: $customerId, vatNumber: $vatNumber) {
|
|
11
|
+
status
|
|
12
|
+
vatNumber
|
|
13
|
+
countryCode
|
|
14
|
+
companyName
|
|
15
|
+
companyAddress
|
|
16
|
+
validatedAt
|
|
17
|
+
error
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
`;
|
|
21
|
+
export const CLEAR_VAT_MUTATION = /* GraphQL */ `
|
|
22
|
+
mutation ClearCustomerVatNumber($customerId: ID!) {
|
|
23
|
+
clearCustomerVatNumber(customerId: $customerId)
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
export function createCustomerVatModule(transport) {
|
|
27
|
+
return {
|
|
28
|
+
async validate(customerId, vatNumber, options) {
|
|
29
|
+
const { value, mark } = await customerDataField(transport, VALIDATE_VAT_MUTATION, 'validateCustomerVatNumber', { customerId, vatNumber },
|
|
30
|
+
// The method's own limit: the transport's default would give up before VIES answers.
|
|
31
|
+
{ ...options, timeoutMs: VAT_VALIDATION_TIMEOUT_MS });
|
|
32
|
+
return mark({
|
|
33
|
+
status: value.status,
|
|
34
|
+
vatNumber: value.vatNumber,
|
|
35
|
+
countryCode: value.countryCode,
|
|
36
|
+
companyName: value.companyName ?? null,
|
|
37
|
+
companyAddress: value.companyAddress ?? null,
|
|
38
|
+
validatedAt: value.validatedAt ?? null,
|
|
39
|
+
error: value.error ?? null,
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
async clear(customerId, options) {
|
|
43
|
+
await fieldOf(transport, CLEAR_VAT_MUTATION, 'clearCustomerVatNumber', { customerId }, options);
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type CallOptions, type Transport } from '@sixtyninecommerce/core';
|
|
2
|
+
import { redactionWatcher } from '../customer-data-redaction.js';
|
|
3
|
+
/**
|
|
4
|
+
* One Admin API document's single root field, with the call's customer-data watcher: `mark`
|
|
5
|
+
* stamps `redacted: true` on a record of the answer when the caller's level blanked anything in
|
|
6
|
+
* it (an app installation below `customerData: full`). An absent field is refused, as
|
|
7
|
+
* `fieldOf` refuses it; a null one is a real answer.
|
|
8
|
+
*/
|
|
9
|
+
export declare function customerDataField<T>(transport: Transport, document: string, field: string, variables: Record<string, unknown>, options: CallOptions | undefined): Promise<{
|
|
10
|
+
value: T;
|
|
11
|
+
mark: ReturnType<typeof redactionWatcher>['mark'];
|
|
12
|
+
}>;
|
|
13
|
+
/** The company flags of one address, as a list row carries them. */
|
|
14
|
+
export interface CustomerAddressSummary {
|
|
15
|
+
company: string | null;
|
|
16
|
+
defaultBillingAddress: boolean | null;
|
|
17
|
+
defaultShippingAddress: boolean | null;
|
|
18
|
+
}
|
|
19
|
+
/** The company a list shows for a customer, by the dashboard's own rule (`customerCompanyOf`). */
|
|
20
|
+
export declare function companyOf(addresses: readonly CustomerAddressSummary[]): string | null;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { UpstreamError } from '@sixtyninecommerce/core';
|
|
2
|
+
import { redactionWatcher } from '../customer-data-redaction.js';
|
|
3
|
+
/**
|
|
4
|
+
* One Admin API document's single root field, with the call's customer-data watcher: `mark`
|
|
5
|
+
* stamps `redacted: true` on a record of the answer when the caller's level blanked anything in
|
|
6
|
+
* it (an app installation below `customerData: full`). An absent field is refused, as
|
|
7
|
+
* `fieldOf` refuses it; a null one is a real answer.
|
|
8
|
+
*/
|
|
9
|
+
export async function customerDataField(transport, document, field, variables, options) {
|
|
10
|
+
const redaction = redactionWatcher();
|
|
11
|
+
const data = await transport.graphql({ api: 'admin', query: document, variables, onExtensions: redaction.onExtensions }, options);
|
|
12
|
+
if (data === null || typeof data !== 'object' || !Object.hasOwn(data, field)) {
|
|
13
|
+
throw new UpstreamError({
|
|
14
|
+
code: 'UNEXPECTED_RESPONSE',
|
|
15
|
+
message: `The engine answered without "${field}".`,
|
|
16
|
+
status: 502,
|
|
17
|
+
service: 'vendure',
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return { value: data[field], mark: redaction.mark };
|
|
21
|
+
}
|
|
22
|
+
/** The company a list shows for a customer, by the dashboard's own rule (`customerCompanyOf`). */
|
|
23
|
+
export function companyOf(addresses) {
|
|
24
|
+
const candidates = [
|
|
25
|
+
addresses.find((address) => address.defaultBillingAddress === true),
|
|
26
|
+
addresses.find((address) => address.defaultShippingAddress === true),
|
|
27
|
+
...addresses,
|
|
28
|
+
];
|
|
29
|
+
for (const address of candidates) {
|
|
30
|
+
const company = address?.company?.trim();
|
|
31
|
+
if (company)
|
|
32
|
+
return company;
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|