@base44/app-plugin-commerce 0.1.6 → 0.1.8
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 +12 -12
- package/base44/agents/commerce/StoreAdmin.jsonc +2 -2
- package/base44/entities/commerce.Cart.jsonc +1 -1
- package/base44/entities/commerce.Coupon.jsonc +5 -0
- package/base44/entities/commerce.Order.jsonc +6 -7
- package/base44/entities/commerce.OrderRefund.jsonc +1 -1
- package/base44/entities/commerce.PaymentGateway.jsonc +1 -1
- package/base44/entities/commerce.Product.jsonc +6 -16
- package/base44/entities/{commerce.ProductTag.jsonc → commerce.ProductRibbon.jsonc} +2 -2
- package/base44/entities/commerce.ProductVariation.jsonc +1 -9
- package/base44/entities/commerce.ShippingTaxLocation.jsonc +85 -0
- package/base44/entities/commerce.Webhook.jsonc +1 -1
- package/base44/functions/commerce/admin-orders/helpers.ts +7 -13
- package/base44/functions/commerce/admin-products/entry.ts +11 -17
- package/base44/functions/commerce/admin-refunds/entry.ts +10 -9
- package/base44/functions/commerce/admin-reports/entry.ts +3 -3
- package/base44/functions/commerce/admin-tools/entry.ts +9 -36
- package/base44/functions/commerce/payment-webhook/entry.ts +50 -89
- package/base44/functions/commerce/payments/entry.ts +46 -42
- package/base44/functions/commerce/seed-store/defaults.ts +35 -42
- package/base44/functions/commerce/seed-store/entry.ts +68 -46
- package/base44/functions/commerce/seed-store/sample-data.ts +2 -15
- package/base44/functions/commerce/seed-store/seed-catalog.ts +105 -55
- package/base44/functions/commerce/storefront-cart/cart-pricing.ts +6 -11
- package/base44/functions/commerce/storefront-cart/entry.ts +36 -2
- package/base44/functions/commerce/storefront-catalog/entry.ts +55 -72
- package/base44/functions/commerce/storefront-checkout/cart-pricing.ts +6 -11
- package/base44/functions/commerce/storefront-checkout/entry.ts +43 -56
- package/base44/shared/commerce/card-payment.ts +80 -0
- package/base44/shared/commerce/coupons.ts +16 -10
- package/base44/shared/commerce/emails.ts +30 -18
- package/base44/shared/commerce/money.ts +11 -24
- package/base44/shared/commerce/payments.ts +55 -286
- package/base44/shared/commerce/scan.ts +1 -1
- package/base44/shared/commerce/sequence.ts +1 -1
- package/base44/shared/commerce/settings.ts +4 -9
- package/base44/shared/commerce/shipping.ts +65 -133
- package/base44/shared/commerce/tax.ts +48 -96
- package/base44/shared/commerce/totals.ts +77 -91
- package/package.json +1 -1
- package/scripts/install.js +28 -7
- package/skills/commerce/SKILL.md +14 -14
- package/skills/commerce/docs/api-admin.md +23 -26
- package/skills/commerce/docs/api-storefront.md +67 -61
- package/skills/commerce/installation-guidelines.md +8 -8
- package/skills/commerce/post-installation.md +60 -39
- package/skills/commerce/references/admin-product-form.md +15 -12
- package/skills/commerce/references/emails.md +2 -2
- package/skills/commerce/references/guest-access-security.md +2 -2
- package/skills/commerce/references/online-payments.md +24 -166
- package/skills/commerce/references/product-render.md +18 -18
- package/skills/commerce/references/reviews.md +14 -8
- package/skills/commerce/references/storefront-product-page.md +1 -1
- package/src/commerce/admin/README.md +5 -6
- package/src/commerce/admin/bot/Markdown.jsx +1 -1
- package/src/commerce/admin/hooks/useMoney.js +13 -22
- package/src/commerce/admin/layout/AuthGuard.jsx +1 -1
- package/src/commerce/admin/lib/constants.js +2 -29
- package/src/commerce/admin/lib/order-utils.js +1 -1
- package/src/commerce/admin/pages/coupons/CouponEditor.jsx +131 -140
- package/src/commerce/admin/pages/coupons/CouponsList.jsx +14 -7
- package/src/commerce/admin/pages/orders/OrderEditor.jsx +3 -3
- package/src/commerce/admin/pages/orders/components/PaymentPanel.jsx +17 -28
- package/src/commerce/admin/pages/orders/components/RefundPanel.jsx +5 -11
- package/src/commerce/admin/pages/products/Categories.jsx +147 -177
- package/src/commerce/admin/pages/products/ProductEditor.jsx +23 -18
- package/src/commerce/admin/pages/products/Reviews.jsx +37 -1
- package/src/commerce/admin/pages/products/components/ProductDataPanel.jsx +33 -47
- package/src/commerce/admin/pages/products/components/PublishBox.jsx +13 -34
- package/src/commerce/admin/pages/products/components/TaxonomyPanel.jsx +29 -29
- package/src/commerce/admin/pages/products/components/tabs/PriceInventoryTab.jsx +14 -44
- package/src/commerce/admin/pages/reports/Reports.jsx +2 -2
- package/src/commerce/admin/pages/settings/EmailsSettings.jsx +101 -68
- package/src/commerce/admin/pages/settings/GeneralSettings.jsx +40 -38
- package/src/commerce/admin/pages/settings/InventorySettings.jsx +1 -41
- package/src/commerce/admin/pages/settings/LocationEditor.jsx +377 -0
- package/src/commerce/admin/pages/settings/PaymentsSettings.jsx +137 -119
- package/src/commerce/admin/pages/settings/SettingsLayout.jsx +2 -4
- package/src/commerce/admin/pages/settings/ShippingTaxSettings.jsx +191 -0
- package/src/commerce/admin/routes.jsx +6 -12
- package/src/commerce/utils/index.js +2 -2
- package/src/commerce/utils/shipping-promos.js +45 -49
- package/src/commerce/utils/variants.js +1 -1
- package/base44/entities/commerce.ShippingClass.jsonc +0 -30
- package/base44/entities/commerce.ShippingZone.jsonc +0 -41
- package/base44/entities/commerce.ShippingZoneMethod.jsonc +0 -84
- package/base44/entities/commerce.TaxClass.jsonc +0 -23
- package/base44/entities/commerce.TaxRate.jsonc +0 -68
- package/base44/shared/commerce/stripe.ts +0 -463
- package/src/commerce/admin/hooks/usePaymentProvider.js +0 -27
- package/src/commerce/admin/pages/settings/ProductsSettings.jsx +0 -118
- package/src/commerce/admin/pages/settings/ShippingSettings.jsx +0 -304
- package/src/commerce/admin/pages/settings/ShippingZoneEditor.jsx +0 -514
- package/src/commerce/admin/pages/settings/TaxRatesTable.jsx +0 -231
- package/src/commerce/admin/pages/settings/TaxSettings.jsx +0 -280
|
@@ -3,87 +3,83 @@
|
|
|
3
3
|
* ("Free shipping over €150", "You're €30 away from free shipping") states a
|
|
4
4
|
* real rule instead of an invented number.
|
|
5
5
|
*
|
|
6
|
-
* A free-shipping claim is only true if a
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* A free-shipping claim is only true if a Shipping & Tax Location carries a
|
|
7
|
+
* shipping rate that is free — `cost: 0` — or becomes free at a threshold
|
|
8
|
+
* (`free_over`). The totals engine zeroes the rate exactly when the discounted
|
|
9
|
+
* items subtotal reaches `free_over`, so anything the UI promises outside
|
|
10
|
+
* these rules is a promise the checkout will not keep.
|
|
10
11
|
*
|
|
11
|
-
* **
|
|
12
|
-
* `
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* projects the rules itself.
|
|
12
|
+
* **Locations are admin-only data.** `commerce.ShippingTaxLocation` is
|
|
13
|
+
* `read: {role: "admin"}` like every entity, so a visitor cannot list them —
|
|
14
|
+
* these helpers run where the records are already in hand: a backend function,
|
|
15
|
+
* an admin screen, or a storefront action you add that projects the rules.
|
|
16
16
|
*
|
|
17
17
|
* ```js
|
|
18
|
-
* const rules = freeShippingRules(
|
|
18
|
+
* const rules = freeShippingRules(locations);
|
|
19
19
|
* // no rules → do not advertise free shipping anywhere.
|
|
20
20
|
* ```
|
|
21
21
|
*
|
|
22
22
|
* For the *live* answer on a real cart, use the cart view's
|
|
23
|
-
* `available_shipping_methods` after `set-shipping-address` — that is computed
|
|
24
|
-
* the same engine and needs no extra exposure.
|
|
23
|
+
* `available_shipping_methods` after `set-shipping-address` — that is computed
|
|
24
|
+
* by the same engine and needs no extra exposure.
|
|
25
25
|
*
|
|
26
26
|
* Framework-free and dependency-free. See
|
|
27
|
-
*
|
|
27
|
+
* `.agents/skills/commerce/docs/api-storefront.md` for the surrounding rules.
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* Normalized free-shipping rules, one per
|
|
31
|
+
* Normalized free-shipping rules, one per rate that is free or has a
|
|
32
|
+
* `free_over` threshold.
|
|
32
33
|
*
|
|
33
34
|
* @returns {Array<{
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* min_amount: number|null, needs_coupon: boolean, ignore_discounts: boolean,
|
|
37
|
-
* unconditional: boolean
|
|
35
|
+
* location_id: string, location_name: string, rate_id: string, title: string,
|
|
36
|
+
* min_amount: number|null, unconditional: boolean
|
|
38
37
|
* }>}
|
|
39
38
|
*/
|
|
40
|
-
export function freeShippingRules(
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
title:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
});
|
|
39
|
+
export function freeShippingRules(locations) {
|
|
40
|
+
const out = [];
|
|
41
|
+
for (const location of locations ?? []) {
|
|
42
|
+
for (const rate of location?.shipping_rates ?? []) {
|
|
43
|
+
const threshold = Number(rate?.free_over);
|
|
44
|
+
const free = Number(rate?.cost ?? 0) === 0;
|
|
45
|
+
const hasThreshold = rate?.free_over != null && Number.isFinite(threshold);
|
|
46
|
+
if (!free && !hasThreshold) continue;
|
|
47
|
+
out.push({
|
|
48
|
+
location_id: location.id ?? "",
|
|
49
|
+
location_name: location.name ?? "",
|
|
50
|
+
rate_id: rate.id ?? "",
|
|
51
|
+
title: rate.name || "Free shipping",
|
|
52
|
+
min_amount: free ? null : threshold,
|
|
53
|
+
unconditional: free,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
60
58
|
}
|
|
61
59
|
|
|
62
60
|
/**
|
|
63
61
|
* The threshold to advertise, or `null` when the store has none — in which case
|
|
64
62
|
* **say nothing about free shipping**. Picks the lowest configured threshold
|
|
65
|
-
* (the one a shopper can actually reach); an
|
|
66
|
-
*
|
|
63
|
+
* (the one a shopper can actually reach); an always-free rate yields `0`,
|
|
64
|
+
* i.e. "free shipping" with no threshold at all.
|
|
67
65
|
*
|
|
68
|
-
* Thresholds are per
|
|
69
|
-
*
|
|
66
|
+
* Thresholds are per location, so a global banner is only honest when the rule
|
|
67
|
+
* covers the customer's location — pass `locationId` once you know it (after
|
|
70
68
|
* `set-shipping-address`, the cart's `available_shipping_methods` is the
|
|
71
69
|
* authoritative answer for that address).
|
|
72
70
|
*/
|
|
73
|
-
export function freeShippingThreshold(rules,
|
|
74
|
-
const scoped = (rules ?? []).filter((r) => (
|
|
71
|
+
export function freeShippingThreshold(rules, locationId = null) {
|
|
72
|
+
const scoped = (rules ?? []).filter((r) => (locationId ? r.location_id === locationId : true));
|
|
75
73
|
if (!scoped.length) return null;
|
|
76
74
|
if (scoped.some((r) => r.unconditional)) return 0;
|
|
77
|
-
const amounts = scoped
|
|
78
|
-
.filter((r) => !r.needs_coupon && r.min_amount != null)
|
|
79
|
-
.map((r) => r.min_amount);
|
|
75
|
+
const amounts = scoped.filter((r) => r.min_amount != null).map((r) => r.min_amount);
|
|
80
76
|
return amounts.length ? Math.min(...amounts) : null;
|
|
81
77
|
}
|
|
82
78
|
|
|
83
79
|
/**
|
|
84
80
|
* Progress toward a threshold, for a "spend X more" nudge. `subtotal` should be
|
|
85
|
-
* the cart's `totals.subtotal
|
|
86
|
-
*
|
|
81
|
+
* the cart's `totals.subtotal - totals.discount_total` — the engine compares
|
|
82
|
+
* `free_over` against the discounted items subtotal.
|
|
87
83
|
*
|
|
88
84
|
* @returns {{threshold: number, qualifies: boolean, remaining: number}|null}
|
|
89
85
|
* `null` when there is no threshold to talk about.
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* Framework-free, dependency-free, no I/O — feed them the `{ product,
|
|
13
13
|
* variations }` pair from `commerce/storefront-catalog` `get-product` (the
|
|
14
14
|
* admin's variation editor can use them too). See
|
|
15
|
-
*
|
|
15
|
+
* `.agents/skills/commerce/references/storefront-product-page.md` for the UI rules.
|
|
16
16
|
*
|
|
17
17
|
* A `selection` throughout is a plain object keyed by axis key (see
|
|
18
18
|
* `attributeKey`): `{ "<color-attr-id>": "Red", "<size-attr-id>": "M" }`.
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "commerce.ShippingClass",
|
|
3
|
-
"type": "object",
|
|
4
|
-
"description": "Shipping class assignable to products; flat-rate methods can charge per class.",
|
|
5
|
-
"properties": {
|
|
6
|
-
"name": {
|
|
7
|
-
"type": "string",
|
|
8
|
-
"minLength": 1
|
|
9
|
-
},
|
|
10
|
-
"slug": {
|
|
11
|
-
"type": "string",
|
|
12
|
-
"description": "Unique slug (enforced in admin UI / functions)"
|
|
13
|
-
},
|
|
14
|
-
"description": {
|
|
15
|
-
"type": "string"
|
|
16
|
-
},
|
|
17
|
-
"count": {
|
|
18
|
-
"type": "integer",
|
|
19
|
-
"default": 0,
|
|
20
|
-
"description": "Derived product count. Maintained by commerce/admin-products; repair via commerce/admin-tools recount-terms."
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
|
-
"required": ["name"],
|
|
24
|
-
"rls": {
|
|
25
|
-
"read": { "user_condition": { "role": "admin" } },
|
|
26
|
-
"create": { "user_condition": { "role": "admin" } },
|
|
27
|
-
"update": { "user_condition": { "role": "admin" } },
|
|
28
|
-
"delete": { "user_condition": { "role": "admin" } }
|
|
29
|
-
}
|
|
30
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "commerce.ShippingZone",
|
|
3
|
-
"type": "object",
|
|
4
|
-
"description": "Geographic shipping zone. Zones are matched by 'order' ascending; the seeded 'Rest of the world' zone (order 999, no locations) catches unmatched addresses.",
|
|
5
|
-
"properties": {
|
|
6
|
-
"name": {
|
|
7
|
-
"type": "string",
|
|
8
|
-
"minLength": 1
|
|
9
|
-
},
|
|
10
|
-
"order": {
|
|
11
|
-
"type": "integer",
|
|
12
|
-
"default": 0,
|
|
13
|
-
"description": "Match priority, ascending"
|
|
14
|
-
},
|
|
15
|
-
"locations": {
|
|
16
|
-
"type": "array",
|
|
17
|
-
"description": "Zone locations; empty = matches everything (fallback zone)",
|
|
18
|
-
"items": {
|
|
19
|
-
"type": "object",
|
|
20
|
-
"properties": {
|
|
21
|
-
"type": {
|
|
22
|
-
"type": "string",
|
|
23
|
-
"enum": ["country", "state", "postcode", "continent"],
|
|
24
|
-
"description": "Location type"
|
|
25
|
-
},
|
|
26
|
-
"code": {
|
|
27
|
-
"type": "string",
|
|
28
|
-
"description": "Country code (US), state code (US:CA), postcode pattern (90*, 1000...2000), or continent code (EU)"
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
"required": ["name"],
|
|
35
|
-
"rls": {
|
|
36
|
-
"read": { "user_condition": { "role": "admin" } },
|
|
37
|
-
"create": { "user_condition": { "role": "admin" } },
|
|
38
|
-
"update": { "user_condition": { "role": "admin" } },
|
|
39
|
-
"delete": { "user_condition": { "role": "admin" } }
|
|
40
|
-
}
|
|
41
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "commerce.ShippingZoneMethod",
|
|
3
|
-
"type": "object",
|
|
4
|
-
"description": "A shipping method instance attached to a zone. The settings object shape depends on method_id.",
|
|
5
|
-
"properties": {
|
|
6
|
-
"zone_id": {
|
|
7
|
-
"type": "string",
|
|
8
|
-
"description": "ShippingZone id"
|
|
9
|
-
},
|
|
10
|
-
"method_id": {
|
|
11
|
-
"type": "string",
|
|
12
|
-
"enum": ["flat_rate", "free_shipping", "local_pickup"],
|
|
13
|
-
"description": "Method type"
|
|
14
|
-
},
|
|
15
|
-
"title": {
|
|
16
|
-
"type": "string",
|
|
17
|
-
"description": "Customer-facing method title"
|
|
18
|
-
},
|
|
19
|
-
"enabled": {
|
|
20
|
-
"type": "boolean",
|
|
21
|
-
"default": true
|
|
22
|
-
},
|
|
23
|
-
"order": {
|
|
24
|
-
"type": "integer",
|
|
25
|
-
"default": 0,
|
|
26
|
-
"description": "Display order within the zone"
|
|
27
|
-
},
|
|
28
|
-
"settings": {
|
|
29
|
-
"type": "object",
|
|
30
|
-
"description": "Per-method settings. flat_rate: {cost, tax_status, class_costs, no_class_cost, calculation_type}; free_shipping: {requires, min_amount, ignore_discounts}; local_pickup: {cost, tax_status}",
|
|
31
|
-
"properties": {
|
|
32
|
-
"cost": {
|
|
33
|
-
"type": "number",
|
|
34
|
-
"description": "flat_rate/local_pickup base cost"
|
|
35
|
-
},
|
|
36
|
-
"tax_status": {
|
|
37
|
-
"type": "string",
|
|
38
|
-
"enum": ["taxable", "none"],
|
|
39
|
-
"description": "flat_rate/local_pickup"
|
|
40
|
-
},
|
|
41
|
-
"class_costs": {
|
|
42
|
-
"type": "array",
|
|
43
|
-
"description": "flat_rate: additional cost per shipping class present in the cart",
|
|
44
|
-
"items": {
|
|
45
|
-
"type": "object",
|
|
46
|
-
"properties": {
|
|
47
|
-
"shipping_class_id": { "type": "string" },
|
|
48
|
-
"cost": { "type": "number" }
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
},
|
|
52
|
-
"no_class_cost": {
|
|
53
|
-
"type": "number",
|
|
54
|
-
"description": "flat_rate: cost applied for items without a shipping class"
|
|
55
|
-
},
|
|
56
|
-
"calculation_type": {
|
|
57
|
-
"type": "string",
|
|
58
|
-
"enum": ["class", "order"],
|
|
59
|
-
"description": "flat_rate: charge per class present (class) or most expensive class only (order)"
|
|
60
|
-
},
|
|
61
|
-
"requires": {
|
|
62
|
-
"type": "string",
|
|
63
|
-
"enum": ["", "coupon", "min_amount", "either", "both"],
|
|
64
|
-
"description": "free_shipping: requirement for the method to be offered"
|
|
65
|
-
},
|
|
66
|
-
"min_amount": {
|
|
67
|
-
"type": "number",
|
|
68
|
-
"description": "free_shipping: minimum items subtotal"
|
|
69
|
-
},
|
|
70
|
-
"ignore_discounts": {
|
|
71
|
-
"type": "boolean",
|
|
72
|
-
"description": "free_shipping: compare min_amount against pre-discount subtotal"
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
"required": ["zone_id", "method_id"],
|
|
78
|
-
"rls": {
|
|
79
|
-
"read": { "user_condition": { "role": "admin" } },
|
|
80
|
-
"create": { "user_condition": { "role": "admin" } },
|
|
81
|
-
"update": { "user_condition": { "role": "admin" } },
|
|
82
|
-
"delete": { "user_condition": { "role": "admin" } }
|
|
83
|
-
}
|
|
84
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "commerce.TaxClass",
|
|
3
|
-
"type": "object",
|
|
4
|
-
"description": "Tax class grouping products for rate matching. Seeded: standard, reduced-rate, zero-rate.",
|
|
5
|
-
"properties": {
|
|
6
|
-
"slug": {
|
|
7
|
-
"type": "string",
|
|
8
|
-
"minLength": 1,
|
|
9
|
-
"description": "Unique slug (enforced in admin UI / seed)"
|
|
10
|
-
},
|
|
11
|
-
"name": {
|
|
12
|
-
"type": "string",
|
|
13
|
-
"minLength": 1
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
"required": ["slug", "name"],
|
|
17
|
-
"rls": {
|
|
18
|
-
"read": { "user_condition": { "role": "admin" } },
|
|
19
|
-
"create": { "user_condition": { "role": "admin" } },
|
|
20
|
-
"update": { "user_condition": { "role": "admin" } },
|
|
21
|
-
"delete": { "user_condition": { "role": "admin" } }
|
|
22
|
-
}
|
|
23
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "commerce.TaxRate",
|
|
3
|
-
"type": "object",
|
|
4
|
-
"description": "A tax rate matched by location and tax class. Applied by shared/tax per priority/compound rules.",
|
|
5
|
-
"properties": {
|
|
6
|
-
"country": {
|
|
7
|
-
"type": "string",
|
|
8
|
-
"default": "",
|
|
9
|
-
"description": "ISO 3166-1 alpha-2 country code; empty = any"
|
|
10
|
-
},
|
|
11
|
-
"state": {
|
|
12
|
-
"type": "string",
|
|
13
|
-
"default": "",
|
|
14
|
-
"description": "State/province code; empty = any"
|
|
15
|
-
},
|
|
16
|
-
"postcodes": {
|
|
17
|
-
"type": "array",
|
|
18
|
-
"items": { "type": "string" },
|
|
19
|
-
"description": "Postcode patterns; supports wildcard (90*) and numeric range (1000...2000); empty = any"
|
|
20
|
-
},
|
|
21
|
-
"cities": {
|
|
22
|
-
"type": "array",
|
|
23
|
-
"items": { "type": "string" },
|
|
24
|
-
"description": "City names; empty = any"
|
|
25
|
-
},
|
|
26
|
-
"rate": {
|
|
27
|
-
"type": "number",
|
|
28
|
-
"description": "Percentage rate, e.g. 20 for 20%"
|
|
29
|
-
},
|
|
30
|
-
"name": {
|
|
31
|
-
"type": "string",
|
|
32
|
-
"minLength": 1,
|
|
33
|
-
"description": "Label, e.g. VAT"
|
|
34
|
-
},
|
|
35
|
-
"priority": {
|
|
36
|
-
"type": "integer",
|
|
37
|
-
"default": 1,
|
|
38
|
-
"description": "Only one matching rate per priority is applied; lower priorities apply first"
|
|
39
|
-
},
|
|
40
|
-
"compound": {
|
|
41
|
-
"type": "boolean",
|
|
42
|
-
"default": false,
|
|
43
|
-
"description": "Applied on top of previously accumulated taxes"
|
|
44
|
-
},
|
|
45
|
-
"shipping": {
|
|
46
|
-
"type": "boolean",
|
|
47
|
-
"default": true,
|
|
48
|
-
"description": "Rate also applies to shipping"
|
|
49
|
-
},
|
|
50
|
-
"tax_class": {
|
|
51
|
-
"type": "string",
|
|
52
|
-
"default": "standard",
|
|
53
|
-
"description": "TaxClass slug this rate belongs to"
|
|
54
|
-
},
|
|
55
|
-
"menu_order": {
|
|
56
|
-
"type": "integer",
|
|
57
|
-
"default": 0,
|
|
58
|
-
"description": "Tie-breaker among rates of the same priority"
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
"required": ["rate", "name"],
|
|
62
|
-
"rls": {
|
|
63
|
-
"read": { "user_condition": { "role": "admin" } },
|
|
64
|
-
"create": { "user_condition": { "role": "admin" } },
|
|
65
|
-
"update": { "user_condition": { "role": "admin" } },
|
|
66
|
-
"delete": { "user_condition": { "role": "admin" } }
|
|
67
|
-
}
|
|
68
|
-
}
|