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 ClienteTabela:PARMFATUR.VL_FATORPONTOSTipo: Numérico inteiro -DOM_INTEGER(persistido no Delphi comoTIntegerField) Valor padrão:NULL(nenhum default é atribuído noAfterInsertdo MFA001) Validação: nenhuma (não existetabPARMFATURVL_FATORPONTOSValidateemUdmMFA001.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ódulo | Código | Como usa VL_FATORPONTOS |
|---|---|---|
| Parâmetros Faturamento | MFA001 | Cadastro 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 Cliente | RNF033 | Ú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 Pedido | CPD009 | Nã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) | RCA006 | Nã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:
| Function | Arquivo | Papel |
|---|---|---|
DIVIDENDO(I_VL_RADICAL, I_VL_DIVIDENDO) | Scripts/DIVIDENDO.sql | Retorna 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
| Campo | Tabela | Descrição |
|---|---|---|
VL_FATORPONTOS | PARMFATUR | Este parâmetro - quantos Reais equivalem a 1 ponto. |
VL_NOTAFISCAL | NOTA | Valor da nota fiscal de venda, somado por cliente para calcular pontos. |
ST_NOTA | NOTA | Filtro fixo: 'V' (venda, situação confirmada). |
TP_NOTA | NOTA | Filtro fixo: 'S' (saída). |
CD_EMPRESA | PARMFATUR / NOTA | Faz o JOIN - cada empresa tem seu próprio fator de pontos. |
CD_PESSOA | NOTA | Agrupamento 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 acontece | Detalhe |
|---|---|
| Cadastro (MFA001) | AfterInsert não atribui default - campo nasce NULL em empresas novas. |
| Ao abrir o RNF033 | No 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ático | Relató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
| Cliente | SUM(VL_NOTAFISCAL) | QT_PONTOS | VL_PONTO (monetário) |
|---|---|---|---|
| A | R$ 1.250,00 | TRUNC(1250 / 100) = 12 | 12 * 100 = R$ 1.200,00 |
| B | R$ 99,50 | TRUNC(99,5 / 100) = 0 | 0 |
| C | R$ 10.000,00 | TRUNC(10000 / 100) = 100 | R$ 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 sendoVL_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
- Em MFA001 → Opção 1 →
Valor do Ponto Clientepreencher com100e salvar. - Lance no período algumas notas de venda (
NOTA.ST_NOTA = 'V',TP_NOTA = 'S') para o cliente X totalizando R$ 1.250,00. - Abra RNF033, selecione a empresa, o período e deixe
Valor do Pontoem branco. - Escolha modelo "Sintético" e gere o relatório.
- Resultado esperado: cliente X aparece com
VL_TOTAL = 1.250,00,QT_PONTOS = 12,VL_PONTO = 1.200,00eVL_REGRA = 100. - Agora regere o relatório preenchendo
Valor do Ponto = 5,00na tela. - Resultado esperado: mesma
QT_PONTOS = 12, masVL_PONTO = 60,00eVL_REGRA = 5,00.
Referências no Código Fonte
Delphi - MFA001 (cadastro do parâmetro)
source/MFA001/UMFA001.dfm:6201-6215-TLabel Label16comCaption = 'Valor do Ponto Cliente'eFocusControl = edtVL_FATORPONTOS.source/MFA001/UMFA001.dfm:6998-7014-edtVL_FATORPONTOS: TDBEditcomDataField = 'VL_FATORPONTOS',DataSource = dmMFA001.dsPARMFATUR,TabOrder = 34.source/MFA001/UMFA001.pas:393- declaraçãoedtVL_FATORPONTOS: TDBEditno form.source/MFA001/UdmMFA001.pas:142-tabPARMFATURVL_FATORPONTOS: TIntegerField(confirma que o tipo em runtime é inteiro).source/MFA001/UdmMFA001.dfm:1170-1172-object tabPARMFATURVL_FATORPONTOScomFieldName = 'VL_FATORPONTOS'eOrigin = '"PARMFATUR"."VL_FATORPONTOS"'.source/MFA001/UdmMFA001.dfm:146, 2381, 2756, 3026- inclusão deVL_FATORPONTOSnos SQL dinâmicosSelectSQL,InsertSQLeUpdateSQLdo datasetdsPARMFATUR.source/MFA001/UdmMFA001.pas:434-...-tabPARMFATURAfterInsertnão atribui valor aVL_FATORPONTOS(nasceNULL). Também não existe proceduretabPARMFATURVL_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 comDIVIDENDO(SUM(N.VL_NOTAFISCAL), PF.VL_FATORPONTOS) QT_PONTOSeGROUP BY P.NM_PESSOA, N.CD_PESSOA, PF.VL_FATORPONTOS.source/RNF033/URNF033.pas:340-341- cálculo deVL_PONTOeVL_REGRAcomCOALESCE(<VL_PONTO override>, PF.VL_FATORPONTOS).source/RNF033/URNF033.pas:356-386- SQL dinâmico do modelo analítico (mesma lógica, masDIVIDENDOé aplicado a subconsulta deSUM(NF.VL_NOTAFISCAL)).source/RNF033/UdmRNF033.dfm:61, 96-97- datasettabEMPRESAexpõe o campoVL_PONTO(override do usuário), que é apenas uma colunaCAST(NULL AS NUMERIC(15,2))do filtro em memória.source/RNF033/URNF033.pas:44-45-edtVL_PONTO: TDBEditelblVL_PONTO: TLabeldo 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_FATORPONTOSpresente emInsertSQL,UpdateSQL,SelectSQLdo 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.