feat(F-181): completed feature
This commit is contained in:
@@ -826,17 +826,79 @@ export async function registerPosRoutes(app: FastifyInstance, deps: PosRouteDeps
|
||||
const { q, limit = 10 } = request.query as { q?: string; limit?: number };
|
||||
if (!q || q.trim().length < 2) return reply.send({ items: [] });
|
||||
const result = await pool.query(
|
||||
`SELECT u.id, u.email, p.first_name AS "firstName", p.last_name AS "lastName", p.phone
|
||||
`SELECT u.id, u.email, p.display_name AS "displayName", COALESCE(p.phone, u.phone) AS phone
|
||||
FROM identity_users u
|
||||
LEFT JOIN users_profiles p ON p.user_id = u.id
|
||||
WHERE u.email ILIKE $1 OR p.first_name ILIKE $1 OR p.last_name ILIKE $1 OR p.phone ILIKE $1
|
||||
ORDER BY p.last_name LIMIT $2`,
|
||||
WHERE u.role = 'customer'
|
||||
AND (u.email ILIKE $1 OR p.display_name ILIKE $1 OR p.phone ILIKE $1 OR u.phone ILIKE $1)
|
||||
ORDER BY p.display_name NULLS LAST, u.email LIMIT $2`,
|
||||
[`%${q.trim()}%`, limit],
|
||||
);
|
||||
return reply.send({ items: result.rows });
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/pos/customers',
|
||||
{
|
||||
schema: {
|
||||
tags: ['POS Terminal'],
|
||||
summary: 'Create a customer from POS',
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['email'],
|
||||
properties: {
|
||||
email: { type: 'string', format: 'email' },
|
||||
displayName: { type: 'string', maxLength: 160 },
|
||||
phone: { type: 'string', maxLength: 40 },
|
||||
},
|
||||
},
|
||||
response: { 401: errorSchema, 409: errorSchema },
|
||||
} as FastifySchema,
|
||||
},
|
||||
async (request, reply) => {
|
||||
const user = await authenticate(request);
|
||||
requireAnyRole(user, ['admin', 'pos_manager', 'pos_cashier'] as ReadonlyArray<Role>);
|
||||
const body = parseJson(
|
||||
z.object({
|
||||
email: z.string().trim().email().transform((value) => value.toLowerCase()),
|
||||
displayName: z.string().trim().min(1).max(160).optional(),
|
||||
phone: z.string().trim().min(1).max(40).optional(),
|
||||
}),
|
||||
request.body ?? {},
|
||||
);
|
||||
const existing = await pool.query('SELECT id FROM identity_users WHERE lower(email) = $1', [body.email]);
|
||||
if (existing.rows[0]) throw new AppError(409, 'CUSTOMER_EXISTS', 'Ya existe un cliente con ese email');
|
||||
const { randomBytes } = await import('node:crypto');
|
||||
const { Argon2PasswordHasher } = await import('../../identity/infrastructure/argon2-password-hasher.js');
|
||||
const passwordHash = await new Argon2PasswordHasher().hash(randomBytes(32).toString('hex'));
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
await client.query('BEGIN');
|
||||
const created = await client.query<{ id: string; email: string }>(
|
||||
`INSERT INTO identity_users (email, password_hash, role, phone)
|
||||
VALUES ($1, $2, 'customer', $3) RETURNING id, email`,
|
||||
[body.email, passwordHash, body.phone ?? null],
|
||||
);
|
||||
const customer = created.rows[0];
|
||||
if (!customer) throw new AppError(500, 'CUSTOMER_CREATE_FAILED', 'No se pudo crear el cliente');
|
||||
await client.query(
|
||||
`INSERT INTO users_profiles (user_id, display_name, phone)
|
||||
VALUES ($1, $2, $3)
|
||||
ON CONFLICT (user_id) DO UPDATE SET display_name = EXCLUDED.display_name, phone = EXCLUDED.phone`,
|
||||
[customer.id, body.displayName ?? null, body.phone ?? null],
|
||||
);
|
||||
await client.query('COMMIT');
|
||||
return reply.code(201).send({ ...customer, displayName: body.displayName ?? null, phone: body.phone ?? null });
|
||||
} catch (error) {
|
||||
await client.query('ROLLBACK');
|
||||
throw error;
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
app.get<{ Params: { id: string } }>(
|
||||
'/pos/customers/:id',
|
||||
{
|
||||
@@ -852,10 +914,10 @@ export async function registerPosRoutes(app: FastifyInstance, deps: PosRouteDeps
|
||||
requireAnyRole(user, ['admin', 'pos_manager', 'pos_cashier'] as ReadonlyArray<Role>);
|
||||
const { id } = request.params;
|
||||
const result = await pool.query(
|
||||
`SELECT u.id, u.email, p.first_name AS "firstName", p.last_name AS "lastName", p.phone
|
||||
`SELECT u.id, u.email, p.display_name AS "displayName", COALESCE(p.phone, u.phone) AS phone
|
||||
FROM identity_users u
|
||||
LEFT JOIN users_profiles p ON p.user_id = u.id
|
||||
WHERE u.id = $1 LIMIT 1`,
|
||||
WHERE u.id = $1 AND u.role = 'customer' LIMIT 1`,
|
||||
[id],
|
||||
);
|
||||
if (!result.rows[0]) throw new AppError(404, 'NOT_FOUND', 'Customer not found');
|
||||
|
||||
Reference in New Issue
Block a user