Módulo Item: mudanças entre as edições

De BIS Wiki
Ir para navegação Ir para pesquisar
 
(54 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 10: Linha 10:
** '''Estrutura Hierárquica:''' As categorias são uma estrutura hierárquica, isto é, permite que uma categoria seja adiciona dentro da outra.
** '''Estrutura Hierárquica:''' As categorias são uma estrutura hierárquica, isto é, permite que uma categoria seja adiciona dentro da outra.
** '''Nomes Únicos 'por Pai':''' Os nomes das categorias são únicos dentro do mesmo pai. Em outras palavras, os nomes das categorias só podem se repetir se estiverem em pontos diferentes da estrutura hierárquica.
** '''Nomes Únicos 'por Pai':''' Os nomes das categorias são únicos dentro do mesmo pai. Em outras palavras, os nomes das categorias só podem se repetir se estiverem em pontos diferentes da estrutura hierárquica.
** '''Tipo da Categoria:''' Toda categoria poderá ser de 2 tipos:
** '''Permite Itens:''' Esta opção define se os itens podem ser alocados nesta categoria ou não. Quando a opção estiver desmarcada nenhum código de item deverá ser definido nesta categoria. Esta função permite que um determinado tipo de item possa ser alocado nesta categoria, mas força que os itens tenham que ser alocados nas subcategorias.
*** '''Categoria:''' Uma categoria do tipo categoria permite que esta categoria tenha categorias filhas (subcategorias).
*** '''Grupo:''' Grupos funcionam praticamente como uma categoria do tipo categoria, a única exceção é que são categorias mais organizacionais ou para separar uma leva de produtos com configurações de Markups diferentes. Outro detalhe é que as categorias do tipo Grupo não aceitam sub categorias. O uso comum de categorias do tipo grupo são por exemplo: Dentro da categoria "Refrigerantes" podemos ter um agrupamento de "Latas" e outro de "PETs 2L". Ambos pertencem a refrigerante, mas é desejável definir Markups diferentes.
** '''Congelamento de Preços:''' Este atributo define se os preços dos itens nesta categoria devem permanecer congelados quando forem editados ou houver uma entrada de NFe.
** '''Congelamento de Preços:''' Este atributo define se os preços dos itens nesta categoria devem permanecer congelados quando forem editados ou houver uma entrada de NFe.
** '''Arredondamento de Preços:''' Permite definir uma regra de arredondamento dos preços de venda de todos os itens que estão nesta categoria. Uma vez definida, nenhum item deverá ter um preço diferente do arredondamento definido.
** '''Arredondamento de Preços:''' Permite definir uma regra de arredondamento dos preços de venda de todos os itens que estão nesta categoria. Uma vez definida, nenhum item deverá ter um preço diferente do arredondamento definido.
** '''Permite Itens:''' Esta opção define se os itens podem ser alocados nesta categoria ou não. Quando a opção estiver desmarcada nenhum código de item deverá ser definido nesta categoria. Esta função permite que um determinado tipo de item possa ser alocado nesta categoria, mas força que os itens tenham que ser alocados nas subcategorias.




* '''Validações Extras:'''
* '''Validações Extras:'''
** '''Categoria do tipo Grupo deve sempre aceitar que itens sejam associados.''' - A única ideia de uma categoria não aceitar associação de itens nela é para garantir que os tipos de itens sejam associados às suas subcategorias e não a ela própria. Se uma categoria for tipo Grupo ela não aceitará subcategorias. Logo, se ela não tiver subcategorias e não aceitar itens, não tem função nenhuma. ''[ve0001]''
** '''[ve0004] Validar a estrutura de uso por Itens e Tipo de Itens quando a categoria pai for alterada.''' - A categoria pai de uma categoria não pode ser alterada se algum item estiver associado à ela ou à alguma subcategoria enquanto que o seu tipo de item aponta para a categoria pai. Em outras palavras, caso ao alterar a categoria de posição na hierarquia se não invalidará as condições do tipo de item.
** '''Categoria do tipo Grupo não pode ser uma categoria raiz.''' - As categorias de grupo são categorias de "pouca importância", tem a finalidade apenas de permitir um agrupamento de produtos de uma categoria com a finalidade maior apenas de definir markups diferentes para aquele conjunto. Por isso não deve ser permitido que as categorias do tipo grupo sejam categorias de raiz.''[ve0002]''
** '''[ve0005] Hierarquia Cíclica.''' - Garantir que durante a atualização uma categoria não passa a apontar "como pai" uma categoria que está abaixo dela na hierarquia, criando um relacionamento cíclico.
** '''Categorias do tipo Grupo não devem ter subcategorias.''' - Durante o cadastro não é necessário validar, no entanto durante uma edição o usuário pode alterar o tipo da categoria. Neste caso é necessário validar se a categoria não tem subcategorias cadastradas no banco de dados. ''[ve0003]''
** '''[ve0007] Validar se temos exatamente 1 ItemCategoryCompanyVO por Empresa''' - Validar se o temos exatamente 1 definição de dados por empresa. Não devemos ter nem duplicadas, nem faltando. (BUG: 270)
** '''[ve0008] Categoria de Item Sendo Usado Por Código do Item, Tipo do Item ou outra Categoria de Item''' - Antes de excluir uma categoria é preciso confirmar se ela não está em uso por outro objeto. Ela pode estar em uso por um código de item (verificar se o Item está ativo), ser referenciada pelo Tipo de Item (também verificar se o mesmo está ativo) ou ser pai de outra categoria (que também precisa verificar se ainda esta ativa). Lembrando que essa validação não pode ser feita pelo BISValidator uma vez que o Item tem o "estado" apagado, e não é excluído fisicamente do banco de dados.
** '''[ve0010] Markup, Congelamento de Preços e Arredondamento de Preços são Obrigatórios quando a Categoria permite que itens sejam adicionados.''' - Validar se estão preenchidos quando a categoria permitir itens, validar se estão nulos quando a categoria não permitir itens. Quando a categoria não permitir itens, o campo MarkUp Mínimo também deve ser nulo.
 
= Tipo do Item =
 
O tipo do item tem a finalidade de agrupar todos os itens de um mesmo tipo. Entende-se por tipo de produto "o que o produto é", por exemplo: Refrigerante, Água, Suco, Pasta de Dente, Pão de Queijo, etc. Não faz parte do tipo a marca, embalagem, quantidades etc. Marca, quantidade, códigos, preços, etc. são parte do cadastro do Iten e não do tipo.
 
* '''Requisitos:'''
** '''Tipo do Item:''' O nome do tipo de item é usado para identificar o cadastro. Deve ser único.
** '''Prefixo:''' O prefixo é um "começo" da descrição, que será usada em todos os itens desse mesmo tipo. Ao forçar que todos os itens comecem com o mesmo prefixo ajuda na organização do cadastro do banco de dados.
** '''Descrição de Exemplo: ''' Cada tipo de item deve ter um espaço para orientar o usuário sobre quais as informações importantes para aquele tipo de produto, além de definir a ordem em que devem aparecer.
** '''Associação com Aliquota ICMS:''' No tipo do item devemos definir qual a alíquota de tributação do ICMS que deverá ser utilizada em todos os itens desse tipo. Centralizando e simplificando as configurações.
** '''Associação com As categorias:''' Cada tipo de item deve associar no mínimo uma categoria de itens. Cada item deste tipo deverá associar seus códigos nessas categorias ou suas subcategorias. O tipo de item pode permitir associação com mais de um "nó" da hierarquia da categoria. Permitindo assim que itens do mesmo tipo possam ser lançados em categorias diferentes. Como por exemplo um refrigerante com um código lançado na categoria de "Geladeiras/Loja" e outro código em "Restaurante/SelfService".
* '''Validações Extras:'''
** '''[ve0001] Categoria em Uso por Itens continua Disponível''' - Quando um tipo de item é alterado, é preciso validar se os itens desse tipo atualmente cadastrados não ficarão inválidos caso a categoria não esteja mais associada ao tipo de item. Ou seja, quando um item associado a esse tipo de item já estiver utilizando determinada categoria ela não pode ser excluída do tipo de item. <u>''Somente Atualização''</u>
** '''[ve0002] Alteração do Prefixo reflete nos itens existentes''' - Caso o prefixo seja alterado, todos os itens deste tipo de item devem ter seu nome atualizado de acordo com o novo prefixo. <u>''Somente Atualização''</u>
** '''[ve0003] Verifica Definições de Impostos para cada empresa''' - Verifica a definição dos impostos para cada empresa existente.
** '''[ve0004] Tipo e Alíquota no ECF igual à Alíquota Efetiva''' - Verifica se o tipo do ICMS definido no tipo de item e a alíquota efetiva do do cálculo é coerente com os valores cadastrados no objeto ICMSVO, usado no momento de venda do ECF.
** '''[ve0005] Natureza da Receita e Tabela são obrigatórios para os CSTs 02, 03, 04, 05, 06, 07, 08 e 09''' - Para todos esses CSTs, os campos de Natureza da Receita e Tabela ser validado.
** '''[ve0006] Verificar se a tabela é valida para o CST de Saída informado''' - Quando a tabela é informada, ela deve ser coerente com o código do CST de saída informado.
** '''[ve0007] Verificar se o Natureza é válida para a Tabela informada''' - Ao informar um código da Natureza da Receita o BIS deve verificar se o código da Receita é válido para a tabela sendo usada.
** '''[ve0008] Tipo de Item Sendo Usado no Momento''' - Antes de excluir o tipo de item é preciso verificar se ele não está em uso no momento. Lembrando que essa validação não pode ser feita pelo BISValidator uma vez que o Item tem o "estado" apagado, e não é excluído fisicamente do banco de dados.
 
= ICMS =
 
O objeto ICMS é a definição das alíquotas de ICMS utilizadas pelos Itens/Tipo de Itens. As alíquotas devem ser cadastradas conforme as alíquotas que a empresa utiliza.
 
* '''Requisitos:'''
** '''Tipo de Alíquota''' - As alíquotas podem ser de 3 tipos diferentes: Isento, Substituição e Tributada.
** '''Alíquota''' - A alíquota é a percentagem usado para calcular o valor do tributo. A alíquota quando definida é um valor positivo.
** '''Nome''' - As alíquotas devem ter um nome que facilite a identificação da alíquota para o usuário. Este nome deve ser único.
* '''Validações Extra:'''
** '''[ve0001] Definição Obrigatória da Alíquota quando o tipo for Tributado''' - A definição da alíquota é obrigatória sempre que o tipo for Tributada.
** '''[ve0002] Não definição da Alíquota para os tipos Isento e Substituição.''' - Para os tipos Isento e Substituição o valor da alíquota devem estar nulos.
** '''[ve0003] Em uso por algum tipo de item''' - durante a tentativa de exclusão, verificar se o ICMS não está em uso atualmente por algum Tipo de Item.
 
 
= ItemCodeGroup =
 
O Grupo de Código de Item tem a finalidade de agrupar diferentes códigos de itens e fazer com que SEMPRE tenham o mesmo preço de venda. Independente de custo, categorias markups, arredondamentos, etc. Uma vez que um preço de venda de um item for alterado, os demais vão segui-lo fielmente.
 
* '''Requisitos:'''
** '''Nome''' - Tudo grupo de código deve ter um nome para facilitar a identificação dos itens que fazem parte do grupo.
** '''Lista de Còdigos''' - Dentro de um mesmo grupo podem ser associados 0+ códigos de itens. Códigos de um mesmo item podem fazer parte do mesmo grupo.
** '''Sempre o mesmo preço de venda''' - Independente das diferentes configurações que um código de item pode ter dentro do mesmo grupo, como diferentes categorias, MarkUps, Custos, definições de arredondamento, package ratios, etc.. O preço de venda de todos os itens do grupo devem ter exatamente o mesmo valor. Mesmo que para isso tenha que desrespeitar qualquer outra regra do sistema (como arredondamento, ou cálculo de package, etc.)
* '''Validações Extra:'''
** '''[ve0001] Códigos de Itens já associados a outros grupos''' - Durante a inserção ou atualização, um grupo não deve permitir que um código de item já associado à outro grupo seja associado a este. Em outras palavras, um código de item não pode estar associado em mais de um grupo ao mesmo tempo.
 
= Item =
 
A entidade Item representa um produto qualquer da empresa. Esse produto por ser um insumo, uma matéria prima ou um produto de venda (ou revenda).
 
* '''Requisitos:'''
** '''Fixação do prefixo da descrição de acordo com o tipo do Item''' - Todo item deve ser de algum ''Tipo de Item''. Uma vez que o tipo de item esteja definido, a descrição do item obrigatoriamente deve começar com o valor do ''Prefixo'' definido no ''Tipo de Item''
** '''Obrigatoriedade da Marca ou da Descrição''' - Todo item deve ter preenchidos no mínimo um dos campos ''Marca'' ou ''Descrição''. Mesmo para produtos de fabricação própria, é recomendável definir a marca da empresa por questões de organização dos itens. Caso nenhum dos dois seja preenchido a descrição pode acabar sendo apenas o ''Prefixo'' do ''Tipo de Item''. Para Itens "genéricos", cuja marca não importa, pois em cada momento uma marca diferente é comprada ou usada, a marca não é necessária, mas uma descrição sim.
** '''Dimensão e Unidade de Medida Padrão''' - Todo item tem uma dimensão (Massa, Unidades, Volume, Cumprimento, etc.) e uma unidade de medida (Kg, Unidades, Litros, Metros, etc.) a que se refere o item. Essa unidade ajuda identifica a unidade de quantização padrão desse item. A unidade em que por padrão esse item é comprado, vendido e movimentado. Outras unidades diferentes para movimentar o mesmo item podem ser definidas em códigos diferentes.
** '''Custo''' - Todo Item tem um custo único padrão. Esse custo é sempre o mesmo, independente da empresa.
** '''Códigos dos Itens:'''
*** '''Múltiplos Códigos''' - Cada item pode ter mais que um código definido, ou seja, uma lista de códigos. Códigos são a maneira definir um modo quantidade, preço de venda, pacote, etc. de um determinado Item. Normalmente tem uma identificação única (e normalmente numérica, embora não obrigatória) para ser referenciada em terminais, notas, códigos de barras, etc. No entanto a identificação única não deve ser obrigatória. Um item pode ter um código para definir uma determinada quantidade de movimentação de entrada ou saída, ou simplesmente para definir uma nova unidade de medida. Por exemplo, produtos identificados hora por Kilos hora por Unidades.
*** '''Categoria do Item''' - De acordo com o ''Tipo de Item'' definido no Item, cada código do item deverá ser alocado em uma das categorias definidas no ''Tipo de Item''. Apesar de ser o mesmo código, cada um pode gerar venda em uma categoria diferente, ou utilizar o MarkUp diferentes de acordo com o definido em cada categoria.
* '''Validações Extras:'''
** '''[ve0001] Validar requisito de Obrigatoriedade entre Marca e Descrição''' - Um dos campos deve sempre ser preenchido.
** '''[ve0002] Validar inconsistência entre Fabricação do Produto e Origem do Item''' - Se o produto for de fabricação própria, ele não pode ter uma das opções de importado definida em Origem do Item.
** '''[ve0003] Validar finalidade do item''' - Todo item deve ter no mínimo 1 finalidade definida em seu cadastro.
** '''[ve0004] Preenchimento completo dos pesos e volumes das embalagens''' - Se algum campo for preenchido, ele deve ser preenchido por completo! Por exemplo, se o "Peso Drenado" for definido, obrigatoriamente sua unidade de medida deve ser preenchida, o mesmo para o caso contrário: se a unidade for definida, a quantidade também deverá ser!
** '''[ve0005] Não permite que um Item tenha dois códigos iguais definidos''' - Validar se o código sendo inserido/alterado não tem definido duas vezes o mesmo código.
** '''[ve0006] Os códigos de item só podem ser associados às categorias definidas no tipo de item''' - Validar se a categoria enviada no ItemCodeVO é uma das categorias disponibilizadas no ItemTypeVO associado ao ItemVO. Os códigos ficam limitados a usarem apenas as categorias permitidas de acordo com o tipo de item.
** '''[ve0007] Validar se a Categoria do Item permite a associação dos itens''' - Os códigos de itens não podem ser associados às categorias que não permitem a associação de itens.
** '''[ve0008] Validar Finalidade do Item''' - O campo de finalidade não pode ter alguns alguns valores de acordo os valores definidos nos outros campos, conforme as seguintes regras:
*** '''Revenda:''' Não pode ser definido quando o produto for de '''Fabricação Própria'''.
*** '''Produto Acabado:''' Não pode ser definido quando o produto for '''Produzido por Terceiros'''.
** '''[ve0009] Valida Item Próprio em Tipo de Substituição''' - Valida se o Item é de produção própria e está em um tipo de item com a tributação de ICMS definida como Substituição Tributária.
** '''[ve0010] Descrição do Item''' - Valida se a descrição do item é única entre os itens ativos no momento.
** '''[ve0011] Itens de Revenda não podem ser Descartáveis''' - Valida se o item tiver o propósito como revenda, não permite que seja do tipo descartável.
 
== Pacotes / Equivalência de Unidades ==
 
Um único item (<code>ItemVO</code>) do sistema pode ter diversos código (<code>ItemCodeVO</code>), chamados de pacotes. A ideia de pacotes é que o mesmo item possa ser vendidos em proporções ou embalagens diferentes, por exemplo, mini-coxinhas podem ser vendidas ao centro, por unidade, por quilo ou empacotadas em bandeijas.
 
Para resolver essa questão o item apresenta uma '''Régua de Equivalência''', que estabelece a relação de proporção de quantidades entre as diferentes gandezas. Por exemplo, define-se que a 1Und tem 30g e que 1 Bandeija tem 30 unidades. Deste ponto em diante o sistema saberá vender o item em bandeijas, unidades (e suas variações como pares, dúzias, etc.) ou quilo (e suas variações como gramas, toneladas, etc.).
 
 
Embora um item possa trabalhar com diferentes sistemas de unidades de medidas, uma unidade de medida principal e imutável é atribuída ao item. Esta unidade é a utilizada pelo sistema para concentrar as quantidades de estoque, relatórios de quantidade de vendas, etc.. Deve ser a unidade de medida que a empresa costuma utilizar no seu dia a dia para contabilizar os itens. Muitas vezes é considerada a menor unidade divísivel do item para evitar trabalhar com frações.
 
 
=== Fator de Conversão de Quantidade ===
 
Um conceito presa ser definido neste ponto: para efeitos de cálculo, criamos o '''Fator de Conversão de Quantidade''' ('''Quantity Conversion Factor''') ou '''qcFactor'''. Esse fator representa o multiplicador necessário para transformar a quantidade de um código (<code>ItemCodeVO</code>) na quantidade equivalente do item (<code>ItemCodeVO</code>), considerando suas unidades de medida e quantidade do pacote.
 
Esse fator é obtido a partir da seguinte equação verdade:
 
 
 
<pre>qtyItemVO = qcFactor * qtyItemCodeVO</pre>
 
 
Ou sua equivalente:
 
 
<pre>qtyItemCodeVO = qtyItemVO / qcFactor</pre>
 
 
 
 
{{nota|Em palavras...|Com o '''qcFactor'''  na mão, temos que:
 
'''''cada unidade vendida do código equivale "X" unidades vendidas do item''''',
 
ou mais precisamente:
 
'''''cada unidade vendida do código equivale "qcFactor" unidades vendidas do item'''''.}}
 
 
 
Assim, o valor de '''qcFactor''' é definido da seguinte forma:
 
<pre>fatorCQ = unitRatio * packageRatio</pre>
 
Onde:
* '''unitRatio''' - É a razão entre os fatores das unidades de medida do código e da unidade principal.
:* '''Exemplo:''' A unidade principal é Kilograma, e a do código é Gramas. Se o fator de Kilograma é 1, a de gramas será 1000, representando que 1Kg = 1000g. Neste caso '''unitRatio = 1/1000 = 0,001'''
* '''packageRatio''' - É a definição do usuário estabelecendo uma proporção de quantidade de venda do código.
 
 
==== Exemplo ====
 
O cadastro de '''Mini Coxinhas''' produzida pela empresa estabelece o seguinte:
* '''Unidade Principal:''' Definido em Kilos, pois o usuário entende que Kilos é a unidade mais usual para trabalhar (controlar estoque, custo, etc.)
* '''Relações de Grandezas:''' Para cobrir seus diferentes métodos de venda o usuário estabelece a seguinte relação de Grandezas:
:* '''1 Und = 30g''' - Define que 1 unidade de Mini Coxinha tem o tamanho de 30g.
:* '''1 Bandeja = 2 Dúzia''' - A unidade personalizada Bandeija equivale a 1 dúzia.
* '''Códigos de Vendas:'''
:* '''1 - Venda por Kilo:''' - Neste código o usuário define o tamanho do pacote em 1, a unidade 'Kilogram' e que o códigio é divisível.
:* '''2 - Venda por Cento:''' - Neste, define o tamanho do pacote em 1, a unidade em 'Centro' e que o código é indivisível.
:* '''3 - Venda por Unidade:''' - Neste, define o tamanho do pacote em 1, a unidade em 'Unidade' e que o código é indivisível.
:* '''4 - Venda por Bandeija:''' - Aqui, define o tamanho do pacote em 2, a unidade em 'Bandeija' e que o código é indivisível.
 
 
Em relação ao código para trabalhar com essas informações vamos dividir em partes:
 
 
{{java|Preparação da Régua e Definições|<syntaxhighlight lang="java">
 
 
    // Utilizamos a classe MeasureUtil para facilitar a criação da Régua e medidas
    MeasureRulerVO rulerVO = MeasureUtil.createSimpleMeasureRulerVO(BigDecimal.ONE, WEIGHTUNIT.KILOGRAM); // Cria a régua com a unidade principal, estabelecendo a razão 1
    MeasureUtil.fillSmartRuler(rulerVO, BigDecimal.ONE, UNITUNIT.UNIT, new BigDecimal("30"), WEIGHTUNIT.GRAM); // Estabelece que 1 unidade = 30 gramas
 
    // Unidade de medida personalizada, oferecida pelo sistema
    MeasureCustomVO measureCustomVO = new MeasureCustomVO();
    measureCustomVO.setCode("BDJ");
    measureCustomVO.setDescription("Bandeja");
 
    // Estabelece a relação da unidade personalizada com uma unidade presente na régua: 1BDJ = 1Dúzia
    MeasureEquivalenceVO equiVO = new MeasureEquivalenceVO();
    equiVO.setMeasureCustomVO(measureCustomVO);
    equiVO.setReferencequantity(new BigDecimal("2"));
    equiVO.setReferenceunit(UNITUNIT.DOZEN);
    equiVO.setMeasurerulervo(rulerVO);
    rulerVO.getMeasurerulerequivalencelist().add(equiVO);
 
 
</syntaxhighlight>}}
 
 
Uma vez que passamos as definições de proporções do <code>ItemCodeVO</code> para a <code>MeasureRulerVO</code>, conseguimos calcular o '''qcFactor''' facilmente com o método <code>MeasureUtil.convertTo(...)</code>. Para o cadastro exemplo acima:
 
{{java|Cálculo do qcFactor:|<syntaxhighlight lang="java">
 
 
    WEIGHTUNIT itemVOUnit = WEIGHTUNIT.KILOGRAM;
 
    // ----- Código 1 - Kilo
    WEIGHTUNIT itemCodeVOUnit1 = WEIGHTUNIT.KILOGRAM;
    BigDecimal packageRatio1 = BigDecimal.ONE;
 
    BigDecimal qcFactor1 = MeasureUtil.convertTo(rulerVO, packageRatio1, itemCodeVOUnit1, itemVOUnit);
    System.out.println("qcFactor 1:" + qcFactor1); // Saída: 1.0000000000
 
    // ----- Código 2 - Cento
    UNITUNIT itemCodeVOUnit2 = UNITUNIT.CENT;
    BigDecimal packageRatio2 = BigDecimal.ONE;
 
    BigDecimal qcFactor2 = MeasureUtil.convertTo(rulerVO, packageRatio2, itemCodeVOUnit2, itemVOUnit);
    System.out.println("qcFactor 2:" + qcFactor2); // Saída: 3.0000300003 (Imprecisão do cáculo por dízima)
 
    // ----- Código 3 - Unidade
    UNITUNIT itemCodeVOUnit3 = UNITUNIT.UNIT;
    BigDecimal packageRatio3 = BigDecimal.ONE;
 
    BigDecimal qcFactor3 = MeasureUtil.convertTo(rulerVO, packageRatio3, itemCodeVOUnit3, itemVOUnit);
    System.out.println("qcFactor 3:" + qcFactor3); // Saída: 0.0300003000 (Imprecisão do cáculo por dízima)
 
    // ----- Código 4 - Bandeja
    // A unidade de medida personalizada precisa ser encapsulada com o MeasureEquivalenceBean para utilizar na MeasureUtil.
    MeasureEquivalenceBean itemCodeVOUnit4 = new MeasureEquivalenceBean();
    itemCodeVOUnit4.setEquiVO(equiVO);
    BigDecimal packageRatio4 = new BigDecimal("1");
 
    BigDecimal qcFactor4 = MeasureUtil.convertTo(rulerVO, packageRatio4, itemCodeVOUnit4, itemVOUnit);
    System.out.println("qcFactor 4:" + qcFactor4); // Saída: 0.7200072001 (Imprecisão do cáculo por dízima)
 
</syntaxhighlight>}}
 
 
=== Fator de Conversão na Prática ===
 
 
Para calcular o custo do <code>ItemCodeVO</code> a partir do custo de <code>ItemVO</code>, precisamos considerar as definições de pacote e unidade de medida como visto no cálculo do '''Fator de Conversão de Quantidade''' acima. Devemos considerar que o '''custo por unidade de medida''' de <code>ItemVO</code> e de <code>ItemCodeVO</code> são os mesmos, apenas proporcionais às suas unidades de medida e quantidades de pacote, podemos utilizar o mesmo '''qcFactor'''.
 
 
A única questão é que são grandezas proporcionalmente invertidas, ou seja, '''quando maior a quantidade menor o custo''''' e vice-versa. No exemplo acima da Mini Coxinha, imaginemos que o o custo do Kilo seja de R$ 10,00. A unidade, que pesa 30g, teria um custo por unidade de R$ 0,30. Estabelecemos acima que o '''qcFactor''' da unidade é '''0.0300003000'''. Ao multiplicar a quantidade de <code>ItemCodeVO</code> pelo '''qcFactor''' chegamos na quantidade equivalente do <code>ItemVO</code>, neste caso, se temos o custo de <code>ItemCodeVO</code> teriamos que dividí-lo pelo mesmo '''qcFactor''' para chegar no custo de <code>ItemVO</code>. E na operação inversa, podemos multiplicar o custo de <code>ItemVO</code> para chegar o custo de <code>ItemCodeVO</code>. O que podemos resumir na seguinte tabela de conversão:
 
* ItemCodeVO.cost = ItemVO.cost * qcFactor
* ItemCodeVO.quantity = ItemVO.quantity / qcFactor
 
E sua inversão:
* ItemVO.cost = ItemCodeVO.cost / qcFactor
* ItemVO.quantity = ItemCodeVO.quantity * qcFactor
 
 
{{nota|Métodos Utilitários|A classe <code>ItemUtils</code> contém métodos para autilizar na criação da régua, conversões e cálculo do '''qcFactor'''.}}
 
 
{{stop|Convenção do qcFactor|
A definição do fator de conversão entre os objetos <code>ItemVO</code> e <code>ItemCodeVO</code> foi criada desde o príncio do sistema, e comumente chamada de '''divider'''. No entanto nunca foi respeitado a "direção" desse fator, em
partes do código '''divider &equals; qcFactor''', e, em outras, '''divider &equals; 1/qcFactor'''.
 
 
A criação da nomenclatura e definição dessa "direção" do fator tente a resolver essa confusão, facilitar a implementação e erros causados por essa misturança do cálculo em diferentes partes do sistema.
 
 
"Divider" continua presente em partes do código pois ele não foi compeltamente revisado. Mas a medida que novos códigos sejam criados ou revisados, é esperado que a nomenclatura 'divider' deixe de ser utilizada.
 
}}
 
== Definição do Preço de Venda ==
 
Há vários fatores sobre a lógica de calcular definir um novo preço de venda. Como as políticas de arredondamento, congelamento de preço, replicação do preço para outros códigos do mesmo grupo, a movimentação de novos preços para histórico, etc.
 
A ordem das operações lógicas a serem aplicadas sobre o ItemPriceVO devem ser conforme a ordem dos métodos listados abaixo. Cada método executa a operação a partir de um determinado ponto. Isso permite que diferentes eventos que causam a alteração do preço de venda possam acionar o ciclo a partir de diferentes pontos.
 
* '''Define um Novo preço de Venda para um Código''' - O início do processo. Quando um novo preço de venda deve ser definido em um código de item. Este passo utiliza o valor recebido as as definições do próprio ItemCode para realizar toda a sequência lógica do preço de venda.
*: '''updateItemPrice_Definition()''' - Método responsável por carregar as informações do ItemCodeVO e iniciar o processo definição do novo preço de venda do código.
 
 
* '''Aplicar Regras de Arredondamento''' - Dependendo das configurações da Categoria do Item definida no Código do Item, o preço precisará ser arredondado para respeitar essas políticas.
*: '''updateItemPrice_RoundApply()''' - Este método recebe o valor do novo preço e a política de arredondamento para aplicar as regras de arredondamento. Uma vez aplicado os arredondamentos o valor será passado para o próximo método da cadeia (o ''updateItemPrice_GroupDisseminate()'') para a efetivação em todos os grupos.
 
 
{{nota|Aplicação da Política|Para centralizar o código de aplicação da política, a efetiva aplicação do arredondamento fica na classe utilitária '''ItemUtils''' no método '''applyRoundPricePolicy()'''. Podendo ser acessado de qualquer ponto, como classes da UI.}}
 
 
* '''Disseminação do Preço de Venda pelo Grupo''' - Caso o ''ItemCode'' cujo preço de venda esteja sendo alterado faça parte de um grupo, este preço de venda deverá ser disseminado para todos os ''ItemCode'' do Grupo.
*: '''updateItemPrice_GroupDisseminate()''' - Avalia se o ''ItemCode'' cujo preço deve ser alterado faz parte de um grupo. Caso faça ele pesquisa todos os itens do grupo e chama o método '''updateItemPrice_Apply()''' todos os envolvidos. Este método não faz qualquer processamento no valor, apenas verifica os códigos envolvidos no grupo e aplica o valor, congelado ou não conforme informado via parâmetros). O valor será aplicado a todos do grupo conforme recebido, "passando por cima" das configurações de arredondamento e políticas de congelamento de cada código.
 
 
* '''Aplicação do Preço de Venda ao Objeto''' - Caso haja real alteração no ItemPriceVO uma cópia deve ser convertida para o ItemPriceHistoryVO e persistida. Por fim atualizar o ItemPriceVO na base de dados.
*: '''updateItemPrice_Apply()''' - Método responsável por atualizar as definições sobre o preço de venda (ItemPriceVO) de um ''Código de Item''. Este método recebe o novo valor, se o preço estará congelado, e outros atributos para identificação do ItemPriceVO correto (dependendo da assinatura). De acordo com os valores passados, este método avalia se haverá alteração das informações atuais, cria um novo objeto para o histórico de preços (ItemPriceHistoryVO) e salva os dados atuais. Em seguida faz as alterações necessárias ao ItemPriceVO e o persiste no banco.
*: '''Este é (e deve continuar sendo) o único método que fará a atualização do ItemPriceVO no banco de dados!'''
 
 
=== Eventos de Alteração do Preço de Venda ===
 
