PDV: mudanças entre as edições

De BIS Wiki
Ir para navegação Ir para pesquisar
Linha 16: Linha 16:


Assim, este relatório tem a intenção de sumarizar essas quantidades para análise de vendas, cancelamentos, erros, falhas, etc.
Assim, este relatório tem a intenção de sumarizar essas quantidades para análise de vendas, cancelamentos, erros, falhas, etc.
* '''Caminho do Relatório:''' Caixa/PDV > Analítico > Finalizações de Vendas
* '''Campos de Filtros:'''
** '''Periodo''' - Filtrar o relatório por um período de datas
** '''Status''' - Campo ComboBoxMultiSelect com as opções do status possíveis: 'CANCELED', 'SOLD', 'STORED', 'ERROR', 'ERROR_SYNC'. Cada um que seja selecionado deverá fazer parte do resultado. Inicialmente deixar selecionado todos os valores.
** '''Reimpressões''' - ComboMultiSelect com duas opções: 'Vendas' e 'Reimpressões'. inicialmente apenas Vendas deve estar selecionados, fazendo com que as Reimpressões não apareçam no relatório.
* '''Colunas do Relatório'''
** '''Status''' - Coluna com o status da finalização. Alinhado a Esquerda.
** '''Colunas Agrupaveis:'''
*** '''Qtde.''' - Coluna com quantidade de finalizações totais. Alinhado a direita. Formatação número inteiro.
*** '''Total''' - Coluna com a somatória dos valores de venda dos cupons. Alinhado a direita. Formatação de valor monetário.


Exemplo de SQL para MySQL para obter os dados como se espera no relatório:
Exemplo de SQL para MySQL para obter os dados como se espera no relatório:
Linha 35: Linha 46:
;
;
</syntaxhighlight>
</syntaxhighlight>
'''''Exibições'''''
* '''Listagem:'''
** '''Status''' - Coluna com o status da finalização. Alinhado a Esquerda.
** '''Colunas Agrupaveis:'''
*** '''Qtde.''' - Coluna com quantidade de finalizações totais. Alinhado a direita. Formatação número inteiro.
*** '''Total''' - Coluna com a somatória dos valores de venda dos cupons. Alinhado a direita. Formatação de valor monetário.


== Vendas ==
== Vendas ==

Edição das 12h54min de 19 de agosto de 2015

Módulo para controle dos PDVs (Ponto de Venda) da Empresa.

Relatórios

Analítico

Finalizações de Vendas

"Finalizações de Vendas" é a maneira como a venda é finalizada no PDV. Neste caso, entende-se por venda cada vez que uma comanda (ou uma venda sem comanda) é iniciada no PDV. E por "finalização de venda" a maneira como o operador sai desse venda iniciada. As opções de finalizações disponíveis atualmente são:

  • SOLD - Quando a venda é realmente efetivada. O processo se completou e o valor foi faturado. Lembrando que esse status indica qualquer tipo de venda, seja por cartão, dinheiro, convênio, fiado (ainda não implementado), etc.
  • CANCELED - Quando a venda é cancelada. Uma venda é cancelada quando seus itens são excluídos e a venda não é mais realizada.
  • STORED - Quando a venda é interrompida para continuar posteriormente. No caso os itens da venda são salvos em uma comanda/mesa e podem ser reiniciada em uma nova venda posteriormente.
  • ERROR - Quando a o sistema detecta um erro mas não consegue se restaurar para continuar a venda que está em aberto. Neste caso o sistema marca a venda como ERRO porque não sabe o real status dessa venda.
  • ERROR_SYNC - Esse status define uma falha detectada no ECF. Este status indica que a venda foi feita pelo sistema e provavelmente recebida, mas que não foi possível reconhecer no ECF se o cupom foi impresso com sucesso. Quando esse erro é detectado (não é possível confirmar se o ECF imprimiu corretamente o cupom) o sistema questiona o operador para saber se o cupom foi impresso corretamente ou não. Caso responda não, um novo cupom é gerado automaticamente com o mesmo conteúdo e marcado como SOLD, no entanto por ser uma reimpressão ele receberá na coluna 'idpdv_cupom' o ID do cupom o qual ele representa uma reimpressão. Diferenciando assim uma venda de "reimpressão" de uma venda real.

