@pcreative/commerce-contract 1.0.0 → 1.3.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 +296 -526
- package/src/index.d.ts +161 -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
|
|
@@ -164,6 +282,10 @@ export interface ShippingOption {
|
|
|
164
282
|
/** El backend calcula el precio al elegirla (envío por peso, por ejemplo). */
|
|
165
283
|
priceCalculated?: boolean
|
|
166
284
|
description?: string | null
|
|
285
|
+
/** Plazo de entrega tal y como lo escribió la tienda: "24-48 h". */
|
|
286
|
+
deliveryTime?: string | null
|
|
287
|
+
/** El cliente recoge el pedido: no hay porte ni reparto. */
|
|
288
|
+
pickup?: boolean
|
|
167
289
|
}
|
|
168
290
|
|
|
169
291
|
export interface PaymentMethod {
|
|
@@ -171,6 +293,10 @@ export interface PaymentMethod {
|
|
|
171
293
|
/** Identificador del proveedor: "transfer", "cod", "bizum", "card"… */
|
|
172
294
|
provider: string
|
|
173
295
|
name?: string
|
|
296
|
+
/** Texto corto que la tienda escribe para explicarla en la caja. */
|
|
297
|
+
description?: string | null
|
|
298
|
+
/** Lo que el comprador tiene que hacer para pagar (datos de una transferencia). */
|
|
299
|
+
instructions?: string | null
|
|
174
300
|
/**
|
|
175
301
|
* Recargo de esta forma de pago, en unidades mayores. Sin definir = ninguno.
|
|
176
302
|
*
|
|
@@ -214,6 +340,10 @@ export interface Cart {
|
|
|
214
340
|
shippingMethods: { id: string; name: string; price: Money }[]
|
|
215
341
|
regionId?: string
|
|
216
342
|
promoCodes?: string[]
|
|
343
|
+
hasDigital?: boolean
|
|
344
|
+
digitalConsent?: { at: string; version: number } | null
|
|
345
|
+
vatNumber?: { number: string; valid: boolean; checked: boolean; name: string | null } | null
|
|
346
|
+
taxExempt?: { reason: "intra_eu"; articles: string[] } | null
|
|
217
347
|
/**
|
|
218
348
|
* El paso que falta para pagar, si el método elegido lo pide. `null` con los
|
|
219
349
|
* métodos sin pasarela: ahí pagar es confirmar el pedido y ya está.
|
|
@@ -313,18 +443,36 @@ export interface CommerceClient {
|
|
|
313
443
|
search(q: string, limit?: number): Promise<Product[]>
|
|
314
444
|
/** Pedido por id, para la página de confirmación tras el checkout. */
|
|
315
445
|
getOrder(id: string): Promise<Order | null>
|
|
446
|
+
/** Sube un fichero que el cliente adjunta a una personalización. */
|
|
447
|
+
subirFichero?(archivo: File): Promise<{ id: string; nombre: string; tipo: string; bytes: number; firma: string }>
|
|
448
|
+
/** Opcional: las descargas de un pedido con contenido digital. */
|
|
449
|
+
getDownloads?(orderId: string): Promise<Download[]>
|
|
450
|
+
/** Opcional: estado del derecho de desistimiento de un pedido. */
|
|
451
|
+
getWithdrawal?(orderId: string): Promise<WithdrawalState | null>
|
|
452
|
+
/** Opcional: solicita el desistimiento de un pedido (botón obligatorio en la UE). */
|
|
453
|
+
requestWithdrawal?(orderId: string, datos?: { lineas?: string[]; motivo?: string }): Promise<{ solicitud: string; aceptadas: number }>
|
|
316
454
|
|
|
317
455
|
cart: {
|
|
318
456
|
get(id: string): Promise<Cart | null>
|
|
319
457
|
create(): Promise<Cart>
|
|
320
|
-
addItem(
|
|
458
|
+
addItem(
|
|
459
|
+
cartId: string,
|
|
460
|
+
variantId: string,
|
|
461
|
+
quantity: number,
|
|
462
|
+
personalizacion?: Record<string, unknown>,
|
|
463
|
+
pack?: Record<string, string[]>
|
|
464
|
+
): Promise<Cart>
|
|
321
465
|
updateItem(cartId: string, lineId: string, quantity: number): Promise<Cart>
|
|
322
466
|
removeItem(cartId: string, lineId: string): Promise<Cart>
|
|
467
|
+
/** Consentimiento previo para entregar contenido digital ya (UE, Reino Unido). */
|
|
468
|
+
consentirDigital?(cartId: string, aceptado: boolean): Promise<Cart>
|
|
323
469
|
applyPromo(cartId: string, code: string): Promise<Cart>
|
|
324
470
|
removePromo(cartId: string, code: string): Promise<Cart>
|
|
325
471
|
}
|
|
326
472
|
|
|
327
473
|
checkout: {
|
|
474
|
+
listCountries?(): Promise<string[]>
|
|
475
|
+
setVatNumber?(cartId: string, vatNumber: string | null): Promise<Cart>
|
|
328
476
|
setEmail(cartId: string, email: string): Promise<Cart>
|
|
329
477
|
setAddresses(cartId: string, shipping: Address, billing?: Address): Promise<Cart>
|
|
330
478
|
listShippingOptions(cartId: string): Promise<ShippingOption[]>
|
|
@@ -360,12 +508,23 @@ export interface CommerceClient {
|
|
|
360
508
|
|
|
361
509
|
/** Opcional: un adaptador puede no soportar cuentas de cliente. */
|
|
362
510
|
account?: {
|
|
363
|
-
login(email: string, password: string): Promise<{ token: string }>
|
|
511
|
+
login(email: string, password: string, cartId?: string): Promise<{ token: string }>
|
|
364
512
|
register(datos: { email: string; password: string; firstName?: string; lastName?: string }): Promise<Customer>
|
|
365
513
|
me(token: string): Promise<Customer | null>
|
|
366
514
|
orders(token: string): Promise<Order[]>
|
|
515
|
+
confirmEmail?(sessionToken: string, token: string): Promise<{ adopted: number } | null>
|
|
367
516
|
}
|
|
368
517
|
|
|
518
|
+
/** Opcional: nombre y datos legales de la tienda, tal y como los tiene el panel. */
|
|
519
|
+
getStore?(): Promise<StoreInfo | null>
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Opcional: manda a la tienda un mensaje del formulario de contacto. Rechaza
|
|
523
|
+
* con `status` 400 si faltan datos, 429 si hay demasiados envíos y 503 si la
|
|
524
|
+
* tienda no tiene a dónde mandarlo.
|
|
525
|
+
*/
|
|
526
|
+
sendContact?(mensaje: { name?: string; email: string; subject?: string; message: string }): Promise<void>
|
|
527
|
+
|
|
369
528
|
/** Opcional: contenido editorial servido por el backend. */
|
|
370
529
|
content?: {
|
|
371
530
|
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"]
|