# ARQUIVO: ./models/crianca.py from odoo import models, fields, api, _ from datetime import date class RecreacaoCrianca(models.Model): _name = 'recreacao.crianca' _description = 'Aluno / Criança' _inherit = ['mail.thread'] # Permite o log de mensagens e chat no rodapé # --- DADOS PESSOAIS --- name = fields.Char(string='Nome da Criança', required=True, tracking=True) foto = fields.Binary(string="Foto") data_nascimento = fields.Date(string='Data de Nascimento') idade = fields.Char(compute='_compute_idade', string='Idade') # --- FAMÍLIA --- pai_id = fields.Many2one('res.partner', string='Pai', domain="[('is_company', '=', False)]") mae_id = fields.Many2one('res.partner', string='Mãe', domain="[('is_company', '=', False)]") responsavel_financeiro_id = fields.Many2one('res.partner', string='Responsável Financeiro', required=True) # --- SAÚDE --- tem_alergia = fields.Boolean(string="Tem Alergia?", tracking=True) alergias = fields.Text(string='Quais Alergias?') toma_remedio = fields.Boolean(string="Toma Remédio?") medicamentos = fields.Text(string='Quais Medicamentos?') horario_medicacao = fields.Char(string='Horários') observacoes_saude = fields.Text(string='Obs. Médicas') # --- PLANO & FINANCEIRO --- plano_id = fields.Many2one('recreacao.plano', string='Plano Contratado', tracking=True) valor_plano = fields.Float(related='plano_id.valor', string='Valor do Plano (R$)', readonly=True) # Novo relacionamento com o Financeiro Simplificado financeiro_ids = fields.One2many('recreacao.financeiro', 'crianca_id', string='Histórico de Pagamentos') # --- HISTÓRICO DE FREQUÊNCIA --- diario_ids = fields.One2many('recreacao.diario', 'crianca_id', string='Histórico Diário') # --- CONTROLE DE STATUS (Lógica Corrigida) --- status_dia = fields.Selection([ ('ausente', 'Ausente'), ('presente', 'Na Creche'), ('finalizado', 'Já Saiu') ], compute='_compute_status_dia', string='Status Hoje', store=False) @api.depends('diario_ids') def _compute_status_dia(self): hoje = fields.Date.today() for rec in self: # Busca o ÚLTIMO movimento de entrada ou saída de hoje ultimo_movimento = self.env['recreacao.diario'].search([ ('crianca_id', '=', rec.id), ('data', '=', hoje), ('tipo', 'in', ['entrada', 'saida']) ], order='create_date desc', limit=1) if not ultimo_movimento: rec.status_dia = 'ausente' elif ultimo_movimento.tipo == 'entrada': rec.status_dia = 'presente' elif ultimo_movimento.tipo == 'saida': rec.status_dia = 'finalizado' else: rec.status_dia = 'ausente' # --- AÇÕES DE FREQUÊNCIA --- def action_marcar_entrada(self): """Botão Verde do Kanban""" for rec in self: self.env['recreacao.diario'].create({ 'crianca_id': rec.id, 'tipo': 'entrada', 'descricao': 'Chegou na recreação.' }) # Força atualização da interface rec._compute_status_dia() def action_marcar_saida(self): """Botão Vermelho do Kanban""" for rec in self: self.env['recreacao.diario'].create({ 'crianca_id': rec.id, 'tipo': 'saida', 'descricao': 'Foi embora.' }) rec._compute_status_dia() # --- AÇÕES DE UTILIDADE --- def action_abrir_whatsapp(self): self.ensure_one() if not self.responsavel_financeiro_id.phone and not self.responsavel_financeiro_id.mobile: return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': {'title': 'Erro', 'message': 'Responsável sem telefone cadastrado!', 'type': 'danger'} } numero = self.responsavel_financeiro_id.mobile or self.responsavel_financeiro_id.phone phone = ''.join(filter(str.isdigit, numero)) msg = f"Olá, gostaria de falar sobre: {self.name}" return { 'type': 'ir.actions.act_url', 'url': f"https://api.whatsapp.com/send?phone={phone}&text={msg}", 'target': 'new', } def action_abrir_historico(self): """Abre a lista filtrada do diário dessa criança""" return { 'name': f'Histórico: {self.name}', 'type': 'ir.actions.act_window', 'res_model': 'recreacao.diario', 'domain': [('crianca_id', '=', self.id)], 'view_mode': 'tree,form', } # --- NOVA AÇÃO FINANCEIRA (SIMPLIFICADA) --- def action_gerar_cobranca(self): """Gera um lançamento de Receita no Financeiro Simplificado""" self.ensure_one() if not self.plano_id: return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': {'title': 'Atenção', 'message': 'Selecione um Plano antes de gerar cobrança.', 'type': 'warning'} } # Cria a cobrança no novo modelo self.env['recreacao.financeiro'].create({ 'name': f"Mensalidade: {self.name} - {fields.Date.today().strftime('%m/%Y')}", 'tipo': 'receita', 'valor': self.valor_plano, 'partner_id': self.responsavel_financeiro_id.id, 'crianca_id': self.id, 'data_vencimento': fields.Date.today(), 'status': 'pendente' }) return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': { 'title': 'Sucesso', 'message': f'Cobrança de R$ {self.valor_plano} gerada no Financeiro!', 'type': 'success', 'sticky': False, } } # --- CÁLCULO DE IDADE --- @api.depends('data_nascimento') def _compute_idade(self): for rec in self: if rec.data_nascimento: today = date.today() # Lógica precisa de cálculo de idade (considera dia e mês) years = today.year - rec.data_nascimento.year - ((today.month, today.day) < (rec.data_nascimento.month, rec.data_nascimento.day)) rec.idade = f"{years} anos" else: rec.idade = "Sem data"