377 lines
13 KiB
HTML
377 lines
13 KiB
HTML
<sbo-toolbar bleed aria-label="Acciones del documento">
|
|
<a class="tb" routerLink=".." title="Volver a la lista"><sbo-icon name="find" />Lista</a>
|
|
<a class="tb" [routerLink]="isNew() ? '.' : '../nuevo'" title="Documento nuevo"><sbo-icon name="new" />Nuevo</a>
|
|
<span class="tb-sep"></span>
|
|
<button class="tb" type="button" aria-label="Primero" (click)="go('first')"><sbo-icon name="first" /></button>
|
|
<button class="tb" type="button" aria-label="Anterior" (click)="go('prev')"><sbo-icon name="prev" /></button>
|
|
<button class="tb" type="button" aria-label="Siguiente" (click)="go('next')"><sbo-icon name="next" /></button>
|
|
<button class="tb" type="button" aria-label="Último" (click)="go('last')"><sbo-icon name="last" /></button>
|
|
<sbo-document-pdf [screen]="screen.path" [docEntry]="docEntry()" />
|
|
</sbo-toolbar>
|
|
|
|
<sbo-window [title]="windowTitle()" [badge]="badge()" [status]="status()">
|
|
<div class="sbo-hdr">
|
|
<div class="sbo-col">
|
|
@for (f of layout.header.left; track $index) {
|
|
<ng-container *ngTemplateOutlet="field; context: { $implicit: f }" />
|
|
}
|
|
</div>
|
|
<div class="sbo-col">
|
|
@for (f of layout.header.right; track $index) {
|
|
<ng-container *ngTemplateOutlet="field; context: { $implicit: f }" />
|
|
}
|
|
</div>
|
|
</div>
|
|
|
|
@if (layout.tabs; as t) {
|
|
<sbo-tabs ariaLabel="Secciones del documento">
|
|
<sbo-tab label="Contenido">
|
|
<ng-container *ngTemplateOutlet="linesBlock" />
|
|
</sbo-tab>
|
|
<sbo-tab label="Logística">
|
|
<div class="sbo-hdr">
|
|
<div class="sbo-col">
|
|
@for (f of t.logistics.left; track $index) {
|
|
<ng-container *ngTemplateOutlet="field; context: { $implicit: f }" />
|
|
}
|
|
</div>
|
|
<div class="sbo-col">
|
|
@for (f of t.logistics.right; track $index) {
|
|
<ng-container *ngTemplateOutlet="field; context: { $implicit: f }" />
|
|
}
|
|
</div>
|
|
</div>
|
|
</sbo-tab>
|
|
<sbo-tab label="Finanzas">
|
|
<div class="sbo-hdr">
|
|
<div class="sbo-col">
|
|
@for (f of t.finance.left; track $index) {
|
|
<ng-container *ngTemplateOutlet="field; context: { $implicit: f }" />
|
|
}
|
|
</div>
|
|
<div class="sbo-col">
|
|
@for (f of t.finance.right; track $index) {
|
|
<ng-container *ngTemplateOutlet="field; context: { $implicit: f }" />
|
|
}
|
|
</div>
|
|
</div>
|
|
</sbo-tab>
|
|
</sbo-tabs>
|
|
} @else {
|
|
<ng-container *ngTemplateOutlet="linesBlock" />
|
|
}
|
|
|
|
<div class="sbo-hdr" style="margin-top: 14px">
|
|
<div class="sbo-col">
|
|
@for (f of layout.footer.left; track $index) {
|
|
<ng-container *ngTemplateOutlet="field; context: { $implicit: f }" />
|
|
}
|
|
</div>
|
|
<div class="sbo-col">
|
|
@for (f of layout.footer.right; track $index) {
|
|
<ng-container *ngTemplateOutlet="field; context: { $implicit: f }" />
|
|
}
|
|
</div>
|
|
</div>
|
|
|
|
@if (!readOnly()) {
|
|
<button sboActions class="btn main" type="button" [disabled]="saving() || loading()" (click)="save()">
|
|
{{ isNew() ? 'Crear' : 'Actualizar' }}
|
|
</button>
|
|
}
|
|
@if (conflict()) {
|
|
<button sboActions class="btn" type="button" (click)="reload()">Recargar</button>
|
|
}
|
|
<a sboActions class="btn" routerLink="..">{{ readOnly() ? 'Cerrar' : 'Cancelar' }}</a>
|
|
@if (cancellation(); as c) {
|
|
<button sboActions class="btn" type="button" (click)="openCancellationPair()">{{ c === 'cancelled' ? 'Ver su cancelación' : 'Ver el documento cancelado' }}</button>
|
|
}
|
|
@if (copyFromItems().length) {
|
|
<sbo-menu-button sboActionsEnd label="Copiar de" [items]="copyFromItems()" (picked)="copyFrom($event)" />
|
|
}
|
|
@if (copyToItems().length) {
|
|
<sbo-menu-button sboActionsEnd label="Copiar a" [items]="copyToItems()" (picked)="copyTo($event)" />
|
|
}
|
|
</sbo-window>
|
|
|
|
@if (addressDialog(); as f) {
|
|
<sbo-address-dialog [title]="f.label" [initial]="addressValues(f)" (saved)="saveAddress(f, $event)" (closed)="addressDialog.set(null)" />
|
|
}
|
|
|
|
@if (groupCell(); as cell) {
|
|
@if (cell.kind === 'lookup') {
|
|
<sbo-value-help
|
|
[open]="true"
|
|
[title]="cell.lookup.title"
|
|
[resource]="cell.lookup.resource"
|
|
[columns]="cell.lookup.columns"
|
|
[baseFilter]="cell.lookup.baseFilter"
|
|
[orderby]="cell.lookup.orderby"
|
|
[rowKey]="cell.lookup.valueKey"
|
|
[extraFields]="cell.lookup.extraFields ?? []"
|
|
(selected)="groupPicked($event)"
|
|
(closed)="groupCell.set(null)"
|
|
/>
|
|
}
|
|
}
|
|
|
|
@if (copyListScreen(); as src) {
|
|
<sbo-value-help
|
|
[open]="true"
|
|
[title]="'Copiar de: ' + copyListTitle()"
|
|
[resource]="src.resource"
|
|
[columns]="copyListColumns"
|
|
[baseFilter]="copyListFilter()"
|
|
orderby="DocEntry desc"
|
|
rowKey="DocEntry"
|
|
(selected)="copyPicked($event)"
|
|
(closed)="copyListFor.set(null)"
|
|
/>
|
|
}
|
|
|
|
<ng-template #field let-f>
|
|
@switch (f.type) {
|
|
@case ('partner') {
|
|
<sbo-lookup-field
|
|
[label]="f.label" [dbName]="f.key"
|
|
[required]="!!f.required"
|
|
[readonly]="readOnly() || !isNew() || locked(f)"
|
|
[value]="str(header()[f.key])"
|
|
(valueChange)="onPartnerText($event)"
|
|
[lookup]="partnerLookup"
|
|
resolveOnLeave
|
|
(picked)="onPartner($event)"
|
|
/>
|
|
}
|
|
@case ('checkbox') {
|
|
<sbo-checkbox-field
|
|
[label]="f.label" [dbName]="f.key"
|
|
[readonly]="readOnly() || !!f.readonly || locked(f)"
|
|
[value]="header()[f.key] === 'tYES'"
|
|
(valueChange)="setHeader(f.key, $event ? 'tYES' : 'tNO')"
|
|
/>
|
|
}
|
|
@case ('lookup') {
|
|
<sbo-lookup-field
|
|
[label]="f.label" [dbName]="f.key"
|
|
[required]="!!f.required"
|
|
[readonly]="readOnly() || locked(f)"
|
|
[value]="str(header()[f.key])"
|
|
(valueChange)="setHeader(f.key, typedLookup(f, $event))"
|
|
[lookup]="lookupOf(f)"
|
|
resolveOnLeave
|
|
(picked)="pickedLookup(f, $event)"
|
|
/>
|
|
}
|
|
@case ('warehouse') {
|
|
<sbo-lookup-field
|
|
[label]="f.label" [dbName]="f.key"
|
|
[required]="!!f.required"
|
|
[readonly]="readOnly() || locked(f)"
|
|
[value]="str(header()[f.key])"
|
|
(valueChange)="setHeader(f.key, $event)"
|
|
[lookup]="warehouseLookup"
|
|
resolveOnLeave
|
|
/>
|
|
}
|
|
@case ('date') {
|
|
<sbo-date-field
|
|
[label]="f.label" [dbName]="f.key"
|
|
[required]="!!f.required"
|
|
[readonly]="readOnly() || locked(f)"
|
|
[value]="str(header()[f.key])"
|
|
(valueChange)="setHeader(f.key, $event)"
|
|
/>
|
|
}
|
|
@case ('select') {
|
|
<sbo-select-field
|
|
[label]="f.label" [dbName]="f.key"
|
|
[required]="!!f.required"
|
|
[readonly]="readOnly() || locked(f)"
|
|
[options]="f.options"
|
|
placeholder=""
|
|
[value]="str(header()[f.key]) || null"
|
|
(valueChange)="setHeader(f.key, $event ?? '')"
|
|
/>
|
|
}
|
|
@case ('number') {
|
|
<sbo-number-field
|
|
[label]="f.label" [dbName]="f.key"
|
|
[decimals]="f.decimals"
|
|
[readonly]="readOnly() || locked(f)"
|
|
[value]="+str(header()[f.key])"
|
|
(valueChange)="setHeader(f.key, $event ?? 0)"
|
|
/>
|
|
}
|
|
@case ('textarea') {
|
|
<sbo-textarea-field
|
|
[label]="f.label" [dbName]="f.key"
|
|
[readonly]="readOnly() || locked(f)"
|
|
[value]="str(header()[f.key])"
|
|
(valueChange)="setHeader(f.key, $event)"
|
|
/>
|
|
}
|
|
@case ('folio') {
|
|
<sbo-field [label]="f.label" [dbName]="f.key">
|
|
<sbo-input
|
|
width="90px"
|
|
[maxlength]="10"
|
|
[readonly]="readOnly() || locked(f)"
|
|
[value]="str(header()[f.prefixKey])"
|
|
(valueChange)="setHeader(f.prefixKey, $event)"
|
|
/>
|
|
<sbo-input
|
|
ariaLabel="Número de folio"
|
|
[readonly]="readOnly() || locked(f)"
|
|
[value]="str(header()[f.numberKey])"
|
|
(valueChange)="setHeader(f.numberKey, $event)"
|
|
/>
|
|
</sbo-field>
|
|
}
|
|
@case ('group') {
|
|
<sbo-field [label]="f.label" [dbName]="f.key">
|
|
@for (c of f.cells; track c.key) {
|
|
<sbo-input
|
|
[width]="c.width"
|
|
[maxlength]="c.kind === 'text' ? c.maxlength : undefined"
|
|
[ariaLabel]="c.label"
|
|
[readonly]="readOnly() || locked(f)"
|
|
[value]="str(header()[c.key])"
|
|
(valueChange)="setHeader(c.key, $event)"
|
|
/>
|
|
@if (c.kind === 'lookup' && !(readOnly() || locked(f))) {
|
|
<button type="button" class="sbo-btn" [attr.aria-label]="'Abrir la lista de ' + c.label.toLowerCase()" title="Lista de valores" (click)="groupCell.set(c)">…</button>
|
|
}
|
|
}
|
|
</sbo-field>
|
|
}
|
|
@case ('series') {
|
|
<sbo-field [label]="f.label" [dbName]="f.key">
|
|
<sbo-select
|
|
width="170px"
|
|
ariaLabel="Serie de numeración"
|
|
placeholder="(por defecto)"
|
|
[options]="seriesOptions()"
|
|
[readonly]="readOnly() || !isNew() || locked(f)"
|
|
[value]="seriesValue()"
|
|
(valueChange)="setHeader(f.key, $event ?? '')"
|
|
/>
|
|
<sbo-input readonly ariaLabel="Número del documento" [value]="str(doc()?.['DocNum'])" />
|
|
</sbo-field>
|
|
}
|
|
@case ('expenses') {
|
|
<div class="exp">
|
|
<h3>{{ f.label }}</h3>
|
|
<sbo-rows-table
|
|
[columns]="expenseColumns"
|
|
[rows]="expenses()"
|
|
(rowsChange)="setExpenses($event)"
|
|
[readonly]="readOnly() || locked(f)"
|
|
[removable]="!readOnly() && !locked(f)"
|
|
emptyText="Sin gastos adicionales."
|
|
/>
|
|
@if (!readOnly() && !locked(f)) {
|
|
<p class="addrow"><button type="button" class="btn" (click)="addExpense()">+ Añadir gasto</button></p>
|
|
}
|
|
</div>
|
|
}
|
|
@case ('contact') {
|
|
<sbo-select-field
|
|
[label]="f.label" [dbName]="f.key"
|
|
[readonly]="readOnly() || locked(f)"
|
|
[options]="contactOptions()"
|
|
placeholder=""
|
|
[value]="str(header()[f.key]) || null"
|
|
(valueChange)="setHeader(f.key, $event === null || $event === '' ? '' : +$event)"
|
|
/>
|
|
}
|
|
@case ('address') {
|
|
<sbo-select-field
|
|
[label]="f.label" [dbName]="f.key"
|
|
[readonly]="readOnly() || locked(f)"
|
|
[options]="f.side === 'ship' ? shipOptions() : billOptions()"
|
|
placeholder=""
|
|
[value]="str(header()[f.key]) || null"
|
|
(valueChange)="setHeader(f.key, $event ?? '')"
|
|
/>
|
|
<sbo-field label="">
|
|
<sbo-textarea [rows]="3" readonly ariaLabel="Texto de la dirección" [value]="addressText(f)" />
|
|
@if (!readOnly() && !locked(f)) {
|
|
<button type="button" class="sbo-btn" [attr.aria-label]="'Corregir la ' + f.label.toLowerCase()" title="Corregir la dirección de este documento" (click)="addressDialog.set(f)">…</button>
|
|
}
|
|
</sbo-field>
|
|
}
|
|
@case ('currency') {
|
|
<sbo-field [label]="f.label" [dbName]="f.key">
|
|
<sbo-select
|
|
width="170px"
|
|
ariaLabel="Moneda del documento"
|
|
[options]="currencyOptions()"
|
|
[readonly]="readOnly() || locked(f)"
|
|
[value]="currencyValue()"
|
|
(valueChange)="onCurrency('' + ($event ?? ''))"
|
|
/>
|
|
<sbo-number
|
|
ariaLabel="Tipo de cambio"
|
|
[decimals]="6"
|
|
[readonly]="readOnly() || locked(f) || isLocalCurrency()"
|
|
[value]="isLocalCurrency() ? null : +str(header()['DocRate'])"
|
|
(valueChange)="setHeader('DocRate', $event ?? '')"
|
|
/>
|
|
</sbo-field>
|
|
}
|
|
@case ('rounding') {
|
|
@if (roundingEnabled()) {
|
|
<sbo-field [label]="f.label" [dbName]="f.key">
|
|
<sbo-checkbox
|
|
ariaLabel="Redondear el total del documento"
|
|
[readonly]="readOnly() || locked(f)"
|
|
[value]="header()['Rounding'] === 'tYES'"
|
|
(valueChange)="setHeader('Rounding', $event ? 'tYES' : 'tNO')"
|
|
/>
|
|
<sbo-number
|
|
ariaLabel="Importe del redondeo"
|
|
[decimals]="2"
|
|
[readonly]="readOnly() || locked(f) || header()['Rounding'] !== 'tYES'"
|
|
[value]="+str(header()['RoundingDiffAmount'])"
|
|
(valueChange)="setHeader('RoundingDiffAmount', $event ?? 0)"
|
|
/>
|
|
</sbo-field>
|
|
}
|
|
}
|
|
@case ('computed') {
|
|
<sbo-text-field [label]="f.label" [dbName]="f.key" readonly [value]="computedValue(f.source)" />
|
|
}
|
|
@default {
|
|
<sbo-text-field
|
|
[label]="f.label" [dbName]="f.key"
|
|
[readonly]="readOnly() || !!f.readonly || locked(f)"
|
|
[value]="str(header()[f.key])"
|
|
(valueChange)="setHeader(f.key, $event)"
|
|
/>
|
|
}
|
|
}
|
|
</ng-template>
|
|
|
|
<ng-template #linesBlock>
|
|
@if (pendingType(); as type) {
|
|
<p class="ask" role="alert">
|
|
Cambiar el tipo a «{{ pendingTypeLabel() }}» descarta {{ lineCount() === 1 ? 'la línea escrita' : 'las ' + lineCount() + ' líneas escritas' }}.
|
|
<button type="button" class="btn main" (click)="applyDocType(type)">Sí, cambiar</button>
|
|
<button type="button" class="btn" (click)="pendingType.set(null)">No, dejar como está</button>
|
|
</p>
|
|
}
|
|
<sbo-lines-grid
|
|
[columns]="columns()"
|
|
[lines]="lines()"
|
|
(linesChange)="setLines($event)"
|
|
(notice)="notify($event)"
|
|
[readonly]="readOnly()"
|
|
[newLine]="newLine"
|
|
[recalc]="recalc()"
|
|
[multiAdd]="serviceMode() ? undefined : multi"
|
|
[details]="serviceMode() ? [] : (layout.details ?? [])"
|
|
[detailHint]="detailHint"
|
|
/>
|
|
</ng-template>
|