Assim, este relatório tem a intenção de sumarizar essas quantidades para análise de vendas, cancelamentos, erros, falhas, etc.

  • Caminho do Relatório: Caixa/PDV > Analítico > Finalizações de Vendas
  • Campos de Filtros:
    • Periodo - Filtrar o relatório por um período de datas
    • Status - Campo ComboBoxMultiSelect com as opções do status possíveis: 'CANCELED', 'SOLD', 'STORED', 'ERROR', 'ERROR_SYNC'. Cada um que seja selecionado deverá fazer parte do resultado. Inicialmente deixar selecionado todos os valores.
    • Reimpressões - ComboMultiSelect com duas opções: 'Vendas' e 'Reimpressões'. inicialmente apenas Vendas deve estar selecionados, fazendo com que as Reimpressões não apareçam no relatório.
  • Colunas do Relatório
    • Status - Coluna com o status da finalização. Alinhado a Esquerda.
    • Colunas Agrupaveis:
      • Qtde. - Coluna com quantidade de finalizações totais. Alinhado a direita. Formatação número inteiro.
      • Total - Coluna com a somatória dos valores de venda dos cupons. Alinhado a direita. Formatação de valor monetário.

Exemplo de SQL para MySQL para obter os dados como se espera no relatório:

-- Relatório de Finalizações de cupoms
select status, count(*), sum(c.total)
-- , hour(c.date) -- Group By Horas do Dia
, weekday(c.date) -- Agrupamento pod dia da semana
from pdv_cupom c
where c.status in ('CANCELED', 'SOLD', 'STORED', 'ERROR', 'ERROR_SYNC') -- Filtar por tipo de Fechamento
AND c.DATE >= '2015-05-01 00:00:00' AND c.DATE <= '2015-05-31 23:59:59' -- Filtra por data
-- and c.idpdv_cupom is null -- Remove os cupoms de Reimpressão
-- and c.idpdv_cupom is not null -- Remove os cupons de venda, deixando apenas as reimpressões
group by status
-- , hour(c.date) -- Group By Horas do Dia
, weekday(c.date) -- Group By Dia da semana
order by status
-- , hour(c.date) -- Group By Horas do Dia
;

Vendas

por Tributação de ICMS

Este relatório agrupa o faturamento de acordo com o tipo de tributação usada na venda.

Exemplo de SQL para MySQL para obter os dados como se espera no relatório:

SELECT ci.icmstype, ci.icmstaxratio, SUM(ci.total) AS tot
FROM pdv_cupomitem ci LEFT JOIN pdv_cupom c ON c.id = ci.idpdv_cupom
-- WHERE OBRIGATÓRIOS
WHERE ci.status = 'SOLD' -- Filtra apenas os itens que foram vendidos no cupom, os itens cancelados não devem ser contabilizados no relatório
and (c.STATUS = 'SOLD' OR c.STATUS = 'ERROR_SYNC') -- Filtra apenas os cupoms que foram vendidos e vendidos sem confirmação do ECF.
-- WHERE de Filtros
-- and c.date >= '2015-03-01 00:00:00' and c.date <= '2015-03-31 23:59:59' -- Filtra por data
GROUP BY icmstype, ci.icmstaxratio -- Agrupa a soma pelo tipo de tributação e aliquota
ORDER BY tot desc; -- Organiza do maior faturamento para o menor.


Exibições

  • Listagem:
    • Tipo de Tributação - Define o tipo de tributação. Enum: ICMSTYPE.
    • Aliquota - Alíquota da tributação (quando existente). Valor em porcentagem.
    • Total - Faturamento total sumarizado.
    • Participação - Valor da representação do valor da coluna Total em relação a soma de todos os itens, utilizando o BISPercentualBarComponent no estilo GREEN para exibição da informação.
  • Gráfico Pizza:
    • Exibe o conteúdo como fatias em um gráfico de pizza.
  • Gráfico Colunas:
    • Exibe o conteúdo como colunas em um gráfico de colunas.


