@rovela-ai/sdk 0.21.0 → 0.22.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/dist/admin/api/products.d.ts.map +1 -1
- package/dist/admin/api/products.js +4 -0
- package/dist/admin/api/products.js.map +1 -1
- package/dist/admin/api/tax-zones.d.ts.map +1 -1
- package/dist/admin/api/tax-zones.js +7 -0
- package/dist/admin/api/tax-zones.js.map +1 -1
- package/dist/admin/components/OrderDetails.d.ts.map +1 -1
- package/dist/admin/components/OrderDetails.js +5 -1
- package/dist/admin/components/OrderDetails.js.map +1 -1
- package/dist/admin/components/ProductForm.d.ts.map +1 -1
- package/dist/admin/components/ProductForm.js +25 -1
- package/dist/admin/components/ProductForm.js.map +1 -1
- package/dist/admin/components/TaxSettings.d.ts.map +1 -1
- package/dist/admin/components/TaxSettings.js +14 -2
- package/dist/admin/components/TaxSettings.js.map +1 -1
- package/dist/admin/types.d.ts +15 -0
- package/dist/admin/types.d.ts.map +1 -1
- package/dist/checkout/api/manual.d.ts.map +1 -1
- package/dist/checkout/api/manual.js +7 -0
- package/dist/checkout/api/manual.js.map +1 -1
- package/dist/checkout/api/shipping.d.ts +0 -18
- package/dist/checkout/api/shipping.d.ts.map +1 -1
- package/dist/checkout/api/shipping.js +33 -3
- package/dist/checkout/api/shipping.js.map +1 -1
- package/dist/checkout/components/CheckoutFlow.d.ts.map +1 -1
- package/dist/checkout/components/CheckoutFlow.js +30 -13
- package/dist/checkout/components/CheckoutFlow.js.map +1 -1
- package/dist/checkout/components/OrderSummary.d.ts +1 -1
- package/dist/checkout/components/OrderSummary.d.ts.map +1 -1
- package/dist/checkout/components/OrderSummary.js +5 -2
- package/dist/checkout/components/OrderSummary.js.map +1 -1
- package/dist/checkout/server/create-checkout-session.d.ts.map +1 -1
- package/dist/checkout/server/create-checkout-session.js +38 -9
- package/dist/checkout/server/create-checkout-session.js.map +1 -1
- package/dist/checkout/server/handle-webhook.js +6 -0
- package/dist/checkout/server/handle-webhook.js.map +1 -1
- package/dist/checkout/server/order-service.d.ts.map +1 -1
- package/dist/checkout/server/order-service.js +21 -0
- package/dist/checkout/server/order-service.js.map +1 -1
- package/dist/checkout/server/pricing.d.ts +28 -1
- package/dist/checkout/server/pricing.d.ts.map +1 -1
- package/dist/checkout/server/pricing.js +84 -6
- package/dist/checkout/server/pricing.js.map +1 -1
- package/dist/checkout/types.d.ts +32 -0
- package/dist/checkout/types.d.ts.map +1 -1
- package/dist/core/db/queries.d.ts +106 -25
- package/dist/core/db/queries.d.ts.map +1 -1
- package/dist/core/db/queries.js +83 -2
- package/dist/core/db/queries.js.map +1 -1
- package/dist/core/db/schema.d.ts +65 -0
- package/dist/core/db/schema.d.ts.map +1 -1
- package/dist/core/db/schema.js +26 -0
- package/dist/core/db/schema.js.map +1 -1
- package/dist/emails/send/orders.d.ts +4 -0
- package/dist/emails/send/orders.d.ts.map +1 -1
- package/dist/emails/send/orders.js +1 -0
- package/dist/emails/send/orders.js.map +1 -1
- package/dist/emails/templates/order-confirmation.d.ts +9 -0
- package/dist/emails/templates/order-confirmation.d.ts.map +1 -1
- package/dist/emails/templates/order-confirmation.js +19 -8
- package/dist/emails/templates/order-confirmation.js.map +1 -1
- package/dist/emails/types.d.ts +5 -0
- package/dist/emails/types.d.ts.map +1 -1
- package/dist/products/api/products.d.ts.map +1 -1
- package/dist/products/api/products.js +18 -3
- package/dist/products/api/products.js.map +1 -1
- package/docs/changelog/epoch-09-catalog-tax.md +91 -0
- package/package.json +1 -1
- package/templates/store-template/.claude/skills/manage-products/SKILL.md +1 -1
- package/templates/store-template/app/account/orders/[id]/invoice/page.tsx +19 -4
- package/templates/store-template/package.json +1 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# E9 Catalog & tax — 0.22.0..0.22.0
|
|
2
|
+
|
|
3
|
+
## What landed
|
|
4
|
+
Two catalog-commerce behaviors every PrestaShop-migrated store needs: the
|
|
5
|
+
public category filter is now TREE-AWARE (a parent-category link includes its
|
|
6
|
+
descendant categories' products — imported catalogs assign products to leaf
|
|
7
|
+
categories), and TAX CLASSES bring per-product VAT rates (French 5.5%/20%
|
|
8
|
+
food split): products carry a `tax_class`, tax zones carry per-class rates,
|
|
9
|
+
and every money surface (quote, Stripe session, orders, emails, invoice,
|
|
10
|
+
admin) computes and renders the per-rate VAT ventilation ("dont TVA par
|
|
11
|
+
taux") French invoices legally require.
|
|
12
|
+
|
|
13
|
+
## SDK-internal (free)
|
|
14
|
+
- `findProducts`/`countProducts` accept `categoryId: string | string[]`
|
|
15
|
+
(IN-match). New `findCategoryDescendantIds(id)` (recursive CTE) and
|
|
16
|
+
`findTaxClassesByProductIds(ids)`.
|
|
17
|
+
- `resolveTax` accepts optional `lines` — per-line computation grouped by
|
|
18
|
+
rate, order discount allocated pro-rata (largest-remainder, sums exact),
|
|
19
|
+
shipping taxed at the zone's base rate. Returns `taxBreakdown` +
|
|
20
|
+
`taxClassRates`. Without `lines`, or on a zone with no `class_rates`, the
|
|
21
|
+
original lump formula runs — cent-identical to 0.21.x.
|
|
22
|
+
- `buildQuote` carries `taxBreakdown`/`taxClassRates` on the Quote; the
|
|
23
|
+
Stripe session divides each line by ITS OWN rate in tax-inclusive mode and
|
|
24
|
+
stamps `rovelaTaxBreakdown` metadata; both order writers persist
|
|
25
|
+
`orders.tax_breakdown`.
|
|
26
|
+
- Admin: TaxSettings zone editor gains per-class rate rows; ProductForm
|
|
27
|
+
gains a Tax class field (datalist fed from the zones' class names);
|
|
28
|
+
tax-zones API accepts `classRates`; products API accepts `taxClass`.
|
|
29
|
+
|
|
30
|
+
## Template contract
|
|
31
|
+
- `app/account/orders/[id]/invoice/page.tsx` — the totals block renders one
|
|
32
|
+
`TVA {rate}%` row per `order.taxBreakdown` entry when the order carries a
|
|
33
|
+
multi-rate ventilation, else the single flat tax row (stock shape: gated
|
|
34
|
+
branch on `order.taxBreakdown?.length > 1`). Stores with a customized
|
|
35
|
+
invoice keep their layout and add the same branch.
|
|
36
|
+
|
|
37
|
+
## Behavior contracts
|
|
38
|
+
- **Public `/api/products?category=` is tree-aware.** A parent category id or
|
|
39
|
+
slug now returns its own products PLUS every descendant category's. Stores
|
|
40
|
+
whose nav deliberately relied on parent links showing ONLY directly-assigned
|
|
41
|
+
products (rare; usually a bug they worked around) will see more products.
|
|
42
|
+
Admin product filters are UNCHANGED (exact match).
|
|
43
|
+
- **`OrderSummary` accepts `taxBreakdown`** and renders per-rate rows when
|
|
44
|
+
more than one rate is present; `CheckoutFlow` computes it from the estimate
|
|
45
|
+
response. Single-rate stores render byte-identically to 0.21.x.
|
|
46
|
+
- The pre-checkout shipping estimate (`/api/checkout/shipping`) accepts an
|
|
47
|
+
optional `productId` per item and returns `tax.breakdown`. Clients that
|
|
48
|
+
omit `productId` get the previous base-rate estimate (totals unchanged in
|
|
49
|
+
tax-inclusive stores).
|
|
50
|
+
|
|
51
|
+
## Custom-code hazards
|
|
52
|
+
- `grep -rn "resolveTax(" app lib components` — custom callers keep working
|
|
53
|
+
(the `lines` param is optional; omitted = old math). If a custom checkout
|
|
54
|
+
displays tax recomputed from `taxRate` alone, it cannot reproduce a
|
|
55
|
+
multi-rate cart: read `tax.breakdown`/`quote.taxBreakdown` when present
|
|
56
|
+
(see CheckoutFlow's per-group recompute for the reference implementation).
|
|
57
|
+
- `grep -rn "taxRate" app components` — any custom "TVA (20%)" label stays
|
|
58
|
+
correct for single-rate stores; multi-rate stores should render the
|
|
59
|
+
breakdown rows instead.
|
|
60
|
+
- `grep -rn "category=" app components lib` — store-authored nav links to
|
|
61
|
+
PARENT categories now include leaf products (this is almost always the
|
|
62
|
+
desired fix, not a regression).
|
|
63
|
+
|
|
64
|
+
## DB
|
|
65
|
+
- `products.tax_class varchar(50)` NULL — self-heals via
|
|
66
|
+
`ensureCatalogTranslationsSchema` (every catalog chokepoint).
|
|
67
|
+
- `tax_zones.class_rates jsonb NOT NULL DEFAULT '{}'` — self-heals via
|
|
68
|
+
`ensureVisibilityColumns`.
|
|
69
|
+
- `orders.tax_breakdown jsonb` NULL — self-heals via
|
|
70
|
+
`ensurePaymentMethodsSchema`.
|
|
71
|
+
- All three are additive with behavior-preserving defaults: no class rates
|
|
72
|
+
configured = 0.21.x math to the cent. Pre-applying is optional.
|
|
73
|
+
|
|
74
|
+
## New surfaces
|
|
75
|
+
- None. (TaxSettings/ProductForm gains are inside existing admin pages; no
|
|
76
|
+
new routes to mount.)
|
|
77
|
+
|
|
78
|
+
## Verify
|
|
79
|
+
1. `/products?category=<parent slug>` lists products assigned to child
|
|
80
|
+
categories; the admin Products page filtered to the same parent does NOT.
|
|
81
|
+
2. Settings → Tax: add a class rate (e.g. `tva-5-5` = 5.5) on the active
|
|
82
|
+
zone; assign the class to one product (Product form → Pricing → Tax
|
|
83
|
+
class).
|
|
84
|
+
3. Cart with one classed + one unclassed product → checkout review shows two
|
|
85
|
+
`TVA x%` rows summing to the receipt tax; totals unchanged
|
|
86
|
+
(tax-inclusive).
|
|
87
|
+
4. Place a test order → `orders.tax_breakdown` populated; invoice page and
|
|
88
|
+
order-confirmation email render the ventilation; admin order detail shows
|
|
89
|
+
per-rate rows.
|
|
90
|
+
5. A store that configures NO class rates: quote totals and every tax line
|
|
91
|
+
render exactly as before the update.
|
package/package.json
CHANGED
|
@@ -27,7 +27,7 @@ Usage: `nextjs_call` with `port="3000"` and `toolName="execute_sql"`
|
|
|
27
27
|
|
|
28
28
|
| Table | Key Columns |
|
|
29
29
|
|-------|-------------|
|
|
30
|
-
| `products` | id, name, slug, price, status (`draft`/`active`/`archived`), categoryId, hasVariants, images (JSONB string[]), videos (JSONB string[]), metafields (JSONB key/label/value/type), translations (JSONB per-locale name/description) |
|
|
30
|
+
| `products` | id, name, slug, price, status (`draft`/`active`/`archived`), categoryId, hasVariants, images (JSONB string[]), videos (JSONB string[]), metafields (JSONB key/label/value/type), translations (JSONB per-locale name/description), taxClass (0.22.0 — names a rate in tax_zones.class_rates; NULL = zone base rate) |
|
|
31
31
|
| `product_variants` | id, productId (CASCADE), sku, name, price, inventory, attributes (JSONB), image, video |
|
|
32
32
|
| `categories` | id, name, slug, parentId (self-ref), order, translations (JSONB) |
|
|
33
33
|
| `orders` | id, customerId, email, status, total, currency (ISO snapshot — display orders in THIS currency), refundAmount, returnReason, shippingAddress (JSONB) |
|
|
@@ -42,6 +42,8 @@ interface InvoiceOrder {
|
|
|
42
42
|
total: number
|
|
43
43
|
subtotal: number
|
|
44
44
|
tax: number
|
|
45
|
+
/** Per-rate VAT ventilation (0.22.0) — cents; null/absent = flat tax line. */
|
|
46
|
+
taxBreakdown?: Array<{ rate: number; baseCents: number; taxCents: number }> | null
|
|
45
47
|
shipping: number
|
|
46
48
|
discountAmount?: number | string
|
|
47
49
|
discountCode?: string | null
|
|
@@ -245,10 +247,23 @@ function InvoiceContent({ orderId }: { orderId: string }) {
|
|
|
245
247
|
<span>{t('common.shipping')}</span>
|
|
246
248
|
<span>{order.shipping > 0 ? formatPrice(order.shipping, orderCurrency) : t('common.free')}</span>
|
|
247
249
|
</div>
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
250
|
+
{order.taxBreakdown && order.taxBreakdown.length > 1 ? (
|
|
251
|
+
// Per-rate VAT ventilation (0.22.0) — the legally required French
|
|
252
|
+
// invoice breakdown ("dont TVA par taux").
|
|
253
|
+
order.taxBreakdown.map((entry) => (
|
|
254
|
+
<div key={entry.rate} className="flex justify-between text-muted-foreground">
|
|
255
|
+
<span>
|
|
256
|
+
{t('common.tax')} {entry.rate}%
|
|
257
|
+
</span>
|
|
258
|
+
<span>{formatPrice(entry.taxCents / 100, orderCurrency)}</span>
|
|
259
|
+
</div>
|
|
260
|
+
))
|
|
261
|
+
) : (
|
|
262
|
+
<div className="flex justify-between text-muted-foreground">
|
|
263
|
+
<span>{t('common.tax')}</span>
|
|
264
|
+
<span>{formatPrice(order.tax, orderCurrency)}</span>
|
|
265
|
+
</div>
|
|
266
|
+
)}
|
|
252
267
|
<div className="flex justify-between border-t pt-2 text-base font-semibold text-foreground">
|
|
253
268
|
<span>{t('common.total')}</span>
|
|
254
269
|
<span>{formatPrice(order.total, orderCurrency)}</span>
|