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
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Deliveries" ADD COLUMN "vehicle_type" VARCHAR(50);
1 change: 1 addition & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,7 @@ model Deliveries {
fk_store Int
fk_user Int @unique
delivery_status DeliveryStatus @default(ACTIVE)
vehicle_type String? @db.VarChar(50)
status Boolean @default(true)
created_at DateTime @default(now()) @db.Timestamptz
updated_at DateTime @updatedAt @db.Timestamptz
Expand Down
44 changes: 42 additions & 2 deletions src/modules/delivery/delivery/delivery.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
import { ZodError } from 'zod';
import {
registerDeliverySchema,
updateDeliveryStatusSchema
updateDeliveryStatusSchema,
updateDeliveryProfileSchema
} from './delivery.validation.js';
import {
registerDeliveryService,
updateDeliveryStatusService,
getPendingAssignmentsService,
getDeliveryByIdService
getDeliveryByIdService,
updateDeliveryProfileService
} from './delivery.service.js';

// Registrar delivery
Expand Down Expand Up @@ -112,3 +114,41 @@ export const getDeliveryById = async (req, res) => {
}
};

// Actualizar perfil del delivery
export const updateDeliveryProfile = async (req, res) => {
try {
const { id } = req.params;
const deliveryId = Number.parseInt(id, 10);
if (Number.isNaN(deliveryId)) {
return res.status(400).json({
error: { code: 400, message: "ID inválido" }
});
}

const validData = updateDeliveryProfileSchema.parse(req.body);
const file = req.file;

const result = await updateDeliveryProfileService(
deliveryId,
req.user,
validData,
file
);

return res.status(200).json(result);
} catch (error) {
if (error instanceof ZodError) {
return res.status(400).json({
error: {
code: 400,
message: error.issues[0].message,
details: error.issues
}
});
}
return res.status(error.status || 500).json({
error: { code: error.status || 500, message: error.message }
});
}
};

5 changes: 4 additions & 1 deletion src/modules/delivery/delivery/delivery.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { Router } from "express";
import authenticate from "../../../config/jwt.config.js";
import { ROLES } from "../../../utils/contants/roles.constant.js";
import { requireRole } from "../../../middlewares/auth.middleware.js";
import { upload } from "../../../middlewares/upload.middleware.js";
import {
registerDelivery,
updateDeliveryStatus,
getPendingAssignments,
getDeliveryById
getDeliveryById,
updateDeliveryProfile
} from "./delivery.controller.js";

const router = Router();
Expand All @@ -20,6 +22,7 @@ router.post("/register", registerDelivery);
router.patch("/:id/status", authenticate, requireRole(ROLES.DELIVERY), updateDeliveryStatus);
router.get("/:id/assignments", authenticate, requireRole(ROLES.DELIVERY), getPendingAssignments);
router.get("/:id", authenticate, requireRole(ROLES.DELIVERY), getDeliveryById);
router.put("/:id", authenticate, requireRole(ROLES.DELIVERY), upload.single("avatarUrl"), updateDeliveryProfile);



Expand Down
70 changes: 70 additions & 0 deletions src/modules/delivery/delivery/delivery.service.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//delivery.service.js
import { prisma } from '../../../lib/prisma.js';
import bcrypt from 'bcrypt';
import { upsertUserImage } from '../../images/services/user-image.service.js';


const SALT_ROUNDS = 10;
Expand Down Expand Up @@ -124,3 +125,72 @@
return delivery;
};


