Pular para o conteúdo principal

VL_FATORPONTOS - Valor (fator) de conversão de Reais em pontos de fidelidade do cliente

Tela: MFA001 - Parâmetros de Faturamento Localização: Parâmetros → Notas Fiscais → Parâmetros de Notas → campo Valor do Ponto Cliente Tabela: PARMFATUR.VL_FATORPONTOS Tipo: Numérico inteiro - DOM_INTEGER (persistido no Delphi como TIntegerField) Valor padrão: NULL (nenhum default é atribuído no AfterInsert do MFA001) Validação: nenhuma (não existe tabPARMFATURVL_FATORPONTOSValidate em UdmMFA001.pas)

O que o parâmetro faz​

VL_FATORPONTOS é o fator de conversão Reais-por-Ponto do programa de fidelidade simples do ERP. Representa "quantos Reais de nota fiscal de venda equivalem a 1 ponto do cliente". Quanto maior o valor, mais caro é ganhar um ponto (cliente acumula menos pontos). Quanto menor, mais barato é ganhar um ponto.

O campo é usado exclusivamente pelo relatório de pontos RNF033 (Relatório de Pontos por Cliente). Os pontos não são armazenados em tabela - são calculados on-the-fly a partir do somatório das notas fiscais de venda (NOTA.VL_NOTAFISCAL com ST_NOTA = 'V' e TP_NOTA = 'S') dividido pelo fator. O cálculo usa a função escalar DIVIDENDO, que retorna a divisão truncada para inteiro (TRUNC(V_RADICAL / V_DIVIDENDO)), garantindo que pontos sempre sejam numeros inteiros.

Existe ainda um override por execução do relatório: o usuário pode informar VL_PONTO no filtro da tela do RNF033; se preenchido, esse valor substitui VL_FATORPONTOS apenas no cálculo do valor monetário por ponto (coluna VL_PONTO do relatório), mas o fator de conversão para gerar a quantidade de pontos (QT_PONTOS) continua sendo sempre PARMFATUR.VL_FATORPONTOS.


Telas impactadas​

MóduloCódigoComo usa VL_FATORPONTOS
Parâmetros FaturamentoMFA001Cadastro do próprio valor - TDBEdit edtVL_FATORPONTOS no grupo Opção 1, label Valor do Ponto Cliente (UMFA001.dfm:6201-6215 / 6998-7014).
Relatório Pontos por ClienteRNF033Única tela consumidora real. Lê PF.VL_FATORPONTOS da PARMFATUR da empresa filtrada; usa como divisor em DIVIDENDO(SUM(VL_NOTAFISCAL), VL_FATORPONTOS) para gerar QT_PONTOS; também usa como fallback (COALESCE) no cálculo do valor monetário do ponto (VL_PONTO). Dispara erro E-0000 "O Valor do Ponto não está Parametrizado! Verifique[MFA001]" se o campo estiver vazio.
Configuração PedidoCPD009Não usa o valor; apenas inclui VL_FATORPONTOS no INSERT/UPDATE/SELECT do dataset dsPARMFATUR por ser uma tela alternativa de edição de alguns parâmetros de faturamento (CRUD replicado).
Análise (módulo Captação Láctea)RCA006Não usa o valor; VL_FATORPONTOS aparece apenas no dataset de PARMFATUR replicado (INSERT/UPDATE/SELECT) porque compartilha o mesmo CRUD de parâmetros. Sem uso em cálculo.

Procedures impactadas​

Nenhuma procedure/view SQL do repositório Scripts/ referencia VL_FATORPONTOS. O cálculo acontece apenas no SQL dinâmico montado pelo Delphi em URNF033.pas (linhas 275, 339-341, 367, 374-375). A única função auxiliar envolvida é a function escalar DIVIDENDO:

FunctionArquivoPapel
DIVIDENDO(I_VL_RADICAL, I_VL_DIVIDENDO)Scripts/DIVIDENDO.sqlRetorna TRUNC(V_RADICAL / V_DIVIDENDO) como DOM_BIGINT. Se VL_FATORPONTOS for NULL ou 0, retorna 0 (COALESCE interno) - o cliente não acumula pontos.

