@reblu/site-contracts 1.14.0 → 1.15.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/CHANGELOG.md CHANGED
@@ -1,5 +1,54 @@
1
1
  # @reblu/site-contracts
2
2
 
3
+ ## 1.15.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 614e826: Shop checkout: full-invoice opt-in and the buyer's identifier (REB-73).
8
+
9
+ `ShopCheckoutInput` gains the optional `wantsFullInvoice` flag, and
10
+ `ShopBillingInput` the optional `billingIdType` (`NIF` for a Spanish
11
+ NIF/NIE/CIF; `02` EU VAT id, `03` passport, `04` ID document of the country
12
+ of residence, `05` residence certificate, `06` other document) and
13
+ `billingIdCountry` (ISO 3166-1 alpha-2, required for `02`–`06`). A full
14
+ invoice needs the identifier, the billing name and a billing address; without
15
+ the identifier the invoice is simplified.
16
+
17
+ `ShopErrorCode` gains two checkout codes, both answered before any payment:
18
+ `BILLING_DATA_REQUIRED` (HTTP 422, `details.field: 'billing'`) when the
19
+ opt-in, or a total over the tenant's simplified-invoice cap, comes without
20
+ those three; and `INVOICING_NOT_READY` (HTTP 503) when the shop cannot issue
21
+ invoices yet. Existing clients that send only `billing.billingNif` keep
22
+ working: its type is derived from the billing address country.
23
+
24
+ - 614e826: Shop checkout: no full-invoice opt-in on a shop that issues no invoices (REB-73).
25
+ - `ShopErrorCode` gains `FULL_INVOICE_UNAVAILABLE` (HTTP 422,
26
+ `details.field: 'wantsFullInvoice'`): `wantsFullInvoice: true` sent to a shop
27
+ whose invoicing is off (`ShopConfig.simplifiedInvoiceCapCents` is `null`) is
28
+ refused before any payment instead of succeeding without an invoice. Clients
29
+ that never send the opt-in are unaffected. The union is additive: a SITE
30
+ with an exhaustive `switch` over `ShopErrorCode` (or a
31
+ `Record<ShopErrorCode, …>`) must add the new member when it upgrades.
32
+ - `@reblu/site-blocks`: new `shopIssuesInvoices(config)`; `FullInvoiceFields`
33
+ takes `issuesInvoices` (default `true`) and renders nothing when it is
34
+ `false`, and `toCheckoutInvoiceFields(value, overCap, issuesInvoices)`
35
+ returns no opt-in and no billing block then. Default Spanish copy for the
36
+ new code in `getShopErrorMessage`.
37
+
38
+ - 614e826: Shop: the order's invoice and the simplified-invoice cap (REB-73).
39
+ - `ShopOrder` gains the optional `invoice: { number, url } | null`
40
+ (`ShopOrderInvoice`): once the sale invoice is issued, its number and the
41
+ shop's authenticated client-portal route that serves it — never a signed
42
+ URL, so the link does not expire; the buyer signs in to open it.
43
+ - `ShopConfig` gains `simplifiedInvoiceCapCents` (cents, never above the legal
44
+ 300000; `null` while the shop issues no invoices): above it, checkout needs
45
+ the buyer's identifier, name and billing address.
46
+ - `@reblu/site-blocks`: new drop-in `OrderInvoiceLink`, which
47
+ `OrderConfirmation` now renders under a confirmed order (labels
48
+ `invoiceLinkLabel`/`invoiceSignInHint`), and default Spanish copy for the
49
+ `BILLING_DATA_REQUIRED`/`INVOICING_NOT_READY` checkout codes in
50
+ `getShopErrorMessage`.
51
+
3
52
  ## 1.14.0
4
53
 
5
54
  ### Minor Changes