* '''Cadastro/Alteração de Itens''' - Quando um item é cadastrado ou alterado ele tem definições de códigos e consequentemente de preços de vendas. Neste caso avaliamos as seguintes condições para cada código:
** '''Não tem um grupo associado''' - Se não tem um grupo adicionado, temos que definir e processar o preço completamente. Chama o '''_Definition()'''
** '''Tem um grupo associado:'''
*** '''Devemos definir novos valores para o código e para o grupo''' - Se devemos associar novos valores para este novo código e para o grupo em que ele vai entrar, processamos o valor deste código completamente, e como a associação ao grupo é feita antes da definição dos preços, a lógica do updateItemPrice fará a disseminação deste valor nos outros códigos do grupo quando chegar no passo ''_GroupDisseminate()''. Chama o '''_Definition()'''
*** '''Devemos copiar o valor atual sendo praticado no grupo''' - Neste caso vamos buscar o valor de qualquer código do grupo (afinal devem ser todos iguais) e copiamos seus valores. Tanto o valor praticado, quanto um eventual valor que esteja congelado. Chama o '''_Apply()'''.
 
 
* '''Descongelar o Preço de Venda''' - Descongelar significa efetivar o preço que está congelado como o preço praticado para venda. Para evitar qualquer reprocessamento no valor, mas ainda assim garantir que o novo valor efetivo de venda será definido em todos os códigos do mesmo grupo este método chama o '''_GroupDisseminate()'''.
* '''Descartar Preço Congelado''' - Quando não queremos que o preço congelado entre em vigor podemos simplesmente descartar o preço congelado, e manter o código com o mesmo preço que já tinha. Neste caso queremos que todos os códigos do mesmo grupo descartem seu preço congelado e que continuem mantendo o preço já praticado. Para evitar o processamento dos valores mas ainda realizar a operação em todos os códigos do grupo chamamos o '''_GroupDisseminate()'''.
 
 
[[File:updateItemPriceFlow.png|frame|center|Diagrama do fluxo da lógica de alteração do preço de venda de um Código de Item. E entrada dos eventos que causam essas alterações.]]

