2026-10-14 16:09:06 -05:00
< sbo-toolbar bleed aria-label = "Acciones del documento" >
2026-10-13 22:00:54 -05:00
< 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-toolbar >
< sbo-window [ title ]=" windowTitle ()" [ badge ]=" badge ()" [ status ]=" status ()" >
2026-10-14 15:10:40 -05:00
< div class = "sbo-hdr" >
< div class = "sbo-col" >
@for (f of layout.header.left; track $index) {
< ng-container * ngTemplateOutlet = "field; context: { $implicit: f }" />
}
2026-10-13 22:00:54 -05:00
</ div >
2026-10-14 15:10:40 -05:00
< div class = "sbo-col" >
@for (f of layout.header.right; track $index) {
< ng-container * ngTemplateOutlet = "field; context: { $implicit: f }" />
}
2026-10-13 22:00:54 -05:00
</ div >
2026-10-14 15:10:40 -05:00
</ div >
2026-10-19 12:19:18 -05:00
@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 >
}
2026-10-14 15:10:40 -05:00
< sbo-lines-grid
2026-10-19 12:19:18 -05:00
[ columns ]=" columns ()"
2026-10-14 15:10:40 -05:00
[ lines ]=" lines ()"
( linesChange )=" setLines ($ event )"
( notice )=" notify ($ event )"
[ readonly ]=" readOnly ()"
[ newLine ]=" newLine "
2026-10-19 12:19:18 -05:00
[ recalc ]=" recalc ()"
[ multiAdd ]=" serviceMode () ? undefined : multi "
[ details ]=" serviceMode () ? [] : ( layout . details ?? [])"
2026-10-16 12:25:01 -05:00
[ detailHint ]=" detailHint "
2026-10-14 15:10:40 -05:00
/>
< 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 }" />
}
2026-10-14 14:37:01 -05:00
</ div >
2026-10-14 15:10:40 -05:00
< div class = "sbo-col" >
@for (f of layout.footer.right; track $index) {
< ng-container * ngTemplateOutlet = "field; context: { $implicit: f }" />
}
2026-10-14 14:37:01 -05:00
</ div >
2026-10-14 15:10:40 -05:00
</ div >
2026-10-13 22:00:54 -05:00
2026-10-14 15:10:40 -05:00
@if (!readOnly()) {
2026-10-13 22:00:54 -05:00
< 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 >
2026-10-16 12:20:26 -05:00
@if (copyFromItems().length) {
2026-10-14 11:59:07 -05:00
< sbo-menu-button sboActionsEnd label = "Copiar de" [ items ]=" copyFromItems ()" ( picked )=" copyFrom ($ event )" />
}
2026-10-16 12:20:26 -05:00
@if (copyToItems().length) {
2026-10-14 11:59:07 -05:00
< sbo-menu-button sboActionsEnd label = "Copiar a" [ items ]=" copyToItems ()" ( picked )=" copyTo ($ event )" />
}
2026-10-13 22:00:54 -05:00
</ sbo-window >
2026-10-14 11:59:07 -05:00
2026-10-19 14:35:54 -05:00
@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 )"
/>
}
}
2026-10-14 11:59:07 -05:00
@if (copyListScreen(); as src) {
< sbo-value-help
[ open ]=" true "
2026-10-14 12:00:58 -05:00
[ title ]="' Copiar de: ' + copyListTitle ()"
2026-10-14 11:59:07 -05:00
[ resource ]=" src . resource "
[ columns ]=" copyListColumns "
[ baseFilter ]=" copyListFilter ()"
orderby = "DocEntry desc"
rowKey = "DocEntry"
( selected )=" copyPicked ($ event )"
( closed )=" copyListFor . set ( null )"
/>
}
2026-10-14 14:37:01 -05:00
< ng-template # field let-f >
@switch (f.type) {
2026-10-14 15:10:40 -05:00
@case ('partner') {
< sbo-lookup-field
2026-10-14 14:37:01 -05:00
[ label ]=" f . label "
[ required ]="!! f . required "
2026-10-16 11:14:52 -05:00
[ readonly ]=" readOnly () || ! isNew () || locked ( f )"
2026-10-14 14:37:01 -05:00
[ value ]=" str ( header ()[ f . key ])"
2026-10-14 15:10:40 -05:00
( valueChange )=" onPartnerText ($ event )"
[ lookup ]=" partnerLookup "
resolveOnLeave
( picked )=" onPartner ($ event )"
2026-10-14 14:37:01 -05:00
/>
}
2026-10-16 11:18:03 -05:00
@case ('checkbox') {
< sbo-checkbox-field
[ label ]=" f . label "
[ readonly ]=" readOnly () || !! f . readonly || locked ( f )"
[ value ]=" header ()[ f . key ] === ' tYES '"
( valueChange )=" setHeader ( f . key , $ event ? ' tYES ' : ' tNO ')"
/>
}
2026-10-16 11:09:47 -05:00
@case ('lookup') {
< sbo-lookup-field
[ label ]=" f . label "
[ required ]="!! f . required "
2026-10-16 11:14:52 -05:00
[ readonly ]=" readOnly () || locked ( f )"
2026-10-16 11:09:47 -05:00
[ value ]=" str ( header ()[ f . key ])"
2026-10-19 14:47:23 -05:00
( valueChange )=" setHeader ( f . key , typedLookup ( f , $ event ))"
2026-10-16 11:09:47 -05:00
[ lookup ]=" f . lookup "
resolveOnLeave
/>
}
2026-10-14 14:37:01 -05:00
@case ('warehouse') {
< sbo-lookup-field
[ label ]=" f . label "
[ required ]="!! f . required "
2026-10-16 11:14:52 -05:00
[ readonly ]=" readOnly () || locked ( f )"
2026-10-14 14:37:01 -05:00
[ value ]=" str ( header ()[ f . key ])"
( valueChange )=" setHeader ( f . key , $ event )"
[ lookup ]=" warehouseLookup "
resolveOnLeave
/>
}
2026-10-14 15:10:40 -05:00
@case ('date') {
< sbo-date-field
[ label ]=" f . label "
[ required ]="!! f . required "
2026-10-16 11:14:52 -05:00
[ readonly ]=" readOnly () || locked ( f )"
2026-10-14 15:10:40 -05:00
[ value ]=" str ( header ()[ f . key ])"
( valueChange )=" setHeader ( f . key , $ event )"
/>
}
2026-10-14 15:28:03 -05:00
@case ('select') {
< sbo-select-field
[ label ]=" f . label "
[ required ]="!! f . required "
2026-10-16 11:14:52 -05:00
[ readonly ]=" readOnly () || locked ( f )"
2026-10-14 15:28:03 -05:00
[ options ]=" f . options "
placeholder = ""
[ value ]=" str ( header ()[ f . key ]) || null "
( valueChange )=" setHeader ( f . key , $ event ?? '')"
/>
}
2026-10-14 15:10:40 -05:00
@case ('number') {
< sbo-number-field
[ label ]=" f . label "
[ decimals ]=" f . decimals "
2026-10-16 11:14:52 -05:00
[ readonly ]=" readOnly () || locked ( f )"
2026-10-14 15:10:40 -05:00
[ value ]="+ str ( header ()[ f . key ])"
( valueChange )=" setHeader ( f . key , $ event ?? 0 )"
/>
}
@case ('textarea') {
< sbo-textarea-field
2026-10-14 14:37:01 -05:00
[ label ]=" f . label "
2026-10-16 11:14:52 -05:00
[ readonly ]=" readOnly () || locked ( f )"
2026-10-14 14:37:01 -05:00
[ value ]=" str ( header ()[ f . key ])"
( valueChange )=" setHeader ( f . key , $ event )"
/>
}
2026-10-14 15:10:40 -05:00
@case ('folio') {
< sbo-field [ label ]=" f . label " >
< sbo-input
width = "90px"
[ maxlength ]=" 10 "
2026-10-16 11:14:52 -05:00
[ readonly ]=" readOnly () || locked ( f )"
2026-10-14 15:10:40 -05:00
[ value ]=" str ( header ()[ f . prefixKey ])"
( valueChange )=" setHeader ( f . prefixKey , $ event )"
/>
< sbo-input
ariaLabel = "Número de folio"
2026-10-16 11:14:52 -05:00
[ readonly ]=" readOnly () || locked ( f )"
2026-10-14 15:10:40 -05:00
[ value ]=" str ( header ()[ f . numberKey ])"
( valueChange )=" setHeader ( f . numberKey , $ event )"
/>
</ sbo-field >
}
2026-10-19 14:35:54 -05:00
@case ('group') {
< sbo-field [ label ]=" f . label " >
@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 >
}
2026-10-16 11:07:38 -05:00
@case ('series') {
< sbo-field [ label ]=" f . label " >
< sbo-select
width = "170px"
ariaLabel = "Serie de numeración"
placeholder = "(por defecto)"
[ options ]=" seriesOptions ()"
2026-10-16 11:14:52 -05:00
[ readonly ]=" readOnly () || ! isNew () || locked ( f )"
2026-10-16 11:07:38 -05:00
[ value ]=" seriesValue ()"
( valueChange )=" setHeader ( f . key , $ event ?? '')"
/>
< sbo-input readonly ariaLabel = "Número del documento" [ value ]=" str ( doc ()?.[' DocNum '])" />
</ sbo-field >
}
2026-10-19 12:46:56 -05:00
@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."
2026-10-14 16:09:06 -05:00
/>
2026-10-19 12:46:56 -05:00
@if (!readOnly() && !locked(f)) {
< p class = "addrow" >< button type = "button" class = "btn" ( click )=" addExpense ()" > + Añadir gasto</ button ></ p >
}
</ div >
2026-10-14 16:09:06 -05:00
}
2026-10-19 14:47:23 -05:00
@case ('contact') {
< sbo-select-field
[ label ]=" f . label "
[ 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 "
[ readonly ]=" readOnly () || locked ( f )"
[ options ]=" f . side = == ' ship ' ? shipOptions () : billOptions ()"
placeholder = ""
[ value ]=" str ( header ()[ f . key ]) || null "
( valueChange )=" setHeader ( f . key , $ event ?? '')"
/>
< sbo-textarea-field label = "" [ rows ]=" 3 " readonly [ value ]=" addressText ( f )" />
}
2026-10-19 14:40:14 -05:00
@case ('currency') {
< sbo-field [ label ]=" f . label " >
< 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 >
}
2026-10-19 12:53:23 -05:00
@case ('rounding') {
@if (roundingEnabled()) {
< sbo-field [ label ]=" f . label " >
< 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 >
}
}
2026-10-14 15:10:40 -05:00
@case ('computed') {
< sbo-text-field [ label ]=" f . label " readonly [ value ]=" computedValue ( f . source )" />
}
@default {
< sbo-text-field
[ label ]=" f . label "
2026-10-16 11:14:52 -05:00
[ readonly ]=" readOnly () || !! f . readonly || locked ( f )"
2026-10-14 15:10:40 -05:00
[ value ]=" str ( header ()[ f . key ])"
( valueChange )=" setHeader ( f . key , $ event )"
/>
}
2026-10-14 14:37:01 -05:00
}
</ ng-template >