package/dist/index.d.cts CHANGED
@@ -145,7 +145,7 @@ export type ShopAddressInput = { firstName: string; lastName: string; s
145
145
 
146
146
  export type ShopApplyDiscountInput = { code: string; orderSubtotal: number; customerEmail?: string | undefined;}
147
147
 
148
- export type ShopBillingInput = { billingName: string; billingNif?: string | undefined; billingEmail?: string | undefined; billingAddress?: { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined; } | undefined;}
148
+ export type ShopBillingInput = { billingName: string; billingNif?: string | undefined; billingIdType?: "NIF" | "02" | "03" | "04" | "05" | "06" | undefined; billingIdCountry?: string | undefined; billingEmail?: string | undefined; billingAddress?: { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined; } | undefined;}
149
149
 
150
150
  export type ShopBundleComponent = { quantity: number; component: { id: string; name: string; slug: string; price: number; };}
151
151
 
@@ -165,11 +165,11 @@ export type ShopCategory = { id: string; name: string; slug: string;
165
165
  */
166
166
  export type ShopCheckEmailInput = { email: string;}
167
167
 
168
- export type ShopCheckoutInput = { items: { productId: string; quantity: number; variantId?: string | null | undefined; }[]; customerEmail: string; customerName: string; successUrl: string; cancelUrl: string; customerPhone?: string | null | undefined; discountCode?: string | undefined; shippingAddress?: { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined; } | undefined; billing?: { billingName: string; billingNif?: string | undefined; billingEmail?: string | undefined; billingAddress?: { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined; } | undefined; } | undefined;}
168
+ export type ShopCheckoutInput = { items: { productId: string; quantity: number; variantId?: string | null | undefined; }[]; customerEmail: string; customerName: string; successUrl: string; cancelUrl: string; customerPhone?: string | null | undefined; discountCode?: string | undefined; shippingAddress?: { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined; } | undefined; billing?: { billingName: string; billingNif?: string | undefined; billingIdType?: "NIF" | "02" | "03" | "04" | "05" | "06" | undefined; billingIdCountry?: string | undefined; billingEmail?: string | undefined; billingAddress?: { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined; } | undefined; } | undefined; wantsFullInvoice?: boolean | undefined;}
169
169
 
170
170
  export type ShopCheckoutSession = { url: string; sessionId: string;}
171
171
 
172
- export type ShopConfig = { shopName: string | null; defaultLowStockThreshold: number; currencyCode: string; stripePublishableKey: string | null; stripeTestPublishableKey: string | null; stripeTestMode: boolean; shippingEnabled: boolean; pickupEnabled: boolean; taxEnabled: boolean; taxIncludedInPrice: boolean; productTrustItems?: { [x: string]: unknown; icon: (string & {}) | "shipping" | "returns" | "secure-payment" | "support" | "gift" | "pickup" | "warranty" | "quality"; text: string; }[] | null | undefined;}
172
+ export type ShopConfig = { shopName: string | null; defaultLowStockThreshold: number; currencyCode: string; stripePublishableKey: string | null; stripeTestPublishableKey: string | null; stripeTestMode: boolean; shippingEnabled: boolean; pickupEnabled: boolean; taxEnabled: boolean; taxIncludedInPrice: boolean; simplifiedInvoiceCapCents?: number | null | undefined; productTrustItems?: { [x: string]: unknown; icon: (string & {}) | "shipping" | "returns" | "secure-payment" | "support" | "gift" | "pickup" | "warranty" | "quality"; text: string; }[] | null | undefined;}
173
173
 
174
174
  export type ShopDiscountApplication = { valid: boolean; discount: number; type: "PERCENTAGE" | "FIXED" | null; code: string | null; error?: string | undefined;}
175
175
 
@@ -181,13 +181,15 @@ export type ShopDiscountApplication = { valid: boolean; discount: number;
181
181
  */
182
182
  export type ShopEmailCheck = { exists: boolean;}
183
183
 
184
- export type ShopErrorCode = "STOCK_CHANGED" | "PRICE_CHANGED" | "PRODUCT_UNAVAILABLE" | "DISCOUNT_INVALID" | "SHIPPING_UNAVAILABLE" | "INVALID_INPUT" | "STORE_DISABLED" | "PAYMENT_PROVIDER_ERROR" | "INTERNAL_ERROR"
184
+ export type ShopErrorCode = "STOCK_CHANGED" | "PRICE_CHANGED" | "PRODUCT_UNAVAILABLE" | "DISCOUNT_INVALID" | "SHIPPING_UNAVAILABLE" | "INVALID_INPUT" | "STORE_DISABLED" | "PAYMENT_PROVIDER_ERROR" | "INTERNAL_ERROR" | "BILLING_DATA_REQUIRED" | "INVOICING_NOT_READY" | "FULL_INVOICE_UNAVAILABLE"
185
185
 
186
186
  export type ShopFacets = { taxonomies: { key: string; label: string; showAsBadge: boolean; selectionMode: "single" | "multiple"; terms: { slug: string; name: string; count: number; }[]; }[]; attributes: { key: string; label: string; valueType: "boolean" | "text" | "select" | "multiselect"; options: { value: string; label: string; count: number; }[]; }[]; price: { min: number; max: number; }; onSale: { count: number; };}
187
187
 
188
188
  export type ShopInventoryRef = { stockQuantity: number; reservedQuantity: number; lowStockThreshold: number | null;}
189
189
 
190
- export type ShopOrder = { id: string; orderNumber: string; status: "PENDING" | "CONFIRMED" | "PROCESSING" | "SHIPPED" | "DELIVERED" | "CANCELLED" | "REFUNDED"; paymentStatus: "PENDING" | "REFUNDED" | "PAID" | "FAILED" | "PARTIALLY_REFUNDED"; customerEmail: string; total: number; items: { product: { id: string; name: string; slug: string; }; quantity: number; unitPrice: number; total: number; variant?: { id: string; name: string; } | null | undefined; }[];}
190
+ export type ShopOrder = { id: string; orderNumber: string; status: "PENDING" | "CONFIRMED" | "PROCESSING" | "SHIPPED" | "DELIVERED" | "CANCELLED" | "REFUNDED"; paymentStatus: "PENDING" | "REFUNDED" | "PAID" | "FAILED" | "PARTIALLY_REFUNDED"; customerEmail: string; total: number; items: { product: { id: string; name: string; slug: string; }; quantity: number; unitPrice: number; total: number; variant?: { id: string; name: string; } | null | undefined; }[]; invoice?: { number: string; url: string; } | null | undefined;}
191
+
192
+ export type ShopOrderInvoice = { number: string; url: string;}
191
193
 
192
194
  export type ShopOrderItem = { product: { id: string; name: string; slug: string; }; quantity: number; unitPrice: number; total: number; variant?: { id: string; name: string; } | null | undefined;}
193
195
 
package/dist/index.d.ts CHANGED
@@ -145,7 +145,7 @@ export type ShopAddressInput = { firstName: string; lastName: string; s
145
145
 
146
146
  export type ShopApplyDiscountInput = { code: string; orderSubtotal: number; customerEmail?: string | undefined;}
147
147
 
148
- export type ShopBillingInput = { billingName: string; billingNif?: string | undefined; billingEmail?: string | undefined; billingAddress?: { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined; } | undefined;}
148
+ export type ShopBillingInput = { billingName: string; billingNif?: string | undefined; billingIdType?: "NIF" | "02" | "03" | "04" | "05" | "06" | undefined; billingIdCountry?: string | undefined; billingEmail?: string | undefined; billingAddress?: { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined; } | undefined;}
149
149
 
150
150
  export type ShopBundleComponent = { quantity: number; component: { id: string; name: string; slug: string; price: number; };}
151
151
 
@@ -165,11 +165,11 @@ export type ShopCategory = { id: string; name: string; slug: string;
165
165
  */
166
166
  export type ShopCheckEmailInput = { email: string;}
167
167
 
168
- export type ShopCheckoutInput = { items: { productId: string; quantity: number; variantId?: string | null | undefined; }[]; customerEmail: string; customerName: string; successUrl: string; cancelUrl: string; customerPhone?: string | null | undefined; discountCode?: string | undefined; shippingAddress?: { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined; } | undefined; billing?: { billingName: string; billingNif?: string | undefined; billingEmail?: string | undefined; billingAddress?: { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined; } | undefined; } | undefined;}
168
+ export type ShopCheckoutInput = { items: { productId: string; quantity: number; variantId?: string | null | undefined; }[]; customerEmail: string; customerName: string; successUrl: string; cancelUrl: string; customerPhone?: string | null | undefined; discountCode?: string | undefined; shippingAddress?: { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined; } | undefined; billing?: { billingName: string; billingNif?: string | undefined; billingIdType?: "NIF" | "02" | "03" | "04" | "05" | "06" | undefined; billingIdCountry?: string | undefined; billingEmail?: string | undefined; billingAddress?: { firstName: string; lastName: string; street: string; city: string; postalCode: string; region?: string | undefined; country?: string | undefined; phone?: string | null | undefined; } | undefined; } | undefined; wantsFullInvoice?: boolean | undefined;}
169
169
 
170
170
  export type ShopCheckoutSession = { url: string; sessionId: string;}
171
171
 
172
- export type ShopConfig = { shopName: string | null; defaultLowStockThreshold: number; currencyCode: string; stripePublishableKey: string | null; stripeTestPublishableKey: string | null; stripeTestMode: boolean; shippingEnabled: boolean; pickupEnabled: boolean; taxEnabled: boolean; taxIncludedInPrice: boolean; productTrustItems?: { [x: string]: unknown; icon: (string & {}) | "shipping" | "returns" | "secure-payment" | "support" | "gift" | "pickup" | "warranty" | "quality"; text: string; }[] | null | undefined;}
172
+ export type ShopConfig = { shopName: string | null; defaultLowStockThreshold: number; currencyCode: string; stripePublishableKey: string | null; stripeTestPublishableKey: string | null; stripeTestMode: boolean; shippingEnabled: boolean; pickupEnabled: boolean; taxEnabled: boolean; taxIncludedInPrice: boolean; simplifiedInvoiceCapCents?: number | null | undefined; productTrustItems?: { [x: string]: unknown; icon: (string & {}) | "shipping" | "returns" | "secure-payment" | "support" | "gift" | "pickup" | "warranty" | "quality"; text: string; }[] | null | undefined;}
173
173
 
174
174
  export type ShopDiscountApplication = { valid: boolean; discount: number; type: "PERCENTAGE" | "FIXED" | null; code: string | null; error?: string | undefined;}
175
175
 
@@ -181,13 +181,15 @@ export type ShopDiscountApplication = { valid: boolean; discount: number;
181
181
  */
182
182
  export type ShopEmailCheck = { exists: boolean;}
183
183
 
184
- export type ShopErrorCode = "STOCK_CHANGED" | "PRICE_CHANGED" | "PRODUCT_UNAVAILABLE" | "DISCOUNT_INVALID" | "SHIPPING_UNAVAILABLE" | "INVALID_INPUT" | "STORE_DISABLED" | "PAYMENT_PROVIDER_ERROR" | "INTERNAL_ERROR"
184
+ export type ShopErrorCode = "STOCK_CHANGED" | "PRICE_CHANGED" | "PRODUCT_UNAVAILABLE" | "DISCOUNT_INVALID" | "SHIPPING_UNAVAILABLE" | "INVALID_INPUT" | "STORE_DISABLED" | "PAYMENT_PROVIDER_ERROR" | "INTERNAL_ERROR" | "BILLING_DATA_REQUIRED" | "INVOICING_NOT_READY" | "FULL_INVOICE_UNAVAILABLE"
185
185
 
186
186
  export type ShopFacets = { taxonomies: { key: string; label: string; showAsBadge: boolean; selectionMode: "single" | "multiple"; terms: { slug: string; name: string; count: number; }[]; }[]; attributes: { key: string; label: string; valueType: "boolean" | "text" | "select" | "multiselect"; options: { value: string; label: string; count: number; }[]; }[]; price: { min: number; max: number; }; onSale: { count: number; };}
187
187
 
188
188
  export type ShopInventoryRef = { stockQuantity: number; reservedQuantity: number; lowStockThreshold: number | null;}
189
189
 
190
- export type ShopOrder = { id: string; orderNumber: string; status: "PENDING" | "CONFIRMED" | "PROCESSING" | "SHIPPED" | "DELIVERED" | "CANCELLED" | "REFUNDED"; paymentStatus: "PENDING" | "REFUNDED" | "PAID" | "FAILED" | "PARTIALLY_REFUNDED"; customerEmail: string; total: number; items: { product: { id: string; name: string; slug: string; }; quantity: number; unitPrice: number; total: number; variant?: { id: string; name: string; } | null | undefined; }[];}
190
+ export type ShopOrder = { id: string; orderNumber: string; status: "PENDING" | "CONFIRMED" | "PROCESSING" | "SHIPPED" | "DELIVERED" | "CANCELLED" | "REFUNDED"; paymentStatus: "PENDING" | "REFUNDED" | "PAID" | "FAILED" | "PARTIALLY_REFUNDED"; customerEmail: string; total: number; items: { product: { id: string; name: string; slug: string; }; quantity: number; unitPrice: number; total: number; variant?: { id: string; name: string; } | null | undefined; }[]; invoice?: { number: string; url: string; } | null | undefined;}
191
+
192
+ export type ShopOrderInvoice = { number: string; url: string;}
191
193
 
192
194
  export type ShopOrderItem = { product: { id: string; name: string; slug: string; }; quantity: number; unitPrice: number; total: number; variant?: { id: string; name: string; } | null | undefined;}
193
195
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reblu/site-contracts",
3
- "version": "1.14.0",
3
+ "version": "1.15.0",
4
4
  "private": false,
5
5
  "description": "Public, dependency-free TypeScript types for the Reblu SITE API (types only — no Zod, no Prisma at runtime).",
6
6
  "license": "Apache-2.0",