6 de agosto de 2010

Cálculo de la rotación del inventario y cobertura de stock


Introducción

Continuando con el tema de stock iniciado en un post anterior, proponemos una nueva consulta para aplicar a SAP B1, para el calculo de la rotación del inventario y la cobertura del stock. A continuación definiremos los elementos utilizados en el cálculo.

Definiciones


  • Consumo (D):El consumo de unidades en un periodo de tiempo, concepto que ya definimos en nuestro post Cálculo de lote económico en SAP Business One
  • Stock promedio (Sm):Se determina calculando la media de 2 valores de stock entre dos fechas conocidas Sm=(Sinicial+Sfinal)/2
  • Rotación del stock (Rs): Frecuencia media de renovación de las existencias consideradas, durante un tiempo dado. Calculado como Rs=D/Sm Por ejemplo una rotación anual de 12 significa que las existencias consideradas se renuevan 12 veces al año, es decir una vez por mes.
  • Consumo medio diario (Cj): Calculado como el consumo D divido por el número de días del periodo de cálculo
  • Cobertura del stock (Cs): La cobertura es el stock promedio Sm dividido por el consumo medio diario Cj. El valor obtenido es el número de días de cobertura.

Consulta

Una vez definidos los conceptos creamos una consulta para calcularlos, y obtener para cada artículo el valor de los mismos. Consulta que mostramos a continuación.

-- Informe para SBO de Indicadores de Inventario

declare @dataInicio datetime
declare @dataFinal datetime
declare @tempo int

SET @tempo=(SELECT TOP 1 T0.TRANSNUM FROM OINM T0 WHERE T0.[DocDate] >=[%0] AND T0.[DocDate] <=[%1])
SET @dataInicio=(SELECT '[%0]')
SET @dataFinal=(SELECT '[%1]')

