Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions src/modules/commerce/deliveries/delivery.controller.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import {
searchDeliveryCandidatesService,
createDeliveryService,
getStoreDeliveryReviewsService
getStoreDeliveriesService,
deleteStoreDeliveryService,
getStoreDeliveryReviewsService,
} from "./delivery.service.js";

export const searchDeliveries = async (req, res) => {
Expand Down Expand Up @@ -39,6 +41,30 @@ export const createDelivery = async (req, res) => {
}
};

export const getStoreDeliveries = async (req, res) => {
try {
const { id } = req.params;
const result = await getStoreDeliveriesService(req.user?.id_user, id);
res.status(200).json(result);
} catch (error) {
return res.status(error.status || error.statusCode || 500).json({
message: error.message || "Error interno del servidor"
});
}
};

export const deleteStoreDelivery = async (req, res) => {
try {
const { id, deliveryId } = req.params;
await deleteStoreDeliveryService(req.user?.id_user, id, deliveryId);
res.status(204).send();
} catch (error) {
return res.status(error.status || error.statusCode || 500).json({
message: error.message || "Error interno del servidor"
});
}
};

export const getStoreDeliveryReviews = async (req, res) => {
try {
const { storeId, deliveryId } = req.params;
Expand All @@ -54,4 +80,4 @@ export const getStoreDeliveryReviews = async (req, res) => {
message: error.message || "Error interno del servidor"
});
}
};
};
174 changes: 105 additions & 69 deletions src/modules/commerce/deliveries/delivery.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,109 +2,145 @@ import { Router } from "express";
import authenticate from "../../../config/jwt.config.js";
import { requireRole } from "../../../middlewares/auth.middleware.js";
import { ROLES } from "../../../utils/contants/roles.constant.js";
import { searchDeliveries, createDelivery, getStoreDeliveryReviews } from "./delivery.controller.js";
import {
searchDeliveries,
createDelivery,
getStoreDeliveries,
deleteStoreDelivery,
getStoreDeliveryReviews,
} from "./delivery.controller.js";

export const deliveryRouter = Router();
export const storeDeliveryRouter = Router();

// GET /api/deliveries/search?q=
deliveryRouter.get("/search", authenticate, requireRole(ROLES.SELLER), searchDeliveries);

// POST /api/stores/:id/deliveries — Vincular delivery al comercio
storeDeliveryRouter.post("/:id/deliveries", authenticate, requireRole(ROLES.SELLER), createDelivery);

/**
* @swagger
* /api/deliveries/search:
* /api/stores/{id}/deliveries:
* get:
* summary: Buscar deliveries disponibles para vincular a un comercio
* description: Busca usuarios activos con rol DELIVERY por email o telefono y retorna candidatos que aun no tienen un registro de delivery vinculado.
* summary: Listar repartidores del comercio
* description: >
* Retorna todos los repartidores vinculados al comercio junto con estadísticas
* agregadas (disponibles, en entrega, total, rating promedio).
* Solo accesible por el dueño del comercio.
* tags: [Deliveries]
* security:
* - cookieAuth: []
* - bearerAuth: []
* parameters:
* - in: query
* name: q
* - in: path
* name: id
* required: true
* schema:
* type: string
* description: Texto a buscar en email o telefono
* type: integer
* description: ID del comercio
* responses:
* 200:
* description: Candidatos encontrados
* description: Lista de repartidores y estadísticas
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/DeliverySearchCandidatesResponse'
* type: object
* properties:
* stats:
* type: object
* properties:
* total:
* type: integer
* available:
* type: integer
* inDelivery:
* type: integer
* avgRating:
* type: number
* nullable: true
* deliveries:
* type: array
* items:
* type: object
* properties:
* id:
* type: integer
* user:
* type: object
* properties:
* id:
* type: integer
* name:
* type: string
* email:
* type: string
* phone:
* type: string
* nullable: true
* status:
* type: string
* enum: [AVAILABLE, IN_DELIVERY, UNAVAILABLE]
* vehicleType:
* type: string
* enum: [CAR, MOTORCYCLE, BICYCLE, ON_FOOT]
* completedDeliveries:
* type: integer
* successRate:
* type: number
* nullable: true
* description: Porcentaje de entregas exitosas sobre el total de terminales (DELIVERED + REJECTED)
* avgRating:
* type: number
* nullable: true
* reviewCount:
* type: integer
* 401:
* description: No autenticado
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/AuthErrorResponse'
* 403:
* description: Solo comercios pueden buscar deliveries
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ErrorResponse'
* description: No tiene permisos para acceder a este comercio
* 404:
* description: Comercio no encontrado
*/
deliveryRouter.get("/search", authenticate, requireRole(ROLES.SELLER), searchDeliveries);
storeDeliveryRouter.get("/:id/deliveries", authenticate, requireRole(ROLES.SELLER), getStoreDeliveries);

/**
* @swagger
* /api/stores/{id}/deliveries:
* post:
* summary: Vincular un delivery a un comercio
* description: Crea un registro en Deliveries para asociar un usuario DELIVERY al comercio del vendedor autenticado. El delivery se crea con estado INACTIVE por defecto.
* /api/stores/{id}/deliveries/{deliveryId}:
* delete:
* summary: Desvincular repartidor del comercio
* description: >
* Desvincula un repartidor del comercio (fk_store = null). No elimina al usuario.
* No se permite desvincular si el repartidor tiene entregas activas (PENDING o ACCEPTED).
* Solo accesible por el dueño del comercio.
* tags: [Deliveries]
* security:
* - cookieAuth: []
* - bearerAuth: []
* parameters:
* - in: path
* name: id
* required: true
* schema:
* type: integer
* description: ID del comercio
* requestBody:
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/LinkStoreDeliveryRequest'
* - in: path
* name: deliveryId
* required: true
* schema:
* type: integer
* description: ID del delivery a desvincular
* responses:
* 201:
* description: Delivery vinculado al comercio
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/StoreDeliveryResponse'
* 204:
* description: Repartidor desvinculado correctamente
* 400:
* description: Datos invalidos o fk_user faltante
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ErrorResponse'
* description: El repartidor tiene entregas activas
* 401:
* description: No autenticado
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/AuthErrorResponse'
* 403:
* description: No tiene permisos para vincular deliveries a este comercio
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ErrorResponse'
* description: No tiene permisos para acceder a este comercio
* 404:
* description: Comercio o candidato a delivery no encontrado
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ErrorResponse'
* 409:
* description: El delivery ya esta vinculado a este comercio o a otro comercio
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/ErrorResponse'
* description: Delivery no encontrado para este comercio
*/
storeDeliveryRouter.post("/:id/deliveries", authenticate, requireRole(ROLES.SELLER), createDelivery);
storeDeliveryRouter.delete("/:id/deliveries/:deliveryId", authenticate, requireRole(ROLES.SELLER), deleteStoreDelivery);

/**
* @swagger
Expand Down Expand Up @@ -195,8 +231,8 @@ storeDeliveryRouter.post("/:id/deliveries", authenticate, requireRole(ROLES.SELL
* message: "Delivery no encontrado para este comercio"
*/
storeDeliveryRouter.get(
"/:storeId/deliveries/:deliveryId/reviews",
authenticate,
requireRole(ROLES.SELLER),
getStoreDeliveryReviews
);
"/:storeId/deliveries/:deliveryId/reviews",
authenticate,
requireRole(ROLES.SELLER),
getStoreDeliveryReviews
);
Loading
Loading