CREATE OR REPLACE PACKAGE PaqPromocion IS
  -- AV: Articulo Vinculado
  -- MM: Monto por Marca
  -- CN: Cliente Nuevo
  -- PG: Producto Gratis
  -- CG: Cliente Ganador
  -- CM: Cantidad Marca   
  PROCEDURE CalcularPromocion(pcia in char,Vsec in out number,psuc in char,pdoc in number,pmoneda in varchar2,
                              pporcimpcli in number,pcliente in varchar2,pcatalogo in varchar2,
                              plote in varchar2,pDDepartamento in varchar2,pPDepartamento in varchar2,ppor_imp_vta in number);
  Procedure ArticuloVinculado(ppromo in varchar2);
  Procedure ClienteNuevo(ppromo in varchar2);
  Procedure ProductoGratis(ppromo in varchar2);
  Procedure Volumen(ppromo in varchar2,pmoneda in varchar2,pporcimpcli in number,ptipo in char);
  Procedure ClienteGanador(ppromo in varchar2,pcliente in varchar2);
  Procedure CuponDescuento(ppromo in varchar2,pmoneda in varchar2,pporcimpcli in number);
  Procedure DatosArticulo(pcia in char,Vart  in varchar2,Vmedida in out varchar2,Vdepto in out varchar2,Vcodlinea in out varchar2,
                        Vcodmarca in out varchar2,Vimptovtas in out varchar2,Vimptocons in out varchar2,Vtipoinv in out varchar2,
                        Vdesarticulo in out varchar2,Verror in out varchar2);
  FUNCTION TipoInv(pCia in char, pArt  in varchar2) return varchar2;
  FUNCTION CatalogoActual(pcia in char) return varchar2; 
  FUNCTION CatalogoAusar(pcia in char,pfecha in date) return varchar2;
END;
/



