diff --git a/apps/web/src/app/features/client/lotes/lote-transfer.page.spec.ts b/apps/web/src/app/features/client/lotes/lote-transfer.page.spec.ts index 6585532..bd87799 100644 --- a/apps/web/src/app/features/client/lotes/lote-transfer.page.spec.ts +++ b/apps/web/src/app/features/client/lotes/lote-transfer.page.spec.ts @@ -43,6 +43,7 @@ describe('LoteTransferPage', () => { await tick(); // catálogos de la solicitud (campos de usuario de SAP) y series for (const alias of Object.keys(FIELDS)) ctrl.expectOne(`/api/sapdb/user-fields/OWTQ/${alias}`).flush(FIELDS[alias]); + ctrl.expectOne('/api/sl/SeriesService_GetDefaultSeries').flush({ Series: 7 }); ctrl.expectOne('/api/sl/SeriesService_GetDocumentSeries').flush({ value: [{ Series: 7, Name: 'TR-01', Locked: 'tNO' }, { Series: 8, Name: 'OLD', Locked: 'tYES' }] }); await tick(); } @@ -71,6 +72,12 @@ describe('LoteTransferPage', () => { expect(rowOf('302').textContent).toContain('Ya inmovilizado'); }); + it('deja elegida la serie por defecto de SAP', async () => { + await search('2090456'); + expect(page().form().series).toBe(7); + expect((el().querySelector('sbo-select-field select') as HTMLSelectElement).selectedOptions[0]?.textContent?.trim()).toBe('TR-01'); + }); + it('al marcar un almacén se precarga todo el stock y no se puede superar', async () => { await search('2090456'); check('201'); @@ -109,7 +116,8 @@ describe('LoteTransferPage', () => { { ItemCode: 'A1', Quantity: 2, WarehouseCode: '302', FromWarehouseCode: '202', BatchNumbers: [{ BatchNumber: '2090456', Quantity: 2 }] }, ], }); - expect(req.request.body).not.toHaveProperty('Series'); + // la serie por defecto de SAP viaja elegida + expect(req.request.body).toHaveProperty('Series', 7); req.flush({ DocEntry: 480, DocNum: 4123 }); await tick(); // vuelve a la búsqueda con el aviso de éxito diff --git a/apps/web/src/app/features/client/lotes/lote-transfer.page.ts b/apps/web/src/app/features/client/lotes/lote-transfer.page.ts index ab9bd84..313e4f2 100644 --- a/apps/web/src/app/features/client/lotes/lote-transfer.page.ts +++ b/apps/web/src/app/features/client/lotes/lote-transfer.page.ts @@ -177,7 +177,7 @@ export class LoteTransferPage { if (!rows.length) throw new Error(`No se encontró stock para el lote «${lot}»`); if (this.config.pickFrom && !rows.some((r) => r.WarehouseCode === this.fromWarehouse())) throw new Error(`El lote «${lot}» no tiene stock en el almacén ${this.fromWarehouse()}`); this.result.set({ lot, rows }); - this.form.set(initialForm(this.config, todayIso())); + this.form.set(initialForm(this.config, todayIso(), this.defaultSeries.value() ?? null)); this.message.set(null); } catch (e) { this.message.set({ kind: 'err', text: e instanceof Error && !('status' in e) ? e.message : apiErrorMessage(e) }); @@ -226,6 +226,8 @@ export class LoteTransferPage { protected readonly catalogs = resource({ loader: () => this.api.catalogs() }); protected readonly options = computed(() => this.catalogs.value() ?? { movimientoInventario: [], tipoOperacion: [], tipoDespacho: [], movimientoAlmacen: [] }); protected readonly series = resource({ loader: () => this.api.series().catch(() => []) }); + /** La serie por defecto de SAP: queda elegida al buscar el lote (se puede cambiar o dejar en blanco). */ + private readonly defaultSeries = resource({ loader: () => this.api.defaultSeries().catch(() => null) }); protected readonly problems = computed(() => { const f = this.form(); diff --git a/apps/web/src/app/features/client/lotes/lotes-flujo-api.ts b/apps/web/src/app/features/client/lotes/lotes-flujo-api.ts index 4544d09..47c21e5 100644 --- a/apps/web/src/app/features/client/lotes/lotes-flujo-api.ts +++ b/apps/web/src/app/features/client/lotes/lotes-flujo-api.ts @@ -70,6 +70,12 @@ export class LotesFlujoApi { return res.value.filter((r) => r['Locked'] !== 'tYES').map((r) => ({ value: Number(r['Series']), label: String(r['Name'] ?? r['Series']) })); } + /** La serie que SAP usa por defecto para las solicitudes de traslado, o `null` si no se pudo saber. */ + async defaultSeries(): Promise { + const res = await firstValueFrom(this.http.post<{ Series?: number }>(`${API_URL}/sl/SeriesService_GetDefaultSeries`, { DocumentTypeParams: { Document: OBJECT_TYPE } })); + return typeof res.Series === 'number' ? res.Series : null; + } + create(body: Row): Promise { return this.master.create(RESOURCE, body); } diff --git a/apps/web/src/app/features/client/lotes/lotes-flujo.spec.ts b/apps/web/src/app/features/client/lotes/lotes-flujo.spec.ts index 6a2ca50..b974a02 100644 --- a/apps/web/src/app/features/client/lotes/lotes-flujo.spec.ts +++ b/apps/web/src/app/features/client/lotes/lotes-flujo.spec.ts @@ -49,6 +49,7 @@ describe('solicitud de inmovilización', () => { it('parte de los valores por defecto del flujo', () => { expect(initialForm(cfg, '2026-10-20')).toMatchObject({ toWarehouse: '302', movimientoAlmacen: '107', movimientoInventario: 'XTD', tipoOperacion: '11', tipoDespacho: 'N', series: null }); expect(initialForm(LOT_FLOWS.liberar, '2026-10-20')).toMatchObject({ toWarehouse: '201', movimientoAlmacen: '108' }); + expect(initialForm(cfg, '2026-10-20', 7).series).toBe(7); }); it('pide motivo, comentario y acción, al menos un almacén y un destino distinto del origen', () => { diff --git a/apps/web/src/app/features/client/lotes/lotes-flujo.ts b/apps/web/src/app/features/client/lotes/lotes-flujo.ts index 6bec3fc..a38b5e3 100644 --- a/apps/web/src/app/features/client/lotes/lotes-flujo.ts +++ b/apps/web/src/app/features/client/lotes/lotes-flujo.ts @@ -77,10 +77,10 @@ export interface TransferForm { accion: string; } -/** Valores iniciales de la solicitud de un flujo. */ -export const initialForm = (config: LotFlowConfig, today: string): TransferForm => ({ +/** Valores iniciales de la solicitud de un flujo (`series`: la que SAP usa por defecto, si se conoce). */ +export const initialForm = (config: LotFlowConfig, today: string, series: number | null = null): TransferForm => ({ docDate: today, - series: null, + series, movimientoInventario: DEFAULT_MOVIMIENTO_INVENTARIO, tipoOperacion: DEFAULT_TIPO_OPERACION, tipoDespacho: DEFAULT_TIPO_DESPACHO,