import logging from datetime import date from odoo import api, fields, models, _ _logger = logging.getLogger(__name__) class FlIntakeWizard(models.TransientModel): """ Phase 7 — Full guided case creation wizard for paralegals/attorneys. Creates fl.party records (petitioner + optional respondent), fl.case record with all intake fields, triggers fee waiver check and AI analysis, then opens the new case form. """ _name = 'fl.intake.wizard' _description = 'Family Law Case Intake Wizard' # ── Step 1: Case identity ──────────────────────────────────────────────── case_type = fields.Selection([ ('modification', 'Child Support Modification'), ('dissolution_children', 'Dissolution of Marriage — With Children'), ('dissolution_no_children', 'Dissolution of Marriage — No Children'), ('paternity', 'Paternity'), ('alimony_modification', 'Alimony Modification'), ('custody_modification', 'Timesharing / Custody Modification'), ], string='Case Type', required=True, default='modification') court_case_number = fields.Char( string='Court Case Number', help='Leave blank if not yet assigned' ) # ── Step 2: Parties ────────────────────────────────────────────────────── # Petitioner petitioner_name = fields.Char(string='Petitioner Full Name', required=True) petitioner_email = fields.Char(string='Petitioner Email') petitioner_phone = fields.Char(string='Petitioner Phone') petitioner_address = fields.Char(string='Petitioner Street Address') petitioner_city = fields.Char(string='Petitioner City') petitioner_fl_resident_since = fields.Date( string='FL Resident Since', help='FL 61.021: Petitioner must be a FL resident for 6 months before filing' ) # Respondent respondent_name = fields.Char(string='Respondent Full Name') respondent_has_counsel = fields.Boolean( string='Respondent Has Legal Counsel?', help='Affects attorney referral recommendation' ) # ── Step 3: Children & Safety ──────────────────────────────────────────── num_children = fields.Integer( string='Number of Minor Children', default=1, help='Children under 18 covered by this case' ) domestic_violence_flag = fields.Boolean( string='History of Domestic Violence?', help='FL 44.102: Requires separate mediation rooms. ' 'Attorney referral is strongly recommended.' ) income_imputation_concern = fields.Boolean( string='Income Imputation Concern?', help='Is one party voluntarily unemployed or underemployed?' ) # ── Step 4: Financial Information ──────────────────────────────────────── petitioner_monthly_gross = fields.Float( string='Petitioner Monthly Gross Income', digits=(10, 2) ) respondent_monthly_gross = fields.Float( string='Respondent Monthly Gross Income', digits=(10, 2) ) current_order_amount = fields.Float( string='Current Support Order Amount ($/month)', help='0 if no existing order', digits=(10, 2) ) household_size = fields.Integer( string='Household Size (petitioner)', default=3, help='Used for fee waiver eligibility (FL 57.082)' ) # ── Step 5: Options ────────────────────────────────────────────────────── fee_waiver_request = fields.Boolean( string='Request Fee Waiver? (FL 57.082)', help='System will check eligibility based on income' ) run_ai_analysis = fields.Boolean( string='Run AI Case Analysis?', default=True, help='Automatically analyze the case using Ollama AI engine' ) notes = fields.Text(string='Additional Notes / Case Summary') # ── Computed helpers ───────────────────────────────────────────────────── residency_warning = fields.Char( string='Residency Status', compute='_compute_residency_warning' ) @api.depends('petitioner_fl_resident_since') def _compute_residency_warning(self): for rec in self: if rec.petitioner_fl_resident_since: days = (date.today() - rec.petitioner_fl_resident_since).days if days < 180: remaining = 180 - days rec.residency_warning = ( f'⚠ Only {days} days as FL resident — ' f'{remaining} more days needed (FL 61.021)' ) else: rec.residency_warning = f'✓ {days} days — Residency requirement met (FL 61.021)' else: rec.residency_warning = '' # ── Action ─────────────────────────────────────────────────────────────── def action_create_case(self): """ Create partner → party → case chain from wizard data. Mirrors the portal intake_submit logic but for authenticated users. """ self.ensure_one() petitioner_name = (self.petitioner_name or '').strip() respondent_name = (self.respondent_name or '').strip() # --- Petitioner partner --- domain = [] if self.petitioner_email: domain = [('email', '=', self.petitioner_email)] else: domain = [('name', '=', petitioner_name)] petitioner_partner = self.env['res.partner'].search(domain, limit=1) if not petitioner_partner: vals = { 'name': petitioner_name, 'is_company': False, } if self.petitioner_email: vals['email'] = self.petitioner_email if self.petitioner_phone: vals['phone'] = self.petitioner_phone if self.petitioner_address: vals['street'] = self.petitioner_address if self.petitioner_city: vals['city'] = self.petitioner_city try: vals['state_id'] = self.env.ref('base.state_us_10').id # Florida vals['country_id'] = self.env.ref('base.us').id except Exception: pass petitioner_partner = self.env['res.partner'].create(vals) # --- Respondent partner --- respondent_partner = False if respondent_name: respondent_partner = self.env['res.partner'].search( [('name', '=', respondent_name)], limit=1 ) if not respondent_partner: respondent_partner = self.env['res.partner'].create({ 'name': respondent_name, 'is_company': False, }) # --- Petitioner fl.party --- petitioner_party = self.env['fl.party'].search( [('partner_id', '=', petitioner_partner.id)], limit=1 ) if not petitioner_party: party_vals = { 'name': petitioner_name, 'partner_id': petitioner_partner.id, 'employment_status': 'employed', 'monthly_gross_income': self.petitioner_monthly_gross, } if self.petitioner_email: party_vals['email'] = self.petitioner_email petitioner_party = self.env['fl.party'].create(party_vals) elif self.petitioner_monthly_gross: petitioner_party.write({'monthly_gross_income': self.petitioner_monthly_gross}) # --- Respondent fl.party --- respondent_party = False if respondent_partner: respondent_party = self.env['fl.party'].search( [('partner_id', '=', respondent_partner.id)], limit=1 ) if not respondent_party: respondent_party = self.env['fl.party'].create({ 'name': respondent_name, 'partner_id': respondent_partner.id, 'monthly_gross_income': self.respondent_monthly_gross, }) elif self.respondent_monthly_gross: respondent_party.write({'monthly_gross_income': self.respondent_monthly_gross}) # --- Residency check --- filing_date = date.today() residency_ok = True if self.petitioner_fl_resident_since: days = (filing_date - self.petitioner_fl_resident_since).days residency_ok = days >= 180 # --- Create fl.case --- case_vals = { 'case_type': self.case_type, 'petitioner_id': petitioner_party.id, 'respondent_id': respondent_party.id if respondent_party else False, 'court_case_number': self.court_case_number or False, 'domestic_violence_flag': self.domestic_violence_flag, 'respondent_has_counsel': self.respondent_has_counsel, 'current_order_amount': self.current_order_amount, 'filing_date': filing_date, 'residency_requirement_met': residency_ok, 'household_size': self.household_size, } if self.petitioner_fl_resident_since: case_vals['petitioner_fl_resident_since'] = self.petitioner_fl_resident_since if self.notes: case_vals['description'] = self.notes case = self.env['fl.case'].create(case_vals) # --- Fee waiver check --- if self.fee_waiver_request: fwv = self.env['fl.fee.waiver'].search( [('case_id', '=', case.id)], limit=1 ) if not fwv: # Create a fee waiver record manually self.env['fl.fee.waiver'].create({'case_id': case.id}) # --- AI analysis --- if self.run_ai_analysis: try: self.env['fl.ai.engine'].analyze_case(case.id) except Exception as e: _logger.warning( 'Intake wizard: AI analysis failed for case %s: %s', case.id, e ) case.message_post( body=f'⚠ AI analysis could not run automatically: {e}', subtype_xmlid='mail.mt_note', ) return { 'type': 'ir.actions.act_window', 'name': _('New Case'), 'res_model': 'fl.case', 'res_id': case.id, 'view_mode': 'form', 'target': 'current', }