@pcreative/commerce-contract 1.0.0 → 1.2.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/package.json +1 -1
- package/src/adapters/api.d.ts +0 -24
- package/src/adapters/api.js +294 -526
- package/src/index.d.ts +157 -2
- package/src/index.js +0 -20
package/src/index.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ export interface OptionValue {
|
|
|
32
32
|
/** Nombre de la opción: "Talla", "Color". */
|
|
33
33
|
name: string
|
|
34
34
|
value: string
|
|
35
|
+
color?: string | null
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
export interface Variant {
|
|
@@ -48,6 +49,84 @@ export interface Variant {
|
|
|
48
49
|
options: OptionValue[]
|
|
49
50
|
weight?: number | null
|
|
50
51
|
image?: Image | null
|
|
52
|
+
images?: Image[]
|
|
53
|
+
tiers?: PriceTier[]
|
|
54
|
+
digital?: boolean
|
|
55
|
+
requiresShipping?: boolean
|
|
56
|
+
bundle?: BundleComponent[] | null
|
|
57
|
+
bundleGroups?: BundleGroup[] | null
|
|
58
|
+
measure?: { quantity: number; unit: string } | null
|
|
59
|
+
unitPrice?: { amount: number; currency: string; unit: string } | null
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface BundleGroup {
|
|
63
|
+
id: string
|
|
64
|
+
title: string
|
|
65
|
+
min: number
|
|
66
|
+
max: number
|
|
67
|
+
options: { variantId: string; title: string; price: number | null; image?: string | null; available: boolean }[]
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface WithdrawalState {
|
|
71
|
+
disponible: boolean
|
|
72
|
+
pais: string
|
|
73
|
+
dias: number | null
|
|
74
|
+
diasHabiles: boolean
|
|
75
|
+
caduca: string | null
|
|
76
|
+
dentroDePlazo: boolean
|
|
77
|
+
lineas: { id: string; titulo: string; cantidad: number; excluida: string | null }[]
|
|
78
|
+
solicitudes: { id: string; recibidoEn: string; acuseEn: string | null; atendidoEn: string | null }[]
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface BundleComponent {
|
|
82
|
+
variantId: string
|
|
83
|
+
title: string
|
|
84
|
+
quantity: number
|
|
85
|
+
handle?: string | null
|
|
86
|
+
image?: string | null
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface Download {
|
|
90
|
+
id: string
|
|
91
|
+
lineId: string
|
|
92
|
+
name: string
|
|
93
|
+
bytes: number
|
|
94
|
+
version: number
|
|
95
|
+
status: "bloqueada" | "activa" | "suspendida" | "revocada"
|
|
96
|
+
remaining: number | null
|
|
97
|
+
expiresAt: string | null
|
|
98
|
+
downloaded: number
|
|
99
|
+
firstDownloadAt: string | null
|
|
100
|
+
url: string | null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface PriceTier {
|
|
104
|
+
minQuantity: number
|
|
105
|
+
maxQuantity?: number | null
|
|
106
|
+
price: Money
|
|
107
|
+
savePercent: number
|
|
108
|
+
unitPrice?: { amount: number; currency: string; unit: string } | null
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface CustomField {
|
|
112
|
+
key: string
|
|
113
|
+
label: string
|
|
114
|
+
type: "texto" | "texto_largo" | "numero" | "lista" | "casilla" | "fecha" | "fichero"
|
|
115
|
+
required: boolean
|
|
116
|
+
help?: string | null
|
|
117
|
+
config: Record<string, unknown>
|
|
118
|
+
variantIds: string[]
|
|
119
|
+
condition?: { field: string; equals: string } | null
|
|
120
|
+
personalizes: boolean
|
|
121
|
+
surcharge: { mode: string; amount: number; freeChars: number }
|
|
122
|
+
values: { id: string; label: string; surcharge: { mode: string; amount: number }; variantIds: string[] }[]
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface QuantityRules {
|
|
126
|
+
scope: "variant" | "product"
|
|
127
|
+
min: number
|
|
128
|
+
max?: number | null
|
|
129
|
+
increment: number
|
|
51
130
|
}
|
|
52
131
|
|
|
53
132
|
export interface Product {
|
|
@@ -75,6 +154,8 @@ export interface Product {
|
|
|
75
154
|
rating?: number | null
|
|
76
155
|
reviewCount?: number
|
|
77
156
|
available: boolean
|
|
157
|
+
quantityRules?: QuantityRules | null
|
|
158
|
+
customization?: CustomField[]
|
|
78
159
|
metadata?: Record<string, unknown>
|
|
79
160
|
}
|
|
80
161
|
|
|
@@ -122,6 +203,14 @@ export interface LineItem {
|
|
|
122
203
|
* subtotal, o lo cuenta dos veces.
|
|
123
204
|
*/
|
|
124
205
|
isFee?: boolean
|
|
206
|
+
quantityRule?: (QuantityRules & { counted: number }) | null
|
|
207
|
+
tier?: { from: number; regularUnitPrice: Money } | null
|
|
208
|
+
nextTier?: { from: number; missing: number; unitPrice: Money } | null
|
|
209
|
+
problem?: { code: string; message: string } | null
|
|
210
|
+
customization?: { label: string; value: string; surcharge: number }[] | null
|
|
211
|
+
personalized?: boolean
|
|
212
|
+
digital?: boolean
|
|
213
|
+
bundle?: { title: string; quantity: number }[] | null
|
|
125
214
|
}
|
|
126
215
|
|
|
127
216
|
/** Un sitio del que sale mercancía: un paquete, un porte. */
|
|
@@ -147,6 +236,35 @@ export interface ShippingGroup {
|
|
|
147
236
|
option_id?: string | null
|
|
148
237
|
}
|
|
149
238
|
|
|
239
|
+
export interface StoreInfo {
|
|
240
|
+
name: string | null
|
|
241
|
+
legalName: string | null
|
|
242
|
+
taxId: string | null
|
|
243
|
+
address: string | null
|
|
244
|
+
email: string | null
|
|
245
|
+
phone: string | null
|
|
246
|
+
country?: string | null
|
|
247
|
+
legal?: {
|
|
248
|
+
digital?: {
|
|
249
|
+
pais: string
|
|
250
|
+
exigir: boolean
|
|
251
|
+
texto: string
|
|
252
|
+
version: number
|
|
253
|
+
}
|
|
254
|
+
personalizados: {
|
|
255
|
+
pais: string
|
|
256
|
+
excluye: boolean
|
|
257
|
+
puedeExcluir: boolean
|
|
258
|
+
porLey: boolean
|
|
259
|
+
dias: number | null
|
|
260
|
+
diasHabiles: boolean
|
|
261
|
+
prohibeNoDevoluciones: boolean
|
|
262
|
+
texto: string
|
|
263
|
+
garantias: string | null
|
|
264
|
+
}
|
|
265
|
+
} | null
|
|
266
|
+
}
|
|
267
|
+
|
|
150
268
|
export interface ShippingGroups {
|
|
151
269
|
grupos: ShippingGroup[]
|
|
152
270
|
moneda: string
|
|
@@ -171,6 +289,10 @@ export interface PaymentMethod {
|
|
|
171
289
|
/** Identificador del proveedor: "transfer", "cod", "bizum", "card"… */
|
|
172
290
|
provider: string
|
|
173
291
|
name?: string
|
|
292
|
+
/** Texto corto que la tienda escribe para explicarla en la caja. */
|
|
293
|
+
description?: string | null
|
|
294
|
+
/** Lo que el comprador tiene que hacer para pagar (datos de una transferencia). */
|
|
295
|
+
instructions?: string | null
|
|
174
296
|
/**
|
|
175
297
|
* Recargo de esta forma de pago, en unidades mayores. Sin definir = ninguno.
|
|
176
298
|
*
|
|
@@ -214,6 +336,10 @@ export interface Cart {
|
|
|
214
336
|
shippingMethods: { id: string; name: string; price: Money }[]
|
|
215
337
|
regionId?: string
|
|
216
338
|
promoCodes?: string[]
|
|
339
|
+
hasDigital?: boolean
|
|
340
|
+
digitalConsent?: { at: string; version: number } | null
|
|
341
|
+
vatNumber?: { number: string; valid: boolean; checked: boolean; name: string | null } | null
|
|
342
|
+
taxExempt?: { reason: "intra_eu"; articles: string[] } | null
|
|
217
343
|
/**
|
|
218
344
|
* El paso que falta para pagar, si el método elegido lo pide. `null` con los
|
|
219
345
|
* métodos sin pasarela: ahí pagar es confirmar el pedido y ya está.
|
|
@@ -313,18 +439,36 @@ export interface CommerceClient {
|
|
|
313
439
|
search(q: string, limit?: number): Promise<Product[]>
|
|
314
440
|
/** Pedido por id, para la página de confirmación tras el checkout. */
|
|
315
441
|
getOrder(id: string): Promise<Order | null>
|
|
442
|
+
/** Sube un fichero que el cliente adjunta a una personalización. */
|
|
443
|
+
subirFichero?(archivo: File): Promise<{ id: string; nombre: string; tipo: string; bytes: number; firma: string }>
|
|
444
|
+
/** Opcional: las descargas de un pedido con contenido digital. */
|
|
445
|
+
getDownloads?(orderId: string): Promise<Download[]>
|
|
446
|
+
/** Opcional: estado del derecho de desistimiento de un pedido. */
|
|
447
|
+
getWithdrawal?(orderId: string): Promise<WithdrawalState | null>
|
|
448
|
+
/** Opcional: solicita el desistimiento de un pedido (botón obligatorio en la UE). */
|
|
449
|
+
requestWithdrawal?(orderId: string, datos?: { lineas?: string[]; motivo?: string }): Promise<{ solicitud: string; aceptadas: number }>
|
|
316
450
|
|
|
317
451
|
cart: {
|
|
318
452
|
get(id: string): Promise<Cart | null>
|
|
319
453
|
create(): Promise<Cart>
|
|
320
|
-
addItem(
|
|
454
|
+
addItem(
|
|
455
|
+
cartId: string,
|
|
456
|
+
variantId: string,
|
|
457
|
+
quantity: number,
|
|
458
|
+
personalizacion?: Record<string, unknown>,
|
|
459
|
+
pack?: Record<string, string[]>
|
|
460
|
+
): Promise<Cart>
|
|
321
461
|
updateItem(cartId: string, lineId: string, quantity: number): Promise<Cart>
|
|
322
462
|
removeItem(cartId: string, lineId: string): Promise<Cart>
|
|
463
|
+
/** Consentimiento previo para entregar contenido digital ya (UE, Reino Unido). */
|
|
464
|
+
consentirDigital?(cartId: string, aceptado: boolean): Promise<Cart>
|
|
323
465
|
applyPromo(cartId: string, code: string): Promise<Cart>
|
|
324
466
|
removePromo(cartId: string, code: string): Promise<Cart>
|
|
325
467
|
}
|
|
326
468
|
|
|
327
469
|
checkout: {
|
|
470
|
+
listCountries?(): Promise<string[]>
|
|
471
|
+
setVatNumber?(cartId: string, vatNumber: string | null): Promise<Cart>
|
|
328
472
|
setEmail(cartId: string, email: string): Promise<Cart>
|
|
329
473
|
setAddresses(cartId: string, shipping: Address, billing?: Address): Promise<Cart>
|
|
330
474
|
listShippingOptions(cartId: string): Promise<ShippingOption[]>
|
|
@@ -360,12 +504,23 @@ export interface CommerceClient {
|
|
|
360
504
|
|
|
361
505
|
/** Opcional: un adaptador puede no soportar cuentas de cliente. */
|
|
362
506
|
account?: {
|
|
363
|
-
login(email: string, password: string): Promise<{ token: string }>
|
|
507
|
+
login(email: string, password: string, cartId?: string): Promise<{ token: string }>
|
|
364
508
|
register(datos: { email: string; password: string; firstName?: string; lastName?: string }): Promise<Customer>
|
|
365
509
|
me(token: string): Promise<Customer | null>
|
|
366
510
|
orders(token: string): Promise<Order[]>
|
|
511
|
+
confirmEmail?(sessionToken: string, token: string): Promise<{ adopted: number } | null>
|
|
367
512
|
}
|
|
368
513
|
|
|
514
|
+
/** Opcional: nombre y datos legales de la tienda, tal y como los tiene el panel. */
|
|
515
|
+
getStore?(): Promise<StoreInfo | null>
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Opcional: manda a la tienda un mensaje del formulario de contacto. Rechaza
|
|
519
|
+
* con `status` 400 si faltan datos, 429 si hay demasiados envíos y 503 si la
|
|
520
|
+
* tienda no tiene a dónde mandarlo.
|
|
521
|
+
*/
|
|
522
|
+
sendContact?(mensaje: { name?: string; email: string; subject?: string; message: string }): Promise<void>
|
|
523
|
+
|
|
369
524
|
/** Opcional: contenido editorial servido por el backend. */
|
|
370
525
|
content?: {
|
|
371
526
|
listPosts(limit?: number): Promise<Post[]>
|
package/src/index.js
CHANGED
|
@@ -1,26 +1,12 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @pcreative/commerce-contract — el contrato de datos que consume un tema.
|
|
3
|
-
*
|
|
4
|
-
* Aquí solo hay las utilidades comunes y el comprobador de conformidad: las
|
|
5
|
-
* entidades viven en `index.d.ts` (son forma, no código) y cada adaptador
|
|
6
|
-
* traduce lo suyo. Sin dependencias, para que valga igual en Next, Astro, Nuxt
|
|
7
|
-
* o un runtime edge.
|
|
8
|
-
*/
|
|
9
1
|
|
|
10
2
|
export const CONTRACT_VERSION = "1.0"
|
|
11
3
|
|
|
12
|
-
/** Construye un importe. Los nulos del backend se vuelven 0, no NaN. */
|
|
13
4
|
export function money(amount, currency, taxIncluded) {
|
|
14
5
|
const m = { amount: Number(amount ?? 0) || 0, currency: String(currency ?? "eur").toLowerCase() }
|
|
15
6
|
if (taxIncluded !== undefined) m.taxIncluded = taxIncluded
|
|
16
7
|
return m
|
|
17
8
|
}
|
|
18
9
|
|
|
19
|
-
/**
|
|
20
|
-
* Formatea con `Intl`. Los importes del contrato son unidades mayores, así que
|
|
21
|
-
* no hay que dividir por 100 en ningún sitio — que es de donde salen la mitad
|
|
22
|
-
* de los errores de precio en las tiendas.
|
|
23
|
-
*/
|
|
24
10
|
export function formatMoney(m, locale = "es-ES") {
|
|
25
11
|
if (!m) return ""
|
|
26
12
|
try {
|
|
@@ -33,7 +19,6 @@ export function formatMoney(m, locale = "es-ES") {
|
|
|
33
19
|
}
|
|
34
20
|
}
|
|
35
21
|
|
|
36
|
-
/** Suma importes. Mezclar monedas es un error, no algo que redondear. */
|
|
37
22
|
export function sumMoney(...importes) {
|
|
38
23
|
const validos = importes.filter(Boolean)
|
|
39
24
|
if (validos.length === 0) return money(0, "eur")
|
|
@@ -56,11 +41,6 @@ const REQUERIDO = {
|
|
|
56
41
|
checkout: ["setEmail", "setAddresses", "listShippingOptions", "setShippingMethod", "listPaymentMethods", "selectPaymentMethod", "complete"],
|
|
57
42
|
}
|
|
58
43
|
|
|
59
|
-
/**
|
|
60
|
-
* Comprueba que un adaptador implementa el contrato. Devuelve la lista de lo
|
|
61
|
-
* que falta (vacía si cumple). Un tema puede llamarlo en desarrollo para
|
|
62
|
-
* enterarse al arrancar y no en mitad del checkout.
|
|
63
|
-
*/
|
|
64
44
|
export function assertCommerceClient(cliente) {
|
|
65
45
|
const faltan = []
|
|
66
46
|
if (!cliente || typeof cliente !== "object") return ["el cliente no es un objeto"]
|