Compatibilidade

RELATÓRIO DE COMPATIBILIDADE: FRONTEND PRODUTOR vs API - AgrSis

RELATÓRIO DE COMPATIBILIDADE: FRONTEND PRODUTOR vs API - AgrSis

RESUMO EXECUTIVO

Verificação completa da compatibilidade entre os componentes do wizard do frontend (Nuxt 3) e o controlador da API (Laravel 11) para o sistema de criação de licitações do AgrSis.

Status Geral: ⚠️ INCOMPATIBILIDADES IDENTIFICADAS - Requer correções


1. ANÁLISE POR STEP

STEP 1: BasicInfo - Tipo de Licitação

Frontend Captura:

  • bidding_type: 'open' | 'closed' ✅
  • product_type_ids: number

API Espera (saveDraft):

  • bidding_type: string ✅
  • product_type_ids: NÃO RECEBE (campo ignorado)

Função convertToApiFormat:

bidding_type: formData.value.bidding_type, // ✅ Correto
// product_type_ids NÃO É ENVIADO PARA A API

Compatibilidade: ✅ PARCIAL

  • bidding_type é mapeado corretamente
  • product_type_ids é capturado no frontend mas NUNCA enviado à API
  • Impacto: Sem impacto crítico - é apenas filtro de UI, não é armazenado no banco

STEP 2: Products - Lista de Produtos

Frontend Captura (array de produtos):

produtos: Array<{
  produtoId: string              // ID do produto
  produtoNome: string            // Nome comercial
  quantidade: number             // Quantidade
  unidade: string                // Sigla (ex: kg, L)
  measurement_unit_id?: number   // ID da unidade
  aceita_similar: boolean        // Aceita similar
  delivery_date?: string         // Data de entrega (específica)
  marca?: string                 // Brand (opcional)
  principio_ativo?: string       // Active ingredient (opcional)
}>

API Espera (convertToApiFormat → saveDraft):

items: Array<{
  product_id: number             // parseInt(p.produtoId) ✅
  quantidade: number             // p.quantidade ✅
  measurement_unit_id: number    // p.measurement_unit_id || 1 ✅
  aceita_similar: boolean        // p.aceita_similar || false ✅
  delivery_date?: string         // p.delivery_date ✅
}>

ERRO IDENTIFICADO - Step2Products.vue (linha 121):

quantidade: item.quantity,  // ERRO: frontend usa "quantity"
                           // mas campo no form é "quantidade"

Frontend possui:

interface ProdutoItem {
  quantidade: number  // Linha 23
  
  ...
  v-model.number="item.quantity"  // Template usa "quantity"!
}

Problema: Inconsistência interna - Template usa item.quantity mas interface declara quantidade

Compatibilidade: 🔴 CRÍTICO

  • Frontend envia quantity (campo inconsistente)
  • API espera quantidade
  • Convertendo para quantidade antes de enviar à API
  • Impacto: Os produtos chegam na API com undefined/0

STEP 3: Deadlines - Prazos e Condições

Frontend Captura:

dataLimite: string          // Data ISO (YYYY-MM-DD)
deadlineMode: 'general' | 'specific'
prazoEntrega: number        // Dias (se general)
condicaoPagamento: string   // avista|parcelado|a_combinar
produtos[].delivery_date: string  // Se specific (YYYY-MM-DD)

API Espera (convertToApiFormat):

deadline_date: formData.value.dataLimite     // ✅
deadline_mode: formData.value.deadlineMode   // ✅
prazo_entrega: formData.value.prazoEntrega   // ✅
condicao_pagamento: formData.value.condicaoPagamento  // ✅
items[].delivery_date: p.delivery_date       // ✅

Validações Frontend (useWizardOrder.ts):

dataLimite:

  • Mínimo: 3 dias no futuro ✅
  • Máximo: 60 dias ✅

prazoEntrega (general mode):

  • Mínimo: 3 dias ✅
  • Máximo: 60 dias ✅

