feat(F-113): completed feature
This commit is contained in:
@@ -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']),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user