Cotacoes (Orders)
Cotacoes (Orders)
O que e uma cotacao no AgrSis
Uma cotacao (internamente chamada de Order) e o mecanismo central da plataforma AgrSis. Ela representa uma solicitacao de compra de insumos agricolas criada por um produtor rural, que e publicada para que fornecedores dentro de um raio geografico possam enviar propostas competitivas.
Cada cotacao recebe automaticamente um numero sequencial unico (gerado por OrderNumberGenerator) e um UUID utilizado para identificacao publica nas URLs e na API.
Status da cotacao
A cotacao possui os seguintes status, definidos no enum OrderStatus:
| Status | Label (PT) | Descricao |
|---|---|---|
draft | Rascunho | Cotacao em criacao, dados incompletos |
pending | Pendente | Dados completos, pronta para publicacao |
published | Publicada | Ativa e recebendo propostas de fornecedores |
in_analysis | Em Analise | Prazo de propostas encerrado, produtor analisa as propostas recebidas |
awarded | Aguardando Confirmacao | Proposta vencedora selecionada, aguardando confirmacao do fornecedor |
finished | Finalizada | Fornecedor confirmou, cotacao encerrada com sucesso |
cancelled | Cancelada | Cancelada pelo produtor (pode ser reaberta) |
revoked | Revogada | Revogada definitivamente (estado final) |
expired | Expirada | Prazo de analise expirou sem selecao de vencedor (estado final) |
completed | Finalizada | Deprecado, mantido para compatibilidade |
Fluxo de status (transicoes permitidas)
DRAFT --> PENDING
PENDING --> DRAFT | PUBLISHED
PUBLISHED --> CANCELLED | REVOKED | IN_ANALYSIS
CANCELLED --> PENDING | PUBLISHED
IN_ANALYSIS --> AWARDED | EXPIRED
AWARDED --> IN_ANALYSIS | FINISHED
Detalhamento do fluxo
- Criacao (DRAFT): O produtor inicia a cotacao pelo wizard. Os dados podem ser salvos parcialmente.
- Revisao (PENDING): Quando todos os campos obrigatorios estao preenchidos, o status muda para PENDING. O produtor pode voltar para DRAFT se precisar editar.
- Publicacao (PUBLISHED): O produtor publica a cotacao. Fornecedores dentro do raio sao notificados e podem enviar propostas.
- Analise (IN_ANALYSIS): Apos o prazo de propostas (
deadline_date) expirar, a cotacao entra em periodo de analise. O prazo de analise e configuravel (padrao: 48h apos o deadline). - Selecao do vencedor (AWARDED): O produtor seleciona uma proposta vencedora. O fornecedor tem um prazo em horas uteis (padrao: 2h uteis) para confirmar.
- Finalizacao (FINISHED): O fornecedor confirma a proposta. A cotacao e encerrada e as demais propostas recebem status
lost. - Retorno a analise (IN_ANALYSIS): Se o fornecedor recusar ou nao confirmar a tempo, a cotacao volta para IN_ANALYSIS com prazo estendido (padrao: +24h) para que o produtor selecione outro fornecedor.
Estados finais (sem retorno)
- REVOKED: Revogada definitivamente pelo produtor.
- EXPIRED: O prazo de analise expirou sem selecao de vencedor.
- FINISHED: Concluida com sucesso.
Campos da cotacao
Campos obrigatorios para publicacao
| Campo | Tipo | Descricao |
|---|---|---|
description | string | Descricao/titulo da cotacao |
customer_address_id | integer | Endereco de entrega (com coordenadas para calculo de raio) |
deadline_date | datetime | Data limite para recebimento de propostas (deve ser futura) |
supply_radius | integer | Raio de fornecimento em km |
freight_type | string | Modalidade de frete: cif (fornecedor entrega) ou fob (produtor retira) |
items | array | Pelo menos 1 item (produto + quantidade + unidade de medida) |
Campos opcionais
| Campo | Tipo | Descricao |
|---|---|---|
bidding_type | string | Tipo de licitacao: open ou closed (padrao: closed) |
product_type_ids | array | IDs dos tipos de produto (filtro) |
deadline_mode | string | Modo do prazo: general ou specific |
delivery_deadline | string | Prazo de entrega em dias |
delivery_date | date | Data especifica de entrega |
wants_scaled_delivery | boolean | Se deseja entrega escalonada |
payment_terms | string | Condicao de pagamento (ex: avista, 30dias) |
estimated_payment_date | date | Data estimada de pagamento (obrigatoria se payment_terms != avista) |
Campos automaticos
| Campo | Descricao |
|---|---|
uuid | Gerado automaticamente na criacao |
number | Numero sequencial gerado por OrderNumberGenerator |
analysis_deadline | Calculado a partir de deadline_date + horas de analise, ou definido manualmente quando a cotacao e reaberta |
published_at | Preenchido ao publicar |
awarded_at | Preenchido ao selecionar vencedor |
finished_at | Preenchido ao finalizar |
cancelled_at | Preenchido ao cancelar |
revoked_at | Preenchido ao revogar |
Prazos
Prazo de propostas (deadline_date)
- Definido pelo produtor ao criar a cotacao.
- Enquanto o prazo esta vigente e o status e
published, fornecedores podem enviar propostas. - Deve ser uma data futura no momento da publicacao.
Prazo de analise (analysis_deadline)
- Calculado automaticamente:
deadline_date+ N horas (configuravel viaanalysis_deadline_hours, padrao: 48h). - Pode ser persistido manualmente no campo
analysis_deadlinequando a cotacao e reaberta apos recusa ou expiracao do vencedor. - Durante esse periodo, o produtor analisa e seleciona a proposta vencedora.
- Se o prazo expirar sem selecao, a cotacao vai para status
expired.
Prazo de confirmacao do vencedor
- Calculado em horas uteis (padrao: 2h uteis) via
BusinessHoursService. - Horas uteis consideram horario comercial (padrao: 8h-18h) e dias uteis (segunda a sexta).
- Se o fornecedor nao confirmar dentro do prazo, a proposta expira e a cotacao volta para
in_analysiscom prazo estendido.
Extensao do prazo de analise
- Quando o fornecedor vencedor recusa ou nao confirma, o prazo de analise e estendido em N horas (configuravel via
analysis_extension_hours, padrao: 24h). - Isso permite ao produtor selecionar outro fornecedor.
Raio de fornecimento
O campo supply_radius define o raio em km a partir do endereco de entrega da cotacao. Apenas fornecedores que possuam endereco ativo com coordenadas dentro desse raio serao notificados sobre a nova cotacao.
O calculo e feito via formula de Haversine no banco de dados (PostgreSQL), comparando as coordenadas (latitude, longitude) do endereco de entrega com as coordenadas dos enderecos dos fornecedores.
Limites configurados via SettingsService:
- Minimo: 10 km (
search_radius_min_km) - Maximo: 500 km (
search_radius_max_km)
Notificacoes automaticas
O sistema dispara notificacoes em cada etapa relevante do ciclo de vida da cotacao. As notificacoes sao enviadas por ate 3 canais: in-app, email e WhatsApp, conforme configuracao global (NotificationChannelConfig) e preferencias do usuario (NotificationSetting).
Eventos que geram notificacao
| Evento | Destinatarios | Tipo |
|---|---|---|
| Cotacao publicada | Fornecedores dentro do raio | NEW_ORDER_AVAILABLE |
| Proposta recebida | Produtor dono da cotacao | PROPOSAL_RECEIVED |
| Proposta cancelada pelo fornecedor | Produtor dono da cotacao | PROPOSAL_CANCELLED |
| Proposta vencedora selecionada | Fornecedor vencedor + produtor + demais participantes | AWARD_PENDING_CONFIRMATION |
| Fornecedor confirma proposta | Produtor + fornecedor vencedor + demais participantes | AWARD_CONFIRMED |
| Fornecedor recusa proposta | Produtor + fornecedor + demais participantes | AWARD_DECLINED |
| Prazo de confirmacao expirou | Produtor + fornecedor + demais participantes | AWARD_CONFIRMATION_EXPIRED |
| Prazo de analise estendido | Demais fornecedores participantes | ANALYSIS_DEADLINE_EXTENDED |
| Cotacao cancelada/revogada | Fornecedores que enviaram propostas | ORDER_UPDATED |
Permissoes por acao
| Acao | Quem pode executar | Restricoes |
|---|---|---|
| Criar cotacao | Produtor com assinatura ativa | - |
| Editar cotacao | Produtor dono | Somente em status draft, pending ou cancelled |
| Publicar cotacao | Produtor dono | Status pending ou cancelled; campos obrigatorios preenchidos; deadline futuro |
| Publicar direto do draft | Produtor dono | Valida campos obrigatorios, promove DRAFT->PENDING->PUBLISHED |
| Cancelar cotacao | Produtor dono | Somente em status published; requer motivo (CancellationReason) |
| Revogar cotacao | Produtor dono | Somente em status published; requer motivo; estado final |
| Excluir cotacao (soft delete) | Produtor dono | Somente em status draft ou pending |
| Duplicar cotacao | Produtor dono | Cria nova cotacao em draft com os mesmos itens |
| Reabrir cotacao | Produtor dono | Somente published sem propostas recebidas; volta para draft |
| Selecionar vencedor | Produtor dono | Somente em in_analysis (dentro do prazo de analise) |
Motivos de cancelamento/revogacao (CancellationReason)
| Valor | Label |
|---|---|
erro_especificacao | Erro na especificacao do produto |
mudanca_necessidade | Mudanca de necessidade |
orcamento_insuficiente | Orcamento insuficiente |
decisao_superior | Decisao superior |
propostas_inadequadas | Todas propostas inadequadas |
problema_prazo | Problema com prazo de entrega |
problema_fornecedor | Problema com fornecedores |
outro | Outro motivo |
Itens da cotacao (OrderItem)
Cada cotacao deve conter pelo menos 1 item. Cada item possui:
| Campo | Descricao |
|---|---|
product_id | Produto solicitado (do catalogo) |
quantity | Quantidade desejada |
measurement_unit_id | Unidade de medida |
accepts_similar | Se aceita produto similar (boolean) |
O sistema valida limites de quantidade por unidade de medida (ex: maximo 100.000 toneladas, 10.000.000 kg, etc.) para evitar erros de digitacao.
Endpoints da API
| Metodo | Rota | Acao |
|---|---|---|
GET | /api/orders | Listar cotacoes do produtor |
POST | /api/orders | Criar cotacao (publicada diretamente) |
POST | /api/orders/draft | Salvar rascunho |
GET | /api/orders/{uuid} | Detalhes da cotacao |
PUT | /api/orders/{uuid} | Atualizar cotacao |
DELETE | /api/orders/{uuid} | Excluir cotacao (soft delete) |
POST | /api/orders/{uuid}/publish | Publicar cotacao |
POST | /api/orders/{uuid}/cancel | Cancelar cotacao |
POST | /api/orders/{uuid}/revoke | Revogar cotacao |
POST | /api/orders/{uuid}/reopen | Reabrir para edicao |
POST | /api/orders/{uuid}/duplicate | Duplicar cotacao |
GET | /api/orders/{uuid}/items | Listar itens |
GET | /api/orders/{uuid}/history | Historico/timeline |
PATCH | /api/orders/{uuid}/status | Atualizar status |