Edição atual tal como às 13h42min de 20 de novembro de 2025

O módulo Item é o módulo responsável por cadastrar os itens de consumo, produtos de revenda, fabricação própria para venda ou consumo, etc. Este módulo oferecerá um cadastro com controle de preços, markups, custos, entre outras funcionalidades que servirão de suporte para diversos outros módulos, como PDV, Controle de Estoques, Base de Custos para Planilhas de Cálculos, etc.

Para oferecer todo o conceito o módulo é dividido nos seguintes cadastros:

Categoria do Item

A categoria do item tem a finalidade de organizar e agrupar os itens de acordo com suas categorias. Mutias vezes a categoria é o corredor em que as mercadorias são agrupadas, como "Bazar", "Açougue", "Produtos de Limpeza", etc.

  • Requisitos:
    • Estrutura Hierárquica: As categorias são uma estrutura hierárquica, isto é, permite que uma categoria seja adiciona dentro da outra.
    • Nomes Únicos 'por Pai': Os nomes das categorias são únicos dentro do mesmo pai. Em outras palavras, os nomes das categorias só podem se repetir se estiverem em pontos diferentes da estrutura hierárquica.
    • Permite Itens: Esta opção define se os itens podem ser alocados nesta categoria ou não. Quando a opção estiver desmarcada nenhum código de item deverá ser definido nesta categoria. Esta função permite que um determinado tipo de item possa ser alocado nesta categoria, mas força que os itens tenham que ser alocados nas subcategorias.
    • Congelamento de Preços: Este atributo define se os preços dos itens nesta categoria devem permanecer congelados quando forem editados ou houver uma entrada de NFe.
    • Arredondamento de Preços: Permite definir uma regra de arredondamento dos preços de venda de todos os itens que estão nesta categoria. Uma vez definida, nenhum item deverá ter um preço diferente do arredondamento definido.


  • Validações Extras:
    • [ve0004] Validar a estrutura de uso por Itens e Tipo de Itens quando a categoria pai for alterada. - A categoria pai de uma categoria não pode ser alterada se algum item estiver associado à ela ou à alguma subcategoria enquanto que o seu tipo de item aponta para a categoria pai. Em outras palavras, caso ao alterar a categoria de posição na hierarquia se não invalidará as condições do tipo de item.
    • [ve0005] Hierarquia Cíclica. - Garantir que durante a atualização uma categoria não passa a apontar "como pai" uma categoria que está abaixo dela na hierarquia, criando um relacionamento cíclico.
    • [ve0007] Validar se temos exatamente 1 ItemCategoryCompanyVO por Empresa - Validar se o temos exatamente 1 definição de dados por empresa. Não devemos ter nem duplicadas, nem faltando. (BUG: 270)
    • [ve0008] Categoria de Item Sendo Usado Por Código do Item, Tipo do Item ou outra Categoria de Item - Antes de excluir uma categoria é preciso confirmar se ela não está em uso por outro objeto. Ela pode estar em uso por um código de item (verificar se o Item está ativo), ser referenciada pelo Tipo de Item (também verificar se o mesmo está ativo) ou ser pai de outra categoria (que também precisa verificar se ainda esta ativa). Lembrando que essa validação não pode ser feita pelo BISValidator uma vez que o Item tem o "estado" apagado, e não é excluído fisicamente do banco de dados.
    • [ve0010] Markup, Congelamento de Preços e Arredondamento de Preços são Obrigatórios quando a Categoria permite que itens sejam adicionados. - Validar se estão preenchidos quando a categoria permitir itens, validar se estão nulos quando a categoria não permitir itens. Quando a categoria não permitir itens, o campo MarkUp Mínimo também deve ser nulo.

