Pedido - Reserva de produtos com Atributos

Grupo sobre o desenvolvimento/extensão das funcionalidades do Compiere / Adempiere onde é necessário alterar o código fonte.
kayado
Mensagens: 15
Registrado em: Ter Mar 15, 2011 11:13 pm

Pedido - Reserva de produtos com Atributos

Mensagempor kayado » Ter Mai 29, 2012 5:42 pm

Pessoal, estou com um problema na Ordem de Venda que preciso de ajuda para solucionar, não consegui encontrar um caminho que não tenha que alterar a forma como o sistema efetua reservas na M_Storage a partir de um pedido de vendas, pesquisei nos foruns e também não encontrei nada relevante.

Uso a branch kenos que esta no Mercurial + 360 lts com algumas customizações internas para adaptar a nossa realidade.

O problema ocorre quando preciso alterar a linha de um pedido que já efetuou a reserva de produtos na M_Storage, geralmente pedidos com status Em Progresso ou Re-Ativados, se altero a M_AttributeSetInstance_ID na C_OrderLine (nós usamos Lote e Validade para rastreabilidade de produtos), a mudança não reflete na M_Storage e quando completo a Remessa, é gerado uma qtyReserved negativa. Por Exemplo:

1. Completo um pedido de venda com 5 unidades do produto "A" e Instancia de Atributo "A1" (O produto possui dois lotes)
2. Minha M_Storage fica com dois registros para o produto:
M_Product_ID | M_AttributeSetInstance_ID| qtyOnHand | qtyReserved | qtyOrdered | M_Locator_ID
2000100 | 2000555 | 70 | 5 | 0 | 2000000
2000100 | 2000556 | 36 | 0 | 0 | 2000000
3. ReAtivo meu pedido e altero a Instancia de Atributo na linha do produto "A", mudo para "A2" e completo o pedido.
4. Ao completar a Remessa/Expedição a M_Storage fica assim:
M_Product_ID | M_AttributeSetInstance_ID| qtyOnHand | qtyReserved | qtyOrdered | M_Locator_ID
2000100 | 2000555 | 70 | 5 | 0 | 2000000
2000100 | 2000556 | 31 | -5| 0 | 2000000
5. A baixa é feita na instancia correta mas a reserva continua na instancia anterior

Analisei a customização da MOrder, MOrderLine, criar um callOut mas sempre encontro contras e excessões. Alguém já passou por este problema ou tem alguma idéia de como posso resolver esta questão?

Obrigado

Kaio Yoshida

paulo_dantas13
Mensagens: 226
Registrado em: Ter Ago 18, 2009 3:44 pm
Localização: Fortaleza/Ceará
Contato:

Re: Pedido - Reserva de produtos com Atributos

Mensagempor paulo_dantas13 » Qua Mai 30, 2012 11:20 am

Kaio Yoshida,

se você completou a venda na primeira situação com o produto A instância A1, você deve estornar a nota fiscal eletrônica, fatura, entrega e reativar o pedido, depois você altera a linha do pedido colocando a nova instância A2 e completar a venda.

Verifique se dá certo, pois acho que seja assim.

Espero ter ajudado.

Abraço.
--
Paulo Dantas O´grady Neto

kayado
Mensagens: 15
Registrado em: Ter Mar 15, 2011 11:13 pm

Re: Pedido - Reserva de produtos com Atributos

Mensagempor kayado » Qua Mai 30, 2012 12:16 pm

Bom dia Paulo, o problema ocorre justamente nesta situação, ao reativar o pedido e alterar a Instância de atributo para A2, o sistema não retira a reserva anterior (A1) e não inclui a reserve nova (A2).

Faz sentido porque na MOrder.reserveStock temos o seguinte código:

// Binding
BigDecimal target = binding ? line.getQtyOrdered() : Env.ZERO;
BigDecimal difference = target
.subtract(line.getQtyReserved())
.subtract(line.getQtyDelivered());
if (difference.signum() == 0)
{
MProduct product = line.getProduct();
if (product != null)
{
Volume = Volume.add(product.getVolume().multiply(line.getQtyOrdered()));
Weight = Weight.add(product.getWeight().multiply(line.getQtyOrdered()));
}
continue;
}

Onde o Adempiere trata sómente alterações de quantidade.

Acredito que o questão principal é comparar a M_AttributeSetInstance_ID Source (anterior) e Target (nova) e caso tenha diferença e a Source for maior que zero, remover a reserva da source e aplicar a nova reserva na target basado na QtyOrdered do documento.

Mas gostaria de saber se mais alguém passou por isso e conseguiu resolver de outra forma ou alguém que conheça melhor o sistema e o Java possa me indicar um caminho mais fácil.

Obrigado

Kaio

paulo_dantas13
Mensagens: 226
Registrado em: Ter Ago 18, 2009 3:44 pm
Localização: Fortaleza/Ceará
Contato:

Re: Pedido - Reserva de produtos com Atributos

Mensagempor paulo_dantas13 » Qui Mai 31, 2012 12:47 pm

