feat(F-113): completed feature

This commit is contained in:
chattie
2026-08-21 12:27:13 +02:00
parent 027cacd871
commit c05c0b0582
25 changed files with 581 additions and 74 deletions

View File

@@ -37,8 +37,28 @@ const updateSettingsSchema = z.object({
smtpUser: z.string().max(255).optional(),
smtpPass: z.string().max(500).optional(),
smtpFrom: z.string().email().optional().or(z.literal('')),
couriers: z.array(z.string().trim().min(1).max(60)).max(30).optional(),
});
/** Lista de transportistas por defecto hasta que el admin la edite. */
export const DEFAULT_COURIERS = ['Correos', 'SEUR', 'MRW', 'GLS', 'DHL', 'UPS'];
export function parseCouriers(raw: string | undefined | null): string[] {
if (!raw?.trim()) return [...DEFAULT_COURIERS];
try {
const parsed: unknown = JSON.parse(raw);
if (!Array.isArray(parsed)) return [...DEFAULT_COURIERS];
const list = parsed
.filter((item): item is string => typeof item === 'string')
.map((item) => item.trim())
.filter((item) => item.length > 0)
.slice(0, 30);
return list.length > 0 ? list : [...DEFAULT_COURIERS];
} catch {
return [...DEFAULT_COURIERS];
}
}
const SETTING_KEYS: Record<string, string> = {
storeName: 'store_name',
storeTagline: 'store_tagline',
@@ -113,6 +133,7 @@ export async function registerStoreSettingsRoutes(
smtpPass: '',
smtpPassConfigured: Boolean(map['smtp_pass'] || process.env.SMTP_PASS),
smtpFrom: map['smtp_from'] ?? process.env.SMTP_FROM ?? '',
couriers: parseCouriers(map['shipping_couriers']),
});
});
@@ -158,6 +179,13 @@ export async function registerStoreSettingsRoutes(
}
}
}
if (input.couriers !== undefined) {
await deps.pool.query(
`INSERT INTO store_settings (key, value, updated_by) VALUES ('shipping_couriers', $1, $2)
ON CONFLICT (key) DO UPDATE SET value = $1, updated_at = NOW(), updated_by = $2`,
[JSON.stringify(input.couriers), updatedBy],
);
}
// Return updated settings
const result = await deps.pool.query<{ key: string; value: string }>(
`SELECT key, value FROM store_settings`,
@@ -193,6 +221,7 @@ export async function registerStoreSettingsRoutes(
smtpPass: '',
smtpPassConfigured: Boolean(map['smtp_pass'] || process.env.SMTP_PASS),
smtpFrom: map['smtp_from'] ?? process.env.SMTP_FROM ?? '',
couriers: parseCouriers(map['shipping_couriers']),
});
});
}

View File

@@ -0,0 +1,29 @@
import { describe, expect, it } from 'vitest';
import { DEFAULT_COURIERS, parseCouriers } from '../api/settings.routes.js';
describe('parseCouriers', () => {
it('returns the default list when the setting is missing or blank', () => {
expect(parseCouriers(undefined)).toEqual(DEFAULT_COURIERS);
expect(parseCouriers('')).toEqual(DEFAULT_COURIERS);
expect(parseCouriers(' ')).toEqual(DEFAULT_COURIERS);
});
it('parses a stored JSON array and trims entries', () => {
expect(parseCouriers(JSON.stringify([' Correos ', 'SEUR']))).toEqual(['Correos', 'SEUR']);
});
it('drops non-string and empty entries', () => {
expect(parseCouriers(JSON.stringify(['MRW', 42, '', null, 'GLS']))).toEqual(['MRW', 'GLS']);
});
it('falls back to defaults on invalid JSON or empty results', () => {
expect(parseCouriers('not json')).toEqual(DEFAULT_COURIERS);
expect(parseCouriers('{"a":1}')).toEqual(DEFAULT_COURIERS);
expect(parseCouriers(JSON.stringify(['', ' ']))).toEqual(DEFAULT_COURIERS);
});
it('caps the list at 30 couriers', () => {
const many = Array.from({ length: 40 }, (_, index) => `Courier ${index}`);
expect(parseCouriers(JSON.stringify(many))).toHaveLength(30);
});
});