Campos envolvidos​

CampoTabelaDescrição
VL_FATORPONTOSPARMFATUREste parâmetro - quantos Reais equivalem a 1 ponto.
VL_NOTAFISCALNOTAValor da nota fiscal de venda, somado por cliente para calcular pontos.
ST_NOTANOTAFiltro fixo: 'V' (venda, situação confirmada).
TP_NOTANOTAFiltro fixo: 'S' (saída).
CD_EMPRESAPARMFATUR / NOTAFaz o JOIN - cada empresa tem seu próprio fator de pontos.
CD_PESSOANOTAAgrupamento do relatório - pontos por cliente.
VL_PONTO(filtro em memória do RNF033)Override opcional informado pelo usuário na tela do relatório. Substitui VL_FATORPONTOS apenas como multiplicador monetário (coluna VL_PONTO), nunca como divisor de pontos.

Comportamento / Fórmula de aplicação​

Fórmulas no SQL dinâmico do RNF033​

Modelo Sintético (por cliente - URNF033.pas:336-350):

SELECT
P.NM_PESSOA || ' - ' || N.CD_PESSOA NM_PESSOA,
SUM(N.VL_NOTAFISCAL) VL_TOTAL,
DIVIDENDO(SUM(N.VL_NOTAFISCAL), PF.VL_FATORPONTOS) QT_PONTOS,
(DIVIDENDO(SUM(N.VL_NOTAFISCAL), PF.VL_FATORPONTOS)
* COALESCE(<VL_PONTO_informado>, PF.VL_FATORPONTOS)) VL_PONTO,
COALESCE(<VL_PONTO_informado>, PF.VL_FATORPONTOS) VL_REGRA
FROM NOTA N
INNER JOIN PESSOA P ON (P.CD_PESSOA = N.CD_PESSOA)
INNER JOIN PARMFATUR PF ON (PF.CD_EMPRESA = N.CD_EMPRESA)
WHERE N.ST_NOTA = 'V'
AND N.TP_NOTA = 'S'
<filtros de empresa/data>
GROUP BY P.NM_PESSOA, N.CD_PESSOA, PF.VL_FATORPONTOS

Modelo Analítico (por nota - URNF033.pas:356-386): mesma lógica, mas DIVIDENDO é aplicado sobre subconsulta que soma VL_NOTAFISCAL no período, dentro de cada linha do relatório.

Observe que QT_PONTOS é sempre TRUNC(SUM(VL_NOTAFISCAL) / VL_FATORPONTOS) - pontos fracionários são descartados (não arredondados).


Valor = 0 ou NULL (não parametrizado)​

O que aconteceDetalhe
Cadastro (MFA001)AfterInsert não atribui default - campo nasce NULL em empresas novas.
Ao abrir o RNF033No clique de "Gerar", o código executa SELECT VL_FATORPONTOS FROM PARMFATUR WHERE CD_EMPRESA = .... Se o resultado retornar string vazia (NULL), dispara E-0000 "O Valor do Ponto não está Parametrizado! Verifique[MFA001]" e aborta o relatório.
Se o valor for 0 (ao invés de NULL)A validação acima não pega (apenas testa string vazia). A query roda, mas DIVIDENDO(x, 0) = 0 por causa do COALESCE(I_VL_DIVIDENDO, 0) = 0 interno da function. Todos os clientes aparecem com QT_PONTOS = 0 e VL_PONTO = 0. O relatório sai "zerado" silenciosamente.
Efeito práticoRelatório de fidelidade não funciona até o parâmetro ser preenchido com valor > 0.

Valor > 0​

O valor informado é o "preço de 1 ponto em Reais". Fórmula:

QT_PONTOS = TRUNC(SUM(VL_NOTAFISCAL do cliente) / VL_FATORPONTOS)
VL_PONTO (monetário) = QT_PONTOS * COALESCE(VL_PONTO_override, VL_FATORPONTOS)

Exemplos numéricos concretos​

Cenário 1: VL_FATORPONTOS = 100 (100 Reais = 1 ponto), sem override

