Venda Casada - Beneficiamento com Vinculação de Pedido de Venda - NH-168
Data de Implementação: 2025-12-01 Jira Issue: NH-168 Módulo: Comercial Tela: Adicionar/Editar Pedido (Cotação) Tipo: Feature - Nova Funcionalidade
Índice
- Resumo
- Contexto e Motivação
- Conceito de Venda Casada
- Comportamento Implementado
- Fluxo de Utilização
- Detalhes Técnicos
- Estrutura de Dados
- Validações e Regras de Negócio
- Restrições de Ações
- Como Testar
- Troubleshooting
- Impacto no Sistema
- Arquivos Modificados
- Referências
Resumo
Implementação da funcionalidade de Venda Casada que permite vincular itens de um Pedido de Venda existente a um Pedido de Beneficiamento. Esta funcionalidade é utilizada quando a empresa realiza um serviço de beneficiamento (ex: corte, usinagem) em material que será posteriormente entregue ao cliente final de uma venda já existente.
Natureza de Operação: "Remessa Beneficiamento para posterior retorno com Venda Casada" (TipoNaturezaOperacaoEnum.BeneficiamentoVendaCasada)
Comportamento Principal: - Quando a natureza de operação é "BeneficiamentoVendaCasada", a interface de inclusão de itens muda - Os botões "Novo Item de Estoque" e "Novo Item de Terceiro" são ocultados - Uma nova seção "Vincular Item de Pedido de Venda (Venda Casada)" é exibida - O usuário busca e seleciona itens de Pedidos de Venda existentes para vincular ao pedido de beneficiamento
Contexto e Motivação
O que é Venda Casada?
A Venda Casada é um processo comercial onde:
- Primeiro: Um cliente faz um pedido de compra de material (Pedido de Venda)
- Segundo: A empresa envia o material para um fornecedor realizar beneficiamento (corte, usinagem, etc.)
- Terceiro: O material beneficiado retorna e é entregue ao cliente final
Neste fluxo, é essencial manter a rastreabilidade entre: - O Pedido de Venda original (cliente final) - O Pedido de Beneficiamento (envio para fornecedor)
Problema Anterior
Antes desta implementação: - Não havia forma de vincular o pedido de beneficiamento ao pedido de venda original - A rastreabilidade era manual, sujeita a erros - Relatórios gerenciais não conseguiam cruzar informações automaticamente
Benefícios da Implementação
- Rastreabilidade automática: Vínculo direto entre pedidos
- Integridade de dados: Referências em banco de dados
- Controle de itens: Itens vinculados têm ações restritas
- Relatórios integrados: Possibilidade de consultas cruzadas
Conceito de Venda Casada
Diagrama do Fluxo
┌─────────────────────────────────────────────────────────────────────────────┐
│ FLUXO DE VENDA CASADA │
└─────────────────────────────────────────────────────────────────────────────┘
┌──────────────────┐ ┌──────────────────┐
│ PEDIDO DE VENDA │ │ PEDIDO DE │
│ (Original) │ │ BENEFICIAMENTO │
│ │ │ │
│ Natureza: │ │ Natureza: │
│ "Vendas de │◄───── VÍNCULO ─────│ "Remessa │
│ Produto" │ │ Beneficiamento │
│ │ │ Venda Casada" │
│ Cliente: ABC │ │ │
│ Item: Barra │ │ Destinatário: │
│ Alumínio 10kg │ │ Fornecedor XYZ │
└────────┬─────────┘ └────────┬─────────┘
│ │
│ │
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ Item Pedido │ │ Item Pedido │
│ de Venda │ │ Beneficiamento │
│ │ │ │
│ PedidoItem.Id=4 │◄─── REFERÊNCIA ────│ PedidoVenda- │
│ │ DIRETA │ VinculadoId=15 │
│ Mercadoria: │ │ │
│ LTBC001 │ │ PedidoItemVenda- │
│ │ │ VinculadoId=4 │
└──────────────────┘ └──────────────────┘
┌──────────────────────────────┐
│ BENEFICIAMENTO │
│ │
│ Material enviado para │
│ FORNECEDOR realizar: │
│ - Corte │
│ - Usinagem │
│ - Tratamento │
│ │
│ Após beneficiamento: │
│ Material retorna para │
│ entrega ao CLIENTE FINAL │
└──────────────────────────────┘
Entidades Envolvidas
| Entidade | Papel | Exemplo |
|---|---|---|
| Cliente | Comprador final do material | Empresa ABC Ltda |
| Fornecedor | Prestador do serviço de beneficiamento | Usinagem XYZ |
| Pedido de Venda | Pedido do cliente para compra do material | Pedido #15 |
| Pedido de Beneficiamento | Pedido de envio ao fornecedor para beneficiamento | Pedido #53 |
| Mercadoria | Material sendo vendido/beneficiado | LTBC001 - Barra Chata Latão |
Tipo de Item: Sempre Estoque (Não Terceiros)
IMPORTANTE: Itens de Venda Casada são sempre itens de estoque, nunca itens de terceiros (Ordem de Compra).
Esta distinção é fundamental porque:
- Fluxo de Material: O material que vai para beneficiamento é mercadoria própria da empresa (estoque), não material comprado de terceiros para revenda
- Origem no SGE 2.0: No sistema legado, a operação
REM.BENEF(Remessa Beneficiamento para Venda Casada) é tratada junto com operações de estoque comoTRANSF.V(Transferência de Venda), usando a gridgvItensTransferencia - Unidade de Medida: O SGE 2.0 configura explicitamente
UnidadePergunta = "KG"para itens de Venda Casada, característico de itens de estoque
Evidência do Código SGE 2.0
// frm_Pedidos.aspx.cs - Linha 5190
if (ddlOperacao.SelectedValue.ToString().ToUpper() == "TRANSF.V" ||
ddlOperacao.SelectedValue.ToString().ToUpper() == "REM.BENEF" || // Venda Casada
ddlOperacao.SelectedValue.ToString().ToUpper() == "ORCA 2")
{
gvItensTransferencia.Visible = true; // Grid de itens de ESTOQUE
gvItens.Visible = false;
// ...
}
// frm_Pedidos.aspx.cs - Linha 7058
if (ddlOperacao.SelectedValue.ToString().ToUpper().Equals("REM.BENEF"))
{
ViewState["UnidadePergunta"] = "KG"; // Unidade de ESTOQUE
ddlUnidadePreco.Items.Clear();
AddEmptyItem(ddlUnidadePreco, "KG", "KG");
// ...
}
Implicação Técnica
No SGE 3.0, a view de visualização de itens de Venda Casada (View) utiliza apenas ItemEstoque/View.cshtml, nunca ItemTerceiro/View.cshtml:
// PedidoItemController.cs
[Route("visualizar-item/{pedidoId:int}/{pedidoItemId:int}")]
public async Task<IActionResult> View(int pedidoId, int pedidoItemId)
{
// ...
// NH-168: Venda Casada é sempre item de estoque (não de terceiros/Ordem de Compra)
return View("ItemEstoque/View", pedidoItemViewModel);
}
Comportamento Implementado
Cenário: Natureza de Operação "BeneficiamentoVendaCasada"
Quando o usuário seleciona a natureza de operação "Remessa Beneficiamento para posterior retorno com Venda Casada":
1. Interface de Inclusão de Itens
Elementos Ocultados: - Botão "Novo Item de Estoque" - Botão "Novo Item de Terceiro"
Elementos Exibidos: - Seção "Vincular Item de Pedido de Venda (Venda Casada)"
┌─────────────────────────────────────────────────────────────────────────────┐
│ SEÇÃO: ITENS │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Vincular Item de Pedido de Venda (Venda Casada) │ │
│ ├─────────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ Nº Pedido de Venda Pedido de Venda Item do Pedido │ │
│ │ ┌─────────┬───┐ ┌──────────────▼┐ ┌──────────────▼┐ [+] │ │
│ │ │ 15 │ 🔍│ │ Pedido #15 │ │ Item 4 - ... │ │ │
│ │ └─────────┴───┘ └───────────────┘ └───────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ │ Mercadoria: LTBC001 - BARRA CHATA LATAO │ │ │
│ │ │ Quantidade: 1,000 PC | Vr. Unitário: R$ 50,00 │ │ │
│ │ │ Vr. Total: R$ 50,00 │ │ │
│ │ └─────────────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ TABELA DE ITENS │ │
│ ├──────┬────────┬────────────────────┬───────────┬────────┬──────────┤ │
│ │ Tipo │ Código │ Descrição │ Qtde Sep. │ Valor │ Ação │ │
│ ├──────┼────────┼────────────────────┼───────────┼────────┼──────────┤ │
│ │ Est. │ LTBC001│ BARRA CHATA LATAO │ 1,000 │ 50,00 │ [🗑] │ │
│ │ │ │ (Venda Casada) │ │ │ │ │
│ └──────┴────────┴────────────────────┴───────────┴────────┴──────────┘ │
│ │
│ * Itens de Venda Casada só podem ser EXCLUÍDOS (não editados) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
2. Restrições em Itens de Venda Casada
Itens vinculados a um Pedido de Venda (Venda Casada) possuem ações restritas:
| Ação | Item Normal | Item Venda Casada |
|---|---|---|
| Editar | ✅ Permitido | ❌ Bloqueado |
| Excluir | ✅ Permitido | ✅ Permitido |
| Expedição | ✅ Permitido | ❌ Bloqueado |
Motivo: Os dados do item vêm do Pedido de Venda original e não devem ser alterados individualmente.
Fluxo de Utilização
Passo a Passo Completo
Pré-requisitos
- Ter um Pedido de Venda existente:
- Status: "A Faturar" ou "Fechado"
- Natureza de Operação: Tipo "Venda"
-
Com pelo menos um item
-
O Destinatário do Pedido de Beneficiamento deve ser um Fornecedor cadastrado
Passo 1: Criar/Editar Pedido de Beneficiamento
- Acesse: Comercial > Adicionar Pedido ou Editar Pedido
- Selecione a Empresa de Emissão
- Selecione a Natureza de Operação: "Remessa Beneficiamento para posterior retorno com Venda Casada"
Passo 2: Configurar Destinatário (Fornecedor)
- Expanda a seção "Destinatário"
- Busque e selecione um Fornecedor cadastrado
- O fornecedor é quem realizará o serviço de beneficiamento
⚠️ IMPORTANTE: A natureza de operação exige que o destinatário seja um Fornecedor. Se o destinatário não estiver cadastrado como Fornecedor, o sistema retornará erro.
Passo 3: Vincular Item de Pedido de Venda
- Expanda a seção "Itens"
- Na seção "Vincular Item de Pedido de Venda (Venda Casada)":
- Digite o número do Pedido de Venda no campo "Nº Pedido de Venda"
- Clique no botão de busca (🔍)
- Selecione o Pedido de Venda no dropdown "Pedido de Venda"
- Selecione o Item no dropdown "Item do Pedido"
- Verifique as informações exibidas (Mercadoria, Quantidade, Valores)
- Clique no botão "+" para adicionar
Passo 4: Verificar Item Adicionado
- O item aparecerá na tabela de itens
- O campo "Observações" do item conterá: "Venda Casada - Pedido de Venda: X, Item: Y"
- O item terá apenas o botão de Excluir (🗑) disponível
Passo 5: Gravar Pedido
- Clique em "Gravar" para salvar o pedido
- O vínculo com o Pedido de Venda é persistido no banco de dados
Detalhes Técnicos
Endpoints da API
1. Buscar Pedidos de Venda para Venda Casada
URL: GET /comercial/pedido/buscar-pedidos-venda-venda-casada
Parâmetros:
- numeroPedido (string, opcional): Filtro por número do pedido
- destinatarioId (int, opcional): Filtro por destinatário
Resposta:
[
{
"id": 15,
"numero": 15,
"dataEmissao": "2025-11-30",
"destinatarioNome": "Cliente ABC Ltda",
"naturezaOperacaoNome": "Vendas de Produto",
"situacao": "A Faturar"
}
]
Filtros aplicados automaticamente:
- TipoPedido = Pedido (não orçamento)
- NaturezaOperacao.TipoNaturezaOperacao = Venda
- TipoSituacaoPedido = AFaturar (3) ou Fechado (4)
2. Buscar Itens do Pedido de Venda
URL: GET /comercial/pedido/buscar-itens-pedido-venda-casada
Parâmetros:
- pedidoVendaId (int, obrigatório): ID do pedido de venda
Resposta:
[
{
"id": 4,
"mercadoriaId": 123,
"mercadoriaCodigo": "LTBC001",
"mercadoriaNome": "BARRA CHATA LATAO (C-270) 3/8\" X 1/16\"",
"quantidade": 1.000,
"unidadeMedidaSigla": "PC",
"valorUnitario": 50.00,
"valorTotal": 50.00
}
]
3. Adicionar Item de Venda Casada
URL: POST /comercial/pedido/adicionar-item-venda-casada
Parâmetros (form data):
- pedidoAtualId (int): ID do pedido de beneficiamento atual
- pedidoVendaId (int): ID do pedido de venda a vincular
- pedidoItemVendaId (int): ID do item do pedido de venda
Resposta (sucesso):
{
"success": true,
"message": "Item adicionado com sucesso!",
"item": {
"id": 13,
"mercadoriaCodigo": "LTBC001",
"mercadoriaNome": "BARRA CHATA LATAO",
"quantidade": 1.000,
"unidadeMedida": "PC",
"valorUnitario": 50.00,
"valorTotal": 50.00,
"pedidoVendaVinculadoId": 15,
"pedidoItemVendaVinculadoId": 4
}
}
Resposta (erro):
Implementação JavaScript
Arquivo: _ValidationScriptsPedidoPartial.cshtml
Funções principais:
// Buscar pedidos de venda para Venda Casada
function buscarPedidosVendaCasada() {
const numeroPedido = $('#numeroPedidoVendaCasada').val();
$.ajax({
url: '/comercial/pedido/buscar-pedidos-venda-venda-casada',
type: 'GET',
data: { numeroPedido: numeroPedido },
success: function(pedidos) {
// Preenche dropdown de pedidos
const select = $('#pedidoVendaCasadaSelecionado');
select.empty().append('<option value="">Selecione...</option>');
pedidos.forEach(p => {
select.append(`<option value="${p.id}">
Pedido #${p.numero} - ${p.destinatarioNome}
</option>`);
});
select.prop('disabled', false);
}
});
}
// Buscar itens do pedido selecionado
function buscarItensPedidoVendaCasada(pedidoVendaId) {
$.ajax({
url: '/comercial/pedido/buscar-itens-pedido-venda-casada',
type: 'GET',
data: { pedidoVendaId: pedidoVendaId },
success: function(itens) {
// Preenche dropdown de itens
const select = $('#itemPedidoVendaCasadaSelecionado');
select.empty().append('<option value="">Selecione...</option>');
itens.forEach(i => {
select.append(`<option value="${i.id}"
data-mercadoria="${i.mercadoriaNome}"
data-quantidade="${i.quantidade}"
data-unidade="${i.unidadeMedidaSigla}"
data-valor-unitario="${i.valorUnitario}"
data-valor-total="${i.valorTotal}">
${i.mercadoriaCodigo} - ${i.mercadoriaNome}
</option>`);
});
select.prop('disabled', false);
}
});
}
// Adicionar item de Venda Casada
function adicionarItemVendaCasada() {
const pedidoAtualId = $('#Id').val();
const pedidoVendaId = $('#pedidoVendaCasadaSelecionado').val();
const pedidoItemVendaId = $('#itemPedidoVendaCasadaSelecionado').val();
$.ajax({
url: '/comercial/pedido/adicionar-item-venda-casada',
type: 'POST',
data: {
pedidoAtualId: pedidoAtualId,
pedidoVendaId: pedidoVendaId,
pedidoItemVendaId: pedidoItemVendaId
},
success: function(response) {
if (response.success) {
alert(response.message);
location.reload(); // Recarrega para atualizar a tabela
} else {
alert('Erro: ' + response.message);
}
}
});
}
Configuração de Visibilidade
A visibilidade dos elementos é controlada pela função configurarNaturezaOperacao():
function configurarNaturezaOperacao(naturezaOperacao) {
const tipoBeneficiamentoVendaCasada = 'BeneficiamentoVendaCasada';
if (naturezaOperacao.tipoNaturezaOperacao === tipoBeneficiamentoVendaCasada) {
// Oculta botões de inclusão manual
$('#botoesIncluirItem').hide();
// Exibe seção de Venda Casada
$('#secaoVendaCasada').show();
} else {
// Exibe botões de inclusão manual
$('#botoesIncluirItem').show();
// Oculta seção de Venda Casada
$('#secaoVendaCasada').hide();
}
}
Estrutura de Dados
Modelo: PedidoItem
Arquivo: src/Nelmetais.SGE.Business/Models/Comercial/PedidoItem.cs
Campos adicionados:
/// <summary>
/// NH-168: ID do Pedido de Venda vinculado (Venda Casada)
/// Usado quando a Natureza de Operação é "Remessa Beneficiamento para
/// posterior retorno com Venda Casada"
/// </summary>
public int? PedidoVendaVinculadoId { get; set; }
/// <summary>
/// NH-168: Pedido de Venda vinculado (Venda Casada)
/// </summary>
public Pedido? PedidoVendaVinculado { get; set; }
/// <summary>
/// NH-168: ID do Item do Pedido de Venda vinculado (Venda Casada)
/// </summary>
public int? PedidoItemVendaVinculadoId { get; set; }
/// <summary>
/// NH-168: Item do Pedido de Venda vinculado (Venda Casada)
/// </summary>
public PedidoItem? PedidoItemVendaVinculado { get; set; }
Configuração Entity Framework
Arquivo: src/Nelmetais.SGE.Data/Configurations/Comercial/PedidoItemConfiguration.cs
// NH-168: Configuração dos campos de Venda Casada
builder.HasOne(pi => pi.PedidoVendaVinculado)
.WithMany()
.HasForeignKey(pi => pi.PedidoVendaVinculadoId)
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne(pi => pi.PedidoItemVendaVinculado)
.WithMany()
.HasForeignKey(pi => pi.PedidoItemVendaVinculadoId)
.OnDelete(DeleteBehavior.Restrict);
Migration
Arquivo: 20251201153423_AddVendaCasadaLinksToPedidoItem.cs
migrationBuilder.AddColumn<int>(
name: "PedidoItemVendaVinculadoId",
table: "PedidoItem",
type: "integer",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "PedidoVendaVinculadoId",
table: "PedidoItem",
type: "integer",
nullable: true);
migrationBuilder.AddForeignKey(
name: "FK_PedidoItem_Pedido_PedidoVendaVinculadoId",
table: "PedidoItem",
column: "PedidoVendaVinculadoId",
principalTable: "Pedido",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
migrationBuilder.AddForeignKey(
name: "FK_PedidoItem_PedidoItem_PedidoItemVendaVinculadoId",
table: "PedidoItem",
column: "PedidoItemVendaVinculadoId",
principalTable: "PedidoItem",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
Diagrama do Banco de Dados
┌─────────────────────────────────────────────────────────────────────────────┐
│ TABELA: PedidoItem │
├─────────────────────────────────────────────────────────────────────────────┤
│ Id INTEGER (PK) │
│ PedidoId INTEGER (FK → Pedido.Id) │
│ MercadoriaId INTEGER (FK → Mercadoria.Id) │
│ Quantidade DECIMAL │
│ ValorUnitario DECIMAL │
│ ValorTotal DECIMAL │
│ ... │
│ ───────────────────────────────────────────────────────────────────────── │
│ PedidoVendaVinculadoId INTEGER (FK → Pedido.Id) [NULLABLE] ◄── NH-168
│ PedidoItemVendaVinculadoId INTEGER (FK → PedidoItem.Id) [NULLABLE]◄── NH-168
└─────────────────────────────────────────────────────────────────────────────┘
│ │
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Pedido │ │ PedidoItem │
│ (Venda) │ │ (Item da Venda) │
│ │ │ │
│ Id = 15 │ │ Id = 4 │
│ Natureza: │ │ PedidoId = 15 │
│ "Venda Produto"│ │ Mercadoria: │
│ │ │ LTBC001 │
└─────────────────┘ └─────────────────┘
Validações e Regras de Negócio
Validações Implementadas
1. Pedido Atual deve ser do tipo BeneficiamentoVendaCasada
if (pedidoAtual.NaturezaOperacao?.TipoNaturezaOperacao !=
TipoNaturezaOperacaoEnum.BeneficiamentoVendaCasada)
{
return Json(new {
success = false,
message = "O pedido atual não é do tipo 'Beneficiamento para Venda Casada'."
});
}
2. Pedido de Venda deve existir
var pedidoVenda = await _pedidoRepository.ObterPedido(pedidoVendaId);
if (pedidoVenda == null)
{
return Json(new {
success = false,
message = "Pedido de Venda não encontrado."
});
}
3. Item do Pedido de Venda deve existir
var itemVenda = pedidoVenda.PedidosItens?.FirstOrDefault(i => i.Id == pedidoItemVendaId);
if (itemVenda == null)
{
return Json(new {
success = false,
message = "Item do Pedido de Venda não encontrado."
});
}
4. Item não pode estar já vinculado ao mesmo pedido
var itemJaVinculado = pedidoAtual.PedidosItens?.Any(i =>
i.PedidoVendaVinculadoId == pedidoVendaId &&
i.PedidoItemVendaVinculadoId == pedidoItemVendaId);
if (itemJaVinculado == true)
{
return Json(new {
success = false,
message = "Este item já foi vinculado a este pedido de Beneficiamento."
});
}
5. Destinatário deve ser um Fornecedor
A natureza de operação "BeneficiamentoVendaCasada" está configurada com:
- NaturezaOperacaoDestinatarioId = 2 (Fornecedor)
Se o destinatário não estiver cadastrado como Fornecedor, o sistema retorna:
"A natureza de operação selecionada solicita que o destinatário informado seja um fornecedor."
Filtros na Busca de Pedidos de Venda
Apenas pedidos que atendem aos critérios são retornados:
| Critério | Valor |
|---|---|
| Tipo do Pedido | Pedido (não Orçamento) |
| Tipo da Natureza | Venda (TipoNaturezaOperacaoEnum.Venda) |
| Situação | A Faturar (3) ou Fechado (4) |
pedidos = pedidos
.Where(p => p.TipoPedido?.Descricao == "Pedido")
.Where(p => p.NaturezaOperacao?.TipoNaturezaOperacao == TipoNaturezaOperacaoEnum.Venda)
.Where(p => p.TipoSituacaoPedido == TipoSituacaoPedidoEnum.AFaturar ||
p.TipoSituacaoPedido == TipoSituacaoPedidoEnum.Fechado)
.ToList();
Restrições de Ações
Implementação na View
Arquivo: _ItensPartial.cshtml
<td class="align-middle text-center">
@* NH-168: Itens de Venda Casada só podem ser excluídos, não editados *@
@if (pedidoItem.PedidoVendaVinculadoId == null)
{
<button type="submit" form="form" name="command"
value="@PedidoCommandSubmitEnum.EditarItemEstoque"
class="btn btn-outline-secondary btn-sm"
title="Editar"
onclick="selecionarPedidoItemId(@pedidoItem.Id)">
<i class="fa fa-pen"></i>
</button>
}
<button type="submit" form="form" name="command"
value="@PedidoCommandSubmitEnum.ExcluirItemEstoque"
class="btn btn-outline-danger btn-sm"
title="Excluir"
onclick="selecionarPedidoItemId(@pedidoItem.Id)">
<i class="fa fa-trash"></i>
</button>
@if (pedidoItem.PedidoVendaVinculadoId == null)
{
<a class="btn btn-outline-primary btn-sm"
asp-action="Edit" asp-area="Expedicao"
asp-controller="ExpedicaoSeparacao"
asp-route-id="@pedidoItem.Id" target="_blank"
title="Expedição">
<i class="fa fa-file-invoice"></i>
</a>
}
</td>
Resultado Visual
| Tipo de Item | Botões Visíveis |
|---|---|
| Item Normal | [✏️ Editar] [🗑 Excluir] [📄 Expedição] |
| Item Venda Casada | [🗑 Excluir] |
Como Testar
Pré-requisitos
- Aplicação rodando: http://localhost:8000
- Usuário com permissões: Permissão de criar/editar pedidos no módulo Comercial
- Dados de teste:
- Pelo menos um Pedido de Venda com status "A Faturar" ou "Fechado"
- Pelo menos um Fornecedor cadastrado
Teste Completo - Passo a Passo
1. Preparar Pedido de Venda (se não existir)
- Acesse: Comercial > Adicionar Pedido
- Crie um pedido com:
- Natureza: "Vendas de Produto"
- Destinatário: Qualquer cliente
- Adicione pelo menos um item
- Avance o pedido para status "A Faturar"
2. Criar Pedido de Beneficiamento
- Acesse: Comercial > Adicionar Pedido
- Selecione Empresa de Emissão
- Selecione Natureza: "Remessa Beneficiamento para posterior retorno com Venda Casada"
Validar: - [ ] Botões "Novo Item de Estoque" e "Novo Item de Terceiro" estão OCULTOS - [ ] Seção "Vincular Item de Pedido de Venda (Venda Casada)" está VISÍVEL
3. Configurar Destinatário
- Expanda seção "Destinatário"
- Busque e selecione um Fornecedor
Validar: - [ ] Fornecedor foi selecionado corretamente
4. Gravar Pedido
- Clique em "Gravar"
Validar: - [ ] Pedido foi salvo com sucesso - [ ] Número do pedido foi gerado
5. Vincular Item de Pedido de Venda
- Na seção "Vincular Item de Pedido de Venda":
- Digite o número do Pedido de Venda
- Clique no botão de busca (🔍)
- Selecione o Pedido de Venda no dropdown
- Selecione o Item no dropdown
- Verifique as informações exibidas
- Clique no botão "+"
Validar: - [ ] Mensagem "Item adicionado com sucesso!" foi exibida - [ ] Página foi recarregada - [ ] Item aparece na tabela de itens
6. Verificar Restrições de Ações
- Localize o item adicionado na tabela
Validar: - [ ] Apenas botão de Excluir (🗑) está visível - [ ] Botões de Editar e Expedição estão OCULTOS
7. Testar Exclusão
- Clique no botão Excluir (🗑) do item
Validar: - [ ] Item foi excluído com sucesso
Cenários de Erro
Erro: Destinatário não é Fornecedor
Como reproduzir: 1. Selecione um destinatário que seja apenas Cliente (não cadastrado como Fornecedor) 2. Tente gravar ou excluir item
Resultado esperado:
"A natureza de operação selecionada solicita que o destinatário informado seja um fornecedor."
Solução: Cadastrar o destinatário também como Fornecedor, ou selecionar outro destinatário.
Erro: Item já vinculado
Como reproduzir: 1. Adicione um item de Venda Casada 2. Tente adicionar o mesmo item novamente
Resultado esperado:
"Este item já foi vinculado a este pedido de Beneficiamento."
Troubleshooting
Problema: "A natureza de operação selecionada solicita que o destinatário informado seja um fornecedor"
Causa: O destinatário selecionado não está cadastrado como Fornecedor.
Solução:
-
Verificar se é Fornecedor:
-
Se não for, cadastrar como Fornecedor:
Problema: Dropdown de Pedidos de Venda vazio
Causas possíveis: 1. Não existem pedidos de venda com status "A Faturar" ou "Fechado" 2. Todos os pedidos são de tipos de natureza que não são "Venda"
Solução: Criar um pedido de venda com: - Natureza: "Vendas de Produto" ou similar (TipoNaturezaOperacao = Venda) - Avançar para status "A Faturar"
Problema: Botão "+" não funciona
Causas possíveis: 1. Pedido atual não foi gravado 2. Item não selecionado
Solução: 1. Grave o pedido primeiro (clique em "Gravar") 2. Selecione um pedido e um item nos dropdowns
Impacto no Sistema
Áreas Afetadas
| Área | Impacto |
|---|---|
| Módulo Comercial | Tela de Pedido alterada |
| Banco de Dados | 2 novos campos em PedidoItem |
| Entity Framework | Nova configuração de relacionamentos |
Compatibilidade
- Retrocompatibilidade garantida: Pedidos existentes continuam funcionando
- Campos novos são nullable: Não quebra registros existentes
- Nenhuma alteração em APIs existentes: Novos endpoints adicionados
Performance
- Impacto mínimo: Consultas otimizadas com
AsNoTracking() - Índices criados: Para os novos campos de FK
Arquivos Modificados
Backend
| Arquivo | Tipo | Descrição |
|---|---|---|
PedidoItem.cs |
Model | Adição dos campos de vínculo |
PedidoItemConfiguration.cs |
Config | Configuração das FKs |
IPedidoRepository.cs |
Interface | Novo método de busca |
PedidoRepository.cs |
Repository | Implementação da busca |
PedidoController.cs |
Controller | Novos endpoints |
PedidoItemViewModel.cs |
ViewModel | Campos de vínculo |
Frontend
| Arquivo | Tipo | Descrição |
|---|---|---|
_ItensPartial.cshtml |
View | Seção de Venda Casada, restrição de botões |
_PedidoPartial.cshtml |
View | Hidden field para suporte |
_ValidationScriptsPedidoPartial.cshtml |
Scripts | Lógica JavaScript |
Database
| Arquivo | Tipo | Descrição |
|---|---|---|
20251201153423_AddVendaCasadaLinksToPedidoItem.cs |
Migration | Criação das colunas e FKs |
NelmetaisDbContextModelSnapshot.cs |
Snapshot | Atualização do modelo |
Referências
Links Úteis
- Jira Issue: NH-168
- Branch Git:
feature/beneficiamento-venda-casada-NH-168 - Análise SGE 2.0: docs/sge-2-0/venda-casada-sge2-analise.md
Documentos Relacionados
- Análise de Venda Casada no SGE 2.0 - Referência do sistema legado
- Política de Venda por Natureza de Operação
- Ocultação de Campos de Item Terceiro
Glossário
| Termo | Definição |
|---|---|
| Venda Casada | Processo onde material vendido passa por beneficiamento antes da entrega |
| Beneficiamento | Serviço de processamento do material (corte, usinagem, etc.) |
| Pedido de Venda | Pedido original do cliente para compra do material |
| Pedido de Beneficiamento | Pedido de envio do material ao fornecedor para beneficiamento |
| Natureza de Operação | Tipo de operação comercial/fiscal que define comportamentos no sistema |
Histórico de Mudanças
| Data | Versão | Alteração | Autor |
|---|---|---|---|
| 2025-12-01 | 1.0 | Implementação inicial da funcionalidade | Claude Code + Bruno Martins |
| 2025-12-01 | 1.1 | Adição da documentação técnica sobre tipo de item (sempre estoque), texto explicativo na interface e análise do SGE 2.0 | Claude Code + Bruno Martins |
Última atualização: 2025-12-01 Versão do documento: 1.1 Status: Implementado e documentado