delivery_date (specific mode):

  • Mínimo: 3 dias ✅
  • Máximo: 60 dias ✅

condicaoPagamento:

  • Obrigatório ✅
  • Valores: avista, parcelado, a_combinar ✅

API Validation (StoreOrderRequest.php):

  • data_limite_cotacao (CAMPO DIFERENTE!) - espera after:+2 days (3 dias) ✅
  • raio_fornecimento - não vem do Step 3 ❌
  • Nenhuma validação para deadline_mode, prazo_entrega, condicao_pagamento

ERRO IDENTIFICADO - Mapeamento de Campo:

Frontend envia: deadline_date StoreOrderRequest espera: data_limite_cotacao

Incompatibilidade detectada no Controller:

'delivery_deadline' => $request->prazo_entrega,  // Campo correto ✅
'payment_terms' => $request->condicao_pagamento,  // Campo correto ✅

Compatibilidade: 🟡 PARCIAL

  • Nomes dos campos estão inconsistentes com o nome esperado
  • Validações não cobrem todos os campos
  • Impacto: Alguns campos podem ser ignorados ou falhar na validação

STEP 4: Location - Localização e Entrega

Frontend Captura:

freight_type: 'cif' | 'fob' | ''  // Modalidade frete
enderecoId: number | null         // ID do endereço
raioFornecimento: number          // Raio em km

API Espera (convertToApiFormat):

freight_type: formData.value.freight_type        // ✅
customer_address_id: formData.value.enderecoId   // ✅
supply_radius: formData.value.raioFornecimento   // ✅

Validações Frontend:

  • freight_type: Obrigatório (cif ou fob) ✅
  • enderecoId: Obrigatório ✅
  • raioFornecimento: 10-500 km ✅

API Validation (StoreOrderRequest.php):

  • raio_fornecimento: required|integer|min:10|max:500 ✅
  • Faltam validações: freight_type, customer_address_id

Controller (saveDraft):

'customer_address_id' => $request->customer_address_id,  // ✅
'supply_radius' => $request->supply_radius,              // ✅
'freight_type' => $request->freight_type,                // ✅

Compatibilidade: ✅ COMPLETO

  • Mapeamento correto
  • Validações adequadas
  • Campos casam perfeitamente

STEP 5: Review - Revisão Final

Step 5 é apenas visualização. Não envia dados novos.

Compatibilidade: ✅ OK


2. ANÁLISE DA FUNÇÃO convertToApiFormat

convertToApiFormat(status: 'draft' | 'completed' = 'draft')

Campos Enviados:

{
  draft_uuid: savedDraftUuid || undefined,
  description: 'Rascunho de licitação',
  status: status,
  bidding_type: formData.value.bidding_type,
  customer_address_id: formData.value.enderecoId || undefined,
  deadline_date: formData.value.dataLimite || undefined,
  supply_radius: formData.value.raioFornecimento || undefined,
  deadline_mode: formData.value.deadlineMode || undefined,
  prazo_entrega: formData.value.prazoEntrega || undefined,
  condicao_pagamento: formData.value.condicaoPagamento || undefined,
  freight_type: formData.value.freight_type || undefined,
  items: [...]  // Produtos
}

Campos que a API RECEBE mas NÃO PROCESSA:

  • product_type_ids - NÃO ENVIADO (não critica)
  • status - Enviado mas API pode ignorar (usa determineDraftStatus)
  • description - Enviado como "Rascunho de licitação" (fixo)

Campos OBRIGATÓRIOS na API que podem vir UNDEFINED:

  • deadline_date - Pode ser undefined ❌
  • items - Array vazio é permitido ✅

3. ANÁLISE DO CONTROLLER (OrderController.php)

Endpoint saveDraft (POST /orders/draft)

Função determineDraftStatus:

private function determineDraftStatus(Request $request): OrderStatus
{
    $hasDataLimite = !empty($request->deadline_date);
    $hasItems = $request->has('items') && is_array($request->items) && count($request->items) > 0;

    if ($hasDataLimite && $hasItems) {
        return OrderStatus::PENDING;  // Pronto para publicar
    }
    return OrderStatus::DRAFT;  // Incompleto
}

Processamento de Items:

if ($request->has('items') && is_array($request->items) && count($request->items) > 0) {
    foreach ($request->items as $item) {
        if (isset($item['product_id']) && $item['product_id'] !== null && isset($item['quantidade'])) {
            // Cria item
        }
    }
}

PROBLEMA: Espera campo quantidade mas frontend envia (através de sincronizarFormData):

quantidade: item.quantity,  // item.quantity é undefined!

4. PROBLEMAS CRÍTICOS ENCONTRADOS

🔴 CRÍTICO #1: Inconsistência de Campo de Quantidade em Step2

Localização: /apps/producer/components/order/wizard/Step2Products.vue

Problema:

// Interface declara
interface ProdutoItem {
  quantidade: number;  // Linha 23
}

// Mas template usa
v-model.number="item.quantity"  // Linha 222

// E sincronização espera
map(item => ({
  quantidade: item.quantity,  // UNDEFINED!
}))

Impacto: Quantidade dos produtos chega como undefined/0 na API

Solução:

// Opção 1: Padronizar como "quantidade"
v-model.number="item.quantidade"

// Opção 2: Padronizar como "quantity"
interface ProdutoItem {
  quantity: number;  // Renomear
}

🔴 CRÍTICO #2: Falta de Validação de Campos no Request

Localização: /apps/api/app/Http/Requests/StoreOrderRequest.php

Problema: StoreOrderRequest não valida:

  • bidding_type
  • customer_address_id
  • freight_type
  • deadline_mode
  • condicao_pagamento
  • product_type_ids (se fosse enviado)

Impacto: Dados inválidos podem ser salvos no banco

Solução: Adicionar regras de validação para todos os campos


🟡 CRÍTICO #3: Inconsistência entre StoreOrderRequest e saveDraft

Localização: /apps/api/app/Http/Controllers/Api/OrderController.php (linha 641-679)

Problema:

// StoreOrderRequest espera:
'data_limite_cotacao'  // Nome diferente!

// saveDraft recebe:
'deadline_date'  // Nome diferente!

Impacto: Os dois endpoints usam convenções de nomes diferentes

Solução: Padronizar nomes de campos em toda a API


🟡 CRÍTICO #4: Campo "description" Fixo no Frontend

Localização: /apps/producer/composables/useWizardOrder.ts (linha 393)

Problema:

description: 'Rascunho de licitação',  // Sempre fixo!

Validação: StoreOrderRequest exige:

'description' => 'required|string|min:50|max:1000'

Impacto: Descrição não customizável pelo usuário

Solução: Adicionar campo de descrição no Step 1


🟡 CRÍTICO #5: API Ignora Status Enviado pelo Frontend

Localização: /apps/api/app/Http/Controllers/Api/OrderController.php (linha 651)

Problema:

// Frontend envia
status: 'draft' | 'completed'

// API ignora e calcula automaticamente
'status' => $this->determineDraftStatus($request)

Impacto: Status enviado é completamente ignorado (design questionável)

Solução: Usar determineDraftStatus corretamente (OK) ou validar que frontend não envie status inválido


5. PROBLEMAS DE DESIGN

🔶 DESIGN #1: Validações Duplicadas

Frontend valida em validateStep3(), validateStep4(), etc. API valida em StoreOrderRequest e determineDraftStatus().

Impacto: Lógica duplicada, difícil de manter


🔶 DESIGN #2: Conversão de Tipos em convertToApiFormat

items: formData.value.produtos.length > 0 ? formData.value.produtos.map(p => ({
  product_id: parseInt(p.produtoId),  // Conversão aqui
})) : []