Tipo do Item

O tipo do item tem a finalidade de agrupar todos os itens de um mesmo tipo. Entende-se por tipo de produto "o que o produto é", por exemplo: Refrigerante, Água, Suco, Pasta de Dente, Pão de Queijo, etc. Não faz parte do tipo a marca, embalagem, quantidades etc. Marca, quantidade, códigos, preços, etc. são parte do cadastro do Iten e não do tipo.

  • Requisitos:
    • Tipo do Item: O nome do tipo de item é usado para identificar o cadastro. Deve ser único.
    • Prefixo: O prefixo é um "começo" da descrição, que será usada em todos os itens desse mesmo tipo. Ao forçar que todos os itens comecem com o mesmo prefixo ajuda na organização do cadastro do banco de dados.
    • Descrição de Exemplo: Cada tipo de item deve ter um espaço para orientar o usuário sobre quais as informações importantes para aquele tipo de produto, além de definir a ordem em que devem aparecer.
    • Associação com Aliquota ICMS: No tipo do item devemos definir qual a alíquota de tributação do ICMS que deverá ser utilizada em todos os itens desse tipo. Centralizando e simplificando as configurações.
    • Associação com As categorias: Cada tipo de item deve associar no mínimo uma categoria de itens. Cada item deste tipo deverá associar seus códigos nessas categorias ou suas subcategorias. O tipo de item pode permitir associação com mais de um "nó" da hierarquia da categoria. Permitindo assim que itens do mesmo tipo possam ser lançados em categorias diferentes. Como por exemplo um refrigerante com um código lançado na categoria de "Geladeiras/Loja" e outro código em "Restaurante/SelfService".
  • Validações Extras:
    • [ve0001] Categoria em Uso por Itens continua Disponível - Quando um tipo de item é alterado, é preciso validar se os itens desse tipo atualmente cadastrados não ficarão inválidos caso a categoria não esteja mais associada ao tipo de item. Ou seja, quando um item associado a esse tipo de item já estiver utilizando determinada categoria ela não pode ser excluída do tipo de item. Somente Atualização
    • [ve0002] Alteração do Prefixo reflete nos itens existentes - Caso o prefixo seja alterado, todos os itens deste tipo de item devem ter seu nome atualizado de acordo com o novo prefixo. Somente Atualização
    • [ve0003] Verifica Definições de Impostos para cada empresa - Verifica a definição dos impostos para cada empresa existente.
    • [ve0004] Tipo e Alíquota no ECF igual à Alíquota Efetiva - Verifica se o tipo do ICMS definido no tipo de item e a alíquota efetiva do do cálculo é coerente com os valores cadastrados no objeto ICMSVO, usado no momento de venda do ECF.
    • [ve0005] Natureza da Receita e Tabela são obrigatórios para os CSTs 02, 03, 04, 05, 06, 07, 08 e 09 - Para todos esses CSTs, os campos de Natureza da Receita e Tabela ser validado.
    • [ve0006] Verificar se a tabela é valida para o CST de Saída informado - Quando a tabela é informada, ela deve ser coerente com o código do CST de saída informado.
    • [ve0007] Verificar se o Natureza é válida para a Tabela informada - Ao informar um código da Natureza da Receita o BIS deve verificar se o código da Receita é válido para a tabela sendo usada.
    • [ve0008] Tipo de Item Sendo Usado no Momento - Antes de excluir o tipo de item é preciso verificar se ele não está em uso no momento. Lembrando que essa validação não pode ser feita pelo BISValidator uma vez que o Item tem o "estado" apagado, e não é excluído fisicamente do banco de dados.