CREATE OR REPLACE PACKAGE BODY PaqPromocion IS
   vcia       venpromocion.cia%type;
   Vsecuencia vendetpedido.secuencia%type;
   Vsuc       vendetpedido.sucursal%type;
   Vdoc       vendetpedido.documento%type;
   VDDepartamento varchar2(10);
   VPDepartamento varchar2(10);  
   Vimpuestovta   gen_impuesto.PORCENTAJE%type;

   FUNCTION TipoInv(pCia in char, pArt  in varchar2) return varchar2 is
      vTipoInv varchar2(3);
   BEGIN
      select tipo_inv
         into Vtipoinv
      from  inv_articulo
      where cod_cia       = pCia
      and   cod_articulo  = pArt;
      return vTipoinv;
   END;

   PROCEDURE DatosArticulo(pcia in char,Vart  in varchar2,Vmedida in out varchar2,Vdepto in out varchar2,Vcodlinea in out varchar2,
                        Vcodmarca in out varchar2,Vimptovtas in out varchar2,Vimptocons in out varchar2,Vtipoinv in out varchar2,
                        Vdesarticulo in out varchar2,Verror in out varchar2) IS
   BEGIN
	    Verror:=null;
      select medida, cod_depto, cod_linea, cod_marca, imptovtas,imptocons, tipo_inv, des_articulo
      into Vmedida, VDepto, Vcodlinea, Vcodmarca, Vimptovtas,Vimptocons, Vtipoinv, vdesarticulo
      from  inv_articulo
      where cod_cia       = pcia
      and   cod_articulo  = Vart;     
 
   Exception
    when others then
       Verror:='ARTICULO '||Vart||' '||UPPER(SQLERRM);
 
   END;

   Function ExisteCupon(ppromo in varchar2) return boolean is
      vexiste char(1);
   Begin
        select 'S' into vexiste
        from vendetpedido
        where cia=Vcia
        and  sucursal=Vsuc
        and  documento=Vdoc
        and  articulo=ppromo;
        return true;
     exception
     	when no_data_found then
     	  return false;
  End ExisteCupon;

  PROCEDURE CalcularPromocion(pcia in char,Vsec in out number,psuc in char,pdoc in number,pmoneda in varchar2,
                              pporcimpcli in number,pcliente in varchar2,pcatalogo in varchar2,
                              plote in varchar2,pDDepartamento in varchar2,pPDepartamento in varchar2,ppor_imp_vta in number) IS
    cursor promociones is
       select promocion, tipo
       from venpromocion
       where cia=vCia
       and rigedesde<=trunc(sysdate)
       and rigehasta>=trunc(sysdate)
       and (catalogo=pcatalogo or catalogo is null)
       and estado='A';
  Begin
     Vcia:=pCia;
     Vsecuencia:=Vsec;
     Vsuc      :=psuc;
     Vdoc      :=pdoc;
     VDDepartamento:=pDDepartamento;
     VPDepartamento:=pPDepartamento;
     Vimpuestovta:=ppor_imp_vta;
     for p in promociones
     loop
      	if p.tipo='AV' then
           ArticuloVinculado(p.promocion);
        elsif p.tipo in ('MM','CM','MA','CA') then
         	 Volumen(p.promocion, pmoneda, pporcimpcli, p.tipo);
        elsif p.tipo='CN' then
         	 if Catalogos.EsClienteNuevo(vCia, vSuc, pCliente)='S' then
              ClienteNuevo(p.promocion);
           end if;
        elsif p.tipo='CG' then
           ClienteGanador(p.promocion, pCliente);
        elsif p.tipo='PG' then
           ProductoGratis(p.promocion);
        elsif p.tipo='CD' then
           CuponDescuento(p.promocion, pmoneda, pporcimpcli);
        end if;
     end loop;
  End CalcularPromocion;

  Procedure RegistraFaltante(pPromo in varchar2, pRequisito in number, pGrupo in number, pRazon in number) is
  begin
  	 insert into venbitpedido
  	    (CIA, SUCURSAL, DOCUMENTO, PROMOCION, REQUISITO, GRUPO, RAZON)
  	 values (vCia, vSuc, vDoc, pPromo, pRequisito, pGrupo, pRazon);
  end;
  
  Procedure RegistraArticulo(pArt in varchar2, pReservado in out number, pCant in number default 1, Vlote in varchar2 default '001') is
    Vbod          vendetpedido.bodega%type;
    vsec          vendetpedido.secuencia%type;
    vcodlinea     inv_articulo.cod_linea%type;
    vimptovtas    inv_articulo.imptovtas%type;
    vimptocons    inv_articulo.imptocons%type;
    vmedida       inv_articulo.medida%type;
    vtipoinv      inv_articulo.tipo_inv%type;
    Vblqprecio    inv_deptos.blqprecios%type;
    Verror        varchar2(1024);
    Vdepto        inv_articulo.cod_depto%type;
    Vcodmarca     inv_articulo.cod_marca%type;
    vdesarticulo  inv_articulo.des_articulo%type;
 begin
  	PaqPromocion.DatosArticulo(Vcia,part,Vmedida,Vdepto,Vcodlinea,Vcodmarca,Vimptovtas,Vimptocons,Vtipoinv,vdesarticulo,Verror);
  	-- Registrar error
    VariosPed.DatosDep(Vcia, Vdepto, Vbod, Vblqprecio);
    Vbod:=VariosPed.CalculaBod(VDDepartamento,VPDepartamento, Vbod);
    pReservado:=VariosPed.Reserva(Vcia, Vtipoinv,part, Vbod, Vlote, 1, pCant, 0);
    if pReservado>0 then
     	 Vsecuencia:=Vsecuencia+1;
       venlevscan.insertaPedido(Vcia,Vsuc ,Vdoc ,vsecuencia,vlote,vbod, part,0,vmedida,pCant , pReservado , 0 ,0 ,0 ,0,0,0, Verror);
    end if;  
  end RegistraArticulo;

  Procedure RecalculaPrecios(pLista in varchar2, pPromo in varchar2, pRequisito in number, pMoneda in varchar2, pPorcimpcli in number,ptipo in char) is
     cursor detped is
    	  select a.articulo,a.porcdescuento,a.secuencia,a.cantidad
    	  from vendetpedido a,inv_articulo b
    	  where a.cia=Vcia
    	  and b.cod_cia=Vcia
    	  and a.sucursal=Vsuc
    	  and a.documento=Vdoc
    	  and a.precio>0
    	  and a.articulo=b.cod_articulo
    	  and b.cod_marca in (select distinct codigo from venreqpromocion
    	                      where cia=Vcia
                            and promocion=ppromo
                            and requisito=pRequisito);

     cursor detpeda is
    	  select a.articulo,a.porcdescuento,a.secuencia,a.cantidad
    	  from vendetpedido a,inv_articulo b
    	  where a.cia=Vcia
    	  and b.cod_cia=Vcia
    	  and a.sucursal=Vsuc
    	  and a.documento=Vdoc
    	  and a.precio>0
    	  and a.articulo=b.cod_articulo
    	  and b.cod_marca in (select distinct a.cod_marca 
    	                      from inv_articulo a,venreqpromocion b
    	                      where a.cod_cia=Vcia 
    	                      and   b.cia=Vcia
    	                      and   a.cod_articulo=b.codigo
                            and   b.promocion=ppromo
                            and   b.requisito=pRequisito);
     varticulo     vendetpedido.articulo%type;
     vporcdescto   vendetpedido.porcdescuento%type;
     vsecuencia    vendetpedido.secuencia%type;
     vcantidad     vendetpedido.cantidad%type;
     vprecio       vendetpedido.precio%type;
     vcodlinea     inv_articulo.cod_linea%type;
     vimptovtas    inv_articulo.imptovtas%type;
     vimptocons    inv_articulo.imptocons%type;
     vmedida       inv_articulo.medida%type;
     vtipoinv      inv_articulo.tipo_inv%type;
     Verror        varchar2(1024);
     Vdepto        inv_articulo.cod_depto%type;
     Vcodmarca     inv_articulo.cod_marca%type;
     Vpor_imptovta number(14,2);
     Vtotallinea   vendetpedido.totallinea%type;
     Vimpuesto     vendetpedido.impuesto%type;
     vdesarticulo  inv_articulo.des_articulo%type;
  begin
   	 if ptipo in ('MM','CM') then
   	 	  open detped;
   	 else
   	 	  open detpeda;
   	 end if;
     loop   	    	 
       if ptipo in ('MM','CM') then
     	 	  fetch detped into Varticulo,Vporcdescto,Vsecuencia,Vcantidad;
         exit when detped%notfound;
       else
     	 fetch detpeda into Varticulo,Vporcdescto,Vsecuencia,Vcantidad;
         exit when detpeda%notfound;
       end if;
       PaqPromocion.DatosArticulo(Vcia,Varticulo,Vmedida,Vdepto,Vcodlinea,Vcodmarca,Vimptovtas,Vimptocons,Vtipoinv,vdesarticulo,Verror);
       Vprecio:=Precios.PrecioLista(Vcia, pLista, Varticulo, pMoneda);
       Vprecio:=Precios.PrecioNeto(Vcia,vprecio,Vcodlinea, pMoneda);
       Vpor_imptovta:=Precios.ObtImpuesto(VCia, Vimptovtas, Vimpuestovta);
       VariosPed.CalculaTotales(VPrecio, Vcantidad,Vporcdescto, Vpor_imptovta,pporcimpcli,VTotalLinea, Vimpuesto);
       if Vprecio is not null then
          update vendetpedido
             set precio=Vprecio,
                 impuesto=Vimpuesto,
                 totallinea=Vtotallinea
          where cia=Vcia
          and sucursal=Vsuc
          and documento=Vdoc
          and secuencia=Vsecuencia;
       end if;
        -- Calcular Precios
     end loop;
   	 if ptipo in ('MM','CM') then
   	 	  close detped;
   	 else
   	 	  close detpeda;
   	 end if;
  end RecalculaPrecios;

  Function RazonRequisito(pPromo in varchar2, pRequisito in number) return number is
     cursor requisitos is
        select distinct grupo
        from venreqpromocion 
        where cia=vCia
        and promocion=pPromo
        and requisito=pRequisito;
     vRazon    number(14,4):=0;
     vTotal    number(14,4):=99999;
  begin
  	 for r in requisitos
  	 loop
  	 	  select sum(decode(req.cantidad, 0, ped.cantidad, ped.cantidad/req.cantidad))
  	 	     into vRazon
  	 	  from venreqpromocion req, vendetpedido ped
  	 	  where req.cia=vCia
  	 	    and req.promocion=pPromo
  	 	    and req.requisito=pRequisito
  	 	    and req.grupo=r.grupo
  	 	    and ped.cia=vCia
  	 	    and ped.sucursal=vSuc
  	 	    and ped.documento=vDoc
  	 	    and ped.articulo=req.codigo;
  	 	  vTotal:=Least(vTotal, nvl(vRazon,0));
  	 end loop;
  	 return vTotal;
  end RazonRequisito;

  Procedure AutorizaArticulo(pArt in varchar2, pRazon in out number, pCant in number default 1) is
  	 cursor detped is
  	    select secuencia, bodega, lote, cantidad, reservado
  	    from vendetpedido
        where cia=Vcia
        and sucursal=Vsuc
        and documento=Vdoc
   	    and articulo=pArt;
   	 vSaldo  number(14,4):=pCant;
   	 vMaxr   number(14,4);
   	 vResv   number(14,4);
  begin
     for a in detped
     loop
        vMaxr:=least(vSaldo, a.cantidad-a.reservado);
        vResv:=VariosPed.Reserva(Vcia, Tipoinv(vCia, pArt), pArt, a.bodega, a.lote, 1, a.reservado+vMaxr, a.reservado);
     	  update vendetpedido
     	     set reservado=reservado+vResv
        where cia=Vcia
        and sucursal=Vsuc
        and documento=Vdoc
   	    and secuencia=a.secuencia;
   	    vSaldo:=vSaldo-vResv;
   	    exit when vSaldo<1;
     end loop;
     if vSaldo=0 or pCant=0 then
     	  pRazon:=0;
     else
     	  pRazon:=vSaldo/pCant;
     end if;
  end AutorizaArticulo;

  Procedure AutorizaCompra(pPromo in varchar2, pRequisito in number, pRazon in number) is

     cursor grupocompra is
        select distinct grupo
        from venadipromocion
        where cia=Vcia
        and promocion=ppromo
        and requisito=pRequisito;

     cursor productocompra(pGrupo in number) is
        select codigo, cantidad
        from venadipromocion
        where cia=vCia
        and promocion=pPromo
        and requisito=pRequisito
        and grupo=pGrupo;

     vRazon     number(14,4);
  begin
     for gc in grupocompra
     loop
        vRazon:=pRazon;
    	  for pc in productocompra(gc.grupo)
    	  loop
           AutorizaArticulo(pc.codigo, vRazon, trunc(pc.cantidad*vRazon));
           exit when vRazon<=0;
    	  end loop;
     end loop;
  end AutorizaCompra;

  Procedure LiberaReserva(pPromo in varchar2, pRequisito in number) is
  begin
  	 update vendetpedido
  	    set reservado=0
     where cia=Vcia
     and sucursal=Vsuc
     and documento=Vdoc
   	 and articulo in (select codigo from venadipromocion
    	                where cia=Vcia
                      and promocion=ppromo
                      and requisito=pRequisito);
  end LiberaReserva;

  Procedure ArticuloVinculado(pPromo in varchar2) is

     cursor reqcompra is
        select distinct requisito
        from venadipromocion
        where cia=Vcia
        and promocion=ppromo;

     vRazon       number(14,4);
  begin
     for rc in reqcompra
     loop
     	  vRazon:=RazonRequisito(pPromo, rc.requisito);
     	  -- Liberar reserva no seria necesario si al inicio no se reservan los vinculados
     	  LiberaReserva(pPromo, rc.requisito);
     	  AutorizaCompra(pPromo, rc.requisito, vRazon);
  	 end loop;
  end ArticuloVinculado;

  Function Premios(pPromo in varchar2, pRequisito in number, pRazon in number) return number is

     cursor grupoganador is
        select distinct grupo
        from venadipromocion
        where cia=Vcia
        and promocion=ppromo
        and requisito=pRequisito;

     cursor productogratis(pGrupo in number) is
        select codigo, cantidad
        from venadipromocion
        where cia=vCia
        and promocion=pPromo
        and requisito=pRequisito
        and grupo=pGrupo;

     vReservado vendetpedido.cantidad%type:=0;
     vEntregado vendetpedido.cantidad%type:=0;
     vMaxr      vendetpedido.cantidad%type:=0;
     vRazon     number(14,4);
  begin  
     vEntregado:=0;
     for gg in grupoganador
     loop
     	  vRazon:=pRazon;
    	  for pg in productogratis(gg.grupo)
    	  loop
           vMaxr:=trunc(pg.cantidad*vRazon);
           RegistraArticulo(pg.codigo, Vreservado, vMaxr);
           if vMaxr=0 then
           	  vRazon:=0;
           else
              vRazon:=(vMaxr-Vreservado)/vMaxr;
           end if;
           exit when vRazon<=0;
    	  end loop;
    	  if vRazon>=1 then
           RegistraFaltante(pPromo, pRequisito, gg.Grupo, vRazon);
        end if;
    	  vEntregado:=vEntregado+nvl(vReservado, 0);
     end loop;
     return vEntregado;
  end Premios;

  Procedure ClienteNuevo(pPromo in varchar2) is
     vReservado vendetpedido.cantidad%type;
  begin
  	 vReservado:=Premios(pPromo, 1, 1);
  end ClienteNuevo;

  Procedure ProductoGratis(ppromo in varchar2) is
     cursor reqgratis is
        select distinct requisito
        from venadipromocion
        where cia=Vcia
        and promocion=ppromo;

     vRazon       number(14,4);
     vReservado   vendetpedido.totallinea%type;
  begin
     for rg in reqgratis
     loop
     	  vRazon:=RazonRequisito(pPromo, rg.requisito);
     	  vReservado:=Premios(pPromo, rg.requisito, vRazon);
     end loop;
  end ProductoGratis;

  Function TotalRequisito(pPromo in varchar2, pTipo in varchar2, pRequisito in number) return number is
     cursor requisitos is
        select distinct grupo
        from venreqpromocion
        where cia=vCia
        and promocion=pPromo
        and requisito=pRequisito;
     vCangrupo   number(14,4):=0;
     vCanreq     number(14,4):=9999999;
  begin
  	 for r in requisitos
  	 loop
  	 	  if ptipo in ('CM','MM') then
      	  select sum(decode(ptipo,'CM',a.cantidad,a.totallinea))
      	     into vCangrupo
      	  from vendetpedido a, inv_articulo b
    	    where a.cia=Vcia
    	    and b.cod_cia=Vcia
    	    and a.sucursal=Vsuc
    	    and a.documento=Vdoc
    	    and a.articulo=b.cod_articulo
    	    and b.cod_marca in (select codigo from venreqpromocion
        	                  where cia=vCia
                            and promocion=pPromo
                            and requisito=pRequisito
                            and grupo=r.grupo);
  	 	  elsif ptipo in ('CA','MA') then 	  	
    	    select sum(decode(ptipo,'CA',a.cantidad,a.totallinea))
    	       into vCangrupo
    	    from vendetpedido a
    	    where a.cia=Vcia
    	    and a.sucursal=Vsuc
    	    and a.documento=Vdoc
    	    and a.articulo in (select codigo from venreqpromocion
          	                  where cia=vCia
                              and promocion=pPromo
                              and requisito=pRequisito
                              and grupo=r.grupo);
        end if;
        vCanreq:=least(vCanreq, nvl(vCangrupo, 0));
  	 end loop;
  	 return vCanreq;
  end TotalRequisito;


  Procedure Volumen(pPromo in varchar2, pMoneda in varchar2, pPorcimpcli in number, pTipo in char) is
      cursor requisitos is
        select requisito,valor
        from venprepromocion
        where cia=Vcia
        and promocion=pPromo
        order by valor desc;

     cursor ListaPrecios(pReq in number, pCant in number) is
        select lista_precio
        from venprepromocion
        where cia=vCia
        and promocion=pPromo
        and requisito=Preq
        and valor<=pcant
        order by valor desc;


     vCanreq      vendetpedido.totallinea%type;
     vLista       venprepromocion.lista_precio%type:=null;
     vEntregado   vendetpedido.cantidad%type:=0;
  begin
    for r in requisitos
    loop
     vCanreq:=TotalRequisito(pPromo, pTipo, r.requisito);
     if nvl(vCanreq, 0)>0 then
        vlista:=null;
        open ListaPrecios(r.requisito, vCanreq);
        fetch ListaPrecios into vLista;
        close ListaPrecios;
        if vLista is not null then
           -- Ojo obliga a que lista sea NO nula...
           -- Si se quisiera que lista pueda ser nula
           -- Hay que probar entrega de premios con otra variable
           RecalculaPrecios(vLista, pPromo, r.requisito, pMoneda, pPorcimpcli,ptipo);
           vEntregado:=Premios(pPromo, r.requisito, 1);
           exit;
        end if; 
        -- Puede que haya producto adicional solamente sin lista de precios
     end if;
    end loop;
  end Volumen;


  Procedure ClienteGanador(pPromo in varchar2, pCliente in varchar2) is

     cursor requisitos is
        select distinct requisito
        from venreqpromocion
        where cia=Vcia
        and promocion=ppromo
        and codigo=pCliente;

     vEntregado vendetpedido.cantidad%type:=0;

  begin
     for r in requisitos
     loop
   	    vEntregado:=Premios(pPromo, r.requisito, 1);
        if vEntregado>0 then
     	     delete venreqpromocion
           where cia=Vcia 
             and promocion=pPromo
             and codigo=pCliente
             and requisito=r.requisito;
        end if;
  	 end loop;  
  end ClienteGanador;

  Procedure CuponDescuento(pPromo in varchar2, pMoneda in varchar2, pPorcimpcli in number) is
  Begin
  	 -- Paso1: xxx falto esto Verificar que pPromo esta en la lista de articulos de vendetpedido
     if ExisteCupon(ppromo) then	  
       Volumen(pPromo, pMoneda, pPorcimpcli, 'CM');
       -- Paso3: borro el cupon (Ojo que talves sea mejor dejarlo)
       delete vendetpedido
       where cia=Vcia
       and  sucursal=Vsuc
       and  documento=Vdoc
       and  articulo=ppromo;
     end if;
  End CuponDescuento;

  FUNCTION CatalogoActual(pcia in char) return varchar2 IS
    cursor catactual is
       select catalogo, max(fecha) fecmax
       from vencatalogo
       where cia=Pcia
          and fecharige<=trunc(sysdate)
          and tipo='C'
          and catalogo in
          (select distinct catalogo from vendetcatalogo
              where cia=Pcia)
        group by catalogo
        order by 2 desc;
     vcatalogo vencatalogo.catalogo%type;  
     vfecha    vencatalogo.fecha%type;
  BEGIN
     Open catactual;
     fetch catactual into vcatalogo,vfecha;
     close catactual;
     return vcatalogo;
  END;

  FUNCTION CatalogoAusar(pcia in char,pfecha in date) return varchar2 IS
    cursor catactual is
       select catalogo, max(fecha) fecmax
       from vencatalogo
       where cia=Pcia
          and fecharige<=trunc(pfecha)
          and tipo='C'
          and catalogo in
          (select distinct catalogo from vendetcatalogo
              where cia=Pcia)
        group by catalogo
        order by 2 desc;
     vcatalogo vencatalogo.catalogo%type;  
     vfecha    vencatalogo.fecha%type;
  BEGIN
     Open catactual;
     fetch catactual into vcatalogo,vfecha;
     close catactual;
     return vcatalogo;
  END;  


END;
/
