Pular para o conteúdo principal

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

TipoCódigo CODFORMDescrição
CLT4Vendedor interno com carteira assinada
Representante Externo1Vendedor autônomo/representante

Configuração de Campos

Campos na Empresa (TGFEMP)

CampoDescriçãoTabelaUso
AD_DIVISAO_COMISSAO_REPRESENTEPercentual do Comissão RepresentanteTGFEMPDefine divisão entre vendedor interno/externo
AD_COMISSAOMENORPercentual Comissão Mínima MenorTGFEMPComissão mínima para vendedores CLT
AD_COMISSAOMINIMAPercentual Comissão MínimaTGFEMPComissão mínima para representantes
AD_COMISSAOMAXIMAPercentual Comissão MáximaTGFEMPLimite máximo de comissão
AD_PRECOMAXIMOPercentual Preço MáximoTGFEMPLimite para aplicação da comissão máxima

Campos no Produto (TGFPRO)

CampoDescriçãoTabelaUso
COMVEND% Comissão VendedorTGFPROComissão base para representantes
AD_COMISSAOMENORComissão MenorTGFPROComissão base para vendedores CLT

Campos do Usuário (TSIUSU)

CampoDescriçãoUso
CODFORMCódigo do Tipo de VendedorIdentifica o perfil: 1=Representante, 4=CLT

Arquivos Modificados

ArquivoLocalizaçãoResponsabilidade
price.products.sale.create.controller.tsControllersLógica principal do cálculo de comissão
index.tsxComponents/ProductModalExibição da comissão por produto
FooterBar.tsxComponents/FooterExibição do total de comissão no rodapé
product.types.tsTypesTipagem para campos de comissão do produto
user.types.tsTypesTipagem para campo CODFORM do usuário
login.service.tsServicesMapeamento do tipo de vendedor
permission.tsUtilsVerificaçã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

// 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 VendaCálculoComissão Final
R$ 943,89 (mínimo)Comissão mínima0,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 produto0,60%

Representante Externo

Preço de VendaCálculoComissão Final
R$ 943,89 (mínimo)Comissão mínima1,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 produto2,90%
Regra de Três Proporcional

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çãoPreço de VendaComissão Aplicada
Dentro do limiteAté 170% do preço tabelaCalculada normalmente
Acima do limiteAcima de 170% do preço tabelaLimitada a 35%
Atenção

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árioPercentual PadrãoCampo de Configuração
Vendedor Interno80%AD_DIVISAO_COMISSAO_REPRESENTE
Vendedor Externo20%Calculado automaticamente (100% - interno)
Configuração Flexível

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
};
}