ICMS

O objeto ICMS é a definição das alíquotas de ICMS utilizadas pelos Itens/Tipo de Itens. As alíquotas devem ser cadastradas conforme as alíquotas que a empresa utiliza.

  • Requisitos:
    • Tipo de Alíquota - As alíquotas podem ser de 3 tipos diferentes: Isento, Substituição e Tributada.
    • Alíquota - A alíquota é a percentagem usado para calcular o valor do tributo. A alíquota quando definida é um valor positivo.
    • Nome - As alíquotas devem ter um nome que facilite a identificação da alíquota para o usuário. Este nome deve ser único.
  • Validações Extra:
    • [ve0001] Definição Obrigatória da Alíquota quando o tipo for Tributado - A definição da alíquota é obrigatória sempre que o tipo for Tributada.
    • [ve0002] Não definição da Alíquota para os tipos Isento e Substituição. - Para os tipos Isento e Substituição o valor da alíquota devem estar nulos.
    • [ve0003] Em uso por algum tipo de item - durante a tentativa de exclusão, verificar se o ICMS não está em uso atualmente por algum Tipo de Item.


ItemCodeGroup

O Grupo de Código de Item tem a finalidade de agrupar diferentes códigos de itens e fazer com que SEMPRE tenham o mesmo preço de venda. Independente de custo, categorias markups, arredondamentos, etc. Uma vez que um preço de venda de um item for alterado, os demais vão segui-lo fielmente.

  • Requisitos:
    • Nome - Tudo grupo de código deve ter um nome para facilitar a identificação dos itens que fazem parte do grupo.
    • Lista de Còdigos - Dentro de um mesmo grupo podem ser associados 0+ códigos de itens. Códigos de um mesmo item podem fazer parte do mesmo grupo.
    • Sempre o mesmo preço de venda - Independente das diferentes configurações que um código de item pode ter dentro do mesmo grupo, como diferentes categorias, MarkUps, Custos, definições de arredondamento, package ratios, etc.. O preço de venda de todos os itens do grupo devem ter exatamente o mesmo valor. Mesmo que para isso tenha que desrespeitar qualquer outra regra do sistema (como arredondamento, ou cálculo de package, etc.)
  • Validações Extra:
    • [ve0001] Códigos de Itens já associados a outros grupos - Durante a inserção ou atualização, um grupo não deve permitir que um código de item já associado à outro grupo seja associado a este. Em outras palavras, um código de item não pode estar associado em mais de um grupo ao mesmo tempo.

