Quando as listas de preços padrão do SAP Business One não são suficientes para expressar a política comercial da empresa, o Vendelo pode delegar o cálculo do preço de venda a uma stored procedure criada por você no próprio banco do SAP. Este artigo é para consultores e administradores do SAP B1: ao final, você saberá habilitar o recurso, escrever a procedure no contrato esperado e montar uma tabela de determinação de preços com vários fatores combinados: cliente, grupo, filial, território, condição de pagamento, moeda e faixas de quantidade.
Índice
Visão geral
No comportamento padrão, o Vendelo busca o preço de venda dos itens nas listas de preços do SAP Business One (as mesmas do cadastro de itens). Esse modelo atende bem quando o preço depende apenas da lista associada ao cliente ou ao documento.
Com o recurso de determinação de preços por procedure, o cálculo passa a ser feito por uma stored procedure sua, no banco do SAP B1. A cada pesquisa de itens em um documento de venda, o Vendelo envia para a procedure o contexto comercial completo (cliente, grupo de clientes, filial, lista de preços, território, condição de pagamento, moeda, desconto global e quantidades) e usa o preço devolvido como preço unitário do item.
A procedure substitui somente a origem do preço unitário. A política de preços e descontos do Vendelo continua valendo e é aplicada depois, sobre o preço retornado, exatamente como hoje acontece sobre o preço da lista: grupos de descontos (campanhas), descontos por período e quantidade, desconto adicional manual do vendedor e desconto padrão manual seguem funcionando normalmente.
A regra de preço fica 100% sob seu controle, dentro do banco do SAP. O Vendelo não impõe um modelo de tabela: você pode ler tabelas de usuário (UDTs), tabelas padrão do SAP, faixas de quantidade, vigências ou qualquer combinação, desde que a procedure respeite o contrato de entrada e saída descrito neste artigo.
Quando usar
O recurso foi criado para cenários em que a formação de preço depende de vários fatores simultâneos, algo que as listas de preços padrão do SAP B1 não expressam sozinhas:
- Preço negociado por cliente: acordos comerciais específicos por
CardCode, com ou sem vigência. - Política por grupo de clientes: atacado, varejo, revenda, key accounts, cada um com sua régua.
- Faixas de quantidade: preço escalonado conforme a quantidade digitada no pedido.
- Preço por filial ou território: diferenciação regional ou por unidade de negócio.
- Condição de pagamento: bonificação para pagamento à vista, acréscimo para prazos longos.
- Moeda: tabela própria em moeda estrangeira para exportação, sem depender de conversão por taxa.
- Regras combinadas: qualquer cruzamento dos fatores acima, com prioridade entre regras.
O recurso não substitui tudo: a política de descontos interna do Vendelo (grupos de descontos, campanhas por período e quantidade, desconto adicional do vendedor, desconto padrão manual e vouchers) continua sendo aplicada pelo próprio Vendelo, sobre o preço devolvido pela procedure. Regras fiscais e de impostos também seguem o fluxo normal do SAP B1.
Como funciona
O vendedor pesquisa itens no documento. Em uma cotação ou pedido de venda, ao pesquisar itens ou recarregar preços, o documento já tem (total ou parcialmente) cliente, filial, lista de preços, condição de pagamento, moeda e quantidades.
O Vendelo monta o contexto comercial. Os dados do documento são convertidos para os códigos nativos do SAP B1: o cliente vira o
CardCode, o grupo de clientes vira oGroupCode, a lista de preços vira oListNum, e assim por diante. Campos ainda não preenchidos no documento seguem vazios.A procedure configurada é executada. O serviço de integração instalado no ambiente do SAP executa a procedure, e somente ela: apenas o nome configurado para a empresa pode ser chamado, o que impede a execução de comandos arbitrários no banco.
A procedure devolve o preço por item. O resultado traz uma linha por item, com o preço na moeda solicitada. O Vendelo não recalcula nem converte esse valor: ele entra como o preço unitário base do item.
Os preços aparecem na tela. Os valores são exibidos na pesquisa de itens e aplicados às linhas do documento, exatamente como acontecia com as listas de preços; a experiência do vendedor não muda.
O Vendelo aplica sua política de descontos. Sobre o preço devolvido pela procedure, o Vendelo aplica normalmente os grupos de descontos, os descontos por período e quantidade, o desconto adicional manual do vendedor e o desconto padrão manual, como faz hoje sobre o preço da lista.
Como a procedure recebe o contexto do documento, o mesmo item pode ter preços diferentes conforme o cliente, a quantidade ou a condição de pagamento selecionada. Se o vendedor alterar esses campos e repesquisar, o preço acompanha.
Configuração
A habilitação tem três passos: criar a procedure no banco do SAP, apontar o nome dela no serviço de integração e ativar o recurso na configuração da empresa no Vendelo.
Crie a procedure no banco do SAP B1 (SQL Server ou HANA), seguindo o contrato da seção Contrato da procedure. Um exemplo completo está na seção Exemplo de procedure.
Configure o serviço de integração. No arquivo de configuração do serviço de integração local (o serviço instalado no ambiente do SAP), informe o nome da procedure no campo
PriceProcedureNameda conexão da empresa e reinicie o serviço. O nome deve ser um identificador simples, com schema opcional (por exemploVDO_GET_PRICESouDBO.VDO_GET_PRICES); nomes com espaços, aspas ou outros caracteres são rejeitados. A configuração é por empresa (por banco): em ambientes multiempresa, cada conexão pode ter sua própria procedure, ou nenhuma.Ative o recurso no Vendelo. Na configuração da integração SAP B1 da empresa, é ativada a opção
UsePriceProcedure. Essa ativação é feita pela equipe de suporte do Vendelo: basta solicitar, informando a empresa e o nome da procedure já configurada no passo anterior.
Exemplo do trecho de configuração do serviço de integração:
"Companies": [
{
"Company": {
"DBProvider": "MSSQL",
"DBName": "SBO_MINHAEMPRESA",
"DBHost": "servidor-sap",
"...": "...",
"PriceProcedureName": "VDO_GET_PRICES"
}
}
]
Os dois lados precisam estar ativos. Com
UsePriceProcedureativo no Vendelo mas semPriceProcedureNameno serviço de integração, a busca de preços retorna erro de configuração. Com o nome configurado mas o recurso desativado no Vendelo, a procedure é ignorada e as listas de preços padrão continuam valendo. Ative sempre em conjunto.
Contrato da procedure
Parâmetros de entrada
A procedure recebe sempre os dez parâmetros abaixo, nesta ordem. Campos não preenchidos no documento chegam como NULL, e a procedure deve tratá-los.
| Parâmetro | Tipo | Conteúdo | Referência SAP B1 |
|---|---|---|---|
ItemCodes | texto | Códigos dos itens pesquisados, separados por vírgula. | OITM.ItemCode |
BranchId | inteiro | Filial do documento. | OBPL.BPLId |
BusinessPartnerId | texto | Cliente do documento. | OCRD.CardCode |
BusinessPartnerGroupId | inteiro | Grupo do cliente. | OCRG.GroupCode |
PriceListId | inteiro | Lista de preços do documento. | OPLN.ListNum |
TerritoryId | inteiro | Território do cliente. | OTER.territryID |
PaymentConditionsId | inteiro | Condição de pagamento. | OCTG.GroupNum |
Currency | texto | Moeda de referência do documento. | Códigos de moeda do B1 |
GlobalDiscountPercentage | decimal | Desconto global do documento (contexto: o Vendelo o aplica depois, sobre o preço retornado). | Informado no Vendelo |
BaseQuantities | texto (JSON) | Quantidade e desconto adicional por item (a quantidade serve para faixas; o desconto é contexto, aplicado depois pelo Vendelo). | Informado no Vendelo |
O parâmetro BaseQuantities chega como um array JSON, com o código SAP do item, a quantidade da linha e um eventual desconto adicional percentual:
[
{ "ItemId": "ITEM-001", "Qty": 60, "AdditionalDiscountPercentage": null },
{ "ItemId": "ITEM-014", "Qty": 250, "AdditionalDiscountPercentage": 2.5 }
]
Os percentuais de desconto (
GlobalDiscountPercentageeAdditionalDiscountPercentage) chegam apenas como informação de contexto. Não os reaplique no cálculo da procedure: o Vendelo aplica sua política de descontos sobre o preço retornado, e o desconto sairia em dobro.
No SQL Server os parâmetros são passados por nome (
@ItemCodes,@BranchId, …), então basta declará-los com esses nomes. No HANA a chamada é posicional: declare os parâmetros de entrada exatamente na ordem da tabela acima.
Retorno esperado
A procedure deve devolver um único conjunto de resultados, com uma linha por item, contendo as colunas abaixo. Use exatamente esses nomes de coluna, entre aspas, para garantir a grafia em ambos os bancos:
| Coluna | Obrigatoriedade | Conteúdo |
|---|---|---|
ItemId | Obrigatório | Código SAP do item (ItemCode). |
Price | Obrigatório | Preço unitário calculado pelas suas regras (a política de descontos do Vendelo é aplicada depois, sobre ele). |
Currency | Obrigatório | Moeda do preço; devolva a mesma moeda recebida. |
ListId | Opcional | Código da lista associada, se quiser ecoar a lista do documento. |
Se a procedure não devolver linha para um item, ele aparece sem preço no Vendelo. Inclua sempre um fallback, como o preço da lista padrão (
ITM1), para os itens que não se encaixarem em nenhuma regra da sua tabela.
Case: tabela de determinação de preços
O case a seguir mostra como substituir as listas de preços padrão do SAP B1 por uma tabela de usuário (UDT) que concentra a política comercial da empresa, com vários fatores combinados e prioridade entre regras.
Isto é apenas um exemplo. A tabela, os campos, os pesos e a regra de desempate mostrados aqui são uma sugestão didática e não fazem parte do produto. O contrato do Vendelo se resume à entrada e à saída da procedure (seção anterior); o miolo é inteiramente seu: você pode modelar a procedure da forma que preferir para calcular os preços com base na política interna da sua empresa: outras tabelas, outros fatores, outra lógica de prioridade, ou nenhuma tabela nova.
A tabela de usuário @VDL_PRECOS
Crie no SAP B1 uma tabela de usuário do tipo “Sem objeto” chamada VDL_PRECOS, com os campos abaixo. Em todos os campos de contexto, vazio significa “vale para todos”:
| Campo | Tipo | Significado |
|---|---|---|
U_ItemCode | texto | Item ao qual a regra se aplica (vazio = todos os itens). |
U_BPLId | inteiro | Filial (vazio = todas). |
U_CardCode | texto | Cliente específico (vazio = todos). |
U_GroupCode | inteiro | Grupo de clientes (vazio = todos). |
U_TerritryID | inteiro | Território (vazio = todos). |
U_PayGroupNum | inteiro | Condição de pagamento (vazio = todas). |
U_ListNum | inteiro | Lista de preços do documento (vazio = todas). |
U_Currency | texto | Moeda da regra (ex.: BRL, USD). |
U_QtyMin | decimal | Quantidade mínima para a regra valer (faixas de quantidade). |
U_Price | decimal | Preço unitário da regra (vazio em regras que só dão desconto). |
U_DiscPct | decimal | Desconto % aplicado sobre a regra de preço vencedora (modificador). |
U_ValidFrom / U_ValidTo | data | Vigência da regra (vazio = sempre válida). |
Regra de prioridade: o mais específico vence
Quando mais de uma regra de preço atende ao contexto, vence a mais específica. Uma forma simples e determinística de implementar isso é atribuir pesos por campo preenchido e somar:
| Campo preenchido | Peso |
|---|---|
U_CardCode (cliente) | 32 |
U_BPLId (filial) | 16 |
U_GroupCode (grupo de clientes) | 8 |
U_TerritryID (território) | 4 |
U_PayGroupNum (condição de pagamento) | 2 |
U_ListNum (lista de preços) | 1 |
- Entre regras de mesmo peso, vence a de maior quantidade mínima atendida (faixa mais vantajosa).
- Persistindo o empate, vence o menor preço (postura conservadora a favor do cliente; inverta se a política for outra).
- Regras só de desconto (
U_Pricevazio eU_DiscPctpreenchido) não competem: elas se aplicam sobre o preço da regra vencedora, de forma cumulativa.
Exemplo de conteúdo da tabela
Cadastro de exemplo para o item ITEM-001 (preço de tabela R$ 100,00) e uma regra geral de grupo:
| Regra | Condições | Qtde mín. | Preço | Desc. % |
|---|---|---|---|---|
| R01 | Item ITEM-001 · lista 1 · BRL | – | 100,00 | – |
| R02 | Item ITEM-001 · grupo 102 Atacado · BRL | – | 95,00 | – |
| R03 | Item ITEM-001 · grupo 102 Atacado · BRL | 50 | 89,90 | – |
| R04 | Item ITEM-001 · grupo 102 Atacado · BRL | 200 | 84,50 | – |
| R05 | Item ITEM-001 · cliente C20000 · BRL | – | 92,00 | – |
| R06 | Item ITEM-001 · cliente C20000 · filial 2 (SP) · BRL | – | 90,00 | – |
| R07 | Item ITEM-001 · território 5 Sul · BRL | – | 97,50 | – |
| R08 | Item ITEM-001 · condição -1 À vista · BRL | – | – | 3,0 |
| R09 | Item ITEM-001 · USD | – | 19,90 | – |
| R10 | Todos os itens · grupo 104 Revenda · BRL | – | – | 5,0 |
Como o preço é resolvido na prática
| Cenário | Regras candidatas | Resultado |
|---|---|---|
| Cliente C20000 (grupo Atacado), filial 2, território Sul, à vista, 60 un, BRL | Candidatas de preço: R01 (peso 1), R02 (8), R03 (8, faixa 50), R05 (32), R06 (48), R07 (4). | Vence R06 = 90,00 (cliente + filial). Modificador R08 (à vista, −3%) → 87,30. |
| Cliente avulso do grupo Varejo, 10 un, BRL, lista 1 | Só R01 atende. | Preço de tabela: 100,00. |
| Cliente do grupo Atacado, a prazo, 250 un, BRL | R01, R02, R03 e R04, todas com o mesmo peso (8); vence a maior faixa atendida. | Vence R04 = 84,50 (faixa de 200 un). |
| Cliente de exportação, documento em USD | Só R09 tem moeda USD. | Preço USD 19,90, sem conversão de câmbio. |
| Cliente do grupo Revenda comprando qualquer item, BRL | Regra de preço vencedora conforme o item, mais o modificador R10 (−5% em tudo para o grupo). | Preço da regra vencedora × 0,95. |
Além das regras da tabela, a procedure recebe o
GlobalDiscountPercentagedo documento e oAdditionalDiscountPercentagepor item (viaBaseQuantities). Use-os apenas como contexto (a quantidade, por exemplo, define a faixa de preço): esses descontos são aplicados pelo próprio Vendelo, depois, sobre o preço retornado.
Case com dados: do pedido ao preço
Para fechar o raciocínio, vamos acompanhar um pedido de ponta a ponta: o que o vendedor preenche, o que a procedure recebe, como cada preço é calculado, o que volta para o Vendelo e o que o Vendelo aplica depois. Os valores e regras usados aqui são os do case anterior, um exemplo ilustrativo; na sua implementação, o cálculo seguirá a lógica que você definir na procedure, conforme a política de preços da sua empresa.
1. O pedido no Vendelo
O vendedor monta um pedido de venda com dois itens para um cliente atacadista:
| Campo do pedido | Valor selecionado | Código SAP enviado |
|---|---|---|
| Cliente | Mercado Bom Preço Ltda. (grupo Atacado) | C20000 |
| Grupo do cliente | Atacado | 102 |
| Filial | São Paulo | 2 |
| Território | Sul | 5 |
| Condição de pagamento | À vista | -1 |
| Lista de preços | Lista de venda | 1 |
| Moeda | Real | BRL |
| Desconto global | 2% | 2.0 |
| Item 1 | ITEM-001, 60 unidades | ITEM-001 |
| Item 2 | ITEM-014, 250 unidades, com 2,5% de desconto adicional na linha | ITEM-014 |
2. O que a procedure recebe
Ao pesquisar os itens, a procedure é executada com estes valores:
@ItemCodes = 'ITEM-001,ITEM-014'
@BranchId = 2
@BusinessPartnerId = 'C20000'
@BusinessPartnerGroupId = 102
@PriceListId = 1
@TerritoryId = 5
@PaymentConditionsId = -1
@Currency = 'BRL'
@GlobalDiscountPercentage = 2.0
@BaseQuantities = '[
{ "ItemId": "ITEM-001", "Qty": 60, "AdditionalDiscountPercentage": null },
{ "ItemId": "ITEM-014", "Qty": 250, "AdditionalDiscountPercentage": 2.5 }
]'
3. O cálculo, item a item
Cálculo do ITEM-001, que tem regras próprias na @VDL_PRECOS:
Regras de preço candidatas: R01 (peso 1), R02 (8), R03 (8, faixa 50 atendida com 60 un), R05 (32), R06 (48) e R07 (4). Vence R06 (cliente C20000 + filial 2): preço base 90,00.
Modificador da tabela: R08 (à vista, −3%) se aplica → 90,00 × 0,97 = 87,30.
Preço devolvido: 87,30. O desconto global de 2% do pedido não entra aqui: ele é contexto, e será aplicado depois, pelo próprio Vendelo.
Cálculo do ITEM-014, que não tem nenhuma regra na tabela (R10 não se aplica, pois o cliente é do grupo Atacado, não Revenda):
Fallback: a procedure busca o preço na lista padrão do SAP (
ITM1, lista 1): 42,00.Preço devolvido: 42,00. O desconto global de 2% e o desconto adicional de 2,5% da linha ficam com o Vendelo, na etapa seguinte.
4. O que volta para o Vendelo
| ItemId | Price | Currency | ListId |
|---|---|---|---|
ITEM-001 | 87.3000 | BRL | 1 |
ITEM-014 | 42.0000 | BRL | 1 |
5. O que o Vendelo aplica depois
O valor devolvido pela procedure entra como preço unitário do item. Sobre ele, o Vendelo aplica sua política de preços e descontos, exatamente como faria sobre o preço da lista:
| Item | Preço da procedure | Descontos aplicados pelo Vendelo | Preço final na linha |
|---|---|---|---|
ITEM-001 | 87,30 | Desconto global do pedido (2%) | 87,30 × 0,98 = 85,55 |
ITEM-014 | 42,00 | Desconto global (2%) e desconto adicional da linha (2,5%) | 42,00 × 0,98 × 0,975 = 40,13 |
Se houver grupos de descontos ou descontos por período e quantidade cadastrados no Vendelo, eles também entram nessa etapa. E se o vendedor trocar a condição de pagamento para “28 dias” e repesquisar, o modificador R08 deixa de valer: a procedure passa a devolver 90,00 e, com o desconto global de 2%, a linha fica em 88,20.
Use este roteiro como massa de teste da sua implementação: cadastre as regras R01 a R10, execute a procedure no banco com os parâmetros acima e confira se o resultado bate com as duas linhas da tabela da etapa 4 (87,30 e 42,00). Os descontos da etapa 5 só aparecem dentro do Vendelo.
Exemplo de procedure
Três modelos prontos para começar. As duas primeiras são cascas de referência, uma para cada banco: elas apenas reproduzem a busca padrão na lista de preços do SAP (ITM1), ou seja, entregam o mesmo resultado do comportamento atual. Servem como ponto de partida seguro: crie a casca, valide o fluxo de ponta a ponta e depois evolua a regra por dentro, mantendo apenas as colunas do SELECT final. O terceiro modelo é o exemplo completo da tabela de determinação.
Casca de referência: SAP HANA (SQLScript)
CREATE PROCEDURE "VDO_GET_PRICES" (
IN "ItemCodes" NCLOB, -- ItemCode separados por virgula
IN "BranchId" INTEGER, -- OBPL.BPLId
IN "BusinessPartnerId" NVARCHAR(50), -- OCRD.CardCode
IN "BusinessPartnerGroupId" INTEGER, -- OCRG.GroupCode
IN "PriceListId" INTEGER, -- OPLN.ListNum
IN "TerritoryId" INTEGER, -- OTER.territryID
IN "PaymentConditionsId" INTEGER, -- OCTG.GroupNum
IN "Currency" NVARCHAR(3), -- Moeda de referencia
IN "GlobalDiscountPercentage" DECIMAL(19,6), -- Desconto global (contexto)
IN "BaseQuantities" NCLOB -- JSON: [{"ItemId":"","Qty":0,"AdditionalDiscountPercentage":0}]
)
LANGUAGE SQLSCRIPT
SQL SECURITY INVOKER
READS SQL DATA
AS
BEGIN
/* Exemplo funcional: reproduz a busca padrao na lista de precos
original do B1 (ITM1). Edite a regra a partir deste ponto,
mantendo as colunas ItemId, ListId, Price e Currency.
A comparacao por LOCATE concatena virgulas nas duas pontas para
garantir o match exato do codigo inteiro (evita que 'P10' case
com 'P100') e funciona em qualquer versao do HANA. Em HANA 2.0
SPS03 ou superior, uma alternativa com melhor plano de execucao
e converter a lista em linhas com SPLIT_TO_ARRAY + UNNEST e
filtrar com IN. */
SELECT
T1."ItemCode" AS "ItemId", -- ItemCode do item
T1."PriceList" AS "ListId", -- ListNum da lista de referencia
COALESCE(T1."Price", 0) AS "Price", -- Preco unitario calculado
COALESCE(T1."Currency", :Currency) AS "Currency" -- Moeda do preco
FROM ITM1 T1
WHERE
T1."PriceList" = :PriceListId
AND LOCATE(',' || :ItemCodes || ',', ',' || T1."ItemCode" || ',') > 0;
END;
Casca de referência: SQL Server (T-SQL)
CREATE PROCEDURE dbo.VDO_GET_PRICES
@ItemCodes NVARCHAR(MAX), -- ItemCode separados por virgula
@BranchId INT, -- OBPL.BPLId
@BusinessPartnerId NVARCHAR(50), -- OCRD.CardCode
@BusinessPartnerGroupId INT, -- OCRG.GroupCode
@PriceListId INT, -- OPLN.ListNum
@TerritoryId INT, -- OTER.territryID
@PaymentConditionsId INT, -- OCTG.GroupNum
@Currency NVARCHAR(3), -- Moeda de referencia
@GlobalDiscountPercentage DECIMAL(19,6), -- Desconto global (contexto)
@BaseQuantities NVARCHAR(MAX) -- JSON: [{"ItemId":"","Qty":0,"AdditionalDiscountPercentage":0}]
AS
BEGIN
SET NOCOUNT ON;
/* Exemplo funcional: reproduz a busca padrao na lista de precos
original do B1 (ITM1). Edite a regra a partir deste ponto,
mantendo as colunas ItemId, ListId, Price e Currency. */
SELECT
T1.ItemCode AS ItemId, -- ItemCode do item
T1.PriceList AS ListId, -- ListNum da lista de referencia
COALESCE(T1.Price, 0) AS Price, -- Preco unitario calculado
COALESCE(T1.Currency, @Currency) AS Currency -- Moeda do preco
FROM ITM1 T1
WHERE
T1.PriceList = @PriceListId
AND T1.ItemCode IN (SELECT value FROM STRING_SPLIT(@ItemCodes, ','));
END
Exemplo completo: tabela de determinação (T-SQL)
Implementação de referência da determinação descrita nos cases, com fallback para a lista de preços padrão. Adapte nomes, pesos e política de desempate à sua realidade; em HANA a lógica é a mesma em SQLScript.
CREATE PROCEDURE VDO_GET_PRICES
@ItemCodes nvarchar(max),
@BranchId int = NULL,
@BusinessPartnerId nvarchar(50) = NULL,
@BusinessPartnerGroupId int = NULL,
@PriceListId int = NULL,
@TerritoryId int = NULL,
@PaymentConditionsId int = NULL,
@Currency nvarchar(3) = NULL,
@GlobalDiscountPercentage decimal(19,6) = NULL,
@BaseQuantities nvarchar(max) = NULL
AS
BEGIN
SET NOCOUNT ON;
-- Itens pesquisados + quantidade e desconto adicional por item
;WITH Itens AS (
SELECT LTRIM(RTRIM(value)) AS ItemCode
FROM STRING_SPLIT(@ItemCodes, ',')
WHERE LTRIM(RTRIM(value)) <> ''
),
Qtds AS (
SELECT ItemId, Qty, AddDisc
FROM OPENJSON(COALESCE(@BaseQuantities, '[]'))
WITH (ItemId nvarchar(50) '$.ItemId',
Qty decimal(19,6) '$.Qty',
AddDisc decimal(19,6) '$.AdditionalDiscountPercentage')
),
-- Regras de PRECO aplicaveis, pontuadas por especificidade
Regras AS (
SELECT i.ItemCode, r.U_Price,
Score = CASE WHEN r.U_CardCode IS NOT NULL THEN 32 ELSE 0 END
+ CASE WHEN r.U_BPLId IS NOT NULL THEN 16 ELSE 0 END
+ CASE WHEN r.U_GroupCode IS NOT NULL THEN 8 ELSE 0 END
+ CASE WHEN r.U_TerritryID IS NOT NULL THEN 4 ELSE 0 END
+ CASE WHEN r.U_PayGroupNum IS NOT NULL THEN 2 ELSE 0 END
+ CASE WHEN r.U_ListNum IS NOT NULL THEN 1 ELSE 0 END,
QtyMin = COALESCE(r.U_QtyMin, 0)
FROM Itens i
LEFT JOIN Qtds q ON q.ItemId = i.ItemCode
JOIN [@VDL_PRECOS] r
ON (r.U_ItemCode IS NULL OR r.U_ItemCode = i.ItemCode)
AND (r.U_BPLId IS NULL OR r.U_BPLId = @BranchId)
AND (r.U_CardCode IS NULL OR r.U_CardCode = @BusinessPartnerId)
AND (r.U_GroupCode IS NULL OR r.U_GroupCode = @BusinessPartnerGroupId)
AND (r.U_TerritryID IS NULL OR r.U_TerritryID = @TerritoryId)
AND (r.U_PayGroupNum IS NULL OR r.U_PayGroupNum = @PaymentConditionsId)
AND (r.U_ListNum IS NULL OR r.U_ListNum = @PriceListId)
AND (r.U_Currency IS NULL OR r.U_Currency = @Currency)
AND (r.U_QtyMin IS NULL OR r.U_QtyMin <= COALESCE(q.Qty, 0))
AND (r.U_ValidFrom IS NULL OR r.U_ValidFrom <= CAST(GETDATE() AS date))
AND (r.U_ValidTo IS NULL OR r.U_ValidTo >= CAST(GETDATE() AS date))
AND r.U_Price IS NOT NULL
),
Vencedora AS (
SELECT ItemCode, U_Price,
rn = ROW_NUMBER() OVER (PARTITION BY ItemCode
ORDER BY Score DESC, QtyMin DESC, U_Price ASC)
FROM Regras
),
-- Modificadores: regras so de desconto, cumulativas sobre a vencedora
Modif AS (
SELECT i.ItemCode,
Fator = EXP(SUM(LOG(1 - r.U_DiscPct / 100.0)))
FROM Itens i
JOIN [@VDL_PRECOS] r
ON (r.U_ItemCode IS NULL OR r.U_ItemCode = i.ItemCode)
AND (r.U_BPLId IS NULL OR r.U_BPLId = @BranchId)
AND (r.U_CardCode IS NULL OR r.U_CardCode = @BusinessPartnerId)
AND (r.U_GroupCode IS NULL OR r.U_GroupCode = @BusinessPartnerGroupId)
AND (r.U_TerritryID IS NULL OR r.U_TerritryID = @TerritoryId)
AND (r.U_PayGroupNum IS NULL OR r.U_PayGroupNum = @PaymentConditionsId)
AND (r.U_Currency IS NULL OR r.U_Currency = @Currency)
AND r.U_Price IS NULL AND r.U_DiscPct IS NOT NULL
GROUP BY i.ItemCode
),
-- Preco resolvido: regra vencedora ou fallback na lista padrao (ITM1)
Resolvido AS (
SELECT i.ItemCode,
Preco = COALESCE(v.U_Price, itm1.Price)
FROM Itens i
LEFT JOIN Vencedora v ON v.ItemCode = i.ItemCode AND v.rn = 1
LEFT JOIN ITM1 itm1 ON itm1.ItemCode = i.ItemCode
AND itm1.PriceList = @PriceListId
)
-- Retorno final: preco base + modificadores da propria tabela.
-- GlobalDiscountPercentage e AdditionalDiscountPercentage NAO sao
-- reaplicados aqui: o Vendelo aplica sua politica de descontos
-- depois, sobre o preco retornado.
SELECT r.ItemCode AS "ItemId",
CAST(r.Preco * COALESCE(m.Fator, 1) AS decimal(19,6)) AS "Price",
@Currency AS "Currency",
CAST(@PriceListId AS nvarchar(10)) AS "ListId"
FROM Resolvido r
LEFT JOIN Modif m ON m.ItemCode = r.ItemCode
WHERE r.Preco IS NOT NULL;
END
O que este exemplo garante: uma linha por item com preço na moeda do documento; regra mais específica vencendo; faixas de quantidade; modificadores de desconto da própria tabela; e fallback para a lista de preços padrão quando nenhuma regra se aplica. Os descontos do documento (global e adicional) não são reaplicados: ficam com o Vendelo, que os aplica sobre o preço retornado.
Boas práticas
| Tema | Recomendação |
|---|---|
| Performance | A procedure roda a cada pesquisa de itens. Mantenha-a leve: índices nos campos de filtro da UDT (item, cliente, grupo), sem cursores e sem gravações. |
| Somente leitura | A procedure deve apenas consultar dados. Não faça INSERT/UPDATE/DELETE nem chamadas externas dentro dela. |
| Fallback | Sempre devolva um preço para todo item recebido; em último caso, o da lista padrão. Item sem linha fica sem preço na tela. |
| Nulos | Todo parâmetro de contexto pode chegar NULL (documento ainda incompleto). Trate NULL como “sem restrição” e garanta um preço mesmo assim. |
| Moeda | Devolva o preço na moeda recebida em Currency. O Vendelo não converte câmbio sobre o valor retornado. |
| Descontos | Não reaplique na procedure os descontos que o Vendelo aplica depois (política de descontos, desconto global, desconto adicional): o desconto sairia em dobro. |
| Determinismo | Defina desempate explícito entre regras (pesos e ordem). Duas execuções com o mesmo contexto devem devolver o mesmo preço. |
| Governança | Versione o script da procedure e controle quem altera a UDT de preços: ela passa a ser a fonte oficial da política comercial. |
| Homologação | Valide primeiro no banco de testes: execute a procedure direto no SSMS ou no HANA Studio com contextos reais antes de ativar em produção. |
Validação e diagnóstico
Roteiro de teste
Teste a procedure no banco. Execute-a diretamente, simulando um contexto real (cliente, filial, quantidades), e confira o resultado: colunas
ItemId,PriceeCurrency, com uma linha por item.Configure e reinicie o serviço de integração com o
PriceProcedureNameapontando para a procedure criada.Valide no Vendelo. Com o recurso ativo, abra um pedido de venda, selecione um cliente com regra específica e pesquise um item coberto pela tabela: o preço exibido deve ser o da regra, não o da lista padrão.
Varie o contexto. Altere quantidade, condição de pagamento e cliente, repesquisando a cada mudança, e confirme que o preço acompanha as regras cadastradas.
Confirme o fallback. Pesquise um item sem regra na tabela e verifique que ele recebe o preço da lista padrão.
Problemas comuns
| Sintoma | Causa provável |
|---|---|
| Erro “PriceProcedureName não configurada” | Recurso ativo no Vendelo, mas nome da procedure ausente na conexão da empresa no serviço de integração. |
| Erro “PriceProcedureName inválida” | Nome com caracteres não permitidos; use apenas identificador simples, com schema opcional. |
| Itens sem preço na pesquisa | Procedure não devolveu linha para o item (falta fallback) ou nome das colunas diferente do contrato. |
| Preço não muda com o contexto | Parâmetro chegando NULL (campo ainda não preenchido no documento) ou regra sem correspondência exata de código SAP. |
| Erro interno ao pesquisar itens | Falha de execução da procedure (sintaxe, permissão, timeout). Teste-a isoladamente no banco com os mesmos parâmetros. |
| Preços continuam vindo da lista padrão | Opção UsePriceProcedure não ativada na configuração da empresa no Vendelo. |
Perguntas frequentes
Preciso mudar alguma coisa nas telas do Vendelo para usar o recurso?
Não. A experiência do vendedor não muda: a pesquisa de itens e as linhas do documento continuam iguais; apenas a origem do preço passa a ser a sua procedure.
O que acontece se a procedure não devolver preço para um item?
O item aparece sem preço na pesquisa. Por isso a recomendação é sempre incluir um fallback dentro da procedure, como o preço da lista padrão do SAP (ITM1).
Posso continuar usando as listas de preços do SAP para parte dos itens?
Sim. Basta a procedure devolver, para esses itens, o próprio preço da lista padrão (é exatamente o que o fallback do exemplo faz). A decisão de quais itens seguem regra própria e quais seguem a lista fica dentro da procedure.
Funciona tanto em SQL Server quanto em SAP HANA?
Sim. A diferença está na forma de passagem dos parâmetros: por nome no SQL Server e por posição no HANA, onde os parâmetros devem ser declarados exatamente na ordem do contrato.
Os descontos do Vendelo (grupos, campanhas, desconto adicional) passam pela procedure?
Não. A procedure devolve o preço unitário base do item. Sobre ele, o Vendelo aplica normalmente sua política de descontos: grupos de descontos (campanhas), descontos por período e quantidade, desconto adicional manual do vendedor, desconto padrão manual e vouchers. Como funciona a hierarquia entre eles está no artigo Política de Descontos no Vendelo.
Sou obrigado a usar uma tabela de usuário (UDT)?
Não. A UDT do case é uma sugestão de organização. A procedure pode consultar qualquer fonte dentro do banco do SAP: tabelas padrão, outras UDTs, visões ou combinações delas.
Como testo sem afetar o ambiente de produção?
Crie a procedure primeiro no banco de testes e execute-a diretamente no SSMS ou no HANA Studio com contextos reais. Só depois configure o serviço de integração do ambiente produtivo e solicite a ativação do recurso.
Se o vendedor mudar a quantidade ou a condição de pagamento, o preço atualiza?
Sim: ao repesquisar itens ou recarregar os preços do documento, o Vendelo envia o novo contexto para a procedure e exibe o preço recalculado.
A procedure pode gravar dados ou chamar outros sistemas?
Não é recomendado. Ela roda a cada pesquisa de itens e deve ser somente leitura, rápida e determinística. Gravações e chamadas externas trazem lentidão e efeitos colaterais difíceis de diagnosticar.
Quem ativa o recurso e o que preciso fornecer?
A criação da procedure e a configuração do serviço de integração são feitas pelo consultor no ambiente do SAP. A ativação da opção UsePriceProcedure na configuração da empresa é feita pela equipe de suporte do Vendelo; informe a empresa e o nome da procedure configurada.
Em um ambiente com várias empresas, todas precisam usar a mesma procedure?
Não. A configuração é por empresa (por banco): cada uma pode ter sua própria procedure, e empresas sem o recurso continuam usando as listas de preços padrão normalmente.
O preço devolvido pela procedure sofre alguma conversão de moeda?
Não. O valor devolvido é usado, sem conversão, como preço unitário na moeda informada na coluna Currency. Se o documento estiver em outra moeda, é responsabilidade da procedure devolver o preço já na moeda solicitada.