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_cotacaopassou) - 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:
| De | Para | Quando | Automático? |
|---|---|---|---|
draft | completed | Clicar "Salvar Rascunho" no Step 5 | ❌ Manual |
completed | draft | Editar licitação concluída | ❌ Manual |
completed | published | Clicar "Publicar" | ❌ Manual |
published | expired | Prazo fim SEM vencedor | ✅ Cron Job |
published | finished | Prazo fim COM vencedor | ✅ Cron Job ou Manual |
Não Permitidas:
| De | Para | Por quê? |
|---|---|---|
draft | published | Precisa passar por completed primeiro |
expired | published | Criar nova licitação (republicar) |
finished | Qualquer | Estado final, imutável |
expired | Qualquer | Estado 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:
| Status | Momento | Mensagem |
|---|---|---|
completed | Ao salvar rascunho no Step 5 | "Licitação salva! Você pode publicá-la quando quiser." |
published | Ao publicar | "Licitação publicada! Fornecedores já podem enviar propostas." |
expired | Ao expirar | "Sua licitação expirou sem receber propostas aprovadas." |
finished | Ao finalizar | "Licitação finalizada com sucesso! Contrato disponível." |
Para Fornecedores:
| Status | Momento | Mensagem |
|---|---|---|
published | Nova licitação no raio | "Nova licitação disponível: Título" |
finished | Se 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 prazorejected: 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