Kaio,

o problema pode ser este mesmo, pois ele não leva em consideração o m_attributesetinstance_id.

Creio que isto ainda não foi resolvido no código, mas para desencargo de consciência, tente pegar a branch da kenos, LBR39 no mercurial e verifique se eles alteraram essa situação.

Abraço.
--
Paulo Dantas O´grady Neto

ralexsander
Mensagens: 579
Registrado em: Ter Nov 21, 2006 7:43 am
Localização: São Paulo
Contato:

Re: Pedido - Reserva de produtos com Atributos

Mensagempor ralexsander » Qui Mai 31, 2012 12:55 pm

Paulo,

A branch LBR-39 tem as modificações para transmissão de CC-e e não corrige este erro.

Kaio,

Sugiro abrir um ticket em: https://adempiere.atlassian.net/secure/Dashboard.jspa que eu tento resolver durante a próxima semana se sobrar algum tempo.

Abs!
Ricardo Alexsander Santana
http://www.kenos.com.br

kayado
Mensagens: 15
Registrado em: Ter Mar 15, 2011 11:13 pm

Re: Pedido - Reserva de produtos com Atributos

Mensagempor kayado » Qui Mai 31, 2012 1:35 pm

Criei o ticket "ADEMPIERE-124" na ferramenta, do tipo Bug e prioridade Major, esta na pendência da triagem para ser encaminhado.

Valeu Paulo e Ricardo, obrigado pela ajuda, se eu tiver sucesso aqui eu posto o código para validação.

Abçs

Kaio

mgrigioni
Mensagens: 483
Registrado em: Sex Jan 05, 2007 3:08 pm
Localização: Jacareí/SP

Re: Pedido - Reserva de produtos com Atributos

Mensagempor mgrigioni » Qui Mai 31, 2012 2:06 pm

kayado escreveu:Bom dia Paulo, o problema ocorre justamente nesta situação, ao reativar o pedido e alterar a Instância de atributo para A2, o sistema não retira a reserva anterior (A1) e não inclui a reserve nova (A2).

Faz sentido porque na MOrder.reserveStock temos o seguinte código:

// Binding
BigDecimal target = binding ? line.getQtyOrdered() : Env.ZERO;
BigDecimal difference = target
.subtract(line.getQtyReserved())
.subtract(line.getQtyDelivered());
if (difference.signum() == 0)
{
MProduct product = line.getProduct();
if (product != null)
{
Volume = Volume.add(product.getVolume().multiply(line.getQtyOrdered()));
Weight = Weight.add(product.getWeight().multiply(line.getQtyOrdered()));
}
continue;
}

Onde o Adempiere trata sómente alterações de quantidade.

Acredito que o questão principal é comparar a M_AttributeSetInstance_ID Source (anterior) e Target (nova) e caso tenha diferença e a Source for maior que zero, remover a reserva da source e aplicar a nova reserva na target basado na QtyOrdered do documento.

Mas gostaria de saber se mais alguém passou por isso e conseguiu resolver de outra forma ou alguém que conheça melhor o sistema e o Java possa me indicar um caminho mais fácil.

Obrigado

Kaio


O problema não é só isso.. a M_Storage é muito "bugada" com relação a QtyReserved e QtyOrdered, isso pq na C_OrderLine vc não atribui um localizador para a sua reserva, ou seja, vc coloca um pedido de uma camiseta do armazém loja 1.. porém o localizador padrão da loja 1 é patreleira 2.. Se vc trocar o localizador padrão para patreleira 3 na cadastro dos localizadores, e dai alterar o seu pedido, já bagunçou toda a sua M_Storage e suas quantidades reservadas...

Existem vários posts no fórum do adempiere sobre a M_Storage, mas parece que até hoje ninguém realmente analisou todos os problemas e corrigiu

kayado
Mensagens: 15
Registrado em: Ter Mar 15, 2011 11:13 pm

Re: Pedido - Reserva de produtos com Atributos

Mensagempor kayado » Qui Mai 31, 2012 4:15 pm

Me parece que o sistema não lida muito bem com estoque de produtos com atributos, como lido com produtos com Validade e Lote eu precisei fazer algumas customizações para lidar com o M_Locator_ID.

Inclusive neste caso da MOrder.reserveStock o sistema busca o M_Locator_ID na M_Storage e se não encontra, pega o default do produto, o que ao meu ver pode gerar problemas, no meu caso específico, eu precisei customizar o atributo como obrigatório na linha do pedido e criar um callout que busca automaticamente na M_Storage o Lote desponível com menor data de validade ao entrar com o produto, este callOut também insere na C_OrderLine o M_Locator_ID referente ao M_AttributeSetInstance_ID no inventário.

kayado
Mensagens: 15
Registrado em: Ter Mar 15, 2011 11:13 pm

Re: Pedido - Reserva de produtos com Atributos

Mensagempor kayado » Qui Mai 31, 2012 6:33 pm

