Comissão Vendedor/Representante
Ticket: FORCEWEB-1244
Última atualização: 18 de setembro de 2025
Visão Geral
Sistema personalizado de cálculo de comissão para a empresa Lubrilages, implementando regras diferenciadas conforme o perfil do vendedor e valores praticados na venda. A solução contempla dois tipos de vendedores com cálculos específicos e apresentação visual das comissões tanto por produto quanto no total do pedido.
Tipos de Vendedor Suportados
| Tipo | Código CODFORM | Descrição |
|---|---|---|
| CLT | 4 | Vendedor interno com carteira assinada |
| Representante Externo | 1 | Vendedor autônomo/representante |
Configuração de Campos
Campos na Empresa (TGFEMP)
| Campo | Descrição | Tabela | Uso |
|---|---|---|---|
AD_DIVISAO_COMISSAO_REPRESENTE | Percentual do Comissão Representante | TGFEMP | Define divisão entre vendedor interno/externo |
AD_COMISSAOMENOR | Percentual Comissão Mínima Menor | TGFEMP | Comissão mínima para vendedores CLT |
AD_COMISSAOMINIMA | Percentual Comissão Mínima | TGFEMP | Comissão mínima para representantes |
AD_COMISSAOMAXIMA | Percentual Comissão Máxima | TGFEMP | Limite máximo de comissão |
AD_PRECOMAXIMO | Percentual Preço Máximo | TGFEMP | Limite para aplicação da comissão máxima |
Campos no Produto (TGFPRO)
| Campo | Descrição | Tabela | Uso |
|---|---|---|---|
COMVEND | % Comissão Vendedor | TGFPRO | Comissão base para representantes |
AD_COMISSAOMENOR | Comissão Menor | TGFPRO | Comissão base para vendedores CLT |
Campos do Usuário (TSIUSU)
| Campo | Descrição | Uso |
|---|---|---|
CODFORM | Código do Tipo de Vendedor | Identifica o perfil: 1=Representante, 4=CLT |
Arquivos Modificados
| Arquivo | Localização | Responsabilidade |
|---|---|---|
price.products.sale.create.controller.ts | Controllers | Lógica principal do cálculo de comissão |
index.tsx | Components/ProductModal | Exibição da comissão por produto |
FooterBar.tsx | Components/Footer | Exibição do total de comissão no rodapé |
product.types.ts | Types | Tipagem para campos de comissão do produto |
user.types.ts | Types | Tipagem para campo CODFORM do usuário |
login.service.ts | Services | Mapeamento do tipo de vendedor |
permission.ts | Utils | Verificação de permissão Lubrilages |
Algoritmo de Cálculo
Fluxograma de Decisão
Fórmulas de Cálculo
Para Vendedores CLT (CODFORM = 4)
if (precoVenda <= precoMinimo) {
comissao = ad_comissaoMenor; // Percentual Comissão Mínima Menor (empresa)
} else if (precoVenda >= precoTabela) {
comissao = AD_COMISSAOMENOR; // Comissão Menor (produto)
} else {
// Regra de três proporcional
comissao =
ad_comissaoMenor +
((precoVenda - precoMinimo) / (precoTabela - precoMinimo)) *
(AD_COMISSAOMENOR - ad_comissaoMenor);
}
Para Representantes Externos (CODFORM = 1)
if (precoVenda <= precoMinimo) {
comissao = ad_comissaoMinima; // Percentual Comissão Mínima (empresa)
} else if (precoVenda >= precoTabela) {
comissao = COMVEND; // % Comissão Vendedor (produto)
} else {
// Regra de três proporcional
comissao =
ad_comissaoMinima +
((precoVenda - precoMinimo) / (precoTabela - precoMinimo)) *
(COMVEND - ad_comissaoMinima);
}
Aplicação de Limite Máximo
const precoMaximo = precoTabela * (1 + ad_precoMaximo / 100);
if (precoVenda >= precoMaximo) {
comissao = ad_comissaoMaxima;
} else {
comissao = Math.min(comissao, ad_comissaoMaxima);
}
Implementação Técnica
Função Principal de Cálculo
calculateCommissionLubrilages - Código Completo
// src/controllers/sale/create/products/price.products.sale.create.controller.ts
const calculateCommissionLubrilages = (
product: Product,
header: any
): { valorComissao: number; percentage: number } => {
const user = useSelector(getUser);
const CODFORM = Number(user?.CODFORM); // 4 = CLT, 1 = Representante
// Campos do produto
const AD_COMISSAOMENOR = product?.AD_COMISSAOMENOR || 0;
const COMVEND = product?.COMVEND || 0;
// Campos da empresa
const ad_comissaoMenor = Number(header?.CODEMP?.ad_comissaoMenor ?? "0") || 0;
const ad_comissaoMinima =
Number(header?.CODEMP?.ad_comissaoMinima ?? "0") || 0;
const ad_comissaoMaxima =
Number(header?.CODEMP?.ad_comissaoMaxima ?? "0") || 0;
const ad_precoMaximo = Number(header?.CODEMP?.ad_precoMaximo ?? "0") || 0;
// Valores do produto
const precoTabela = Number(product?.VLRUNIT) || 0;
const precoMinimo = Number(product?.VLRUNIT) || 0;
const precoVenda =
Number(product?.VLRUNIT) + Number(product?.VLRDESC ?? "0") || 0;
const QTDNEG = Number(product?.QTDNEG) || 0;
let comissaoCalculada = 0;
// Cálculo para CLT
if (CODFORM === 4) {
if (precoVenda <= precoMinimo) {
comissaoCalculada = ad_comissaoMenor;
} else if (precoVenda >= precoTabela) {
comissaoCalculada = AD_COMISSAOMENOR;
} else {
comissaoCalculada =
ad_comissaoMenor +
((precoVenda - precoMinimo) / (precoTabela - precoMinimo)) *
(AD_COMISSAOMENOR - ad_comissaoMenor);
}
}
// Cálculo para Representante
if (CODFORM === 1) {
if (precoVenda <= precoMinimo) {
comissaoCalculada = ad_comissaoMinima;
} else if (precoVenda >= precoTabela) {
comissaoCalculada = COMVEND;
} else {
comissaoCalculada =
ad_comissaoMinima +
((precoVenda - precoMinimo) / (precoTabela - precoMinimo)) *
(COMVEND - ad_comissaoMinima);
}
}
// Aplicação do limite máximo
const precoMaximo = precoTabela * (1 + ad_precoMaximo / 100);
if (precoVenda >= precoMaximo) {
comissaoCalculada = ad_comissaoMaxima;
} else {
comissaoCalculada = Math.min(comissaoCalculada, ad_comissaoMaxima);
}
// Valor da comissão em R$
const valorComissao = (comissaoCalculada / 100) * precoVenda;
return {
percentage: Number(comissaoCalculada?.toFixed(2)),
valorComissao: Number((valorComissao * QTDNEG)?.toFixed(2)),
};
};
Exibição no Interface
Modal do Produto
// src/screens/catalogo/components/ProductModal/components/Tabs/BusinessRulesTab/index.tsx
const comissionisLubrilages = useSelector(
getValueCommissionLubrilages(product?.CODPROD)
);
{
permission?.permissionByCompany?.isLubrilages() &&
!!comissionisLubrilages &&
renderInfomation(
"Comissão",
formatMoney(comissionisLubrilages?.valorComissao ?? "0")
);
}
Rodapé do Pedido
// src/screens/nova-venda/components/Footer/Bar/FooterBar.tsx
const totalValueCommissionLubrilages = useSelector(
getValueTotalCommissionLubrilages
);
{
permission?.permissionByCompany?.isLubrilages() && (
<div className="flex gap-2 justify-start items-center">
<p className="text-lg font-medium text-[#4e4a52]">Comissão:</p>
<p className="text-lg font-semibold text-[#009353]">
R$ {formatMoney(totalValueCommissionLubrilages, 2)}
</p>
</div>
);
}
Exemplos Práticos
Cenário: Produto 4746
Configurações do exemplo:
- Preço de Tabela: R$ 968,10
- Preço Mínimo: R$ 943,89
- Comissão Menor (CLT): 0,60%
- Comissão Mínima Menor (CLT): 0,40%
- % Comissão Vendedor (Representante): 2,90%
- Comissão Mínima (Representante): 1,50%
Vendedor CLT
| Preço de Venda | Cálculo | Comissão Final |
|---|---|---|
| R$ 943,89 (mínimo) | Comissão mínima | 0,40% |
| R$ 950,00 (intermediário) | Regra de três: 0,40% + [(950-943,89)/(968,10-943,89)] × (0,60%-0,40%) | ≈ 0,45% |
| R$ 968,10 (tabela) | Comissão do produto | 0,60% |
Representante Externo
| Preço de Venda | Cálculo | Comissão Final |
|---|---|---|
| R$ 943,89 (mínimo) | Comissão mínima | 1,50% |
| R$ 950,00 (intermediário) | Regra de três: 1,50% + [(950-943,89)/(968,10-943,89)] × (2,90%-1,50%) | ≈ 1,85% |
| R$ 968,10 (tabela) | Comissão do produto | 2,90% |
A fórmula utilizada para preços intermediários:
comissao = comissaoMinima +
((precoVenda - precoMinimo) / (precoTabela - precoMinimo)) ×
(comissaoMaxima - comissaoMinima)
Limites de Comissão
Exemplo de Configuração
- Comissão Máxima: 35%
- Preço Máximo: 170% (do preço de tabela)
| Situação | Preço de Venda | Comissão Aplicada |
|---|---|---|
| Dentro do limite | Até 170% do preço tabela | Calculada normalmente |
| Acima do limite | Acima de 170% do preço tabela | Limitada a 35% |
Os valores de Comissão Máxima e Preço Máximo podem ser alterados a qualquer momento via configuração no Sankhya.
Divisão de Comissão Interna
Regra de Divisão 80/20
Para vendedores internos, a comissão total é dividida conforme os percentuais configurados:
| Destinatário | Percentual Padrão | Campo de Configuração |
|---|---|---|
| Vendedor Interno | 80% | AD_DIVISAO_COMISSAO_REPRESENTE |
| Vendedor Externo | 20% | Calculado automaticamente (100% - interno) |
Os percentuais de divisão podem ser alterados via campos específicos na aba Comissão da tela de Empresa no Sankhya.
Controle de Permissões
Verificação Lubrilages
// src/utils/permission.ts
isLubrilages = () =>
this?.baseImage?.includes?.("187.72.81.210:8080") ||
this?.baseUrl?.includes?.("lubrilages");
Integração com Redux
Seletores Utilizados
// Comissão individual por produto
const comissionisLubrilages = useSelector(
getValueCommissionLubrilages(product?.CODPROD)
);
// Total de comissão do pedido
const totalValueCommissionLubrilages = useSelector(
getValueTotalCommissionLubrilages
);
Tipagem TypeScript
Interface do Produto
// src/types/product/product.types.ts
export interface Product {
// Campos básicos
VLRUNIT?: number; // Preço unitário
VLRDESC?: number; // Valor do desconto
QTDNEG?: number; // Quantidade negociada
CODPROD?: string; // Código do produto
// Campos para comissão
COMVEND?: number; // % Comissão Vendedor (representantes)
AD_COMISSAOMENOR?: number; // Comissão Menor (CLT)
}
Interface do Usuário
// src/types/user/user.types.ts
export type User = {
// ...campos existentes...
CODFORM?: string; // Código do tipo de vendedor
};
export interface IUserData {
// ...campos existentes...
CODFORM?: string; // Código do tipo de vendedor
}
Interface de Retorno da Função
interface CommissionResult {
valorComissao: number; // Valor em R$ da comissão
percentage: number; // Percentual de comissão aplicado
}
Mapeamento de Dados
Login Service
// src/service/auth/login.service.ts
export function mapUserDataToUser(userData: IUserData): User {
return {
// ...campos existentes...
CODFORM: userData?.CODFORM, // Mapeia tipo de vendedor
};
}