ClienteSUM(VL_NOTAFISCAL)QT_PONTOSVL_PONTO (monetário)
AR$ 1.250,00TRUNC(1250 / 100) = 1212 * 100 = R$ 1.200,00
BR$ 99,50TRUNC(99,5 / 100) = 00
CR$ 10.000,00TRUNC(10000 / 100) = 100R$ 10.000,00

Observe em A: do R$ 1.250 comprado, R$ 50 "sobram" porque não completam outro ponto inteiro (o TRUNC descarta a fração - o cliente não carrega saldo acumulado para o próximo relatório, já que não existe tabela persistindo pontos).

Cenário 2: VL_FATORPONTOS = 50 (mais barato - 50 Reais = 1 ponto), sem override

  • Cliente A com SUM(VL_NOTAFISCAL) = R$ 1.250,00:
    • QT_PONTOS = TRUNC(1250 / 50) = 25 pontos (mais do que o dobro do cenário 1).
    • VL_PONTO = 25 * 50 = R$ 1.250,00 (coincide com o total comprado quando não há override).

Cenário 3: VL_FATORPONTOS = 100, com override VL_PONTO = 5,00 informado no filtro

  • Cliente A com SUM(VL_NOTAFISCAL) = R$ 1.250,00:
    • QT_PONTOS = TRUNC(1250 / 100) = 12 pontos (divisor segue sendo VL_FATORPONTOS, não o override).
    • VL_PONTO = 12 * COALESCE(5,00, 100) = 12 * 5,00 = R$ 60,00.
  • Interpretação: o override é uma "régua de valor" - mostra quanto vale em dinheiro cada ponto, independente de quanto custou ganhá-lo. Útil para políticas tipo "cada ponto vale R$ 5 em desconto", enquanto o fator de cálculo continua governando como os pontos são gerados.

Cenário 4: VL_FATORPONTOS = 1 (caso limite - 1 ponto por Real)

  • Cliente A com SUM(VL_NOTAFISCAL) = R$ 1.250,00:
    • QT_PONTOS = TRUNC(1250 / 1) = 1.250 pontos.
    • VL_PONTO = 1.250 * 1 = R$ 1.250,00.
  • É o limite inferior útil; como o campo é DOM_INTEGER, não aceita frações (ex.: 0,5 não é permitido).

Simulação passo a passo​

  1. Em MFA001 → Opção 1 → Valor do Ponto Cliente preencher com 100 e salvar.
  2. Lance no período algumas notas de venda (NOTA.ST_NOTA = 'V', TP_NOTA = 'S') para o cliente X totalizando R$ 1.250,00.
  3. Abra RNF033, selecione a empresa, o período e deixe Valor do Ponto em branco.
  4. Escolha modelo "Sintético" e gere o relatório.
  5. Resultado esperado: cliente X aparece com VL_TOTAL = 1.250,00, QT_PONTOS = 12, VL_PONTO = 1.200,00 e VL_REGRA = 100.
  6. Agora regere o relatório preenchendo Valor do Ponto = 5,00 na tela.
  7. Resultado esperado: mesma QT_PONTOS = 12, mas VL_PONTO = 60,00 e VL_REGRA = 5,00.

Referências no Código Fonte​

Delphi - MFA001 (cadastro do parâmetro)​

  • source/MFA001/UMFA001.dfm:6201-6215 - TLabel Label16 com Caption = 'Valor do Ponto Cliente' e FocusControl = edtVL_FATORPONTOS.
  • source/MFA001/UMFA001.dfm:6998-7014 - edtVL_FATORPONTOS: TDBEdit com DataField = 'VL_FATORPONTOS', DataSource = dmMFA001.dsPARMFATUR, TabOrder = 34.
  • source/MFA001/UMFA001.pas:393 - declaração edtVL_FATORPONTOS: TDBEdit no form.
  • source/MFA001/UdmMFA001.pas:142 - tabPARMFATURVL_FATORPONTOS: TIntegerField (confirma que o tipo em runtime é inteiro).
  • source/MFA001/UdmMFA001.dfm:1170-1172 - object tabPARMFATURVL_FATORPONTOS com FieldName = 'VL_FATORPONTOS' e Origin = '"PARMFATUR"."VL_FATORPONTOS"'.
  • source/MFA001/UdmMFA001.dfm:146, 2381, 2756, 3026 - inclusão de VL_FATORPONTOS nos SQL dinâmicos SelectSQL, InsertSQL e UpdateSQL do dataset dsPARMFATUR.
  • source/MFA001/UdmMFA001.pas:434-... - tabPARMFATURAfterInsert não atribui valor a VL_FATORPONTOS (nasce NULL). Também não existe procedure tabPARMFATURVL_FATORPONTOSValidate - nenhuma validação é aplicada no post.