// Actualizar perfil de delivery (nombre, teléfono, tipo de vehículo y avatar)
export const updateDeliveryProfileService = async (id_delivery, authUser, data, file) => {
const deliveryId = Number(id_delivery);

const delivery = await prisma.deliveries.findUnique({
where: { id_delivery: deliveryId },
include: { user: true }
});

if (!delivery) {
throw { status: 404, message: "Delivery no encontrado" };

Check warning on line 139 in src/modules/delivery/delivery/delivery.service.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Expected an error object to be thrown.

See more on https://sonarcloud.io/project/issues?id=CrisNAC_BackendMarketplace&issues=AZ3gmhmbWfC-ETgZ5isw&open=AZ3gmhmbWfC-ETgZ5isw&pullRequest=131
}

// Verificar que sea el dueño
if (delivery.fk_user !== authUser.id_user && authUser.role !== 'ADMIN') {
throw { status: 403, message: "No tienes permiso para actualizar este perfil de delivery" };

Check warning on line 144 in src/modules/delivery/delivery/delivery.service.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Expected an error object to be thrown.

See more on https://sonarcloud.io/project/issues?id=CrisNAC_BackendMarketplace&issues=AZ3gmhmbWfC-ETgZ5isx&open=AZ3gmhmbWfC-ETgZ5isx&pullRequest=131
}

const { name, phone, vehicleType } = data;
let avatarUrl = delivery.user.avatar_url;

Check warning on line 148 in src/modules/delivery/delivery/delivery.service.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this useless assignment to variable "avatarUrl".

See more on https://sonarcloud.io/project/issues?id=CrisNAC_BackendMarketplace&issues=AZ3gmhmbWfC-ETgZ5isy&open=AZ3gmhmbWfC-ETgZ5isy&pullRequest=131

// Si envían un archivo de imagen, usar upsertUserImage
if (file) {
try {
avatarUrl = await upsertUserImage(delivery.fk_user, file, authUser);

Check warning on line 153 in src/modules/delivery/delivery/delivery.service.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this useless assignment to variable "avatarUrl".

See more on https://sonarcloud.io/project/issues?id=CrisNAC_BackendMarketplace&issues=AZ3gmhmbWfC-ETgZ5isz&open=AZ3gmhmbWfC-ETgZ5isz&pullRequest=131
} catch (error) {
if (error.statusCode) throw { status: error.statusCode, message: error.message };

Check warning on line 155 in src/modules/delivery/delivery/delivery.service.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Expected an error object to be thrown.

See more on https://sonarcloud.io/project/issues?id=CrisNAC_BackendMarketplace&issues=AZ3gmhmbWfC-ETgZ5is0&open=AZ3gmhmbWfC-ETgZ5is0&pullRequest=131
throw { status: 500, message: `Error al subir imagen: ${error.message}` };

Check warning on line 156 in src/modules/delivery/delivery/delivery.service.js

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Expected an error object to be thrown.

See more on https://sonarcloud.io/project/issues?id=CrisNAC_BackendMarketplace&issues=AZ3gmhmbWfC-ETgZ5is1&open=AZ3gmhmbWfC-ETgZ5is1&pullRequest=131
}
}

// Actualizar Users y Deliveries en una sola transacción para evitar estados parciales
const hasUserChanges = name || phone;
const hasDeliveryChanges = vehicleType !== undefined;

if (hasUserChanges || hasDeliveryChanges) {
await prisma.$transaction(async (tx) => {
if (hasUserChanges) {
await tx.users.update({
where: { id_user: delivery.fk_user },
data: {
...(name && { name }),
...(phone && { phone })
}
});
}

if (hasDeliveryChanges) {
await tx.deliveries.update({
where: { id_delivery: deliveryId },
data: { vehicle_type: vehicleType }
});
}
});
}

// Obtener delivery actualizado para devolverlo
const updatedDelivery = await prisma.deliveries.findUnique({
where: { id_delivery: deliveryId },
include: {
user: {
select: { name: true, phone: true, avatar_url: true, email: true }
}
}
});

return updatedDelivery;
};
6 changes: 6 additions & 0 deletions src/modules/delivery/delivery/delivery.validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ export const registerDeliverySchema = z.object({
});


export const updateDeliveryProfileSchema = z.object({
name: z.string().min(2, "Nombre debe tener mínimo 2 caracteres").optional(),
phone: z.string().regex(/^\d{10,}$/, "Teléfono debe tener mínimo 10 dígitos").optional(),
vehicleType: z.string().min(1, "Tipo de vehículo no puede estar vacío").max(50, "Tipo de vehículo no puede exceder 50 caracteres").optional()
});



export const updateDeliveryStatusSchema = z.object({
Expand Down
Loading
Loading