'use strict' const Cliente = require('../models/Cliente') function validarCpf(cpf) { cpf = cpf.replace(/\D/g, '') if (cpf.length !== 11 || /^(\d)\1+$/.test(cpf)) return false let s = 0 for (let i = 0; i < 9; i++) s += +cpf[i] * (10 - i) let r = (s * 10) % 11; if (r === 10 || r === 11) r = 0 if (r !== +cpf[9]) return false s = 0 for (let i = 0; i < 10; i++) s += +cpf[i] * (11 - i) r = (s * 10) % 11; if (r === 10 || r === 11) r = 0 return r === +cpf[10] } function validarCnpj(cnpj) { cnpj = cnpj.replace(/\D/g, '') if (cnpj.length !== 14 || /^(\d)\1+$/.test(cnpj)) return false const calc = (n) => { let s = 0, p = n - 7 for (let i = 0; i < n; i++) { p = p < 2 ? p + 9 : p; s += +cnpj[i] * p--; } return s % 11 < 2 ? 0 : 11 - (s % 11) } return calc(12) === +cnpj[12] && calc(13) === +cnpj[13] } const clienteController = { async list(req, res) { try { const tenantId = req.tenant.id const { search, tipo, status, limit, offset } = req.query const rows = await Cliente.list(tenantId, { search, tipo, status, limit, offset }) res.json(rows) } catch (err) { console.error('[cliente.list]', err.message) res.status(500).json({ error: 'Erro ao listar clientes' }) } }, async get(req, res) { try { const cliente = await Cliente.findComplete(req.params.id) if (!cliente) return res.status(404).json({ error: 'Cliente não encontrado' }) res.json(cliente) } catch (err) { console.error('[cliente.get]', err.message) res.status(500).json({ error: 'Erro ao buscar cliente' }) } }, async create(req, res) { try { const tenantId = req.tenant.id const { tipo, nome, cpf_cnpj, email, status } = req.body if (!tipo || !['PF', 'PJ'].includes(tipo)) return res.status(400).json({ error: 'tipo deve ser PF ou PJ' }) if (!nome?.trim()) return res.status(400).json({ error: 'nome é obrigatório' }) if (!cpf_cnpj?.trim()) return res.status(400).json({ error: 'cpf_cnpj é obrigatório' }) const doc = cpf_cnpj.replace(/\D/g, '') if (tipo === 'PF' && !validarCpf(doc)) return res.status(400).json({ error: 'CPF inválido' }) if (tipo === 'PJ' && !validarCnpj(doc)) return res.status(400).json({ error: 'CNPJ inválido' }) const existe = await Cliente.findByCpfCnpj(doc, tenantId) if (existe) return res.status(409).json({ error: 'CPF/CNPJ já cadastrado' }) const user_id = req.user?.id || null const cliente = await Cliente.create({ tenant_id: tenantId, tipo, nome: nome.trim(), cpf_cnpj: doc, email, status, user_id }) res.status(201).json(cliente) } catch (err) { console.error('[cliente.create]', err.message) res.status(500).json({ error: 'Erro ao criar cliente' }) } }, async update(req, res) { try { const { nome, email, status } = req.body if (!nome?.trim()) return res.status(400).json({ error: 'nome é obrigatório' }) await Cliente.update(req.params.id, { nome: nome.trim(), email, status }) res.json({ ok: true }) } catch (err) { console.error('[cliente.update]', err.message) res.status(500).json({ error: 'Erro ao atualizar cliente' }) } }, async remove(req, res) { try { await Cliente.delete(req.params.id) res.json({ ok: true }) } catch (err) { console.error('[cliente.remove]', err.message) res.status(500).json({ error: 'Erro ao remover cliente' }) } }, // ── Endereços ───────────────────────────────────────────── async listEnderecos(req, res) { try { res.json(await Cliente.listEnderecos(req.params.id)) } catch (err) { res.status(500).json({ error: 'Erro ao listar endereços' }) } }, async addEndereco(req, res) { try { const dados = { ...req.body, cliente_id: req.params.id } const end = await Cliente.createEndereco(dados) if (dados.principal) await Cliente.setEndereçoPrincipal(req.params.id, end.id) res.status(201).json(end) } catch (err) { console.error('[cliente.addEndereco]', err.message) res.status(500).json({ error: 'Erro ao adicionar endereço' }) } }, async updateEndereco(req, res) { try { await Cliente.updateEndereco(req.params.endId, req.body) if (req.body.principal) await Cliente.setEndereçoPrincipal(req.params.id, req.params.endId) res.json({ ok: true }) } catch (err) { res.status(500).json({ error: 'Erro ao atualizar endereço' }) } }, async removeEndereco(req, res) { try { await Cliente.deleteEndereco(req.params.endId) res.json({ ok: true }) } catch (err) { res.status(500).json({ error: 'Erro ao remover endereço' }) } }, // ── Telefones ───────────────────────────────────────────── async listTelefones(req, res) { try { res.json(await Cliente.listTelefones(req.params.id)) } catch (err) { res.status(500).json({ error: 'Erro ao listar telefones' }) } }, async addTelefone(req, res) { try { const tel = await Cliente.createTelefone({ ...req.body, cliente_id: req.params.id }) res.status(201).json(tel) } catch (err) { res.status(500).json({ error: 'Erro ao adicionar telefone' }) } }, async updateTelefone(req, res) { try { await Cliente.updateTelefone(req.params.telId, req.body) res.json({ ok: true }) } catch (err) { res.status(500).json({ error: 'Erro ao atualizar telefone' }) } }, async removeTelefone(req, res) { try { await Cliente.deleteTelefone(req.params.telId) res.json({ ok: true }) } catch (err) { res.status(500).json({ error: 'Erro ao remover telefone' }) } }, // ── Responsáveis ───────────────────────────────────────── async listResponsaveis(req, res) { try { res.json(await Cliente.listResponsaveis(req.params.id)) } catch (err) { res.status(500).json({ error: 'Erro ao listar responsáveis' }) } }, async addResponsavel(req, res) { try { const r = await Cliente.createResponsavel({ ...req.body, cliente_id: req.params.id }) res.status(201).json(r) } catch (err) { res.status(500).json({ error: 'Erro ao adicionar responsável' }) } }, async updateResponsavel(req, res) { try { await Cliente.updateResponsavel(req.params.respId, req.body) res.json({ ok: true }) } catch (err) { res.status(500).json({ error: 'Erro ao atualizar responsável' }) } }, async removeResponsavel(req, res) { try { await Cliente.deleteResponsavel(req.params.respId) res.json({ ok: true }) } catch (err) { res.status(500).json({ error: 'Erro ao remover responsável' }) } }, } module.exports = clienteController