feat: moneda y tipo de cambio del documento (debajo del Nº de referencia) y ajustes de moneda local de la empresa

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GeorgeandClaude Sonnet 5.5 committed 2026-10-19 14:40:14 -05:00
1 parent a74c19a139
commit b85383dda1
11 files changed
+229 -9

No files matched your search

+3 -3
View File
@@ -9,15 +9,15 @@ describe('CompanyService', () => {
};
it('entrega solo el redondeo y el separador, sin el resto de la información de la empresa', async () => {
const { service, request } = make({ RoundingMethod: 'tYES', AccountSegmentsSeparator: '.', DefaultBankAccount: '192-1153365-0-50' });
const { service, request } = make({ RoundingMethod: 'tYES', AccountSegmentsSeparator: '.', LocalCurrency: 'SOL', DefaultBankAccount: '192-1153365-0-50' });
const settings = await service.settings();
expect(settings).toEqual({ roundingEnabled: true, accountSegmentsSeparator: '.' });
expect(settings).toEqual({ roundingEnabled: true, accountSegmentsSeparator: '.', localCurrency: 'SOL' });
expect(request).toHaveBeenCalledWith({ method: 'POST', path: 'CompanyService_GetAdminInfo', body: {} });
});
it('sin redondeo ni separador usa los valores por defecto', async () => {
const { service } = make({ RoundingMethod: 'tNO', AccountSegmentsSeparator: null });
expect(await service.settings()).toEqual({ roundingEnabled: false, accountSegmentsSeparator: '-' });
expect(await service.settings()).toEqual({ roundingEnabled: false, accountSegmentsSeparator: '-', localCurrency: '' });
});
it('recuerda la respuesta un rato y luego la vuelve a pedir', async () => {
+2
View File
@@ -8,6 +8,7 @@ const TTL_MS = 10 * 60 * 1000;
interface AdminInfo {
RoundingMethod?: string;
AccountSegmentsSeparator?: string | null;
LocalCurrency?: string | null;
}
/**
@@ -26,6 +27,7 @@ export class CompanyService {
const value: CompanySettings = {
roundingEnabled: res.data?.RoundingMethod === 'tYES',
accountSegmentsSeparator: res.data?.AccountSegmentsSeparator?.trim() || '-',
localCurrency: res.data?.LocalCurrency?.trim() || '',
};
this.cached = { at: now, value };
return value;
+7
View File
@@ -77,4 +77,11 @@ describe('recursos del Service Layer', () => {
expect(r.actions).toEqual(['Cancel']);
expect(r.write).toBe('/finanzas/asientos');
});
it('el tipo de cambio es una acción de solo consulta y las formas de envío y de pago son catálogos', () => {
const rate = SL_RESOURCE_MAP.get('SBOBobService_GetCurrencyRate')!;
expect(rate.methods).toEqual(['POST']);
expect(rate.write).toBeNull();
for (const name of ['ShippingTypes', 'WizardPaymentMethods']) expect(SL_RESOURCE_MAP.get(name)!.methods, name).toEqual(['GET']);
});
});
+5
View File
@@ -110,6 +110,11 @@ export const SL_RESOURCES: readonly SlResource[] = [
catalog('AccountSegmentations', 'number'),
// Series de numeración válidas de un tipo de documento.
queryAction('SeriesService_GetDocumentSeries'),
// Tipo de cambio de una moneda en una fecha (para documentos en moneda extranjera): solo consulta.
queryAction('SBOBobService_GetCurrencyRate'),
// Logística y finanzas de los documentos: formas de envío y métodos de pago.
catalog('ShippingTypes', 'number'),
catalog('WizardPaymentMethods', 'string'),
// Gastos adicionales de un documento (el flete): se leen para elegir el código de gasto.
catalog('AdditionalExpenses', 'number'),
];