SELECT
[Artículo]=t1.itemcode,
Consumo=isnull(t1.consumo,0),
[Consumo medio diario]=isnull(t1.consumo/datediff(day,@dataInicio,@dataFinal),0),
[Stock inicial]=isnull(coalesce(t0.saldoinic,0),0),
[Stock final]=isnull(coalesce(t0.saldoinic,0)+coalesce(t1.saldofin,0),0),
[Stock promedio]= isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0),
[Rotación stock]= case isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0) when 0 then 0 else isnull(t1.consumo / ((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2) ,0) end,
[Cobertura de stock]= case isnull(coalesce(t1.consumo/datediff(day,@dataInicio,@dataFinal),0),0) when 0 then 0 else isnull(((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2)/ ( t1.consumo/datediff(day,@dataInicio,@dataFinal)),0) end
FROM (
SELECT
a1.itemcode,
saldoInic=isnull(sum(coalesce(s1.Inqty,0))-sum(coalesce(s1.outqty,0)),0)
FROM OITM a1
JOIN OINM s1 on a1.itemcode=s1.itemcode
WHERE s1.docdate<@dataInicio
GROUP BY a1.itemcode
) as t0
RIGHT JOIN (
SELECT
a.itemcode,
entradas=isnull(sum(s.Inqty),0),
consumo=isnull(sum(s.outqty),0),
saldoFin=isnull(sum(s.Inqty)-sum(s.outqty),0)
FROM OINM s
JOIN OITM a on a.itemcode=s.itemcode
WHERE s.docdate BETWEEN @dataInicio and @dataFinal
GROUP BY a.itemcode ) t1 on t1.itemcode=t0.itemcode

Al ejecutarla, nos pide como parámetros el ámbito de tiempo entre fechas para calcular el consumo y los indicadores de inventario para este intervalo de fechas.

El resultado es el que sigue:

El listado nos muestra la siguiente información:
  • El código del artículo.
  • El consumo (D) en el periodo indicado al inicio.
  • El consumo diario de cada artículo (Cj), según la media entre el consumo y los días del intervalo informado.
  • El stock inicial (Sinicial), o stock al principio del periodo de tiempo informado.
  • El stock final (Sfinal) o stock en el momento de la fecha final del ámbito estudiado.
  • El stock promedio (Sm) en el periodo estudiado.
  • La rotación de stock (Rs), o las veces que se ha repuesto durante el periodo estudiado
  • La cobertura de stock (Cs), o los días que disponemos de stock de este articulo.

Conclusiones

Toda la información para el calculo de la rotación del inventario y la cobertura de stock, está disponible en nuestro ERP, en este caso SAP B1. Disponer de esta información en tiempo real nos ayuda a e encontrar aspecto de mejora en nuestro inventario para optimizar costes, o determinar acciones concretas de mejora en nuestra empresa.

70 comentarios:

  1. ese reporte funciona es para todos los almacenes, pero que podria hacer para especificar un almacen determinado

    ResponderEliminar
  2. Buenas Anónimo,
    para filtrar por almacén debes añadir en la cláusula WHERE de las 2 subconsultas la siguiente condición:
    Subconsulta 1: s1.Warehouse='XX'
    Subconsulta 2: s.Warehouse='XX',
    donde "s1" y "s" son los alias de la tabla OINM en cada subconsulta y XX es el código del almacén que quieres utilizar.
    Para filtrar por más de un almacén, puedes hacerlo mediante la cláusulas.Warehouse='XX' IN ('XX','YY').

    Saludos

    ResponderEliminar
    Respuestas
    1. ¿Sería posible que el almacén fuera una variable a declarar, como las fechas de inicio y fin?

      Eliminar
  3. Gracias Emili, el reporte es buenisimo.

    ResponderEliminar
  4. Muy buenas tardes
    En mi empresa trabajamos en base a Precio medio ponderado y con varios almacenes.
    Genere una query para saber el stock por alamcen e item y su determinado valor a una fecha.
    Pero el problema lo tengo en el calculo del PMP a la fecha de corte.

    La query es la siguiente
    SELECT T1.[WhsCode], T1.[WhsName], T0.[ItemCode], T2.[ItemName],
    (SELECT (SUM(Y.InQty)-SUM(Y.OutQty)) FROM OINM Y WHERE Y.ItemCode = T2.ItemCode AND Y.Warehouse = T1.WhsCode AND Y.DocDate BETWEEN '[%0]' AND '[%1]') 'Stock',
    (SELECT Y.CalcPrice FROM OINM Y WHERE Y.TransNum IN (SELECT MAX(Y1.TransNum) FROM OINM Y1 WHERE Y1.DocDate IN (SELECT MAX(Y2.DocDate) FROM OINM Y2 WHERE Y2.DocDate <= '[%0]' AND Y2.ItemCode = Y1.ItemCode) AND Y1.ItemCode = Y.ItemCode) AND Y.ItemCode = T2.ItemCode) 'PMP'
    FROM OITW T0
    INNER JOIN OWHS T1 ON T0.WhsCode = T1.WhsCode
    INNER JOIN OITM T2 ON T0.ItemCode = T2.ItemCode
    WHERE (SELECT (SUM(Y.InQty)-SUM(Y.OutQty)) FROM OINM Y WHERE Y.ItemCode = T2.ItemCode AND Y.Warehouse = T1.WhsCode AND Y.DocDate BETWEEN '20010101' AND '[%0]') != '0'
    ORDER BY T0.[WhsCode], T0.[ItemCode]

    Cuando el ultimo movimiento del articulo es a la fecha de corte me arroja el PMP correcto, no asi cuando el articulo tiene movimientos antes.

    Estare omitiendo algo? tambien lo intente generar sumando el valor total del articulo y dividirlo por el total de cantidades, pero me distorsiona los datos.
    Ya no se me ocurre nada mas.

    Saludos

    ResponderEliminar
    Respuestas
    1. hola Felipe podrias mostrarme tu query? estoy tratando de hacer pero no lo tengo claro

      Eliminar
  5. Buenas Felipe,
    a lo largo del día publicaremos un artículo con una consulta para obtener el precio medio ponderado a fecha, tal y como indicas.
    Un saludo.

    ResponderEliminar
  6. Gran Ayuda!! resolvio mi problema para planificar Compras!!

    ResponderEliminar
  7. Primero que nada muchas Gracias por compartir, he tomado tu código y lo he adaptado a lo que solicita mi empresa, mi problema es que al ejecutar esta consulta en SAP me marca un error y al ejecutarla desde SQL Management no hay problema
    ---El error es:

    1). [Microsoft][SQL Native Client][SQL Server]Must specify table to select from. 2). [Microsoft][SQL Native Client][SQL Server]Statement 'Contratos de servicio' (OCTR) (s) could not be prepared.

    ---El código adaptado quedo así:

    declare @dataInicio datetime
    declare @dataFinal datetime

    SET @dataInicio=(SELECT '[%0]') --Estos los cambio por cadenas '20110218', por ejemplo
    SET @dataFinal=(SELECT '[%1]') --Estos los cambio por cadenas '20110218', por ejemplo

    SELECT DISTINCT
    [Codigo] = t1.itemcode,
    [Producto] = t1.Dscription,
    [Inv. Inicial] = isnull(coalesce(t0.saldoinic,0),0),
    [Compras] = isnull(coalesce(t1.entradas,0),0),
    [Consumo] = isnull(t1.consumo,0),
    [Inv. Final] = isnull(coalesce(t0.saldoinic,0)+coalesce(t1.saldofin,0),0),
    [Costo] = --Costo Inventario Final
    (SELECT TOP 1 costo=isnull(coalesce(s2.Price,0),0) FROM OINM s2 JOIN OITM a2 on a2.itemcode=s2.itemcode
    WHERE s2.docdate<@dataFinal AND a2.itemcode=t1.itemcode AND s2.Price <> 0 AND s2.Transnum = (SELECT max(s3.Transnum) FROM OINM s3 WHERE s3.docdate<@dataFinal and s2.itemcode=s3.itemcode AND s3.Price <> 0)
    GROUP BY a2.itemcode, s2.Price) * isnull(coalesce(t0.saldoinic,0)+coalesce(t1.saldofin,0),0)
    FROM (
    SELECT
    a1.itemcode,
    s1.Dscription,
    saldoInic=isnull(sum(coalesce(s1.Inqty,0))-sum(coalesce(s1.outqty,0)),0)
    FROM OITM a1
    JOIN OINM s1 on a1.itemcode=s1.itemcode
    WHERE
    s1.docdate<@dataInicio
    GROUP BY
    a1.itemcode,
    s1.Dscription
    ) as t0
    RIGHT JOIN (
    SELECT
    a.itemcode,
    s.Dscription,
    entradas=isnull(sum(s.Inqty),0),
    consumo=isnull(sum(s.Outqty),0),
    saldoFin=isnull(sum(s.Inqty)-sum(s.outqty),0),
    costo=isnull(sum(s.Price),0)
    FROM
    OINM s
    JOIN OITM a on a.itemcode=s.itemcode
    WHERE
    s.docdate BETWEEN @dataInicio and @dataFinal
    GROUP BY
    a.itemcode,
    s.Dscription
    ) t1 on t1.itemcode=t0.itemcode
    order by 2


    ----- alguna idea para que SAP no marque ese error?

    Gracias.

    ResponderEliminar
  8. Hola Edgar, el problema lo tienes al principio de la sentencia de SQL donde asignas los parámetros a las variables @dataInicio y @datFinal. Fíjate que nosotros construimos una sentencia SQL válida en SAP B1 para recoger estos parámetros.
    En nuestro caso utilizamos esta sentencia:

    SET @tempo=(SELECT TOP 1 T0.TRANSNUM FROM OINM T0 WHERE T0.[DocDate] >=[%0] AND T0.[DocDate] <=[%1]) “

    De este modo SAP B1 asigna valores correctos a los valores [%0] y [%1]. Si no realizas este tipo de acciones SAP no puede identificar ni el tipo de dato que son los parámetros ni cuáles son sus posibles valores.
    Atentamente

    ResponderEliminar
  9. Muchísimas Gracias Roberto, y fíjate que este es uno de los problemas que me pasan recurrentemente y todo por no colocar esa sentencia, con esto acabas de ayudarme a muchas consultas.

    MUCHISIMAS GRACIAS.

    ResponderEliminar
    Respuestas
    1. Edgar, Soy Nuevo en SAP B1, me puede ayudar con el codigo que lo adecuo con valor, con cantidades ya logre implemetar ahora me piden con valor y veo que usted lo tiene, gracias

      Eliminar
  10. Buenas tardes,
    Yo también la he modificado, pero el problema es que yo la necesito visualizar en crystal report por comandos, pero me saca un error yo creo que es por las variables de las fechas porque cuando ingreso la fecha en el código funciona muy bien, saben cómo puedo manejar yo estas variables en crystal
    DECLARE @FechaInicial DATETIME
    DECLARE @FechaFinal DATETIME
    DECLARE @RangoFech INT

    SET @RangoFech=(SELECT TOP 1 T0.Transnum FROM OINM T0 WHERE T0.[DocDate] >='{?FechaInicial}' AND T0.[DocDate] <='{?FechaFinal}')
    SET @FechaInicial=(SELECT '{?FechaInicial}')
    SET @FechaFinal=(SELECT '{?FechaFinal}')

    SELECT
    [Articulo]=T1.ItemCode,
    [GrupArt]=T1.ItmsGrpCod,
    [Producto] = T1.Dscription,
    [StockInicial]=ISNULL(COALESCE(T0.SaldoInic,0),0),
    [CostoInicial]=(SELECT TOP 1 CostoInicial=ISNULL(COALESCE(S2.CalcPrice,0),0) FROM OINM S2 JOIN OITM A2 ON A2.ItemCode=S2.ItemCode
    WHERE S2.DocDate<@FechaFinal AND A2.ItemCode=T1.ItemCode AND S2.CalcPrice <> 0 AND S2.Transnum = (SELECT MAX(S3.Transnum) FROM OINM S3 WHERE S3.DocDate<@FechaFinal AND S2.ItemCode=S3.ItemCode AND S3.CalcPrice <> 0)
    GROUP BY A2.ItemCode, S2.CalcPrice) * ISNULL(COALESCE(T0.SaldoInic,0),0),
    [Entradas]=ISNULL(COALESCE(T1.Entradas,0),0),

    [Salidas]=ISNULL(COALESCE(T1.Consumo,0),0),

    [Stock ]=ISNULL(COALESCE(T0.SaldoInic,0)+COALESCE(T1.SaldoFin,0),0),
    [Costo] = (SELECT TOP 1 Costo=ISNULL(COALESCE(S2.CalcPrice,0),0) FROM OINM S2 JOIN OITM A2 ON A2.ItemCode=S2.ItemCode
    WHERE S2.DocDate<@FechaFinal AND A2.ItemCode=T1.ItemCode AND S2.CalcPrice <> 0 AND S2.Transnum = (SELECT MAX(S3.Transnum) FROM OINM S3 WHERE S3.DocDate<@FechaFinal AND S2.ItemCode=S3.ItemCode AND S3.CalcPrice <> 0)
    GROUP BY A2.ItemCode, S2.CalcPrice) * ISNULL(COALESCE(T0.SaldoInic,0)+COALESCE(T1.SaldoFin,0),0)


    FROM (
    SELECT A1.ItemCode,A1.ItmsGrpCod,S1.Dscription,
    SaldoInic=ISNULL(SUM(COALESCE(S1.Inqty,0))-SUM(COALESCE(S1.outqty,0)),0)
    FROM OITM A1 JOIN OINM S1 ON A1.ItemCode=S1.ItemCode
    WHERE S1.DocDate<@FechaInicial AND S1.Warehouse='{?Bodega}'
    GROUP BY A1.ItemCode,A1.ItmsGrpCod,S1.Dscription
    ) AS T0 RIGHT JOIN (
    SELECT A.ItemCode,A.ItmsGrpCod,S.Dscription,
    Entradas=ISNULL(SUM(S.Inqty),0),
    Consumo=ISNULL(SUM(S.Outqty),0),
    SaldoFin=ISNULL(SUM(S.Inqty)-SUM(S.Outqty),0)
    FROM OINM S JOIN OITM A ON A.ItemCode=S.ItemCode
    WHERE S.DocDate BETWEEN @FechaInicial AND @FechaFinal AND S.Warehouse='{?Bodega}'
    GROUP BY A.ItemCode,A.ItmsGrpCod,S.Dscription
    ) T1 ON T1.ItemCode=T0.ItemCode

    ResponderEliminar
  11. La parte inicial de la construcción de la consulta no te sirve para Crystal. La primera parte donde se obtiene los parámetros lo hacemos de este modo para poder utilizar los parametros en la consulta de SAP.

    Pero si estas utilizando Crystal Report estos parámetros pueden ser directamenta los parametros de Crystal Report los que has puesto con '{?Parametro X}' y lógicamente deberás sustituir donde nosotros ponemos @Parametro X por '{?Parametro X}'.

    Un saludo.

    ResponderEliminar
  12. Gracias por su ayuda,
    El problema ahora es que no se como organizar esta variable que tiene una consulta
    DECLARE @RangoFech INT
    {@Rango}=(SELECT TOP 1 T0.Transnum FROM OINM T0 WHERE T0.[DocDate] >='{?FechaInicial}' AND T0.[DocDate] <='{?FechaFinal}')
    Como puedo hacer yo esto, o cambiar la consulta para no tener que hacer este paso,

    Saludos

    ResponderEliminar
  13. Esto como lo anterior es algo que utilizamos para realizar la consulta con SAP Business One. En Crystal Reports no hace falta.

    ResponderEliminar
  14. Gracias por tu ayuda, me ha servido de mucho tu consulta, solo tengo una duda, al aplicar la consulta me desaparecen los links (flechas amarillas) de los registros para abrir las facturas directamente desde el reporte, esto tiene solución?

    gracias.

    ResponderEliminar
  15. Hola José, el informe no obtiene la información directamente de los documentos de SAP B1. Si no que lo hace a través de la tabla de OINM por eso no hace los links. Por otra, parte la consulta también tiene información de varias tablas en esos casos SAP B1 no muestra en algunas ocasiones los enlaces.

    Un saludo.

    ResponderEliminar
  16. Muy Bien, muchas gracias por tu ayuda!

    ResponderEliminar
  17. Yo tengo una pregunta...
    En lista de resultado del query, solo aparecen las referencias que tienen stock?

    ResponderEliminar
  18. Buenas Anónimo,
    Sólo aparecen los artículos que hayan tenido movimientos entre las fechas indicadas en el filtro.

    ResponderEliminar
  19. una pregunta, como hago para poder mostrar la descripcion del articulo en esta consulta?

    ResponderEliminar
  20. Buenas Anónimo,
    debes añadir el campo ItemCode tanto en la consulta principal como en las 2 subconsultas.

    En la principal: [Desc. Artículo]=T1.ItemName
    En las 2 subconsultas: a1.ItemName y a.ItemName respectivamente.

    Saludos

    ResponderEliminar
    Respuestas
    1. Hola Emili, se que este tema es extremadamente viejo pero yo no se como hacer esa parte que dices. He tratado y tratado y siempre me salen los mismos errores, pero seguramente no lo estoy implimentando correctamente. ¿Me lo puedes explicar de otra manera? (Agregar columna descripcion)
      Estare pendiente, muchas gracias.

      Eliminar
  21. una consulta, quize verificar la veracidad de la consulta, y pues no entiendo muy bien el dato consumo, verifique el primero codigo, y en el rango de fecha solo habia consumido 13 unidades y en el query me sale en el dato consumo 20??

    que estara pasando.?

    ResponderEliminar
  22. Esta consulta está validada y tiene en cuenta los datos de la tabla OINM (convertida en vista a partir de la versión 8.8), que es la que SAP utiliza para registrar los movimientos de stock. Si los datos no te cuadran será porqué lo estás comparando con datos filtrados de forma distinta.
    Saludos,

    ResponderEliminar
  23. muchas gracias por tu respuesta, manejo la version 8.8 de sap-bo, y lo compare, con el informe de auditoria de stock, y ahi verifique que no concordaban, por eso hize la pregunta, porque no tenia claro el dato de consumo!

    entonces aunque me aparezcan 13 en la auditoria de stock y 2o en el query, esta correcto.?

    ResponderEliminar
  24. disculpa que moleste tanto, te agradezco por tu post, porque me ha servido muchiiiisimo... ahora, solo que quiero tener claro algo, que toma como consumo,? solo salidas y entregas? o tambien toma como consumo los traslados..?

    ResponderEliminar
  25. En esta consulta se tienen en cuenta TODOS LOS MOVIEMIENTOS DE STOCK. Albaranes, traslados, entradas/salidas manuales o cualquier documento que genere un movimiento de stock.
    Saludos,

    ResponderEliminar
  26. Muchas gracias por el query esta buenísimo pero tengo una duda.
    Que pasa si generamos un nota de credito esto quiere decir que los items que salieron ahora regresaron al inventario. hice un par de pruebas y el reporte no toma en cuenta las devoluciones.

    ResponderEliminar
  27. Buenas tardes como podria yo tener un query parecido a este pero que me muestre solo los articulos con baja rtacion, es decir que no hayan tenido entregas en los ultimos 30 dias, tengo algo asi:
    --QUERY BAJA ROTACION POR SUCURSAL
    --QUERY MANAGER

    --SUCURSAL
    /*SELECT FROM [dbo].[OWHS] B*/
    declare @SUC as CHAR(32)
    /* WHERE */
    set @SUC = /* B.BLOCK */ '[%0]'
    --UNIDAD
    /*SELECT FROM [dbo].[OIBT] L*/
    declare @UNIDAD as CHAR(02)
    /* WHERE */
    set @UNIDAD = /* L.ITEMCODE */ '[%1]'
    --FECHA INICIAL
    /*SELECT FROM [dbo].[IBT1] */
    declare @FECHAINI as DATETIME
    /* WHERE */
    set @FECHAINI = /* IBT1.DOCDATE */ '[%2]'
    --FECHA FINAL
    /*SELECT FROM [dbo].[IBT1] */
    declare @FECHAFIN as DATETIME
    /* WHERE */
    set @FECHAFIN = /* IBT1.DOCDATE */ '[%3]'

    --IMPORTADOS
    SELECT L.ITEMCODE AS CODIGO,L.ITEMNAME AS REFERENCIA,SUBSTRING(L.ITEMCODE,1,2) UNIDAD,'IMPORTADO' TIPO,
    L.WHSCODE BODEGA,B.BLOCK AS SUCURSAL,L.BATCHNUM LOTE,Q.CANTIDAD,P.AVGPRICE AS PRECIO_UNITARIO,
    (Q.CANTIDAD*P.AVGPRICE ) as COSTO
    FROM OIBT L,OITM A,OWHS B,OITW P,
    (SELECT A.DOCDATE,A.BATCHNUM,A.WHSCODE,SUM(A.CANTIDAD) CANTIDAD
    FROM
    (SELECT DOCDATE,BATCHNUM,WHSCODE,'CANTIDAD'=CASE WHEN DIRECTION =1 THEN SUM(QUANTITY)*-1 ELSE SUM(QUANTITY) END
    FROM IBT1 WHERE [DocDate] <='[%3]' AND [DOCDATE] >='[%2]'
    GROUP BY DOCDATE,BATCHNUM,WHSCODE,DIRECTION )A
    GROUP BY A.DocDate, A.BATCHNUM,A.WHSCODE HAVING SUM(CANTIDAD) <>0) Q
    WHERE --L.QUANTITY <> 0
    -- DATEDIFF(DAY,L.CREATEDATE,'20111116') >'30'
    B.[Block]='[%0]'
    AND SUBSTRING(L.[ITEMCODE],1,2)='[%1]'
    --AND L.ItemCode='SI2200040'
    --AND L.ItemCode NOT IN (SELECT ItemCode FROM DLN1 WHERE DOCDATE <=@FECHAFIN AND DOCDATE >=@FECHAINI )
    AND L.ITEMCODE = A.ITEMCODE
    AND A.U_QCA_TIPOCOMPRA ='001'
    AND B.WHSCODE=L.WHSCODE
    AND P.ITEMCODE=L.ITEMCODE
    AND P.WHSCODE=L.WHSCODE
    AND Q.BATCHNUM=L.BATCHNUM
    AND Q.WHSCODE=L.WHSCODE
    --ORDER BY L.CreateDate DESC
    UNION ALL
    --NACIONALES
    SELECT L.ITEMCODE AS CODIGO,L.ITEMNAME AS REFERENCIA,SUBSTRING(L.ITEMCODE,1,2) UNIDAD,'IMPORTADO' TIPO,
    L.WHSCODE BODEGA,B.BLOCK AS SUCURSAL,L.BATCHNUM LOTE,Q.CANTIDAD,P.AVGPRICE AS PRECIO_UNITARIO,
    (Q.CANTIDAD*P.AVGPRICE ) as COSTO
    FROM OIBT L,OITM A,OWHS B,OITW P,
    (SELECT A.DOCDATE,A.BATCHNUM,A.WHSCODE,SUM(A.CANTIDAD) CANTIDAD
    FROM
    (SELECT DOCDATE,BATCHNUM,WHSCODE,'CANTIDAD'=CASE WHEN DIRECTION =1 THEN SUM(QUANTITY)*-1 ELSE SUM(QUANTITY) END
    FROM IBT1 WHERE [DocDate] <='[%3]' AND [DOCDATE] >='[%2]'
    GROUP BY DOCDATE,BATCHNUM,WHSCODE,DIRECTION )A
    GROUP BY A.DocDate, A.BATCHNUM,A.WHSCODE HAVING SUM(CANTIDAD) <>0) Q
    WHERE --L.QUANTITY <> 0
    -- DATEDIFF(DAY,L.CREATEDATE,'20111116') >'30'
    B.[Block]='[%0]'
    AND SUBSTRING(L.[ITEMCODE],1,2)='[%1]'
    --AND L.ItemCode='SI2200040'
    --AND L.ItemCode NOT IN (SELECT ItemCode FROM DLN1 WHERE DOCDATE <=@FECHAFIN AND DOCDATE >=@FECHAINI )
    AND L.ITEMCODE = A.ITEMCODE
    AND A.U_QCA_TIPOCOMPRA ='002'
    AND B.WHSCODE=L.WHSCODE
    AND P.ITEMCODE=L.ITEMCODE
    AND P.WHSCODE=L.WHSCODE
    AND Q.BATCHNUM=L.BATCHNUM
    AND Q.WHSCODE=L.WHSCODE
    --ORDER BY L.CreateDate DESC
    pero me muestra todos los movimientos y deseo ver solo los que no han tenido entregas, muchas gracias.

    ResponderEliminar
  28. Creo que si estas sacando datos de los ultimos 30 dias , entonces podrias en vez de poner un rango de fechas , poner
    [DOCDATE] >= dateadd(dd,-30,getdate())
    con lo cual sacas transacciones desde hace 30 dias hasta hoy.

    ResponderEliminar
  29. HOla , consulta , alguien tiene un query para sap bo , para realizar un kardex de inventario , agrupado por tipo de documento y por alamacen?
    por que esto , bueno para poder ver como se movio
    el inventario de acuerdo a los distintos tipos de docmentos, sean estos , guias, facturas , notas de credito, ingresos y egresos de inventarios, produccion etc.

    ResponderEliminar
  30. Buenas tardes, como puedo ver en el sap bo la cantidad de inventario que tenia en cierto dia

    ResponderEliminar
  31. Esta consulta genera bloqueo en todo el sistema sobre una BD de SAP B1 de 47 GB ... mejor dicho, imposible de poder usar.

    ResponderEliminar
  32. Buenas Tardes utilice esta consulta en mi base de datos y fue exitosa, sin embargo al validarla noto que no toma en cuenta las devoluciones en el consumo del período, es decir no las resta. Y adicionalmente suma los traslados salientes

    ResponderEliminar
  33. Podría algunos de ustedes orientarme como incluir las devoluciones y extraer los traslados salientes. Agradezco su aporte...

    ResponderEliminar
  34. Buenas Ragmasel,

    esta consulta tiene en cuenta todos los documentos de SAP B1 que generan movimientos de stock, entre ellos las devoluciones, así que revisa bien los resultados porqué las devoluciones han de estar.

    Por lo que refiere a los traslados, para omitirlos en la consulta debes añadir el siguiente filtro en las 2 subconsultas: "s1.TransType<>67" en la primera i "s.TransType<>67" en la segunda, ya que una utiliza un alias distinto para la tabla/vista OINM.

    Saludos.

    ResponderEliminar
  35. Alguien a mejorado esta consulta? Para empresas con bd grandes demora mucho y cuelga el SQL.

    ResponderEliminar
  36. Hola Buenas Tardes, quien me puede ayudar por favor a terminar una consulta que tengo, en donde necesito filtrar unos items por rango de fechas pero adicional también que me filtre los clientes que tienen facturas en ese rango de fechas que puse arriba.

    Por ejemplo hice mi Query pero al escoger el rango de fechas y abajo escoger el cliente me salen todos los clientes que tienen facturas , necesito que si escojo las fechas me filtre los clientes que tienen en esas fechas para no estar adivinando.

    SELECT T1.[ItemCode], T1.[Dscription], T2.[U_marca],
    T0.[DocNum], T0.[DocDate], T1.[Quantity], T1.[Price],
    T1.[LineTotal], T1.[GPTtlBasPr], (T1.[LineTotal]-T1.[GPTtlBasPr])
    as 'Ganancia' ,((( T1.[LineTotal]-T1.[GPTtlBasPr])/
    T1.[LineTotal])*100) as '% Ganancia'
    FROM [dbo].[OINV] T0 INNER JOIN [dbo].[INV1] T1
    ON
    T0.DocEntry = T1.DocEntry INNER JOIN [dbo].[OITM] T2
    ON T1.ItemCode = T2.ItemCode
    WHERE T0.[DocDate] >='[%0]' and T0.[DocDate] <='[%1]' and T0.[CardName] ='[%2]'

    Aqui es donde tengo el problema porque no me esta trayendo los clientes que me comprenden en las fechas que escojo arriba, hay alguna forma de que al escojer las fechas solo me salgan los clientes que tienen articulos facturados en esas fechas? O si fuera al revez que si escojo el clliente me salgan las fechas en que hay artículos facturados.

    Espero me puedan ayudar por favor.

    ResponderEliminar
  37. declare @dataInicio datetime
    declare @dataFinal datetime
    declare @tempo int
    SET @tempo=(SELECT TOP 1 T0.TRANSNUM FROM OINM T0 WHERE T0.[DocDate] >=[%0] AND T0.[DocDate] <=[%1])
    SET @dataInicio=(SELECT '[%0]')
    SET @dataFinal=(SELECT '[%1]')

    SELECT
    [Artículo]=t1.itemcode,
    [Desc. Artículo]=t1.ItemName,
    Consumo=isnull(t1.consumo,0),
    [Consumo medio diario]=isnull(t1.consumo/datediff(day,@dataInicio,@dataFinal),0),
    [Stock inicial]=isnull(coalesce(t0.saldoinic,0),0),
    [Stock final]=isnull(coalesce(t0.saldoinic,0)+coalesce(t1.saldofin,0),0),
    [Stock promedio]= isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0),
    [Rotación stock]= case isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0) when 0 then 0 else isnull(t1.consumo / ((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2) ,0) end,
    [Cobertura de stock]= case isnull(coalesce(t1.consumo/datediff(day,@dataInicio,@dataFinal),0),0) when 0 then 0 else isnull(((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2)/ ( t1.consumo/datediff(day,@dataInicio,@dataFinal)),0) end
    FROM (

    SELECT
    a1.itemcode,
    a1.ItemName,
    saldoInic=isnull(sum(coalesce(s1.Inqty,0))-sum(coalesce(s1.outqty,0)),0)
    FROM OITM a1
    JOIN OINM s1 on a1.itemcode=s1.itemcode

    WHERE s1.docdate<@dataInicio
    GROUP BY
    a1.itemcode,
    a1. ItemName
    ) as t0
    RIGHT JOIN (

    SELECT
    a.itemcode,
    a.ItemName,
    entradas=isnull(sum(s.Inqty),0),
    consumo=isnull(sum(s.outqty),0),
    saldoFin=isnull(sum(s.Inqty)-sum(s.outqty),0)
    FROM OINM s
    JOIN OITM a on a.itemcode=s.itemcode,


    WHERE s.docdate BETWEEN @dataInicio and @dataFinal
    GROUP BY
    a.itemcode,
    a.ItemName
    ) t1 on t1.itemcode=t0.itemcode

    QUE PUEDO HACER?
    NO SE QUE ESTOY HACIENDO MAL, ME SALE ERROR AL INGRESAR EL CAMPO ITEMNAME

    ResponderEliminar
    Respuestas
    1. Saludos.
      Probé la consulta tal cual y no muestra ningún resultado (utilizo sap b1 2007A).
      ¿Qué podría hacer para que funcione ?

      Eliminar
  38. Estimado mauricio, la tabla t1 no contiene el ItemName. La incluyes o realizas una subconsulta.
    SLDS.

    ResponderEliminar
  39. Buen dia disculpen, necesito que me ayuden en mi empresa manejamos SBO 8.8 y necesito saber que query puedo utilizar para un kardex que lleve columnas de entradas, salidas, y saldo de gual manera que lleve columnas de costo por articulo. Gracias espero me ayuden con mi consulta.

    ResponderEliminar
  40. no esta tomando en cuenta las NOTAS DE CREDITO!!!

    ResponderEliminar
  41. Os recordamos que, tal y como dijimos hace meses, esta consulta tiene en cuenta todos los documentos que realizan movimientos de estoc, entre ellos abonos y devoluciones. Si en algún momento no visualizáis un abono (nota de crédito), la razón más probable sea que no está generando un movimiento de estoc porqué proviene de una devolución de mercancías.

    Saludos

    ResponderEliminar
    Respuestas
    1. buenas noches , podrias ayudarme como sacar el costo pónderado (kardex valorizado) en una consulta para mostrarlo en un datagridview en sql y vb.net.
      gracias
      markho34
      en h o t m a i l

      Eliminar
  42. he probado la consulta tal cual y me sale ningún resultado, ni error. uso la versión de sap b1 2007A. Alguien me podría ayudar con esto? estaré muy agradecido

    ResponderEliminar
  43. Muy buenos dias compañeros del foro yo tengo una preguntas no tanto orientada a la creación de consultas sino mas bien de comportamiento de SAP, les cuento mi problema:

    Entro a "Datos maestros de articulo" y consulto el listado de productos que tengo creados de una categoria que en nuestro caso el ItemName empiza con 4 letras seguido de un guión mas 6 digitos, entonces abro el listado de articulos haciendo SUMI-* y SAP me muestra el "LISTADO DE ARTICULOS" con su ItemName, description, OnHand, WhsCode, CodeBars y otros campos; el campo que me interesa es ONHAND que aqui me muestra una cantidad pero si escojo un producto y me voy a la ficha "Datos de Inventario" la cantidad que me muestra es CERO, es decir no hay existencia, ésto me pasa con unos codigos no todos es quizas un 1% del 100% de codigos que tenemos pero quiero saber a que se debe este comportamiento. si pueden responderme me gustaria que me ayudaran
    gracias.

    ResponderEliminar
  44. Muy buenos dias compañeros del foro yo tengo una preguntas no tanto orientada a la creación de consultas sino mas bien de comportamiento de SAP, les cuento mi problema:

    Entro a "Datos maestros de articulo" y consulto el listado de productos que tengo creados de una categoria que en nuestro caso el ItemName empiza con 4 letras seguido de un guión mas 6 digitos, entonces abro el listado de articulos haciendo SUMI-* y SAP me muestra el "LISTADO DE ARTICULOS" con su ItemName, description, OnHand, WhsCode, CodeBars y otros campos; el campo que me interesa es ONHAND que aqui me muestra una cantidad pero si escojo un producto y me voy a la ficha "Datos de Inventario" la cantidad que me muestra es CERO, es decir no hay existencia, ésto me pasa con unos codigos no todos es quizas un 1% del 100% de codigos que tenemos pero quiero saber a que se debe este comportamiento. si pueden responderme me gustaria que me ayudaran
    gracias.

    ResponderEliminar
  45. ESTIMADOS NO APLIQUE LA CONSULTA EN SAP PERO CUANDO LO EJECUTO EL STOCK FINAL DEBERIA COINCIDIR CON EL DISPONIBLE REGISTRADO EN LOS DATOS MAESTROS DE PRODUCTOS PERO NO ES ASI SI TIENEN ALGUN COMENTARIO GRACIAS

    ResponderEliminar
    Respuestas
    1. Hola Miguel, el stock final debe coincidir con el existente a la fecha final del informe no con el que se indica en el maestro de artículos.

      Un saludo.

      Eliminar
  46. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  47. Existe alguna forma de mostrar el movimiento del inventario mes a mes por codigo de articulo?, es decir que me muestre este mismo informe pero como roto x producto en Enero, Febrero, Marzo, etc. Agradeciendo de antemano cualquier orientacion.

    ResponderEliminar
  48. Como puede obtener los codigo de articulos que nunca han tenido movimiento, osea que no han sido involucrados en ningun documento.

    ResponderEliminar
  49. Hola, Emili, que campos podria usar de la tabla OINM para traerme la última compra y la última venta del articulo?

    ResponderEliminar
  50. Hola saludos que Reporte mas interesante y útil Felicitaciones y gracias

    ResponderEliminar
  51. Buenas solo tengo una duda con el reporte y es con las notas de crédito al hacer la NC devuelve el producto por lo tanto aumenta el stock pero no las resta al consumo aparecen siempre como consumidas como puedo hacer para que las reduzca del consumo?

    ResponderEliminar
  52. Hola a todos,

    Adjunto mi adaptación de la consulta para que ignore los traslados entre bodegas. Ademas esta considera los débitos y créditos:

    declare @dataInicio datetime
    declare @dataFinal datetime
    declare @tempo int

    SET @tempo=(SELECT TOP 1 T0.TRANSNUM FROM OINM T0 WHERE T0.[DocDate] >=[%0] AND T0.[DocDate] <=[%1])
    SET @dataInicio=(SELECT '[%0]')
    SET @dataFinal=(SELECT '[%1]')

    SELECT

    [Artículo]=t1.itemcode,
    Consumo=isnull(isnull(t1.consumo,0)-isnull(t2.consumorev,0),0),
    [Consumo medio diario]=isnull(isnull(isnull(t1.consumo,0)-isnull(t2.consumorev,0),0)/datediff(day,@dataInicio,@dataFinal),0),
    [Stock inicial]=isnull(coalesce(t0.saldoinic,0),0),
    [Stock final]=isnull(coalesce(t0.saldoinic,0)+coalesce(t1.saldofin,0),0),
    [Stock promedio]= isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0),
    [Rotación stock]= case isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0) when 0 then 0 else isnull(isnull(isnull(t1.consumo,0)-isnull(t2.consumorev,0),0)/ ((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2) ,0) end,
    [Cobertura de stock]= case isnull(coalesce(isnull(isnull(t1.consumo,0)-isnull(t2.consumorev,0),0)/datediff(day,@dataInicio,@dataFinal),0),0) when 0 then 0 else isnull(((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2)/ (isnull(isnull(t1.consumo,0)-isnull(t2.consumorev,0),0)/datediff(day,@dataInicio,@dataFinal)),0) end

    FROM (
    SELECT
    a1.itemcode,
    saldoInic=isnull(sum(coalesce(s1.Inqty,0))-sum(coalesce(s1.outqty,0)),0)
    FROM OITM a1
    JOIN OINM s1 on a1.itemcode=s1.itemcode
    WHERE s1.docdate<@dataInicio
    GROUP BY a1.itemcode
    ) as t0
    RIGHT JOIN ( (

    SELECT

    a.itemcode,
    entradas=isnull(sum(s.Inqty),0),
    consumo=isnull(sum(s.outqty),0),
    saldoFin=isnull(sum(s.Inqty)-sum(s.outqty),0)

    FROM OINM s
    JOIN OITM a on a.itemcode=s.itemcode
    WHERE s.TransType <> '19' AND s.TransType <> '21' AND s.TransType <> '67'
    AND s.docdate BETWEEN @dataInicio and @dataFinal
    GROUP BY a.itemcode ) as t1

    FULL JOIN (

    SELECT

    a.itemcode,
    entradas=isnull(sum(s.Inqty),0),
    consumorev=isnull(sum(s.Inqty),0),
    saldoFin=isnull(sum(s.Inqty)-sum(s.outqty),0)

    FROM OINM s
    JOIN OITM a on a.itemcode=s.itemcode
    WHERE s.TransType = '14'
    AND s.docdate BETWEEN @dataInicio and @dataFinal
    GROUP BY a.itemcode ) as t2
    on t1.itemcode=t2.itemcode)
    on t1.itemcode=t0.itemcode

    Order by t1.itemcode

    ResponderEliminar
    Respuestas
    1. Hola, Gracias por adaptar la consulta con los traslados y devoluciones de mercancias, como en mi caso no vendo con sap, las notas de credito son entradas de mercancias ( TransType 59) por lo que la adapte a eso y para que se pueda elegir de que almacen se quiere hacer la consulta. Dejo mi consulta, talvez le pueda ser de ayuda a alguien.

      declare @dataInicio datetime
      declare @dataFinal datetime
      declare @tempo int

      SET @tempo=(SELECT TOP 1 T0.TRANSNUM FROM OINM T0 WHERE T0.[DocDate] >=[%0] AND T0.[DocDate] <=[%1] and t0.[Warehouse] = [%2])
      SET @dataInicio=(SELECT '[%0]')
      SET @dataFinal=(SELECT '[%1]')

      SELECT

      [Artículo]=t1.itemcode,
      Consumo=isnull(isnull(t1.consumo,0)-isnull(t2.consumorev,0),0),
      [Consumo medio diario]=isnull(isnull(isnull(t1.consumo,0)-isnull(t2.consumorev,0),0)/datediff(day,@dataInicio,@dataFinal),0),
      [Stock inicial]=isnull(coalesce(t0.saldoinic,0),0),
      [Stock final]=isnull(coalesce(t0.saldoinic,0)+coalesce(t1.saldofin,0),0),
      [Stock promedio]= isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0),
      [Rotación stock]= case isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0) when 0 then 0 else isnull(isnull(isnull(t1.consumo,0)-isnull(t2.consumorev,0),0)/ ((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2) ,0) end,
      [Cobertura de stock]= case isnull(coalesce(isnull(isnull(t1.consumo,0)-isnull(t2.consumorev,0),0)/datediff(day,@dataInicio,@dataFinal),0),0) when 0 then 0 else isnull(((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2)/ (isnull(isnull(t1.consumo,0)-isnull(t2.consumorev,0),0)/datediff(day,@dataInicio,@dataFinal)),0) end

      FROM (
      SELECT
      a1.itemcode,
      saldoInic=isnull(sum(coalesce(s1.Inqty,0))-sum(coalesce(s1.outqty,0)),0)
      FROM OITM a1
      JOIN OINM s1 on a1.itemcode=s1.itemcode
      WHERE s1.docdate<@dataInicio and s1.[Warehouse] = [%2]
      GROUP BY a1.itemcode
      ) as t0
      RIGHT JOIN ( (

      SELECT

      a.itemcode,
      entradas=isnull(sum(s.Inqty),0),
      consumo=isnull(sum(s.outqty),0),
      saldoFin=isnull(sum(s.Inqty)-sum(s.outqty),0)

      FROM OINM s
      JOIN OITM a on a.itemcode=s.itemcode
      WHERE s.TransType <> '19' AND s.TransType <> '21' AND s.TransType <> '67'
      AND s.docdate BETWEEN @dataInicio and @dataFinal and s.[Warehouse] = [%2]
      GROUP BY a.itemcode ) as t1

      FULL JOIN (

      SELECT

      a.itemcode,
      entradas=isnull(sum(s.Inqty),0),
      consumorev=isnull(sum(s.Inqty),0),
      saldoFin=isnull(sum(s.Inqty)-sum(s.outqty),0)

      FROM OINM s
      JOIN OITM a on a.itemcode=s.itemcode
      WHERE s.TransType = '59'
      AND s.docdate BETWEEN @dataInicio and @dataFinal and s.[Warehouse] = [%2]
      GROUP BY a.itemcode ) as t2
      on t1.itemcode=t2.itemcode)
      on t1.itemcode=t0.itemcode

      Order by t1.itemcode

      Eliminar
  53. Buenos Días a todos, ya hace 4 años y medio que se publico este código pero aun sigue valido y de mucha utilidad, me ha servido de mucho, un gran blog éste, felicito a sus autores y a quienes colaboran.
    A partir de este query yo he creado otro reporte que me han solicitado el cual debe calcular el stock por almacén a cierta fecha determinada que se pida, y realizar todos los cálculos a esa fecha (stock a esa fecha, costo, total costo, precio, total precio y fecha de ultima venta para ese almacen en especifico ).

    La verdad yo no se ni la mitad de lo básico de SQL por lo cual con mucho esfuerzo y a prueba y error logre modificar el código y que me arroje los datos que me solicitaron, pero yo se que mi query esta muy mal hecho y alguien que sepa realmente de SQL lo puede mejorar y optimizar.
    Les dejo mi código y si alguien me hace el favor de revisarlo e indicarme que se puede eliminar, corregir o simplificar para un mejor rendimiento del reporte le estaría muy agradecido, de antemano muchas gracias!!

    (Las fechas las tengo estáticas así como el almacén, esto lo cambiare al momento de ponerlo en SAP)

    declare @dataInicio datetime
    declare @dataFinal datetime

    SET @dataInicio=(SELECT '2005-01-01')
    SET @dataFinal=(SELECT '2015-01-01')


    SELECT
    [Artículo]=t1.itemcode,
    [Descripcion]=t1.itemname,
    [Stock Actual] = (SELECT T4.OnHand FROM OITW T4 WHERE (T4.ItemCode = t1.itemcode) AND (T4.WhsCode = '08-01')),
    [Stock Fecha Seleccionada]=isnull(coalesce(t0.saldoinic,0)+coalesce(t1.saldofin,0),0),
    [Costo] = t1.AvgPrice,
    [Total Costo] = t1.AvgPrice * isnull (t1.saldofin, 0),
    [Precio Dist.]=(SELECT Price FROM ITM1 T3 WHERE (T3.ItemCode = t1.itemcode) AND (T3.PriceList = 1)),
    [Total P.]=(SELECT Price FROM ITM1 T3 WHERE (T3.ItemCode = t1.itemcode) AND (T3.PriceList = 1)) * isnull (t1.saldofin, 0),
    [Ultima Venta]=(SELECT MAX(T2.DocDate) FROM INV1 T2 WHERE (T2.ItemCode = t1.itemcode) and T2.WhsCode = '08-01')
    FROM (
    SELECT
    a1.itemcode,
    a1.itemname,
    a1.AvgPrice,
    saldoInic=isnull(sum(coalesce(s1.Inqty,0))-sum(coalesce(s1.outqty,0)),0)
    FROM OITM a1
    JOIN OINM s1 on a1.itemcode=s1.itemcode
    WHERE (s1.docdate=@dataInicio) AND (s1.Warehouse = '08-01')
    GROUP BY a1.itemcode, a1.ItemName, a1.AvgPrice
    ) as t0
    RIGHT JOIN (
    SELECT
    a.itemcode,
    a.itemname,
    a.AvgPrice,
    saldoFin=isnull(sum(s.Inqty)-sum(s.outqty),0)
    FROM OINM s
    JOIN OITM a on a.itemcode=s.itemcode
    WHERE (s.docdate >='2005-01-01' AND s.docdate <='2015-01-01') AND (s.Warehouse = '08-01')
    GROUP BY a.itemcode, a.ItemName, a.AvgPrice) t1 on t1.itemcode=t0.itemcode

    ResponderEliminar
  54. Buenas tardes

    me interesa mucho este codigo se me hace muy bueno, solo que tengo un pequeño error

    Msg 207, Level 16, State 1, Line 5
    Invalid column name '%0'.
    Msg 207, Level 16, State 1, Line 5
    Invalid column name '%1'.

    es mi primera ves que trabajo con SQL y estoy utilizando SQL server 2012

    si me puedan ayudar se los agradeceria.

    ResponderEliminar
  55. Estas corriendo el script dentro del sql... debes correrlo en sap b1

    ResponderEliminar
  56. con tus procedimientos ¿cual es la utilidad si lo q dices es confuso?

    ResponderEliminar
  57. Muy bueno pero al correr la consulta no me arroja todos los articulos de mi inventario que le falta ?

    declare @dataInicio datetime
    declare @dataFinal datetime
    declare @tempo int

    SET @tempo=(SELECT TOP 1 T0.TRANSNUM FROM OINM T0 WHERE T0.[DocDate] >=[%0] AND T0.[DocDate] <=[%1])
    SET @dataInicio=(SELECT '[%0]')
    SET @dataFinal=(SELECT '[%1]')

    SELECT
    [Artículo]=t1.itemcode,
    Consumo=isnull(t1.consumo,0),
    [Consumo medio diario]=isnull(t1.consumo/datediff(day,@dataInicio,@dataFinal),0),
    [Stock inicial]=isnull(coalesce(t0.saldoinic,0),0),
    [Stock final]=isnull(coalesce(t0.saldoinic,0)+coalesce(t1.saldofin,0),0),
    [Stock promedio]= isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0),
    [Rotación stock]= case isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0) when 0 then 0 else isnull(t1.consumo / ((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2) ,0) end,
    [Cobertura de stock]= case isnull(coalesce(t1.consumo/datediff(day,@dataInicio,@dataFinal),0),0) when 0 then 0 else isnull(((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2)/ ( t1.consumo/datediff(day,@dataInicio,@dataFinal)),0) end
    FROM (
    SELECT
    a1.itemcode,
    saldoInic=isnull(sum(coalesce(s1.Inqty,0))-sum(coalesce(s1.outqty,0)),0)
    FROM OITM a1
    JOIN OINM s1 on a1.itemcode=s1.itemcode
    WHERE s1.docdate<@dataInicio
    GROUP BY a1.itemcode
    ) as t0
    RIGHT JOIN (
    SELECT
    a.itemcode,
    entradas=isnull(sum(s.Inqty),0),
    consumo=isnull(sum(s.outqty),0),
    saldoFin=isnull(sum(s.Inqty)-sum(s.outqty),0)
    FROM OINM s
    JOIN OITM a on a.itemcode=s.itemcode
    WHERE s.docdate BETWEEN @dataInicio and @dataFinal
    GROUP BY a.itemcode ) t1 on t1.itemcode=t0.itemcode

    ResponderEliminar
  58. Buenas tardes,
    El código me parece excelente. sin embargo yo no tengo SAP pero si un sistemita propio sobre el cual necesito implementar un reporte que me muestre los productos con lenta rotación. Serías tan amable de identificar las tablas para poder hacer la equivalencia con mis tablas.
    Básicamente manejo estas tablas: Productos, Cabecera_Movimiento, Detalle_movimiento, Saldos.

    Gracias

    Saludos

    Juan

    ResponderEliminar
  59. Hola Buen día, sé que la publicación es un poco antigua me base en todos los ejemplos que se aportaron en este post para darle forma a mi informe, agregue esta consulta por si alguien la requiere.

    [Indice de Rotación]= case isnull(coalesce((T1.consumo/12),0),0) when 0 then 0 else isnull(((coalesce(T0.saldoinic,0)+(coalesce(T0.saldoinic,0)+T1.saldofin))/2)/(T1.consumo/12),0) END,--(InventarioPromedio/VentasPromedio

    -->Ahora necesito hallar [Días de inventario] mediante la siguiente formula (365/Indice de Rotación, agradezco la colaboración mil gracias.

    ResponderEliminar
  60. Hola , alguien me puede explicar Porque en rotación de inventario me dan números mayores de 90 o 100 , su interpretación seria que hemos renovado 100 veces el stock durante un año? eso no es posible :s , alguien que me ayude por favor

    ResponderEliminar
  61. Buen día, tengo este código con la ayuda de todos ustedes pero me piden que genere con precios de costo específicamente con el Ultimo Precio de Compra (esta en la tabla OITM como LasPurPrc)

    declare @dataInicio datetime
    declare @dataFinal datetime
    declare @tempo int

    SET @tempo=(SELECT TOP 1 T0.TRANSNUM FROM OINM T0 WHERE T0.[DocDate] >=[%0] AND T0.[DocDate] <=[%1])
    SET @dataInicio=(SELECT '[%0]')
    SET @dataFinal=(SELECT '[%1]')


    SELECT DISTINCT

    [Codigo] = t1.itemcode,
    [Producto] = t1.Dscription,
    [Inv. Inicial] = isnull(coalesce(t0.saldoinic,0),0),
    [Compras] = isnull(coalesce(t1.entradas,0),0),
    [Consumo] = isnull(t1.consumo,0),
    [Consumo medio diario]=isnull(t1.consumo/datediff(day,@dataInicio,@dataFinal),0),
    [Stock promedio]= isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0),
    [Rotación stock]= case isnull((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2,0) when 0 then 0 else isnull(t1.consumo / ((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2) ,0) end,
    [Cobertura de stock]= case isnull(coalesce(t1.consumo/datediff(day,@dataInicio,@dataFinal),0),0) when 0 then 0 else isnull(((coalesce(t0.saldoinic,0)+(coalesce(t0.saldoinic,0)+t1.saldofin))/2)/ ( t1.consumo/datediff(day,@dataInicio,@dataFinal)),0) end,


    [Inv. Final] = isnull(coalesce(t0.saldoinic,0)+coalesce(t1.saldofin,0),0),
    [Costo] = --Costo Inventario Final
    (SELECT TOP 1 costo=isnull(coalesce(s2.Price,0),0)
    FROM OINM s2 JOIN OITM a2 on a2.itemcode=s2.itemcode
    WHERE s2.docdate<@dataFinal AND a2.itemcode=t1.itemcode AND s2.Price <> 0 AND s2.Transnum =
    (SELECT max(s3.Transnum)
    FROM OINM s3
    WHERE s3.docdate<@dataFinal and s2.itemcode=s3.itemcode AND s3.Price <> 0)
    GROUP BY a2.itemcode, s2.Price) * isnull(coalesce(t0.saldoinic,0)+coalesce(t1.saldofin,0),0)
    FROM (
    SELECT
    a1.itemcode,
    s1.Dscription,
    saldoInic=isnull(sum(coalesce(s1.Inqty,0))-sum(coalesce(s1.outqty,0)),0)
    FROM OITM a1 JOIN OINM s1 on a1.itemcode=s1.itemcode
    WHERE s1.docdate<@dataInicio and s1.Warehouse='[%3]'
    GROUP BY a1.itemcode, s1.Dscription
    ) as t0
    RIGHT JOIN (
    SELECT
    a.itemcode,
    s.Dscription,
    entradas=isnull(sum(s.Inqty),0),
    consumo=isnull(sum(s.Outqty),0),
    saldoFin=isnull(sum(s.Inqty)-sum(s.outqty),0),
    costo=isnull(sum(s.Price),0)
    FROM
    OINM s JOIN OITM a on a.itemcode=s.itemcode
    WHERE s.docdate BETWEEN @dataInicio and @dataFinal and s.Warehouse='[%3]'
    GROUP BY
    a.itemcode,
    s.Dscription
    ) t1 on t1.itemcode=t0.itemcode
    order by 2

    ResponderEliminar
  62. Hola buenos dias , me podrian ayudar por favor con un query que estoy realizando un inventario de ventas y proximos embarques ,al momento de agregar los proximos embarques se me duplica los valores ,de pronto mi inner join lo estoy realizando mal ,su ayuda por favor ,muchas gracias:
    SELECT distinct
    --T3."U_FAMILIA",T4."Name" AS "LINEA",T3."U_GRUPO",T5."U_EXX_NOMBRE"AS "GRUPO",
    --T3."U_SUBGRUPO",T6."U_EXX_NOMBRE",
    T2."ItemCode", T3."ItemName", T2."Venta", T2."OnHand",
    T2."Promedio",
    T2."LastPurPrc"--, (T2."OnHand"/T2."Promedio") AS "MDI",
    --,T3."U_R_FAMILIA",
    ,CASE T3."U_R_FAMILIA" WHEN '01' THEN 'HOSPITALARIO'
    WHEN '02' THEN 'INFANTIL'
    WHEN '03' THEN 'SERVICIOS'
    WHEN '04' THEN 'GASTOS(INSUMOS)'
    WHEN '05' THEN 'OTROS(JOSA)'
    WHEN '06' THEN 'ALIMENTOS'
    WHEN '07' THEN 'MEDICAMENTOS' END as "FAMILIA"
    --,T3."U_R_GRUPO"
    ,CASE T3."U_R_GRUPO" WHEN '01' THEN 'CURACIONES'END as "GRUPO"
    ,CASE T3."U_R_SUBGRUPO" WHEN '01' THEN 'GASA'END as "SUBGRUPO"
    ,CASE T3."U_R_CATEGORIA" WHEN '01' THEN 'COMPRESA'
    WHEN '02' THEN 'HOSPITALARIA'
    WHEN '03' THEN 'NON WOMEN'
    WHEN '04' THEN 'PARAFINA' END as "CATEGORIA",
    T8."PriceAtWH",T9."DocDate",t8."Quantity"
    ,T11."ShipDate",T11."Quantity"

    FROM (

    SELECT T0."ItemCode", T1."ItemName",
    SUM("OutQty"-"InQty")AS "Venta",
    ---sum("OutQty") AS "Venta",
    ROUND((SUM("OutQty"-"InQty")/6),0) As "Promedio",
    T1."OnHand" , T1."LastPurPrc"
    --T1."U_FAMILIA"
    FROM "OINM" T0
    INNER JOIN "OITM" T1 ON T0."ItemCode"=T1."ItemCode"
    ---left JOIN "IPF1" T4 ON T4."ItemCode" = T1."ItemCode"
    ---left JOIN "OIPF" T5 ON T5."DocEntry" = T4."DocEntry"
    WHERE
    --"DocDate" BETWEEN FechaInicio AND FechaFin
    --AND T1."ItemCode"='01ICESHERROL001'
    ---AND
    ---T1."U_FAMILIA"=:Linea

    --AND T1."U_GRUPO"=:Grupo
    ---AND
    "TransType" IN (13,15,14,16)
    AND T1."ItemCode"='01ICGAHERQUE005'
    and T1."U_R_SUBGRUPO"='01'
    and "DocDate" >= '20230101' and "DocDate" <= '20230620'
    --AND "Warehouse" IN ('GYE-A01', 'GYE-B01','GYE-C01','GYE-D01','GYE-F01','GYE-G01', 'GYE-RES')
    GROUP BY T0."ItemCode", T1."ItemName", T1."OnHand",T1."LastPurPrc"
    ,T1."U_FAMILIA"

    ORDER BY T1."ItemName") T2
    INNER JOIN OITM T3 ON T2."ItemCode"=T3."ItemCode"
    INNER JOIN "@EXX_FAMILIA" T4 ON T4."Code"=T3."U_FAMILIA"
    INNER JOIN "@EXX_GRUPO" T5 ON T5."Name"=T3."U_GRUPO"
    left JOIN "IPF1" T8 ON T8."ItemCode" = T3."ItemCode"
    left JOIN "OIPF" T9 ON T9."DocEntry" = T8."DocEntry"
    iNner joiN "OPOR" T10 on t10."DocEntry" = T9."DocEntry"
    inner join "POR1" t11 on t11."ItemCode" = T3."ItemCode"
    ---LEFT JOIN "@EXX_SUBGRUPO" T6 ON T6."Name"=T3."U_SUBGRUPO"

    ResponderEliminar