feat: redondeo en el pie de los documentos de ventas y compras (visible según OADM.RoundMthd) y endpoint /api/company/settings
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6c2cb30d63
commit
e9e3ba03e5
19 files changed
+270
-17
No files matched your search
@@ -0,0 +1,13 @@
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
import { CompanyService } from './company.service.js';
|
||||
|
||||
/** Ajustes de la empresa de SAP para la interfaz: cualquier sesión puede consultarlos. */
|
||||
@Controller('company')
|
||||
export class CompanyController {
|
||||
constructor(private readonly company: CompanyService) {}
|
||||
|
||||
@Get('settings')
|
||||
settings() {
|
||||
return this.company.settings();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { vi } from 'vitest';
|
||||
import type { SapClientService } from '../sap/sap-client.service.js';
|
||||
import { CompanyService } from './company.service.js';
|
||||
|
||||
describe('CompanyService', () => {
|
||||
const make = (data: unknown) => {
|
||||
const request = vi.fn(async () => ({ data }));
|
||||
return { service: new CompanyService({ request } as unknown as SapClientService), request };
|
||||
};
|
||||
|
||||
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 settings = await service.settings();
|
||||
expect(settings).toEqual({ roundingEnabled: true, accountSegmentsSeparator: '.' });
|
||||
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: '-' });
|
||||
});
|
||||
|
||||
it('recuerda la respuesta un rato y luego la vuelve a pedir', async () => {
|
||||
const { service, request } = make({ RoundingMethod: 'tYES' });
|
||||
await service.settings(1000);
|
||||
await service.settings(1000 + 60_000);
|
||||
expect(request).toHaveBeenCalledTimes(1);
|
||||
await service.settings(1000 + 11 * 60_000);
|
||||
expect(request).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,33 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import type { CompanySettings } from '@basic-erp/sap-types';
|
||||
import { SapClientService } from '../sap/sap-client.service.js';
|
||||
|
||||
/** Cuánto se recuerdan los ajustes de la empresa: cambian casi nunca. */
|
||||
const TTL_MS = 10 * 60 * 1000;
|
||||
|
||||
interface AdminInfo {
|
||||
RoundingMethod?: string;
|
||||
AccountSegmentsSeparator?: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajustes de la empresa que necesita la interfaz. Se leen de `CompanyService_GetAdminInfo` y solo se entregan los
|
||||
* campos de `CompanySettings`: esa respuesta trae mucho más (cuentas bancarias, carpetas) que no debe salir.
|
||||
*/
|
||||
@Injectable()
|
||||
export class CompanyService {
|
||||
private cached: { at: number; value: CompanySettings } | null = null;
|
||||
|
||||
constructor(private readonly sap: SapClientService) {}
|
||||
|
||||
async settings(now = Date.now()): Promise<CompanySettings> {
|
||||
if (this.cached && now - this.cached.at < TTL_MS) return this.cached.value;
|
||||
const res = await this.sap.request<AdminInfo>({ method: 'POST', path: 'CompanyService_GetAdminInfo', body: {} });
|
||||
const value: CompanySettings = {
|
||||
roundingEnabled: res.data?.RoundingMethod === 'tYES',
|
||||
accountSegmentsSeparator: res.data?.AccountSegmentsSeparator?.trim() || '-',
|
||||
};
|
||||
this.cached = { at: now, value };
|
||||
return value;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user