Compare commits
6
Commits
cd748bb4ef
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e343a18da1 | ||
|
|
29dcc8ccef | ||
|
|
7efdcce113 | ||
|
|
b6c553fed3 | ||
|
|
691aa454ca | ||
|
|
67a80e18db |
No files matched your search
@@ -48,10 +48,11 @@ Pasos de la UI (decididos):
|
|||||||
para cerrarla a mano).
|
para cerrarla a mano).
|
||||||
- **Crear devoluciones**: resultado **parcial por documento**. Cada Devolución se crea aparte; las
|
- **Crear devoluciones**: resultado **parcial por documento**. Cada Devolución se crea aparte; las
|
||||||
buenas graban `U_TargetType`/`U_TargetEntry`, las fallidas `U_ErrCode`/`U_ErrMsg` y se reintentan.
|
buenas graban `U_TargetType`/`U_TargetEntry`, las fallidas `U_ErrCode`/`U_ErrMsg` y se reintentan.
|
||||||
- **El "stock" que se muestra y valida es la Consignación**, no `OITW.OnHand`: `DP_Stock` (v2) suma
|
- **El "stock" que se muestra y valida es la Consignación**, no `OITW.OnHand`: `DP_Stock` (v3) suma
|
||||||
`PDN1.OpenInvQty` de las líneas abiertas de Entradas con `U_DOT_TipoRecepcion = 'C'` del almacén, o sea lo
|
`PDN1.OpenInvQty` de las líneas abiertas de Entradas con `U_DOT_TipoRecepcion = 'C'` del almacén, o sea lo
|
||||||
mismo que consume el FIFO y lo único que se puede devolver. Si el artículo existe sin consignación devuelve 0
|
mismo que consume el FIFO y lo único que se puede devolver. Sin consignación no hay fila: entonces `DP_Articulo`
|
||||||
(queda "Sin stock"); si no existe, error. La columna se sigue llamando `OnHand` en la consulta, el modelo y
|
distingue artículo existente (0, queda "Sin stock") de inexistente (error). **El analizador SQL del Service Layer
|
||||||
|
no admite `COALESCE` ni subconsultas** (error `Cannot support this function or expression`): solo JOIN + GROUP BY. La columna se sigue llamando `OnHand` en la consulta, el modelo y
|
||||||
el UDO (`U_OnHand`); en pantalla y en Excel el encabezado es **Consignación**. Las planificaciones guardadas
|
el UDO (`U_OnHand`); en pantalla y en Excel el encabezado es **Consignación**. Las planificaciones guardadas
|
||||||
antes de la 2.0.0 conservan el valor viejo hasta rehacer el FIFO.
|
antes de la 2.0.0 conservan el valor viejo hasta rehacer el FIFO.
|
||||||
- **Consultas SQL** por `SQLQueries` del Service Layer (no hay conexión directa a la BD). La API
|
- **Consultas SQL** por `SQLQueries` del Service Layer (no hay conexión directa a la BD). La API
|
||||||
@@ -91,6 +92,11 @@ Pasos de la UI (decididos):
|
|||||||
`npm run publicar`, que deja `app/version.json` (número, fecha y commit). La API lo lee al arrancar
|
`npm run publicar`, que deja `app/version.json` (número, fecha y commit). La API lo lee al arrancar
|
||||||
(`src/version.ts`), lo informa en `/auth/info` y `/auth/me`, y la web lo muestra en el login y en la barra
|
(`src/version.ts`), lo informa en `/auth/info` y `/auth/me`, y la web lo muestra en el login y en la barra
|
||||||
superior (en desarrollo dice "desarrollo").
|
superior (en desarrollo dice "desarrollo").
|
||||||
|
- **Repositorio**: Gitea, remoto `origin` = `https://unasgeorge.vaquita-hadar.ts.net/george/devolucion_proveedores.git`
|
||||||
|
(rama `main`; reemplaza al anterior `http://100.68.242.27:30000/...`). Cada release lleva un **tag SemVer
|
||||||
|
anotado `vX.Y.Z`** igual al `version` del `package.json` (`git tag -a vX.Y.Z` + `git push origin main --tags`),
|
||||||
|
hecho **antes** de `npm run publicar` para que `version.json` lleve el commit correcto. El primero es
|
||||||
|
`v2.0.1`. El procedimiento para el usuario está en `README.md` ("Generar un release").
|
||||||
- **Logs**: la aplicación **no escribe logs a archivo**; usa el `Logger` de Nest por consola. En
|
- **Logs**: la aplicación **no escribe logs a archivo**; usa el `Logger` de Nest por consola. En
|
||||||
producción NSSM captura la salida y la rota a los 10 MB (no limita cuántos archivos conserva: hay que
|
producción NSSM captura la salida y la rota a los 10 MB (no limita cuántos archivos conserva: hay que
|
||||||
limpiar los viejos). Con `NO_COLOR=1` el log sale sin códigos de
|
limpiar los viejos). Con `NO_COLOR=1` el log sale sin códigos de
|
||||||
@@ -245,6 +251,8 @@ Reglas:
|
|||||||
## Estado al 2026-10-13
|
## Estado al 2026-10-13
|
||||||
|
|
||||||
**Hecho y verificado contra el Service Layer real (SBOLibros, MSSQL):**
|
**Hecho y verificado contra el Service Layer real (SBOLibros, MSSQL):**
|
||||||
|
- **Validación contra Consignación** (2026-10-19, 2.0.1): `DP_Stock` v3 (`SUM` + `GROUP BY`) y `DP_Articulo` funcionan
|
||||||
|
contra el Service Layer real (confirmado por el usuario; la variante probada fue HANA, la de la v2 rechazada).
|
||||||
- Login, Metadatos y **Reconstruir** (creación de tablas, campos y UDO desde cero).
|
- Login, Metadatos y **Reconstruir** (creación de tablas, campos y UDO desde cero).
|
||||||
- `libs/shared`: modelos y dominio portado del .NET. 14 tests.
|
- `libs/shared`: modelos y dominio portado del .NET. 14 tests.
|
||||||
- `apps/api`: Service Layer, autenticación, metadatos, catálogos, planificaciones y PDF. 81 tests
|
- `apps/api`: Service Layer, autenticación, metadatos, catálogos, planificaciones y PDF. 81 tests
|
||||||
@@ -278,8 +286,6 @@ Reglas:
|
|||||||
devuelve siempre un JSON (`{abierta: null}`).
|
devuelve siempre un JSON (`{abierta: null}`).
|
||||||
|
|
||||||
**Sin verificar:**
|
**Sin verificar:**
|
||||||
- **`DP_Stock` v2** (2026-10-19, versión 2.0.0): suma de Consignación, solo con tests; no se ha ejecutado contra el
|
|
||||||
Service Layer (ni HANA ni MSSQL). Probar con un pegado real y comparar con la suma de `OpenInvQty`.
|
|
||||||
- **HANA**: el usuario confirmó (2026-10-13) que las consultas `DP_Stock` y `DP_EntradasAbiertas`
|
- **HANA**: el usuario confirmó (2026-10-13) que las consultas `DP_Stock` y `DP_EntradasAbiertas`
|
||||||
(con `PDN1.OpenInvQty`, filtro por almacén y parámetros con nombre) **funcionan en HANA** a través del
|
(con `PDN1.OpenInvQty`, filtro por almacén y parámetros con nombre) **funcionan en HANA** a través del
|
||||||
Service Layer. Falta confirmar en HANA el paginado (`$inlinecount`/`odata.count` es de `/b1s/v1`; en
|
Service Layer. Falta confirmar en HANA el paginado (`$inlinecount`/`odata.count` es de `/b1s/v1`; en
|
||||||
@@ -300,11 +306,6 @@ Reglas:
|
|||||||
la cookie de sesión en un navegador real sobre HTTPS.
|
la cookie de sesión en un navegador real sobre HTTPS.
|
||||||
- **`OpenInvQty`** (2026-10-13): la consulta `DP_EntradasAbiertas` v3 todavía no se ha ejecutado contra el
|
- **`OpenInvQty`** (2026-10-13): la consulta `DP_EntradasAbiertas` v3 todavía no se ha ejecutado contra el
|
||||||
Service Layer de HANA. Se prueba con *Rehacer FIFO* de la planificación 7 de `SBOTSTLIBROS`.
|
Service Layer de HANA. Se prueba con *Rehacer FIFO* de la planificación 7 de `SBOTSTLIBROS`.
|
||||||
- **Versión del release** (2026-10-15): release **1.1.0** generado en el servidor Windows de pruebas (Excel,
|
|
||||||
valores por defecto de la cabecera, versión visible). Lleva "(sin git)": **git no está instalado en ese
|
|
||||||
servidor**, aunque la carpeta es un repositorio con commits y remoto `origin`
|
|
||||||
(`http://100.68.242.27:30000/george/devolucion_proveedores.git`). Los cambios del 2026-10-15 **no están en
|
|
||||||
ningún commit**: hacerlo (y `push`) cuando haya git, antes de seguir trabajando desde el Mac.
|
|
||||||
- **Estilos:** son CSS porque, en el Mac con macOS 12, el compilador nativo de Sass exige
|
- **Estilos:** son CSS porque, en el Mac con macOS 12, el compilador nativo de Sass exige
|
||||||
macOS 14 o superior. En Sequoia se puede volver a SCSS si se prefiere.
|
macOS 14 o superior. En Sequoia se puede volver a SCSS si se prefiere.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
# Devolución a Proveedores
|
||||||
|
|
||||||
|
Aplicación web (Angular + NestJS) para SAP Business One que genera **Devoluciones de mercancías**
|
||||||
|
(ORPD) enlazadas a sus **Entradas de mercancías por compra** (OPDN), a partir de un listado de
|
||||||
|
artículos y cantidades pegado desde Excel. Reemplaza al addon .NET anterior.
|
||||||
|
|
||||||
|
## Cómo funciona
|
||||||
|
|
||||||
|
1. **Pegar**: ItemCode + cantidad desde Excel. Se valida contra la **Consignación** del almacén elegido.
|
||||||
|
2. **Procesar**: asignación FIFO contra las líneas abiertas de Entradas de mercancías del almacén,
|
||||||
|
ordenadas por fecha. El usuario marca qué líneas devolver.
|
||||||
|
3. **Crear devoluciones**: agrupa las líneas marcadas por proveedor y crea una Devolución por lote
|
||||||
|
(11 líneas por defecto).
|
||||||
|
4. **Descargar PDF**: pide al web service de BES el PDF de la Guía de despacho (DTE 52) de cada
|
||||||
|
Devolución, con opción de unirlos en uno.
|
||||||
|
|
||||||
|
Cada ejecución (planificación) se guarda en el UDO `LIB_ODEV`. Solo puede haber una planificación
|
||||||
|
abierta a la vez; se cierra a mano.
|
||||||
|
|
||||||
|
## Requisitos
|
||||||
|
|
||||||
|
- Node.js 22 LTS o superior.
|
||||||
|
- SAP Business One con **Service Layer** (`/b1s/v1`), base **HANA** (producción) o **MSSQL** (pruebas).
|
||||||
|
- El usuario de SAP inicia sesión en la web; sus credenciales no se guardan en la configuración.
|
||||||
|
|
||||||
|
## Estructura
|
||||||
|
|
||||||
|
```
|
||||||
|
libs/shared/ @dp/shared tipos y lógica de dominio (parseo de Excel, FIFO)
|
||||||
|
apps/api/ NestJS API REST (/api) sobre el Service Layer; en producción sirve también la web
|
||||||
|
apps/web/ Angular interfaz
|
||||||
|
scripts/ publicar.mjs arma la carpeta de despliegue en release/
|
||||||
|
deploy/windows/ instalación como servicio de Windows (NSSM)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Puesta en marcha (desarrollo)
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install
|
||||||
|
cp apps/api/.env.example apps/api/.env # completar SL_URL, SL_COMPANY_DB y DB_TYPE
|
||||||
|
npm run dev:api # API NestJS (puerto PORT del .env)
|
||||||
|
npm run dev:web # Angular en http://localhost:4215 (proxy /api → API)
|
||||||
|
```
|
||||||
|
|
||||||
|
Variables principales del `.env`: `PORT`, `SL_URL`, `SL_COMPANY_DB`, `SL_REJECT_UNAUTHORIZED`,
|
||||||
|
`DB_TYPE` (`HANA`/`MSSQL`) y `COOKIE_SECURE`. Para producción con HTTPS: `HTTPS_PFX_PATH` y
|
||||||
|
`HTTPS_PFX_PASSPHRASE` (o `HTTPS_KEY_PATH`/`HTTPS_CERT_PATH`) y `HTTP_REDIRECT_PORT`.
|
||||||
|
Ver `apps/api/.env.example`.
|
||||||
|
|
||||||
|
En el primer ingreso, **Configuración → Metadatos → Reconstruir** crea las tablas, los campos y
|
||||||
|
el UDO necesarios en SAP.
|
||||||
|
|
||||||
|
## Pruebas y compilación
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm test # shared + api + web
|
||||||
|
npm run test:e2e -w api
|
||||||
|
npm run lint -w api
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Generar un release
|
||||||
|
|
||||||
|
La versión es el `version` del `package.json` raíz y sigue SemVer (`MAYOR.MENOR.PARCHE`). Cada
|
||||||
|
release sube la versión y lleva un tag `vX.Y.Z` en git.
|
||||||
|
|
||||||
|
1. **Subir la versión** (elegir uno; no crea commit ni tag):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run version:parche # 2.0.1 → 2.0.2 correcciones
|
||||||
|
npm run version:menor # 2.0.1 → 2.1.0 funciones nuevas compatibles
|
||||||
|
npm run version:mayor # 2.0.1 → 3.0.0 cambios incompatibles
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Commit y tag**:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git add -A
|
||||||
|
git commit -m "Versión X.Y.Z"
|
||||||
|
git tag -a vX.Y.Z -m "Versión X.Y.Z"
|
||||||
|
git push origin main --tags
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Armar la carpeta de despliegue** (después del commit, para que el release lleve el commit
|
||||||
|
correcto):
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm run publicar # compila shared + api + web y arma la carpeta
|
||||||
|
npm run publicar -- --sin-build # reutiliza los builds ya hechos (más rápido)
|
||||||
|
```
|
||||||
|
|
||||||
|
El resultado queda en `release/devolucion-proveedores/` (ignorada por git): la API compilada,
|
||||||
|
la web compilada, solo las dependencias de producción y los scripts de instalación. Incluye
|
||||||
|
`app/version.json` con el número, la fecha y el commit (si hay cambios sin commit, el commit
|
||||||
|
aparece con `-modificado`). La versión se muestra en el login y en la barra superior.
|
||||||
|
|
||||||
|
4. **Instalar o actualizar en el servidor**: copiar esa carpeta al servidor Windows. Se instala
|
||||||
|
como un único servicio (NSSM) con HTTPS directo en Node. Instalación nueva: secciones 1 a 8 de
|
||||||
|
[`deploy/windows/DEPLOY.md`](deploy/windows/DEPLOY.md); actualizar una instalación existente
|
||||||
|
sin tocar el `.env`: sección 11.
|
||||||
@@ -22,7 +22,7 @@ const filaHijo = (extra: Record<string, unknown> = {}) => ({ LineId: 2, U_LineTy
|
|||||||
|
|
||||||
const dto = (texto = 'A1\t5'): ProcesarDto => ({ whsCode: '01', docDate: '2026-10-13', texto }) as ProcesarDto;
|
const dto = (texto = 'A1\t5'): ProcesarDto => ({ whsCode: '01', docDate: '2026-10-13', texto }) as ProcesarDto;
|
||||||
|
|
||||||
function crear(anterior: ReturnType<typeof udo>, opciones: { stock?: unknown[]; fallaCierre?: boolean } = {}) {
|
function crear(anterior: ReturnType<typeof udo>, opciones: { stock?: unknown[]; articulo?: unknown[]; fallaCierre?: boolean } = {}) {
|
||||||
const llamadas: string[] = [];
|
const llamadas: string[] = [];
|
||||||
const sl = {
|
const sl = {
|
||||||
get: vi.fn(async (_s: unknown, path: string): Promise<unknown> => {
|
get: vi.fn(async (_s: unknown, path: string): Promise<unknown> => {
|
||||||
@@ -42,6 +42,7 @@ function crear(anterior: ReturnType<typeof udo>, opciones: { stock?: unknown[];
|
|||||||
const sql = {
|
const sql = {
|
||||||
consultar: vi.fn(async (_s: unknown, consulta: { codigo: string }) => {
|
consultar: vi.fn(async (_s: unknown, consulta: { codigo: string }) => {
|
||||||
if (consulta.codigo === 'DP_Stock') return opciones.stock ?? [{ ItemCode: 'A1', ItemName: 'Libro', OnHand: 100 }];
|
if (consulta.codigo === 'DP_Stock') return opciones.stock ?? [{ ItemCode: 'A1', ItemName: 'Libro', OnHand: 100 }];
|
||||||
|
if (consulta.codigo === 'DP_Articulo') return opciones.articulo ?? [];
|
||||||
return [{ DocNum: 101, CardCode: 'P1', CardName: 'Prov', DocDate: '2026-01-31T00:00:00Z', DocEntry: 15, LineNum: 0, OpenInvQty: 10 }];
|
return [{ DocNum: 101, CardCode: 'P1', CardName: 'Prov', DocDate: '2026-01-31T00:00:00Z', DocEntry: 15, LineNum: 0, OpenInvQty: 10 }];
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
@@ -166,3 +167,18 @@ describe('PlanificacionesService.listar', () => {
|
|||||||
expect((sl.request.mock.calls[0] as unknown as [unknown, string, string])[2]).toContain('$top=100');
|
expect((sl.request.mock.calls[0] as unknown as [unknown, string, string])[2]).toContain('$top=100');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('PlanificacionesService.validarPegado', () => {
|
||||||
|
it('un artículo que existe pero no tiene consignación abierta queda con 0 (Sin stock)', async () => {
|
||||||
|
const { servicio } = crear(udo(3, 'O'), { stock: [], articulo: [{ ItemCode: 'A1', ItemName: 'Libro' }] });
|
||||||
|
const r = await servicio.validarPegado(sesion, 'B1', 'A1\t5');
|
||||||
|
expect(r.errores).toEqual([]);
|
||||||
|
expect(r.lineas[0]).toMatchObject({ itemCode: 'A1', onHand: 0, status: 'SIN_STOCK' });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('un artículo inexistente es un error', async () => {
|
||||||
|
const { servicio } = crear(udo(3, 'O'), { stock: [], articulo: [] });
|
||||||
|
const r = await servicio.validarPegado(sesion, 'B1', 'X9\t5');
|
||||||
|
expect(r.errores[0]).toMatch(/no existe/);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -29,7 +29,7 @@ import {
|
|||||||
import { CatalogosService } from '../catalogos/catalogos.service.js';
|
import { CatalogosService } from '../catalogos/catalogos.service.js';
|
||||||
import { ServiceLayerClient, ServiceLayerException } from '../service-layer/service-layer.client.js';
|
import { ServiceLayerClient, ServiceLayerException } from '../service-layer/service-layer.client.js';
|
||||||
import type { SapSession } from '../service-layer/session.store.js';
|
import type { SapSession } from '../service-layer/session.store.js';
|
||||||
import { CONSULTA_ENTRADAS_ABIERTAS, CONSULTA_STOCK } from '../sql-queries/sql-queries.definitions.js';
|
import { CONSULTA_ARTICULO, CONSULTA_ENTRADAS_ABIERTAS, CONSULTA_STOCK } from '../sql-queries/sql-queries.definitions.js';
|
||||||
import { SqlQueriesService } from '../sql-queries/sql-queries.service.js';
|
import { SqlQueriesService } from '../sql-queries/sql-queries.service.js';
|
||||||
import type { ProcesarDto } from './dto/planificaciones.dto.js';
|
import type { ProcesarDto } from './dto/planificaciones.dto.js';
|
||||||
import { cabeceraAUdo, lineaAUdo, planificacionDesdeUdo } from './udo.mapper.js';
|
import { cabeceraAUdo, lineaAUdo, planificacionDesdeUdo } from './udo.mapper.js';
|
||||||
@@ -38,7 +38,8 @@ import type { UdoSl } from './udo.mapper.js';
|
|||||||
interface FilaStock {
|
interface FilaStock {
|
||||||
ItemCode: string;
|
ItemCode: string;
|
||||||
ItemName: string | null;
|
ItemName: string | null;
|
||||||
OnHand: number | string;
|
/** Ausente cuando la fila viene de DP_Articulo (sin consignación). */
|
||||||
|
OnHand?: number | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FilaEntrada {
|
interface FilaEntrada {
|
||||||
@@ -100,21 +101,24 @@ export class PlanificacionesService {
|
|||||||
const { filas, errores } = parsearPortapapeles(texto);
|
const { filas, errores } = parsearPortapapeles(texto);
|
||||||
const lineas = [];
|
const lineas = [];
|
||||||
|
|
||||||
const consultas = await enLotes(filas, CONCURRENCIA_CONSULTAS, async (fila) => ({
|
const consultas = await enLotes(filas, CONCURRENCIA_CONSULTAS, async (fila) => {
|
||||||
fila,
|
const params = { whs: whsCode, item: fila.itemCode };
|
||||||
stock: (await this.sql.consultar<FilaStock>(sesion, CONSULTA_STOCK, { whs: whsCode, item: fila.itemCode }))[0],
|
const stock = (await this.sql.consultar<FilaStock>(sesion, CONSULTA_STOCK, params))[0];
|
||||||
}));
|
// Sin consignación abierta no hay fila: el artículo puede existir con 0 o no existir.
|
||||||
|
const articulo = stock ?? (await this.sql.consultar<FilaStock>(sesion, CONSULTA_ARTICULO, { item: fila.itemCode }))[0];
|
||||||
|
return { fila, articulo };
|
||||||
|
});
|
||||||
|
|
||||||
for (const { fila, stock } of consultas) {
|
for (const { fila, articulo: datos } of consultas) {
|
||||||
if (!stock) {
|
if (!datos) {
|
||||||
errores.push(`${fila.itemCode}: el artículo no existe.`);
|
errores.push(`${fila.itemCode}: el artículo no existe.`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const articulo: ArticuloADevolver = {
|
const articulo: ArticuloADevolver = {
|
||||||
itemCode: stock.ItemCode,
|
itemCode: datos.ItemCode,
|
||||||
itemName: stock.ItemName ?? '',
|
itemName: datos.ItemName ?? '',
|
||||||
quantity: fila.quantity,
|
quantity: fila.quantity,
|
||||||
onHand: Math.floor(Number(stock.OnHand)),
|
onHand: Math.floor(Number(datos.OnHand ?? 0)),
|
||||||
};
|
};
|
||||||
lineas.push(crearLineaPadre(articulo));
|
lineas.push(crearLineaPadre(articulo));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,24 +19,35 @@ export interface ConsultaGuardada {
|
|||||||
* "Stock" = lo que realmente se puede devolver: la suma de PDN1.OpenInvQty de las líneas abiertas de
|
* "Stock" = lo que realmente se puede devolver: la suma de PDN1.OpenInvQty de las líneas abiertas de
|
||||||
* Entradas de mercancías de Consignación (U_DOT_TipoRecepcion = 'C') del almacén, las mismas que usa el
|
* Entradas de mercancías de Consignación (U_DOT_TipoRecepcion = 'C') del almacén, las mismas que usa el
|
||||||
* FIFO. No es OITW.OnHand: el stock físico incluye mercancía que no es devolvible por esta vía.
|
* FIFO. No es OITW.OnHand: el stock físico incluye mercancía que no es devolvible por esta vía.
|
||||||
* Devuelve fila (con 0) si el artículo existe pero no tiene consignación; ninguna si no existe.
|
* Sin filas si el artículo no tiene consignación abierta (el servicio lo distingue con DP_Articulo).
|
||||||
* La columna se sigue llamando OnHand porque así se guarda en el UDO (U_OnHand).
|
* El analizador del Service Layer no admite COALESCE ni subconsultas: por eso solo JOIN + GROUP BY.
|
||||||
|
* La columna se llama OnHand porque así se guarda en el UDO (U_OnHand).
|
||||||
*/
|
*/
|
||||||
export const CONSULTA_STOCK: ConsultaGuardada = {
|
export const CONSULTA_STOCK: ConsultaGuardada = {
|
||||||
codigo: 'DP_Stock',
|
codigo: 'DP_Stock',
|
||||||
version: 2,
|
version: 3,
|
||||||
mssql:
|
mssql:
|
||||||
'SELECT T0.[ItemCode], T0.[ItemName], ' +
|
'SELECT T2.[ItemCode], T0.[ItemName], SUM(T2.[OpenInvQty]) AS [OnHand] ' +
|
||||||
'COALESCE((SELECT SUM(T2.[OpenInvQty]) FROM OPDN T1 INNER JOIN PDN1 T2 ON T2.[DocEntry] = T1.[DocEntry] ' +
|
'FROM OPDN T1 INNER JOIN PDN1 T2 ON T2.[DocEntry] = T1.[DocEntry] ' +
|
||||||
|
'INNER JOIN OITM T0 ON T0.[ItemCode] = T2.[ItemCode] ' +
|
||||||
"WHERE T1.[U_DOT_TipoRecepcion] = 'C' AND T2.[LineStatus] = 'O' " +
|
"WHERE T1.[U_DOT_TipoRecepcion] = 'C' AND T2.[LineStatus] = 'O' " +
|
||||||
'AND T2.[ItemCode] = T0.[ItemCode] AND T2.[WhsCode] = :whs), 0) AS [OnHand] ' +
|
'AND T2.[ItemCode] = :item AND T2.[WhsCode] = :whs ' +
|
||||||
'FROM OITM T0 WHERE T0.[ItemCode] = :item',
|
'GROUP BY T2.[ItemCode], T0.[ItemName]',
|
||||||
hana:
|
hana:
|
||||||
'SELECT T0."ItemCode", T0."ItemName", ' +
|
'SELECT T2."ItemCode", T0."ItemName", SUM(T2."OpenInvQty") AS "OnHand" ' +
|
||||||
'COALESCE((SELECT SUM(T2."OpenInvQty") FROM OPDN T1 INNER JOIN PDN1 T2 ON T2."DocEntry" = T1."DocEntry" ' +
|
'FROM OPDN T1 INNER JOIN PDN1 T2 ON T2."DocEntry" = T1."DocEntry" ' +
|
||||||
|
'INNER JOIN OITM T0 ON T0."ItemCode" = T2."ItemCode" ' +
|
||||||
"WHERE T1.\"U_DOT_TipoRecepcion\" = 'C' AND T2.\"LineStatus\" = 'O' " +
|
"WHERE T1.\"U_DOT_TipoRecepcion\" = 'C' AND T2.\"LineStatus\" = 'O' " +
|
||||||
'AND T2."ItemCode" = T0."ItemCode" AND T2."WhsCode" = :whs), 0) AS "OnHand" ' +
|
'AND T2."ItemCode" = :item AND T2."WhsCode" = :whs ' +
|
||||||
'FROM OITM T0 WHERE T0."ItemCode" = :item',
|
'GROUP BY T2."ItemCode", T0."ItemName"',
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Solo para saber si el artículo existe (y su nombre) cuando DP_Stock no devuelve filas. */
|
||||||
|
export const CONSULTA_ARTICULO: ConsultaGuardada = {
|
||||||
|
codigo: 'DP_Articulo',
|
||||||
|
version: 1,
|
||||||
|
mssql: 'SELECT T0.[ItemCode], T0.[ItemName] FROM OITM T0 WHERE T0.[ItemCode] = :item',
|
||||||
|
hana: 'SELECT T0."ItemCode", T0."ItemName" FROM OITM T0 WHERE T0."ItemCode" = :item',
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "devolucion-proveedores-web",
|
"name": "devolucion-proveedores-web",
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "devolucion-proveedores-web",
|
"name": "devolucion-proveedores-web",
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"libs/*",
|
"libs/*",
|
||||||
"apps/*"
|
"apps/*"
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "devolucion-proveedores-web",
|
"name": "devolucion-proveedores-web",
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"libs/*",
|
"libs/*",
|
||||||
|
|||||||
Reference in new issue
Block a user