fix: save and display professional profile address, payment methods, and docs

- DTO: add payment_methods field so whitelist pipe no longer strips it
- Service upsert(): extract payment_methods and write as Prisma nested upsert instead of passing flat object
- Admin detail page: fix image regex to handle Firebase URLs with query params; fix payment_methods display for 1:1 Prisma relation (object, not array)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-07-02 21:42:37 -05:00
co-authored by Claude Sonnet 4.6
parent 1e0de51ec5
commit 72777df52c
3 changed files with 40 additions and 12 deletions
@@ -1,4 +1,4 @@
import { IsString, IsOptional, IsArray, IsNumber, IsBoolean, MinLength, Matches } from 'class-validator';
import { IsString, IsOptional, IsArray, IsNumber, IsBoolean, MinLength, Matches, IsObject } from 'class-validator';
export class CreateProfessionalDto {
@IsString()
@@ -80,6 +80,14 @@ export class UpdateProfessionalDto {
@IsOptional()
@IsString()
location_preferences?: string;
@IsOptional()
@IsObject()
payment_methods?: {
nequi?: boolean;
datafono?: boolean;
transferencia?: boolean;
};
}
export class ScheduleDto {
@@ -83,11 +83,21 @@ export class ProfessionalsService {
}
async upsert(userId: string, data: any) {
const { payment_methods: pm, ...profData } = data;
const buildPm = (forCreate = false) => {
if (!pm) return undefined;
const pmFields = { nequi: pm.nequi ?? false, datafono: pm.datafono ?? false, transferencia: pm.transferencia ?? false };
return forCreate ? { create: pmFields } : { upsert: { update: pmFields, create: pmFields } };
};
const existing = await this.prisma.professionals.findUnique({ where: { user_id: userId } });
if (!existing) {
await this.prisma.users.update({ where: { id: userId }, data: { pro_state: 1 } });
const prof = await this.prisma.professionals.create({ data: { user_id: userId, is_active: false, ...data } });
const createData: any = { user_id: userId, is_active: false, ...profData };
if (pm) createData.payment_methods = buildPm(true);
const prof = await this.prisma.professionals.create({ data: createData });
const u = await this.prisma.users.findUnique({ where: { id: userId }, select: { name: true, email: true } });
if (u?.email) this.mail.sendProfessionalSubmitted(u.name || 'Usuario', u.email, data.profession || '').catch(() => {});
this.tryPush(userId, 'Solicitud recibida', 'Hemos recibido tu solicitud profesional. Te avisaremos cuando sea revisada.');
@@ -97,8 +107,10 @@ export class ProfessionalsService {
// Re-submitting after rejection reset (pro_state=0): move back to pending
const user = await this.prisma.users.findUnique({ where: { id: userId }, select: { pro_state: true, name: true, email: true } });
if (user?.pro_state === 0) {
const resubData: any = { ...profData, is_active: false };
if (pm) resubData.payment_methods = buildPm();
await this.prisma.$transaction([
this.prisma.professionals.update({ where: { user_id: userId }, data: { ...data, is_active: false } }),
this.prisma.professionals.update({ where: { user_id: userId }, data: resubData }),
this.prisma.users.update({ where: { id: userId }, data: { pro_state: 1 } }),
]);
if (user.email) this.mail.sendProfessionalSubmitted(user.name || 'Usuario', user.email, data.profession || '').catch(() => {});
@@ -106,7 +118,9 @@ export class ProfessionalsService {
return this.prisma.professionals.findUnique({ where: { user_id: userId } });
}
return this.prisma.professionals.update({ where: { user_id: userId }, data });
const updateData: any = { ...profData };
if (pm) updateData.payment_methods = buildPm();
return this.prisma.professionals.update({ where: { user_id: userId }, data: updateData });
}
async updateSchedules(professionalId: string, schedules: any[]) {