Delphi - RNF033 (único consumidor de cálculo)​

  • source/RNF033/URNF033.pas:273-280 - pré-validação ao gerar:
Consulta :=
'SELECT VL_FATORPONTOS '+
'FROM PARMFATUR '+
'WHERE CD_EMPRESA = ' + dmRNF033.tabEMPRESACD_EMPRESA.AsString ;
Resultado := ExecutaConsulta(dmRNF033.transaction, Consulta);
if ( Trim(Resultado[0]) = '' ) then
raise JException.Create('E-0000',[ 'O Valor do Ponto não está Parametrizado! Verifique[MFA001]']);
  • source/RNF033/URNF033.pas:336-350 - SQL dinâmico do modelo sintético com DIVIDENDO(SUM(N.VL_NOTAFISCAL), PF.VL_FATORPONTOS) QT_PONTOS e GROUP BY P.NM_PESSOA, N.CD_PESSOA, PF.VL_FATORPONTOS.
  • source/RNF033/URNF033.pas:340-341 - cálculo de VL_PONTO e VL_REGRA com COALESCE(<VL_PONTO override>, PF.VL_FATORPONTOS).
  • source/RNF033/URNF033.pas:356-386 - SQL dinâmico do modelo analítico (mesma lógica, mas DIVIDENDO é aplicado a subconsulta de SUM(NF.VL_NOTAFISCAL)).
  • source/RNF033/UdmRNF033.dfm:61, 96-97 - dataset tabEMPRESA expõe o campo VL_PONTO (override do usuário), que é apenas uma coluna CAST(NULL AS NUMERIC(15,2)) do filtro em memória.
  • source/RNF033/URNF033.pas:44-45 - edtVL_PONTO: TDBEdit e lblVL_PONTO: TLabel do filtro do relatório.

Delphi - telas que replicam o campo no CRUD (sem uso de cálculo)​

  • source/CPD009/UdmCPD009.dfm:332, 396, 500, 604 - VL_FATORPONTOS presente em InsertSQL, UpdateSQL, SelectSQL do dataset de PARMFATUR (CRUD alternativo). Sem cálculo.
  • source/RCA006/UdmRCA006.dfm:3081, 3145, 3249, 3353 - mesmo caso (CRUD replicado), sem cálculo.

SQL - Function auxiliar​

  • Scripts/DIVIDENDO.sql:3-16:
CREATE OR ALTER function DIVIDENDO (
I_VL_RADICAL DOM_NUMERIC15_4,
I_VL_DIVIDENDO DOM_NUMERIC15_4)
returns DOM_BIGINT
as
declare variable V_VL_DIVISOR DOM_BIGINT;
BEGIN
if ( COALESCE(I_VL_DIVIDENDO,0) = 0 ) then
V_VL_DIVISOR = 0;
ELSE
V_VL_DIVISOR = TRUNC(I_VL_RADICAL / I_VL_DIVIDENDO);

RETURN V_VL_DIVISOR;
END^

Garante que divisor NULL ou 0 produza 0 (cliente sem pontos) ao invés de erro de divisão por zero, e trunca sempre (pontos fracionários são descartados).

DDL​

  • docs/schema/tables/PARMFATUR.sql:105 - definição:
VL_FATORPONTOS DOM_INTEGER,

Permite NULL (sem NOT NULL, sem DEFAULT). Como DOM_INTEGER, aceita apenas valores inteiros - não é possível configurar, por exemplo, 1,5 Reais = 1 ponto.