Frontend armazena IDs como string, converte para number antes de enviar.

Impacto: Unnecessary conversions, tipo fraco


6. MATRIZ DE COMPATIBILIDADE

CampoFrontendAPI EsperaConvertido?Status
bidding_typestringstring✅ OK
product_type_idsnumber-❌ NÃO ENVIADO⚠️ OK
produtos.produtoIdstringproduct_id✅ parseInt✅ OK
produtos.quantidade--❌ UNDEFINED🔴 ERRO
produtos.quantitynumber-❌ NÃO MAPEADO🔴 ERRO
produtos.measurement_unit_idnumbermeasurement_unit_id✅ OK
produtos.aceita_similarbooleanaceita_similar✅ OK
produtos.delivery_datestringdelivery_date✅ OK
dataLimitestringdeadline_date✅ OK
deadlineModestringdeadline_mode✅ OK
prazoEntreganumberprazo_entrega✅ OK
condicaoPagamentostringcondicao_pagamento✅ OK
freight_typestringfreight_type✅ OK
enderecoIdnumbercustomer_address_id✅ OK
raioFornecimentonumbersupply_radius✅ OK
descriptionstring (fixo)description❌ FIXO🟡 AVISO

7. LISTA DE CORREÇÕES NECESSÁRIAS

PRIORIDADE ALTA (Impede funcionamento):

  1. Frontend Step2Products.vue - Linha 222
    • Trocar item.quantity por item.quantidade
    • OU renomear interface e uso consistente
  2. Frontend Step2Products.vue - Linha 116-129
    • Sincronizar nomenclatura de campos
  3. Backend StoreOrderRequest.php
    • Adicionar regras para validar todos os campos
    • Especialmente: bidding_type, freight_type, customer_address_id
  4. Backend OrderController::saveDraft
    • Adicionar validação de request (usar Form Request)
    • OU aceitar e validar os campos manualmente

PRIORIDADE MÉDIA (Afeta UX/dados):

  1. Frontend useWizardOrder.ts - Linha 393
    • Permitir que usuário customize "description"
    • Adicionar campo no Step 1
  2. Frontend Step2Products.vue - Interface ProdutoItem
    • Adicionar interface tipada para evitar erros
    • Usar tipos genéricos corretamente
  3. Backend OrderController
    • Padronizar nomes de campos entre endpoints
    • data_limite_cotacao vs deadline_date

PRIORIDADE BAIXA (Melhorias):

  1. Ambos Validação de dados
    • Considerar single source of truth para regras
    • Usar JSON Schema ou similar
  2. Backend determineDraftStatus
    • Adicionar mais lógica de validação
    • Considerar validar relationship (endereço existe?)
  3. Frontend convertToApiFormat
    • Adicionar tipo explícito para return
    • Documentar transformações

8. RECOMENDAÇÕES

Curto Prazo (Corrigir erros):

  1. Corrigir inconsistência de quantidade vs quantity
  2. Adicionar validações faltantes na API
  3. Padronizar nomes de campos

Médio Prazo (Melhorar design):

  1. Usar TypeScript mais rigorosamente (strict mode)
  2. Criar interfaces compartilhadas frontend-backend
  3. Documentar contrato API

Longo Prazo (Arquitetura):

  1. Considerar geração automática de tipos (OpenAPI)
  2. Implementar validação schema única (JSON Schema)
  3. Adicionar testes E2E que validem frontend-backend

9. CONCLUSÃO

Status Geral: 🔴 CRÍTICO - NÃO RECOMENDADO PARA PRODUÇÃO

O sistema possui 2 erros críticos que impedem o funcionamento correto:

  1. Campo quantidade não é mapeado corretamente
  2. Falta validação completa na API

Recomenda-se corrigir antes de qualquer deploy em produção.

Tempo estimado para correção: 2-3 horas de desenvolvimento

Copyright © 2026