from odoo import api, fields, models from dateutil.relativedelta import relativedelta class FlChild(models.Model): _name = 'fl.child' _description = 'Child on Case' _order = 'date_of_birth' case_id = fields.Many2one( 'fl.case', string='Case', required=True, ondelete='cascade', index=True ) name = fields.Char(string='Full Name', required=True) date_of_birth = fields.Date(string='Date of Birth', required=True) age = fields.Integer( string='Age', compute='_compute_age', store=True ) gender = fields.Selection([ ('m', 'Male'), ('f', 'Female'), ('x', 'Non-binary / Other'), ], string='Gender') school = fields.Char(string='School') medical_provider = fields.Char(string='Primary Care Provider') # ── Support Per Child ────────────────────────────────────────────────── support_amount = fields.Float( string='Support Amount This Child ($)', help='Per-child support amount from the calculation' ) health_insurance_premium = fields.Float( string='Health Insurance Premium ($)', help='Monthly cost of health insurance for this child only' ) childcare_cost = fields.Float( string='Work-Related Childcare ($)', help='FL 61.30(7): Only work or job-search related childcare costs qualify' ) extraordinary_expenses = fields.Float( string='Extraordinary Expenses ($)', help='FL 61.30(9): Medical or educational expenses beyond ordinary child-rearing costs' ) # ── Emancipation Tracking ────────────────────────────────────────────── emancipation_date = fields.Date( string='Emancipation Date', compute='_compute_emancipation', store=True, help='18th birthday (or high school graduation, whichever is later). ' 'Support terminates on this date.' ) approaching_emancipation = fields.Boolean( string='Approaching Emancipation', compute='_compute_approaching_emancipation', store=True, help='True when emancipation is within 90 days' ) emancipation_alert_sent = fields.Boolean( string='Emancipation Alert Sent', default=False ) emancipated = fields.Boolean( string='Emancipated', compute='_compute_emancipated', store=True ) days_until_emancipation = fields.Integer( string='Days Until Emancipation', compute='_compute_approaching_emancipation' ) # ── Early Emancipation Factors ───────────────────────────────────────── married = fields.Boolean( string='Child is Married', help='Marriage constitutes emancipation under FL law' ) active_military = fields.Boolean( string='Active Military Service', help='Active duty military service constitutes emancipation under FL law' ) declared_emancipated = fields.Boolean( string='Court-Declared Emancipated', help='Court has entered an order declaring this child emancipated' ) emancipation_notes = fields.Text( string='Emancipation Notes', help='Document basis for any early emancipation determination' ) # ── Computed ────────────────────────────────────────────────────────── @api.depends('date_of_birth') def _compute_age(self): today = fields.Date.today() for rec in self: if rec.date_of_birth: delta = relativedelta(today, rec.date_of_birth) rec.age = delta.years else: rec.age = 0 @api.depends('date_of_birth') def _compute_emancipation(self): for rec in self: if rec.date_of_birth: rec.emancipation_date = rec.date_of_birth + relativedelta(years=18) else: rec.emancipation_date = False @api.depends('emancipation_date', 'married', 'active_military', 'declared_emancipated') def _compute_approaching_emancipation(self): today = fields.Date.today() for rec in self: # Early emancipation factors if rec.married or rec.active_military or rec.declared_emancipated: rec.approaching_emancipation = False rec.days_until_emancipation = 0 continue if rec.emancipation_date: days_remaining = (rec.emancipation_date - today).days rec.days_until_emancipation = max(days_remaining, 0) rec.approaching_emancipation = 0 < days_remaining <= 90 else: rec.approaching_emancipation = False rec.days_until_emancipation = 0 @api.depends('emancipation_date', 'married', 'active_military', 'declared_emancipated') def _compute_emancipated(self): today = fields.Date.today() for rec in self: if rec.married or rec.active_military or rec.declared_emancipated: rec.emancipated = True elif rec.emancipation_date: rec.emancipated = today >= rec.emancipation_date else: rec.emancipated = False # ── Cron ────────────────────────────────────────────────────────────── def _cron_emancipation_alerts(self): """ Run daily via ir.cron. Sends chatter alert on cases where a child is approaching emancipation and no alert has been sent yet. """ approaching = self.search([ ('approaching_emancipation', '=', True), ('emancipation_alert_sent', '=', False), ]) for child in approaching: days = child.days_until_emancipation child.case_id.message_post( body=( f'⚠️ EMANCIPATION ALERT
' f'{child.name} will turn 18 on ' f'{child.emancipation_date} ' f'({days} days from today).
' f'Child support for this child terminates on that date.
' f'Action required: A Motion to Modify should be filed ' f'at least 60 days before emancipation to address the change ' f'in support obligation.' ), subtype_xmlid='mail.mt_note', ) child.emancipation_alert_sent = True