Item

A entidade Item representa um produto qualquer da empresa. Esse produto por ser um insumo, uma matéria prima ou um produto de venda (ou revenda).

  • Requisitos:
    • Fixação do prefixo da descrição de acordo com o tipo do Item - Todo item deve ser de algum Tipo de Item. Uma vez que o tipo de item esteja definido, a descrição do item obrigatoriamente deve começar com o valor do Prefixo definido no Tipo de Item
    • Obrigatoriedade da Marca ou da Descrição - Todo item deve ter preenchidos no mínimo um dos campos Marca ou Descrição. Mesmo para produtos de fabricação própria, é recomendável definir a marca da empresa por questões de organização dos itens. Caso nenhum dos dois seja preenchido a descrição pode acabar sendo apenas o Prefixo do Tipo de Item. Para Itens "genéricos", cuja marca não importa, pois em cada momento uma marca diferente é comprada ou usada, a marca não é necessária, mas uma descrição sim.
    • Dimensão e Unidade de Medida Padrão - Todo item tem uma dimensão (Massa, Unidades, Volume, Cumprimento, etc.) e uma unidade de medida (Kg, Unidades, Litros, Metros, etc.) a que se refere o item. Essa unidade ajuda identifica a unidade de quantização padrão desse item. A unidade em que por padrão esse item é comprado, vendido e movimentado. Outras unidades diferentes para movimentar o mesmo item podem ser definidas em códigos diferentes.
    • Custo - Todo Item tem um custo único padrão. Esse custo é sempre o mesmo, independente da empresa.
    • Códigos dos Itens:
      • Múltiplos Códigos - Cada item pode ter mais que um código definido, ou seja, uma lista de códigos. Códigos são a maneira definir um modo quantidade, preço de venda, pacote, etc. de um determinado Item. Normalmente tem uma identificação única (e normalmente numérica, embora não obrigatória) para ser referenciada em terminais, notas, códigos de barras, etc. No entanto a identificação única não deve ser obrigatória. Um item pode ter um código para definir uma determinada quantidade de movimentação de entrada ou saída, ou simplesmente para definir uma nova unidade de medida. Por exemplo, produtos identificados hora por Kilos hora por Unidades.
      • Categoria do Item - De acordo com o Tipo de Item definido no Item, cada código do item deverá ser alocado em uma das categorias definidas no Tipo de Item. Apesar de ser o mesmo código, cada um pode gerar venda em uma categoria diferente, ou utilizar o MarkUp diferentes de acordo com o definido em cada categoria.
  • Validações Extras:
    • [ve0001] Validar requisito de Obrigatoriedade entre Marca e Descrição - Um dos campos deve sempre ser preenchido.
    • [ve0002] Validar inconsistência entre Fabricação do Produto e Origem do Item - Se o produto for de fabricação própria, ele não pode ter uma das opções de importado definida em Origem do Item.
    • [ve0003] Validar finalidade do item - Todo item deve ter no mínimo 1 finalidade definida em seu cadastro.
    • [ve0004] Preenchimento completo dos pesos e volumes das embalagens - Se algum campo for preenchido, ele deve ser preenchido por completo! Por exemplo, se o "Peso Drenado" for definido, obrigatoriamente sua unidade de medida deve ser preenchida, o mesmo para o caso contrário: se a unidade for definida, a quantidade também deverá ser!
    • [ve0005] Não permite que um Item tenha dois códigos iguais definidos - Validar se o código sendo inserido/alterado não tem definido duas vezes o mesmo código.
    • [ve0006] Os códigos de item só podem ser associados às categorias definidas no tipo de item - Validar se a categoria enviada no ItemCodeVO é uma das categorias disponibilizadas no ItemTypeVO associado ao ItemVO. Os códigos ficam limitados a usarem apenas as categorias permitidas de acordo com o tipo de item.
    • [ve0007] Validar se a Categoria do Item permite a associação dos itens - Os códigos de itens não podem ser associados às categorias que não permitem a associação de itens.
    • [ve0008] Validar Finalidade do Item - O campo de finalidade não pode ter alguns alguns valores de acordo os valores definidos nos outros campos, conforme as seguintes regras:
      • Revenda: Não pode ser definido quando o produto for de Fabricação Própria.
      • Produto Acabado: Não pode ser definido quando o produto for Produzido por Terceiros.
    • [ve0009] Valida Item Próprio em Tipo de Substituição - Valida se o Item é de produção própria e está em um tipo de item com a tributação de ICMS definida como Substituição Tributária.
    • [ve0010] Descrição do Item - Valida se a descrição do item é única entre os itens ativos no momento.
    • [ve0011] Itens de Revenda não podem ser Descartáveis - Valida se o item tiver o propósito como revenda, não permite que seja do tipo descartável.

