feat(web): la «Cuenta / socio» del asiento se elige de cuentas, clientes o proveedores y completa la cuenta de control del socio

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GeorgeandClaude Sonnet 5.5 committed 2026-10-19 11:17:44 -05:00
1 parent 5dfe096c5d
commit c567bc6836
3 files changed
+129 -16

No files matched your search

@@ -1,9 +1,9 @@
import { HttpErrorResponse, httpResource } from '@angular/common/http';
import { HttpClient, HttpErrorResponse, HttpParams, httpResource } from '@angular/common/http';
import { ChangeDetectionStrategy, Component, computed, inject, linkedSignal, signal } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import type { SlListResponse } from '@basic-erp/sap-types';
import { map } from 'rxjs';
import { firstValueFrom, map } from 'rxjs';
import { API_URL, apiErrorMessage } from '../../core/api';
import { formatNumber } from '../../core/format';
import { SlDocumentApi } from '../../core/sl/sl-document';
@@ -11,12 +11,29 @@ import { DateField, LookupField, SboField, SelectField, TextField, TextInput } f
import type { DetailColumn } from '../../shared/grid/grid.types';
import { RowsTable } from '../../shared/grid/rows-table';
import { Icon, SboWindow, Toolbar, type StatusMessage, type WindowBadge } from '../../shared/window';
import { ACCOUNT_CODES } from '../../core/sl/account-codes';
import type { VhLookup } from '../../shared/value-help/value-help.types';
import { ACCOUNT_LOOKUP, INDICATOR_LOOKUP, PROJECT_LOOKUP, dimensionLookup } from '../documents/dimension-lookups';
import type { NavTarget } from '../documents/document-model';
import { isManualJournal, journalOrigin, journalPayload, journalTotals, validateJournal } from './journal-model';
type Row = Record<string, unknown>;
/** Clientes o proveedores para la «Cuenta / socio» de una línea; piden su cuenta de control para completar la «Cuenta». */
const partnerLookup = (type: 'cCustomer' | 'cSupplier', title: string): VhLookup => ({
title,
resource: 'BusinessPartners',
baseFilter: `CardType eq '${type}'`,
orderby: 'CardCode',
columns: [
{ key: 'CardCode', title: 'Código', width: '130px', mono: true },
{ key: 'CardName', title: 'Nombre' },
],
});
/** Una línea de socio: el código del socio (su cuenta de control se pide aparte: SAP falla al listarla junto con los socios). */
const partnerLine = (partner: Record<string, unknown>): Record<string, unknown> => ({ ShortName: partner['CardCode'] });
/** Tipo de objeto de SAP del asiento contable (para pedir sus series de numeración). */
const OBJECT_TYPE = 30;
@@ -40,6 +57,7 @@ export class JournalFormPage {
private readonly route = inject(ActivatedRoute);
private readonly router = inject(Router);
private readonly api = inject(SlDocumentApi);
private readonly http = inject(HttpClient);
protected readonly title = this.route.snapshot.data['title'] as string;
protected readonly jdtNum = toSignal(this.route.paramMap.pipe(map((p) => (p.has('jdtNum') ? Number(p.get('jdtNum')) : null))), {
@@ -105,9 +123,29 @@ export class JournalFormPage {
// --- vista -----------------------------------------------------------------------------------
/** La cuenta de control del socio, para una línea que todavía no tiene cuenta. */
private async controlAccount(partner: Record<string, unknown>, row: Record<string, unknown>): Promise<Record<string, unknown>> {
if (row['AccountCode']) return {};
const res = await firstValueFrom(
this.http.get<{ DebitorAccount?: string }>(`${API_URL}/sl/BusinessPartners/${encodeURIComponent(String(partner['CardCode']))}`, { params: new HttpParams().set('$select', 'DebitorAccount') }),
);
return res.DebitorAccount ? { AccountCode: res.DebitorAccount } : {};
}
protected readonly columns: readonly DetailColumn[] = [
{ key: 'AccountCode', title: 'Cuenta', type: 'lookup', required: true, lookup: ACCOUNT_LOOKUP, width: '170px' },
{ key: 'ShortName', title: 'Cuenta / socio', type: 'lookup', lookup: ACCOUNT_LOOKUP, width: '170px' },
{
key: 'ShortName',
title: 'Cuenta / socio',
type: 'lookup',
width: '170px',
codes: ACCOUNT_CODES,
lookups: [
{ label: 'Cuentas', lookup: ACCOUNT_LOOKUP, apply: (a) => ({ ShortName: a['Code'], AccountCode: a['Code'] }) },
{ label: 'Clientes', lookup: partnerLookup('cCustomer', 'Clientes'), apply: partnerLine, complete: (p, row) => this.controlAccount(p, row) },
{ label: 'Proveedores', lookup: partnerLookup('cSupplier', 'Proveedores'), apply: partnerLine, complete: (p, row) => this.controlAccount(p, row) },
],
},
{ key: 'Debit', title: 'Debe', type: 'number', decimals: 2, width: '120px' },
{ key: 'Credit', title: 'Haber', type: 'number', decimals: 2, width: '120px' },
{ key: 'DueDate', title: 'Vencimiento', type: 'date', width: '120px' },