Files

115 lines
3.7 KiB
JavaScript

'use strict'
/**
* FUT-02 — Job de Recompra Automática PJ
* Roda diariamente às 07:00.
* Para cada pedido_recorrente com proximo_em <= hoje, cria uma nova cotação
* e converte para pedido automaticamente.
*/
const PedidoRecorrente = require('../models/PedidoRecorrente')
const Cotacao = require('../models/Cotacao')
const Produto = require('../models/Produto')
const TENANT_ID = parseInt(process.env.TENANT_ID || '1', 10)
async function runRecorrentes() {
console.log('[recorrentes] Verificando pedidos recorrentes vencidos…')
let processados = 0, erros = 0
try {
const lista = await PedidoRecorrente.listDue(TENANT_ID)
if (!lista.length) {
console.log('[recorrentes] Nenhum pedido vencido hoje.')
return
}
for (const rec of lista) {
try {
// Resolver preços atuais dos produtos
const itens = Array.isArray(rec.itens) ? rec.itens : JSON.parse(rec.itens || '[]')
let total = 0
const itensResolvidos = []
for (const item of itens) {
const prod = item.produto_id
? await Produto.findById(item.produto_id, TENANT_ID).catch(() => null)
: await Produto.findBySku(item.sku, TENANT_ID).catch(() => null)
if (!prod) {
console.warn(`[recorrentes] Produto não encontrado: ${item.produto_id || item.sku}`)
continue
}
const preco = parseFloat(prod.preco || 0)
const subtotal = preco * item.quantidade
total += subtotal
itensResolvidos.push({ ...item, preco_unitario: preco, subtotal })
}
if (!itensResolvidos.length) {
console.warn(`[recorrentes] Recorrente #${rec.id} sem itens válidos — pulando.`)
continue
}
// Criar cotação
const cotacao = await Cotacao.create({
tenant_id: TENANT_ID,
cliente_id: rec.cliente_id || null,
user_id: rec.user_id,
status: 'rascunho',
total,
desconto: 0,
observacao: `Recompra automática: ${rec.nome}`,
})
// Adicionar itens
for (const item of itensResolvidos) {
await Cotacao.addItem({
cotacao_id: cotacao.id,
produto_id: item.produto_id || null,
nome_produto: item.nome_produto || item.nome || '—',
sku: item.sku || null,
quantidade: item.quantidade,
preco_unitario: item.preco_unitario,
preco_promocional: null,
desconto_pct: 0,
})
}
// Converter para pedido (status aguardando)
await Cotacao.toOrder(cotacao.id, {
forma_pagto: 'faturado',
tipo_entrega: 'entrega',
observacao: `Recompra automática: ${rec.nome}`,
total,
})
// Avançar proximo_em
await PedidoRecorrente.avancaProximo(rec.id, rec.frequencia)
processados++
console.log(`[recorrentes] Recorrente #${rec.id} (${rec.nome}) → pedido criado.`)
} catch (err) {
erros++
console.error(`[recorrentes] Erro no recorrente #${rec.id}:`, err.message)
}
}
} catch (err) {
console.error('[recorrentes] Erro geral:', err.message)
}
console.log(`[recorrentes] Concluído — ${processados} processados, ${erros} erros.`)
}
function startRecorrentesJob() {
// Roda uma vez após 5min do boot, depois a cada 24h
setTimeout(() => {
runRecorrentes()
setInterval(runRecorrentes, 24 * 60 * 60 * 1000)
}, 5 * 60 * 1000)
console.log('[recorrentes] Job agendado (diário, 24h).')
}
module.exports = { startRecorrentesJob, runRecorrentes }