Filtros do Relatório

  • Período - Campo com data inicial e final para filtrar o periodo


por Código de Produto

O relatório de Faturamento por Código de Produto visa exibir as informações das vendas agrupadas pelo código do produto.

Exemplo de SQL para MySQL para obter os dados como se espera no relatório:

SELECT ci.code, ci.displayline, min(ci.price), max(ci.price) , round(sum(ci.total)/sum(ci.quantity),2), sum(ci.quantity) as qt, ci.unit, ci.measureunit, SUM(ci.total) AS tot
FROM pdv_cupomitem ci LEFT JOIN pdv_cupom c ON c.id = ci.idpdv_cupom LEFT JOIN item_itemcodes ic ON ic.code = ci.code 
-- LEFT JOIN item_itemcategory icat ON icat.id = ic.iditemcategory
WHERE ci.STATUS = 'SOLD' AND (c.STATUS = 'SOLD' OR c.STATUS = 'ERROR_SYNC') -- where obrigatória
-- WHERE de Filtros
-- AND c.DATE >= '2015-03-01 00:00:00' AND c.DATE <= '2015-03-31 23:59:59' -- Filtra por data
-- and icat.id is null -- Filtra código exclúidos / Sem categoria
-- and icat.id = 50 -- Filtra pela Categoria de Item
GROUP BY ci.code, ci.displayline, ci.unit -- GROUPS
ORDER BY tot DESC; -- Order By


Exibições

  • Listagem
  • Gráfico Pizza

Filtros do Relatório

  • Período - exibe dois campos de data para marcação do período que se deseja o relatório.
  • Categoria do Item - filtra os itens de acordo com sua categoria. Exibir dados em forma hierárquica para escolha.

por Categoria de Itens

Relatório para exibir o faturamento agrupado por Categoria e subCategorias. O tela deve exibir os dados de forma hierarquica, similar a própria janela de categoria de itens, só que com as colunas mencionadas abaixo.

