feat(F-113): completed feature
This commit is contained in:
@@ -227,6 +227,7 @@ export async function registerOrdersRoutes(
|
||||
],
|
||||
},
|
||||
trackingNumber: { type: 'string', maxLength: 120, description: 'Número de seguimiento del envío (obligatorio al marcar como Enviado)' },
|
||||
courier: { type: 'string', maxLength: 120, description: 'Transportista del envío, de la lista editable en Ajustes (obligatorio al marcar como Enviado)' },
|
||||
},
|
||||
},
|
||||
response: { 401: errorSchema, 403: errorSchema, 404: errorSchema },
|
||||
@@ -238,16 +239,22 @@ export async function registerOrdersRoutes(
|
||||
const user = await deps.authenticate(request);
|
||||
requireRole(user, 'admin');
|
||||
const { id } = parseJson(orderIdParamSchema, request.params);
|
||||
const { state, trackingNumber } = parseJson(
|
||||
transitionSchema.extend({ trackingNumber: z.string().min(1).max(120).optional() }),
|
||||
const { state, trackingNumber, courier } = parseJson(
|
||||
transitionSchema.extend({
|
||||
trackingNumber: z.string().min(1).max(120).optional(),
|
||||
courier: z.string().min(1).max(120).optional(),
|
||||
}),
|
||||
request.body,
|
||||
);
|
||||
if (state === 'SHIPPED' && !trackingNumber?.trim()) {
|
||||
throw new AppError(422, 'TRACKING_NUMBER_REQUIRED', 'Indica el número de seguimiento para marcar el pedido como enviado');
|
||||
}
|
||||
if (state === 'SHIPPED' && !courier?.trim()) {
|
||||
throw new AppError(422, 'COURIER_REQUIRED', 'Indica el transportista para marcar el pedido como enviado');
|
||||
}
|
||||
let order;
|
||||
try {
|
||||
order = await service.transitionAdmin(id, state as OrderState, trackingNumber?.trim() || undefined);
|
||||
order = await service.transitionAdmin(id, state as OrderState, trackingNumber?.trim() || undefined, courier?.trim() || undefined);
|
||||
} catch (error) {
|
||||
throw mapOrderError(error);
|
||||
}
|
||||
@@ -266,6 +273,7 @@ export async function registerOrdersRoutes(
|
||||
orderId: order.id,
|
||||
state: order.state,
|
||||
trackingNumber: order.trackingNumber,
|
||||
courier: order.courier,
|
||||
});
|
||||
notified = true;
|
||||
} else {
|
||||
@@ -279,7 +287,7 @@ export async function registerOrdersRoutes(
|
||||
deps.pool,
|
||||
order.id,
|
||||
'STATE_CHANGE',
|
||||
`Estado cambiado a ${ORDER_STATE_LABELS[order.state] ?? order.state}${order.trackingNumber ? ` · Tracking: ${order.trackingNumber}` : ''}`,
|
||||
`Estado cambiado a ${ORDER_STATE_LABELS[order.state] ?? order.state}${order.courier ? ` · Transportista: ${order.courier}` : ''}${order.trackingNumber ? ` · Tracking: ${order.trackingNumber}` : ''}`,
|
||||
order.trackingNumber ?? null,
|
||||
user.email,
|
||||
);
|
||||
@@ -304,9 +312,10 @@ export async function registerOrdersRoutes(
|
||||
const user = await deps.authenticate(request);
|
||||
requireRole(user, 'admin');
|
||||
const { id } = parseJson(orderIdParamSchema, request.params);
|
||||
const { trackingNumber, note } = parseJson(
|
||||
const { trackingNumber, courier, note } = parseJson(
|
||||
z.object({
|
||||
trackingNumber: z.string().trim().min(1).max(120),
|
||||
courier: z.string().trim().min(1).max(120).optional(),
|
||||
note: z.string().trim().max(500).optional(),
|
||||
}),
|
||||
request.body,
|
||||
@@ -314,13 +323,13 @@ export async function registerOrdersRoutes(
|
||||
const existing = await service.getOrderAdmin(id);
|
||||
if (!existing) throw new AppError(404, 'ORDER_NOT_FOUND', 'Order not found');
|
||||
await deps.pool.query(
|
||||
`UPDATE orders_orders SET tracking_number = $2, updated_at = now() WHERE id = $1`,
|
||||
[id, trackingNumber],
|
||||
`UPDATE orders_orders SET tracking_number = $2, courier = COALESCE($3, courier), updated_at = now() WHERE id = $1`,
|
||||
[id, trackingNumber, courier ?? null],
|
||||
);
|
||||
const message = `Seguimiento actualizado: ${trackingNumber}${note ? ` · Nota: ${note}` : ''}`;
|
||||
const message = `Seguimiento actualizado: ${trackingNumber}${courier ? ` · Transportista: ${courier}` : ''}${note ? ` · Nota: ${note}` : ''}`;
|
||||
await recordOrderHistory(deps.pool, id, 'SHIPPING_UPDATE', message, trackingNumber, user.email);
|
||||
const updated = await service.getOrderAdmin(id);
|
||||
return reply.send(serializeOrder(updated ?? { ...existing, trackingNumber }));
|
||||
return reply.send(serializeOrder(updated ?? { ...existing, trackingNumber, courier: courier ?? existing.courier }));
|
||||
});
|
||||
|
||||
const historySchema: FastifySchema = {
|
||||
@@ -490,6 +499,7 @@ function serializeOrder(order: {
|
||||
taxCents: number;
|
||||
totalCents: number;
|
||||
trackingNumber?: string | null;
|
||||
courier?: string | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
idempotencyKey: string | null;
|
||||
@@ -518,6 +528,7 @@ function serializeOrder(order: {
|
||||
taxCents: order.taxCents,
|
||||
totalCents: order.totalCents,
|
||||
trackingNumber: order.trackingNumber ?? null,
|
||||
courier: order.courier ?? null,
|
||||
idempotencyKey: order.idempotencyKey,
|
||||
items: order.items.map((item) => ({
|
||||
id: item.id,
|
||||
|
||||
Reference in New Issue
Block a user