Pacotes / Equivalência de Unidades

Um único item (ItemVO) do sistema pode ter diversos código (ItemCodeVO), chamados de pacotes. A ideia de pacotes é que o mesmo item possa ser vendidos em proporções ou embalagens diferentes, por exemplo, mini-coxinhas podem ser vendidas ao centro, por unidade, por quilo ou empacotadas em bandeijas.

Para resolver essa questão o item apresenta uma Régua de Equivalência, que estabelece a relação de proporção de quantidades entre as diferentes gandezas. Por exemplo, define-se que a 1Und tem 30g e que 1 Bandeija tem 30 unidades. Deste ponto em diante o sistema saberá vender o item em bandeijas, unidades (e suas variações como pares, dúzias, etc.) ou quilo (e suas variações como gramas, toneladas, etc.).


Embora um item possa trabalhar com diferentes sistemas de unidades de medidas, uma unidade de medida principal e imutável é atribuída ao item. Esta unidade é a utilizada pelo sistema para concentrar as quantidades de estoque, relatórios de quantidade de vendas, etc.. Deve ser a unidade de medida que a empresa costuma utilizar no seu dia a dia para contabilizar os itens. Muitas vezes é considerada a menor unidade divísivel do item para evitar trabalhar com frações.


Fator de Conversão de Quantidade

Um conceito presa ser definido neste ponto: para efeitos de cálculo, criamos o Fator de Conversão de Quantidade (Quantity Conversion Factor) ou qcFactor. Esse fator representa o multiplicador necessário para transformar a quantidade de um código (ItemCodeVO) na quantidade equivalente do item (ItemCodeVO), considerando suas unidades de medida e quantidade do pacote.

Esse fator é obtido a partir da seguinte equação verdade:


qtyItemVO = qcFactor * qtyItemCodeVO


Ou sua equivalente:


qtyItemCodeVO = qtyItemVO / qcFactor



Em palavras...
Com o qcFactor na mão, temos que:

cada unidade vendida do código equivale "X" unidades vendidas do item,

ou mais precisamente:

cada unidade vendida do código equivale "qcFactor" unidades vendidas do item.


Assim, o valor de qcFactor é definido da seguinte forma:

fatorCQ = unitRatio * packageRatio

Onde:

  • unitRatio - É a razão entre os fatores das unidades de medida do código e da unidade principal.
  • Exemplo: A unidade principal é Kilograma, e a do código é Gramas. Se o fator de Kilograma é 1, a de gramas será 1000, representando que 1Kg = 1000g. Neste caso unitRatio = 1/1000 = 0,001
  • packageRatio - É a definição do usuário estabelecendo uma proporção de quantidade de venda do código.


Exemplo

O cadastro de Mini Coxinhas produzida pela empresa estabelece o seguinte:

  • Unidade Principal: Definido em Kilos, pois o usuário entende que Kilos é a unidade mais usual para trabalhar (controlar estoque, custo, etc.)
  • Relações de Grandezas: Para cobrir seus diferentes métodos de venda o usuário estabelece a seguinte relação de Grandezas:
  • 1 Und = 30g - Define que 1 unidade de Mini Coxinha tem o tamanho de 30g.
  • 1 Bandeja = 2 Dúzia - A unidade personalizada Bandeija equivale a 1 dúzia.
  • Códigos de Vendas:
  • 1 - Venda por Kilo: - Neste código o usuário define o tamanho do pacote em 1, a unidade 'Kilogram' e que o códigio é divisível.
  • 2 - Venda por Cento: - Neste, define o tamanho do pacote em 1, a unidade em 'Centro' e que o código é indivisível.
  • 3 - Venda por Unidade: - Neste, define o tamanho do pacote em 1, a unidade em 'Unidade' e que o código é indivisível.
  • 4 - Venda por Bandeija: - Aqui, define o tamanho do pacote em 2, a unidade em 'Bandeija' e que o código é indivisível.


Em relação ao código para trabalhar com essas informações vamos dividir em partes:


Preparação da Régua e Definições
    // Utilizamos a classe MeasureUtil para facilitar a criação da Régua e medidas
    MeasureRulerVO rulerVO = MeasureUtil.createSimpleMeasureRulerVO(BigDecimal.ONE, WEIGHTUNIT.KILOGRAM); // Cria a régua com a unidade principal, estabelecendo a razão 1
    MeasureUtil.fillSmartRuler(rulerVO, BigDecimal.ONE, UNITUNIT.UNIT, new BigDecimal("30"), WEIGHTUNIT.GRAM); // Estabelece que 1 unidade = 30 gramas

    // Unidade de medida personalizada, oferecida pelo sistema
    MeasureCustomVO measureCustomVO = new MeasureCustomVO();
    measureCustomVO.setCode("BDJ");
    measureCustomVO.setDescription("Bandeja");

    // Estabelece a relação da unidade personalizada com uma unidade presente na régua: 1BDJ = 1Dúzia
    MeasureEquivalenceVO equiVO = new MeasureEquivalenceVO();
    equiVO.setMeasureCustomVO(measureCustomVO);
    equiVO.setReferencequantity(new BigDecimal("2"));
    equiVO.setReferenceunit(UNITUNIT.DOZEN);
    equiVO.setMeasurerulervo(rulerVO);
    rulerVO.getMeasurerulerequivalencelist().add(equiVO);


Uma vez que passamos as definições de proporções do ItemCodeVO para a MeasureRulerVO, conseguimos calcular o qcFactor facilmente com o método MeasureUtil.convertTo(...). Para o cadastro exemplo acima:

Cálculo do qcFactor:
    WEIGHTUNIT itemVOUnit = WEIGHTUNIT.KILOGRAM;

    // ----- Código 1 - Kilo
    WEIGHTUNIT itemCodeVOUnit1 = WEIGHTUNIT.KILOGRAM;
    BigDecimal packageRatio1 = BigDecimal.ONE;

    BigDecimal qcFactor1 = MeasureUtil.convertTo(rulerVO, packageRatio1, itemCodeVOUnit1, itemVOUnit);
    System.out.println("qcFactor 1:" + qcFactor1); // Saída: 1.0000000000

    // ----- Código 2 - Cento
    UNITUNIT itemCodeVOUnit2 = UNITUNIT.CENT;
    BigDecimal packageRatio2 = BigDecimal.ONE;

    BigDecimal qcFactor2 = MeasureUtil.convertTo(rulerVO, packageRatio2, itemCodeVOUnit2, itemVOUnit);
    System.out.println("qcFactor 2:" + qcFactor2); // Saída: 3.0000300003 (Imprecisão do cáculo por dízima)

    // ----- Código 3 - Unidade
    UNITUNIT itemCodeVOUnit3 = UNITUNIT.UNIT;
    BigDecimal packageRatio3 = BigDecimal.ONE;

    BigDecimal qcFactor3 = MeasureUtil.convertTo(rulerVO, packageRatio3, itemCodeVOUnit3, itemVOUnit);
    System.out.println("qcFactor 3:" + qcFactor3); // Saída: 0.0300003000 (Imprecisão do cáculo por dízima)

    // ----- Código 4 - Bandeja
    // A unidade de medida personalizada precisa ser encapsulada com o MeasureEquivalenceBean para utilizar na MeasureUtil.
    MeasureEquivalenceBean itemCodeVOUnit4 = new MeasureEquivalenceBean();
    itemCodeVOUnit4.setEquiVO(equiVO);
    BigDecimal packageRatio4 = new BigDecimal("1");

    BigDecimal qcFactor4 = MeasureUtil.convertTo(rulerVO, packageRatio4, itemCodeVOUnit4, itemVOUnit);
    System.out.println("qcFactor 4:" + qcFactor4); // Saída: 0.7200072001 (Imprecisão do cáculo por dízima)