Sugiro que o "bean" que trará os dados do CRUD para a tela faça uso do próprio ItemCategoryVO, e use já os métodos existentes para recuperar os nós conforme necessário, e em seguida, de acordo com os objetos recuperados, seja carregado diretamente do banco de dados os dados necessários sobre o faturamente e incorporados no Bean. Dessa forma poderemos manter o LazyLoad na tela e obter os totais a partir de diversas consultas rápidas no banco.

  • Caminho do Relatório: Caixa / PDV > Faturamento > por Categorias de Itens
  • Campos de Filtro
    • Período - Campo de filtro por período com precisão de minutos.
    • Categoria Raiz - Usar o ComboBoxHierarchical (vou adapta-lo para single selection também) para permitir que o usuário escolha um único ramo para visualizar. A categoria escolhida deverá ser o único elemento raiz do container, e apenas ele e seus filhos passarão a ser exibidos e calculados. Se este filtro for aplicado diretamente na obtenção dos ItemCategoryVOs raíz, o restante do código deve permanecer sem alterações.
  • Campos de Agrupamento
    • Agrupar - ComboBox com opções de agrupamento dos dados filtrados:
      • Dia/Mês/Ano - Permite o agrupamento do Faturamento por dia/mês/ano.
      • Mês/Ano - Permite o agrupamento do faturamento por mês/ano.
      • Dias da Semana - Permite o agrupamento do Faturamento por dias da semana (Dom-Sáb).
  • Validações
    • Caso o agrupamento esteja definido como 'dia/mês/ano' não permitir que o período extrapole 90 dias.
    • Caso o agrupamento esteja definido como 'mês/ano' não permitir que o período extrapole 60 meses.
  • Colunas do Relatório
    • Nome da Categoria - Nome da categoria. Alinhamento: Esquerda.
    • Tipo da Categoria - Tipo da categoria. Alinhamento: Centralizado. Collapsed.
    • Colunas Agrupaveis - As colunas abaixo quando algum agrupamento estiver definido devem se repetir e indicar o título do agrupamento. Por exemplo, se agrupada por mês, indicarem o mês: "Jan", "Fev", etc. (O segredo pra fazer isso será usar o novo componente BISGrid ;) Tão novo que nem existe ainda)
      • Faturamento - Faturamento dos itens apenas nesta categoria. Formato: Currency. Alinhamento direita.
      • Faturamento Grupo - Faturamento dos itens nesta categoria e nas categorias filhas. Formato: Currency. Alinhamento Direita.
      • % Grupo - Participação do Faturamento em relação ao valor do 'Faturamento Grupo' do objeto pai. Usar a barra percentual. Deixa esta coluna em branco, nem colocar a barra com o 0% caso o valor do Faturamento seja zero.
      • % Faturamento - Participação do Faturamento total. Nesta coluna não usar a Barra Percentual. Formato: Porcentagem com duas casas decimais. Alinhamento: Direita.
  • Menus de Contexto
    • "Visualizar Faturamento de Itens" - Este menu deve abrir o relatório de venda de itens (feito anteriormente) transportando o filtro de período, e definindo a categoria no filtro de categoria. A seleção do Menu também deve ser alterada, para deixar evidente que o cliente mudou de relatório, bem como permitir que ele volte para o relatório anterior novamente escolhendo-o no menu.
      Como fazer essa definição no menu eu não sei ainda... penso em passar a própria InfoBoardWindow como parametro ao instanciar as janelas internas. Fazer esse o novo padrão ao invés do construtor vazio. E obviamente na InfoBoardWindow Fazer alguns métodos que permitam a escolha do menu através de algum ID, talvez a própria classe da Window e deixa a InfoWindow iterar e encontrar o menu correto no container. Só seria bom algo padronizado assim pois acabará sendo comum termos links de um relatório para outro para "abrir" dados de um em outro...
  • Gráfico Stackedbar - http://demo.vaadin.com/charts/#StackedBar
    • O Eixo Vertical (Apples, oranges, Pears, etc. do exemplo) serão os dados agrupados. Por exemplo, no agrupamento por mês serão os meses disponíveis de acordo com o filtro: "Fevereiro", "Março", "Abril", etc.
    • As séries de dados (John, Jane e Joe do exemplo) serão as categorias raiz e os valores serão os valores da coluna 'Faturamento Grupo'. As categorias filhas não serão expostas no gráfico.
      Note que caso o filtro da 'Categoria Raiz' esteja definido, temos apenas um único objeto raiz. Neste caso a série de dados deverá ser esta única categoria raiz, utilizando o valor da coluna 'Faturamento', mais todas as suas categorias filha com o valor da coluna 'Faturamento do Grupo'.
  • Gráfico DualAxes - http://demo.vaadin.com/charts/#DualAxesLineAndColumn
    • A ideia desse gráfico é exibir as barras sem sobreposição, permitindo a comparação entre elas, além do total na linha (segundo eixo). Embora tenha passado o link do dual axes para entender a questão da linha total, a parte das barras deve ter um visual mais parecido com http://demo.vaadin.com/charts/#ToggledSeriesVisibility por conta da quantidade de séries de valores.
    • Assim como anterior, o eixo (agora horizontal) será a informação de acordo com o tipo do agrupamento.
    • Cada barra/serie de dados será uma categoria raiz. Ou no caso do filtro de 'Categoria Pai' estar definido as séries incluem a própria categoria pai além das suas categorias filhas. Usando as mesmas colunas de valores como no gráfico anterior.
    • O segundo eixo, responsável por gerar a linha, será uma linha totalizadora. Os valores de cada série será a soma de todos os valores das barras. Quando há o filtro de categoria pai, e estiver tudo correto obviamente, o valor da soma já será o valor da coluna 'Faturamento Grupo' do objeto pai (usado na primeira série de dados).

SQL Guia

O SQL abaixo pode servir de guia para a criação do método de consulta no DAO. Note que o código tem linhas comentadas no bloco de select e no groupby que fazem "pares" para realizar as consultas dos Agrupamentos solicitados no relatório. Ao descomentar uma das linhas de SELECT a linha equivalente de GROUP BY também deve ser descomentada para que o SQL funcione. Assim como a outra linha deverá ser comentada novamente.