Consegui resolver o problema e parece que esta OK, preciso completar mais alguns testcases mas a principio funcionou, ficou bem específico, não sei se serve para todos os casos.

A implementação ficou apenas no MOrder.reserveStock e eu inclui uma nova coluna M_AttributeSetInstanceTo_ID (integer, default 0), com os métodos get e set no Model do PO, na C_OrderLine para comparar com a M_AttributeSetInstance_ID, se os valores forem validos e distintos na comparação das duas colunas, eu chamo o MStorage.add para os dois Atributos de Instância. Segue o código completo:

Código: Selecionar todos

   private boolean reserveStock (MDocType dt, MOrderLine[] lines)
   {
      if (dt == null)
         dt = MDocType.get(getCtx(), getC_DocType_ID());

      //   Binding
      boolean binding = !dt.isProposal();
      //   Not binding - i.e. Target=0
      if (DOCACTION_Void.equals(getDocAction())
         //   Closing Binding Quotation
         || (MDocType.DOCSUBTYPESO_Quotation.equals(dt.getDocSubTypeSO())
            && DOCACTION_Close.equals(getDocAction()))
         ) // || isDropShip() )
         binding = false;
      boolean isSOTrx = isSOTrx();
      log.fine("Binding=" + binding + " - IsSOTrx=" + isSOTrx);
      //   Force same WH for all but SO/PO
      int header_M_Warehouse_ID = getM_Warehouse_ID();
      if (MDocType.DOCSUBTYPESO_StandardOrder.equals(dt.getDocSubTypeSO())
         || MDocType.DOCBASETYPE_PurchaseOrder.equals(dt.getDocBaseType()))
         header_M_Warehouse_ID = 0;      //   don't enforce

      BigDecimal Volume = Env.ZERO;
      BigDecimal Weight = Env.ZERO;

      //   Always check and (un) Reserve Inventory
      for (int i = 0; i < lines.length; i++)
      {
         MOrderLine line = lines[i];
         //   Check/set WH/Org
         if (header_M_Warehouse_ID != 0)   //   enforce WH
         {
            if (header_M_Warehouse_ID != line.getM_Warehouse_ID())
               line.setM_Warehouse_ID(header_M_Warehouse_ID);
            if (getAD_Org_ID() != line.getAD_Org_ID())
               line.setAD_Org_ID(getAD_Org_ID());
         }
         //   Binding
         BigDecimal target = binding ? line.getQtyOrdered() : Env.ZERO;
         BigDecimal difference = target
            .subtract(line.getQtyReserved())
            .subtract(line.getQtyDelivered());
         if (difference.signum() == 0 && !chkAttribute(line)) // add chkAttribute
         {
            MProduct product = line.getProduct();
            if (product != null)
            {
               Volume = Volume.add(product.getVolume().multiply(line.getQtyOrdered()));
               Weight = Weight.add(product.getWeight().multiply(line.getQtyOrdered()));
            }
            continue;
         }

         log.fine("Line=" + line.getLine()
            + " - Target=" + target + ",Difference=" + difference
            + " - Ordered=" + line.getQtyOrdered()
            + ",Reserved=" + line.getQtyReserved() + ",Delivered=" + line.getQtyDelivered());

         //   Check Product - Stocked and Item
         MProduct product = line.getProduct();
         if (product != null)
         {
            if (product.isStocked())
            {
               BigDecimal ordered = isSOTrx ? Env.ZERO : difference;
               BigDecimal reserved = isSOTrx ? difference : Env.ZERO;
               int M_Locator_ID = getLocator(line, product);
               //   Update Storage
               if (!updStorage(line, reserved, ordered, M_Locator_ID, line.getM_AttributeSetInstance_ID()))
                  return false;
            }   //   stockec
            
            // Release reserved if have an old Attribute
            // and update for the new one
            if (chkAttribute(line))
            {
               BigDecimal reserved = line.getQtyReserved();
               int M_Locator_ID = getLocator(line, product);
               //   Update Storage Old
               if (!updStorage(line, reserved.negate(), Env.ZERO, M_Locator_ID, line.getM_AttributeSetInstanceTo_ID()))
                  return false;
               //   Update Storage New
               if (!updStorage(line, reserved, Env.ZERO, M_Locator_ID, line.getM_AttributeSetInstance_ID()))
                  return false;
               //   Save the value of M_AttributeSetInstance_ID into M_AttributeSetInstanceTo_ID
               if (!updAttribute(line))
                  return false;
            }
            
            //   update line
            line.setQtyReserved(line.getQtyReserved().add(difference));
            if (!line.save(get_TrxName()))
               return false;
            //
            Volume = Volume.add(product.getVolume().multiply(line.getQtyOrdered()));
            Weight = Weight.add(product.getWeight().multiply(line.getQtyOrdered()));
         }   //   product
      }   //   reverse inventory

      setVolume(Volume);
      setWeight(Weight);
      return true;
   }   //   reserveStock


Voltar para “Desenvolvimento - Java”

Quem está online

Usuários neste fórum: Nenhum usuário registrado e 1 visitante