Negócio

Status de Licitações - Documentação

Status de Licitações - Documentação

Visão Geral

Sistema de 5 status para gerenciar o ciclo de vida completo das licitações na plataforma AgrSis.


Enum OrderStatus

Código/DB/API (Inglês):

enum OrderStatus {
  draft = 'draft',           // Rascunho
  completed = 'completed',   // Concluída
  published = 'published',   // Publicada
  expired = 'expired',       // Expirada
  finished = 'finished'      // Finalizada
}

Definição dos Status

1. DRAFT (Rascunho)

Código: draftLabel UI: Rascunho Badge: 🟡 Amarelo (#fbbf24) CSS Classes: bg-yellow-100 text-yellow-800 border-yellow-300

Descrição:

  • Licitação em preenchimento
  • Pode ter campos incompletos
  • Auto-save ativo durante preenchimento
  • Visível apenas para o produtor criador

Quando entra neste status:

  • Ao criar nova licitação (início do wizard)
  • Ao clicar "Salvar e Continuar Depois" nos Steps 1-4

Ações disponíveis:

  • Continuar Preenchendo
  • Editar
  • Excluir

Visibilidade:

  • ✅ Produtor criador
  • ❌ Fornecedores

2. COMPLETED (Concluída)

Código: completedLabel UI: Concluída Badge: 🔵 Azul (#3b82f6) CSS Classes: bg-blue-100 text-blue-800 border-blue-300

Descrição:

  • Wizard completamente preenchido (Step 5)
  • Todos os campos obrigatórios validados
  • Pronta para ser publicada
  • Visível apenas para o produtor criador

Quando entra neste status:

  • Ao clicar "Salvar Rascunho" no Step 5 (último step)

Ações disponíveis:

  • Editar
  • Publicar
  • Excluir

Visibilidade:

  • ✅ Produtor criador
  • ❌ Fornecedores

Validações obrigatórias:

  • ✅ Tipo de licitação selecionado
  • ✅ Tipos de insumos selecionados
  • ✅ Pelo menos 1 produto adicionado
  • ✅ Data limite de cotação definida
  • ✅ Prazos de entrega definidos
  • ✅ Condição de pagamento definida
  • ✅ Endereço de entrega selecionado
  • ✅ Raio de fornecimento definido
  • ✅ Modalidade de frete selecionada (CIF/FOB)

3. PUBLISHED (Publicada)

Código: publishedLabel UI: Publicada Badge: 🟢 Verde (#10b981) CSS Classes: bg-green-100 text-green-800 border-green-300

Descrição:

  • Licitação ativa e visível para fornecedores
  • Recebendo propostas
  • Dentro do prazo de cotação
  • Não pode mais ser editada (ou edição limitada)

Quando entra neste status:

  • Ao clicar "Publicar" no Step 5

Ações disponíveis:

  • Ver Propostas Recebidas
  • Aprovar Proposta Vencedora
  • Cancelar Licitação (muda para cancelled - futuro)

Visibilidade:

  • ✅ Produtor criador
  • ✅ Fornecedores (todos dentro do raio)

Regras:

  • Fornecedores podem enviar propostas até data_limite_cotacao
  • Notificação enviada para fornecedores no raio
  • Aparece na listagem pública de licitações

4. EXPIRED (Expirada)

Código: expiredLabel UI: Expirada Badge: 🔴 Vermelho (#ef4444) CSS Classes: bg-red-100 text-red-800 border-red-300

Descrição:

  • Prazo de cotação encerrado (data_limite_cotacao passou)
  • SEM proposta vencedora selecionada
  • Licitação sem sucesso
  • Mantém histórico de propostas recebidas

Quando entra neste status:

  • Automático: Cron job diário verifica licitações onde:
    • status = 'published'
    • data_limite_cotacao < NOW()
    • proposta_vencedora_id IS NULL

Ações disponíveis:

  • Ver Histórico de Propostas
  • Republicar (cria nova licitação baseada nesta)
  • Gerar Relatório

Visibilidade:

  • ✅ Produtor criador
  • ⚠️ Fornecedores (somente leitura, se tiverem enviado proposta)

Motivos comuns:

  • Nenhuma proposta recebida
  • Propostas recebidas mas nenhuma aprovada
  • Produtor não selecionou vencedor a tempo

5. FINISHED (Finalizada)

Código: finishedLabel UI: Finalizada Badge: ⚫ Cinza Escuro (#6b7280) CSS Classes: bg-gray-100 text-gray-800 border-gray-300

Descrição:

  • Prazo de cotação encerrado
  • COM proposta vencedora aprovada
  • Processo de licitação concluído com sucesso
  • Contrato gerado (se aplicável)

Quando entra neste status:

  • Automático: Cron job diário verifica licitações onde:
    • status = 'published'
    • data_limite_cotacao < NOW()
    • proposta_vencedora_id IS NOT NULL

OU Manual:

  • Produtor aprova última proposta necessária

Ações disponíveis:

  • Ver Detalhes da Proposta Vencedora
  • Ver Contrato Gerado
  • Gerar Relatório Final
  • Avaliar Fornecedor

Visibilidade:

  • ✅ Produtor criador
  • ✅ Fornecedor vencedor
  • ⚠️ Outros fornecedores (somente leitura, se tiverem enviado proposta)

Dados importantes preservados:

  • Proposta vencedora
  • Histórico de propostas
  • Valores negociados
  • Prazos acordados

Fluxo de Estados

┌─────────┐    Preenche       ┌───────────┐    Clica        ┌───────────┐
│ draft   │────Wizard────────→│ completed │──"Publicar"────→│ published │
│Rascunho │   (Steps 1-4)     │ Concluída │                 │ Publicada │
└─────────┘                   └───────────┘                 └─────┬─────┘
     ▲                              │                              │
     │                              │                              │
     │                        Edita/Volta                          │
     └──────────────────────────────┘                              │
                                                                   │
                                   ┌───────────────────────────────┴───────────────────────┐
                                   │                                                       │
                            Prazo encerra                                           Prazo encerra
                            SEM vencedor                                            COM vencedor
                                   │                                                       │
                                   ▼                                                       ▼
                            ┌───────────┐                                          ┌────────────┐
                            │ expired   │                                          │ finished   │
                            │ Expirada  │                                          │ Finalizada │
                            └───────────┘                                          └────────────┘
                                   │                                                       │
                                   │                                                       │
                            Republicar (cria nova)                              Processo concluído

Regras de Transição

Permitidas:

DeParaQuandoAutomático?
draftcompletedClicar "Salvar Rascunho" no Step 5❌ Manual
completeddraftEditar licitação concluída❌ Manual
completedpublishedClicar "Publicar"❌ Manual
publishedexpiredPrazo fim SEM vencedor✅ Cron Job
publishedfinishedPrazo fim COM vencedor✅ Cron Job ou Manual

Não Permitidas:

DeParaPor quê?
draftpublishedPrecisa passar por completed primeiro
expiredpublishedCriar nova licitação (republicar)
finishedQualquerEstado final, imutável
expiredQualquerEstado final, imutável

Implementação Backend

Migration:

Schema::table('orders', function (Blueprint $table) {
    $table->enum('status', [
        'draft',
        'completed',
        'published',
        'expired',
        'finished'
    ])->default('draft');
});

Enum PHP:

namespace App\Enums;

enum OrderStatus: string
{
    case DRAFT = 'draft';
    case COMPLETED = 'completed';
    case PUBLISHED = 'published';
    case EXPIRED = 'expired';
    case FINISHED = 'finished';

    public function label(): string
    {
        return match($this) {
            self::DRAFT => 'Rascunho',
            self::COMPLETED => 'Concluída',
            self::PUBLISHED => 'Publicada',
            self::EXPIRED => 'Expirada',
            self::FINISHED => 'Finalizada',
        };
    }

    public function color(): string
    {
        return match($this) {
            self::DRAFT => 'yellow',
            self::COMPLETED => 'blue',
            self::PUBLISHED => 'green',
            self::EXPIRED => 'red',
            self::FINISHED => 'gray',
        };
    }

    public function isEditable(): bool
    {
        return in_array($this, [self::DRAFT, self::COMPLETED]);
    }

    public function isActive(): bool
    {
        return $this === self::PUBLISHED;
    }

    public function isFinal(): bool
    {
        return in_array($this, [self::EXPIRED, self::FINISHED]);
    }
}

Cron Job (Atualização Automática):

// app/Console/Commands/UpdateExpiredOrders.php

namespace App\Console\Commands;

use App\Models\Order;
use App\Enums\OrderStatus;
use Illuminate\Console\Command;

class UpdateExpiredOrders extends Command
{
    protected $signature = 'orders:update-expired';
    protected $description = 'Atualiza status de licitações expiradas e finalizadas';

    public function handle()
    {
        $now = now();

        // Marcar como EXPIRED (sem vencedor)
        $expired = Order::where('status', OrderStatus::PUBLISHED)
            ->where('data_limite_cotacao', '<', $now)
            ->whereNull('proposta_vencedora_id')
            ->update(['status' => OrderStatus::EXPIRED]);

        $this->info("$expired licitações marcadas como EXPIRADAS");

        // Marcar como FINISHED (com vencedor)
        $finished = Order::where('status', OrderStatus::PUBLISHED)
            ->where('data_limite_cotacao', '<', $now)
            ->whereNotNull('proposta_vencedora_id')
            ->update(['status' => OrderStatus::FINISHED]);

        $this->info("$finished licitações marcadas como FINALIZADAS");

        return 0;
    }
}

Registrar no Kernel:

// app/Console/Kernel.php

protected function schedule(Schedule $schedule)
{
    // Executar diariamente às 00:05
    $schedule->command('orders:update-expired')
             ->dailyAt('00:05');
}

Implementação Frontend

Type Definition:

// types/order.ts

export type OrderStatus = 'draft' | 'completed' | 'published' | 'expired' | 'finished'

export interface OrderStatusConfig {
  value: OrderStatus
  label: string
  color: string
  badgeClass: string
  icon: string
}

export const ORDER_STATUS: Record<OrderStatus, OrderStatusConfig> = {
  draft: {
    value: 'draft',
    label: 'Rascunho',
    color: 'yellow',
    badgeClass: 'bg-yellow-100 text-yellow-800 border-yellow-300',
    icon: '📝'
  },
  completed: {
    value: 'completed',
    label: 'Concluída',
    color: 'blue',
    badgeClass: 'bg-blue-100 text-blue-800 border-blue-300',
    icon: ''
  },
  published: {
    value: 'published',
    label: 'Publicada',
    color: 'green',
    badgeClass: 'bg-green-100 text-green-800 border-green-300',
    icon: '🟢'
  },
  expired: {
    value: 'expired',
    label: 'Expirada',
    color: 'red',
    badgeClass: 'bg-red-100 text-red-800 border-red-300',
    icon: '🔴'
  },
  finished: {
    value: 'finished',
    label: 'Finalizada',
    color: 'gray',
    badgeClass: 'bg-gray-100 text-gray-800 border-gray-300',
    icon: ''
  }
}

Componente Badge:

<!-- components/OrderStatusBadge.vue -->
<template>
  <span
    class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-semibold border-2"
    :class="statusConfig.badgeClass"
  >
    <span>{{ statusConfig.icon }}</span>
    <span>{{ statusConfig.label }}</span>
  </span>
</template>

<script setup lang="ts">
import { ORDER_STATUS, type OrderStatus } from '~/types/order'

interface Props {
  status: OrderStatus
}

const props = defineProps<Props>()

const statusConfig = computed(() => ORDER_STATUS[props.status])
</script>

Listagem de Licitações

Filtros por Status:

// Tabs na listagem
const tabs = [
  { status: null, label: 'Todas', count: totalCount },
  { status: 'draft', label: 'Rascunhos', count: draftCount },
  { status: 'completed', label: 'Concluídas', count: completedCount },
  { status: 'published', label: 'Publicadas', count: publishedCount },
  { status: 'expired', label: 'Expiradas', count: expiredCount },
  { status: 'finished', label: 'Finalizadas', count: finishedCount },
]

Notificações

Para Produtor:

StatusMomentoMensagem
completedAo salvar rascunho no Step 5"Licitação salva! Você pode publicá-la quando quiser."
publishedAo publicar"Licitação publicada! Fornecedores já podem enviar propostas."
expiredAo expirar"Sua licitação expirou sem receber propostas aprovadas."
finishedAo finalizar"Licitação finalizada com sucesso! Contrato disponível."

Para Fornecedores:

StatusMomentoMensagem
publishedNova licitação no raio"Nova licitação disponível: Título"
finishedSe for vencedor"Parabéns! Sua proposta foi aprovada."

Relatórios e Métricas

Dashboard Produtor:

  • Total de licitações por status
  • Taxa de sucesso: finished / (expired + finished) * 100%
  • Tempo médio até publicação: published_at - created_at
  • Tempo médio até conclusão: finished_at - published_at

Dashboard Fornecedor:

  • Licitações participadas por status
  • Taxa de vitória: propostas_vencedoras / total_propostas * 100%

Próximas Implementações

Status Futuros (Opcional):

  • cancelled: Licitação cancelada pelo produtor antes do prazo
  • rejected: Licitação rejeitada por não atender critérios (admin)

Última atualização: 2025-12-16 Versão: 1.0 Relacionado: AGR-156, AGR-157

Copyright © 2026