115 lines
3.7 KiB
JavaScript
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 }
|