Fator de Conversão na Prática

Para calcular o custo do ItemCodeVO a partir do custo de ItemVO, precisamos considerar as definições de pacote e unidade de medida como visto no cálculo do Fator de Conversão de Quantidade acima. Devemos considerar que o custo por unidade de medida de ItemVO e de ItemCodeVO são os mesmos, apenas proporcionais às suas unidades de medida e quantidades de pacote, podemos utilizar o mesmo qcFactor.


A única questão é que são grandezas proporcionalmente invertidas, ou seja, quando maior a quantidade menor o custo e vice-versa. No exemplo acima da Mini Coxinha, imaginemos que o o custo do Kilo seja de R$ 10,00. A unidade, que pesa 30g, teria um custo por unidade de R$ 0,30. Estabelecemos acima que o qcFactor da unidade é 0.0300003000. Ao multiplicar a quantidade de ItemCodeVO pelo qcFactor chegamos na quantidade equivalente do ItemVO, neste caso, se temos o custo de ItemCodeVO teriamos que dividí-lo pelo mesmo qcFactor para chegar no custo de ItemVO. E na operação inversa, podemos multiplicar o custo de ItemVO para chegar o custo de ItemCodeVO. O que podemos resumir na seguinte tabela de conversão:

  • ItemCodeVO.cost = ItemVO.cost * qcFactor
  • ItemCodeVO.quantity = ItemVO.quantity / qcFactor

E sua inversão:

  • ItemVO.cost = ItemCodeVO.cost / qcFactor
  • ItemVO.quantity = ItemCodeVO.quantity * qcFactor


Métodos Utilitários
A classe ItemUtils contém métodos para autilizar na criação da régua, conversões e cálculo do qcFactor.


Convenção do qcFactor

A definição do fator de conversão entre os objetos ItemVO e ItemCodeVO foi criada desde o príncio do sistema, e comumente chamada de divider. No entanto nunca foi respeitado a "direção" desse fator, em partes do código divider = qcFactor, e, em outras, divider = 1/qcFactor.


A criação da nomenclatura e definição dessa "direção" do fator tente a resolver essa confusão, facilitar a implementação e erros causados por essa misturança do cálculo em diferentes partes do sistema.


"Divider" continua presente em partes do código pois ele não foi compeltamente revisado. Mas a medida que novos códigos sejam criados ou revisados, é esperado que a nomenclatura 'divider' deixe de ser utilizada.


Definição do Preço de Venda

Há vários fatores sobre a lógica de calcular definir um novo preço de venda. Como as políticas de arredondamento, congelamento de preço, replicação do preço para outros códigos do mesmo grupo, a movimentação de novos preços para histórico, etc.

A ordem das operações lógicas a serem aplicadas sobre o ItemPriceVO devem ser conforme a ordem dos métodos listados abaixo. Cada método executa a operação a partir de um determinado ponto. Isso permite que diferentes eventos que causam a alteração do preço de venda possam acionar o ciclo a partir de diferentes pontos.

  • Define um Novo preço de Venda para um Código - O início do processo. Quando um novo preço de venda deve ser definido em um código de item. Este passo utiliza o valor recebido as as definições do próprio ItemCode para realizar toda a sequência lógica do preço de venda.
    updateItemPrice_Definition() - Método responsável por carregar as informações do ItemCodeVO e iniciar o processo definição do novo preço de venda do código.


  • Aplicar Regras de Arredondamento - Dependendo das configurações da Categoria do Item definida no Código do Item, o preço precisará ser arredondado para respeitar essas políticas.
    updateItemPrice_RoundApply() - Este método recebe o valor do novo preço e a política de arredondamento para aplicar as regras de arredondamento. Uma vez aplicado os arredondamentos o valor será passado para o próximo método da cadeia (o updateItemPrice_GroupDisseminate()) para a efetivação em todos os grupos.


Aplicação da Política
Para centralizar o código de aplicação da política, a efetiva aplicação do arredondamento fica na classe utilitária ItemUtils no método applyRoundPricePolicy(). Podendo ser acessado de qualquer ponto, como classes da UI.


  • Disseminação do Preço de Venda pelo Grupo - Caso o ItemCode cujo preço de venda esteja sendo alterado faça parte de um grupo, este preço de venda deverá ser disseminado para todos os ItemCode do Grupo.
    updateItemPrice_GroupDisseminate() - Avalia se o ItemCode cujo preço deve ser alterado faz parte de um grupo. Caso faça ele pesquisa todos os itens do grupo e chama o método updateItemPrice_Apply() todos os envolvidos. Este método não faz qualquer processamento no valor, apenas verifica os códigos envolvidos no grupo e aplica o valor, congelado ou não conforme informado via parâmetros). O valor será aplicado a todos do grupo conforme recebido, "passando por cima" das configurações de arredondamento e políticas de congelamento de cada código.


  • Aplicação do Preço de Venda ao Objeto - Caso haja real alteração no ItemPriceVO uma cópia deve ser convertida para o ItemPriceHistoryVO e persistida. Por fim atualizar o ItemPriceVO na base de dados.
    updateItemPrice_Apply() - Método responsável por atualizar as definições sobre o preço de venda (ItemPriceVO) de um Código de Item. Este método recebe o novo valor, se o preço estará congelado, e outros atributos para identificação do ItemPriceVO correto (dependendo da assinatura). De acordo com os valores passados, este método avalia se haverá alteração das informações atuais, cria um novo objeto para o histórico de preços (ItemPriceHistoryVO) e salva os dados atuais. Em seguida faz as alterações necessárias ao ItemPriceVO e já o persiste no banco.
    Este é (e deve continuar sendo) o único método que fará a atualização do ItemPriceVO no banco de dados!


Eventos de Alteração do Preço de Venda

  • Cadastro/Alteração de Itens - Quando um item é cadastrado ou alterado ele tem definições de códigos e consequentemente de preços de vendas. Neste caso avaliamos as seguintes condições para cada código:
    • Não tem um grupo associado - Se não tem um grupo adicionado, temos que definir e processar o preço completamente. Chama o _Definition()
    • Tem um grupo associado:
      • Devemos definir novos valores para o código e para o grupo - Se devemos associar novos valores para este novo código e para o grupo em que ele vai entrar, processamos o valor deste código completamente, e como a associação ao grupo é feita antes da definição dos preços, a lógica do updateItemPrice fará a disseminação deste valor nos outros códigos do grupo quando chegar no passo _GroupDisseminate(). Chama o _Definition()
      • Devemos copiar o valor atual sendo praticado no grupo - Neste caso vamos buscar o valor de qualquer código do grupo (afinal devem ser todos iguais) e copiamos seus valores. Tanto o valor praticado, quanto um eventual valor que esteja congelado. Chama o _Apply().


  • Descongelar o Preço de Venda - Descongelar significa efetivar o preço que está congelado como o preço praticado para venda. Para evitar qualquer reprocessamento no valor, mas ainda assim garantir que o novo valor efetivo de venda será definido em todos os códigos do mesmo grupo este método chama o _GroupDisseminate().
  • Descartar Preço Congelado - Quando não queremos que o preço congelado entre em vigor podemos simplesmente descartar o preço congelado, e manter o código com o mesmo preço que já tinha. Neste caso queremos que todos os códigos do mesmo grupo descartem seu preço congelado e que continuem mantendo o preço já praticado. Para evitar o processamento dos valores mas ainda realizar a operação em todos os códigos do grupo chamamos o _GroupDisseminate().


Diagrama do fluxo da lógica de alteração do preço de venda de um Código de Item. E entrada dos eventos que causam essas alterações.