SELECT 
-- day(c.date), month(c.date), year(c.date), -- Agrupamento Diário
month(c.date), year(c.date), -- Agrupamento por mês
-- weekday(c.date), -- Agrupamento pod dia da semana
icat.id, icat.name, sum(ci.total)
FROM pdv_cupomitem ci LEFT JOIN item_itemcodes ic on ic.code = ci.code LEFT JOIN item_itemcategory icat on icat.id = ic.iditemcategory, pdv_cupom c 
WHERE ci.idpdv_cupom = c.id and ci.status = 'SOLD' AND (c.STATUS = 'SOLD' OR c.STATUS = 'ERROR_SYNC') -- where obrigatória
-- AND c.DATE >= '2015-06-22 00:00:00' AND c.DATE <= '2015-07-22 23:59:59' -- Filtra por periodo
-- AND icat.id = 225 -- filtra pelo ID da categoria
GROUP BY icat.id
-- , day(c.date), month(c.date), year(c.date) -- Agrupamento diário
, month(c.date), year(c.date) -- Agrupamento por mês
-- , weekday(c.date) -- Agrupamento por dia da semana
;


Filtro de Categoria Pai
Embora "meio que óbvio" as vezes passa despercebido. Quando o texto acima fala que o category pai esteja definido, significa que o filtro está atualmente em uso. Não pode ser usado o campo do filtro para checar essa condição, uma vez que o usuário pode alterar esse valor e não clicar em procurar. Fazendo com que os dados existentes não sejam compatíveis com o valor do filtro. Gerar gráficos com base em dados "dessincronizados" acabariam com um relatório confuso e sem sentido.
Vendas sem Categorias
Note que o SQL faz 2 Left Joins, e como a venda não "armazena" qual era a categoria do produto na época da venda, essa associação de venda por categoria é resgatada fazendo um join com o código da venda e a categoria em que o código atual está. Caso o código ou a categoria tenha sido excluído, o resultado poderá apresentar um categoria com "ID nulo", o que indica a impossibilidade de associar a venda à alguma categoria.

Quando isso correr o sistema deve "simular" uma categoria chamada "Sem Categoria" para apresentar esses valores. Caso contrário os totais declarados como faturado neste relatório podem não bater com outros do sistema.


Criação dos Beans e IDs
Como o relatório é criado baseado em um objeto existente, o ItemCategoryVO, sugiro que o Bean que carregará todos copie as informações a serem utilizadas do ItemCategoryVO para ele. Como id, nome da categoria e tipo da categoria. Além dos outros campos que serão obtidos a partir do SQL de somatória de agrupamento do faturamento.

Para a categoria a ser simulada dos "Sem Categoria", sugiro que jogue o id -1. Por ser um Long funciona normalmente nas telas e UIs, e com certeza não fará comflito com outros objetos.


Aproveitamento de Query e Performance
Nos meus testes com o SQL, usando o SQL oferecido acima, usando o filtro de ID da categoria a query levou 4s, sem o filtro de categoria a mesma query levou 4,5s. Pelo volume de categorias, é melhor realizar sempre a consulta SEM o id da categoria. Assim receberá todos os dados necessários, e provavelmente até mais do que necessitaria, mas evitaria ter que fazer múltiplas queries em que já a partir da segunda temos quase o dobro do tempo de consulta.

Assim, por conta de salvar a performance do banco, é melhor obter toda a query e salvar os valores obtidos nos beans de acordo. Seguindo essa lógico não teremos LazyLoad da consulta do banco de dados e retornaremos todos os Beans totalmente preenchidos. do CRUD para a tela. A manipulação dos dados, mesmo que feitos pelo java e em memória devem ser tratadas ainda no DAO. O acredito que o tempo não deva nem chegar ao tempo de outra query, mas se ficar ruim podemos facilmente implementar um paralelismo para esse tipo de informação, provavelmente usando os novos recursos do Java 8 (que eu não sei usar ainda rs).

Os dados a serem gerados/calculados são a somatória dos itens filhos, que não são geradas pelo SQL e depois do total calculado, o calculo das porcentagens de participação.