feat(F-048): completed feature
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import type { FastifyInstance } from 'fastify';
|
||||
import type { FastifySchema } from 'fastify';
|
||||
import type pg from 'pg';
|
||||
import { z } from 'zod';
|
||||
import type { Authenticate } from '../../../shared/auth.js';
|
||||
import { AppError } from '../../../shared/errors.js';
|
||||
import { errorSchema } from '../../../shared/swagger.js';
|
||||
import { parseJson } from '../../../shared/http-input.js';
|
||||
import type { InventoryServicePort } from '../../inventory/index.js';
|
||||
import type { PricingServicePort } from '../../pricing/index.js';
|
||||
@@ -38,12 +40,24 @@ export async function registerCartRoutes(
|
||||
deps.promotions,
|
||||
);
|
||||
|
||||
app.get('/cart', async (request, reply) => {
|
||||
const cartSchema: FastifySchema = {
|
||||
tags: ['Cart'],
|
||||
summary: 'Get cart',
|
||||
description: 'Devuelve el carrito del usuario autenticado.',
|
||||
response: { 401: errorSchema },
|
||||
};
|
||||
app.get('/cart', { schema: cartSchema }, async (request, reply) => {
|
||||
const user = await deps.authenticate(request);
|
||||
return reply.send(serializeCart(await service.getCart(user.id)));
|
||||
});
|
||||
|
||||
app.post('/cart/items', async (request, reply) => {
|
||||
const addItemSchema: FastifySchema = {
|
||||
tags: ['Cart'],
|
||||
summary: 'Add item to cart',
|
||||
body: { type: 'object' },
|
||||
response: { 201: { type: 'object' }, 401: errorSchema },
|
||||
};
|
||||
app.post('/cart/items', { schema: addItemSchema }, async (request, reply) => {
|
||||
const user = await deps.authenticate(request);
|
||||
const input = parseJson(itemBodySchema, request.body);
|
||||
try {
|
||||
@@ -53,7 +67,22 @@ export async function registerCartRoutes(
|
||||
}
|
||||
});
|
||||
|
||||
app.patch('/cart/items/:variantId', async (request, reply) => {
|
||||
const updateItemSchema: FastifySchema = {
|
||||
tags: ['Cart'],
|
||||
summary: 'Change item quantity',
|
||||
params: {
|
||||
type: 'object',
|
||||
required: ['variantId'],
|
||||
properties: { variantId: { type: 'string', format: 'uuid' } },
|
||||
},
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['quantity'],
|
||||
properties: { quantity: { type: 'integer', minimum: 1 } },
|
||||
},
|
||||
response: { 401: errorSchema },
|
||||
};
|
||||
app.patch('/cart/items/:variantId', { schema: updateItemSchema }, async (request, reply) => {
|
||||
const user = await deps.authenticate(request);
|
||||
const { variantId } = parseJson(variantParamSchema, request.params);
|
||||
const { quantity } = parseJson(quantityBodySchema, request.body);
|
||||
@@ -64,13 +93,33 @@ export async function registerCartRoutes(
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/cart/items/:variantId', async (request, reply) => {
|
||||
const removeItemSchema: FastifySchema = {
|
||||
tags: ['Cart'],
|
||||
summary: 'Remove item from cart',
|
||||
params: {
|
||||
type: 'object',
|
||||
required: ['variantId'],
|
||||
properties: { variantId: { type: 'string', format: 'uuid' } },
|
||||
},
|
||||
response: { 401: errorSchema },
|
||||
};
|
||||
app.delete('/cart/items/:variantId', { schema: removeItemSchema }, async (request, reply) => {
|
||||
const user = await deps.authenticate(request);
|
||||
const { variantId } = parseJson(variantParamSchema, request.params);
|
||||
return reply.send(serializeCart(await service.removeItem(user.id, variantId)));
|
||||
});
|
||||
|
||||
app.post('/cart/promo-code', async (request, reply) => {
|
||||
const promoSchema: FastifySchema = {
|
||||
tags: ['Cart'],
|
||||
summary: 'Apply promo code',
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['code'],
|
||||
properties: { code: { type: 'string', maxLength: 64 } },
|
||||
},
|
||||
response: { 401: errorSchema },
|
||||
};
|
||||
app.post('/cart/promo-code', { schema: promoSchema }, async (request, reply) => {
|
||||
const user = await deps.authenticate(request);
|
||||
const { code } = parseJson(promoCodeBodySchema, request.body);
|
||||
try {
|
||||
|
||||
@@ -32,9 +32,10 @@ export class CartService {
|
||||
}
|
||||
|
||||
async applyPromoCode(userId: string, code: string): Promise<CartView> {
|
||||
if (!this.promotions) return this.toView(await this.carts.setPromoCode(userId, code));
|
||||
await this.promotions.validateCode(code);
|
||||
return this.toView(await this.carts.setPromoCode(userId, code.trim().toUpperCase()));
|
||||
const normalizedCode = code.trim().toUpperCase();
|
||||
if (!this.promotions) return this.toView(await this.carts.setPromoCode(userId, normalizedCode));
|
||||
await this.promotions.validateCode(normalizedCode);
|
||||
return this.toView(await this.carts.setPromoCode(userId, normalizedCode));
|
||||
}
|
||||
|
||||
private async toView(
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
/** Public API of the cart module. */
|
||||
import type pg from 'pg';
|
||||
import type { InventoryServicePort } from '../inventory/index.js';
|
||||
import type { PricingServicePort } from '../pricing/index.js';
|
||||
import type { PromotionServicePort } from '../promotions/index.js';
|
||||
import { CartService } from './application/cart-service.js';
|
||||
import { PgCartRepository } from './infrastructure/pg-cart-repository.js';
|
||||
|
||||
export { registerCartRoutes, type CartRoutesDeps } from './api/cart.routes.js';
|
||||
export { CartService } from './application/cart-service.js';
|
||||
export type { Cart, CartItem, CartItemInput, CartItemView, CartView } from './domain/cart.js';
|
||||
export type { CartRepository } from './domain/ports.js';
|
||||
|
||||
export function createCartService(
|
||||
pool: pg.Pool,
|
||||
pricing: PricingServicePort,
|
||||
inventory: InventoryServicePort,
|
||||
promotions?: PromotionServicePort,
|
||||
): CartService {
|
||||
return new CartService(new PgCartRepository(pool), pricing, inventory, promotions);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user