- controllers/portal.py: FamilyLawPortal with 8 routes (cases list, case detail, calculator pre-fill, caselaw library, deadline complete AJAX, public intake landing/form/submit) - views/portal_case_templates.xml: portal home card, case list, full case detail with timeline widget, AI summary, DV safety banner - views/portal_calculator_templates.xml: FL 61.30 interactive calculator - views/portal_caselaw_templates.xml: searchable case law library (EN/ES) - views/website_intake_templates.xml: public 4-step intake form with DV quick-exit, fee waiver, and intake confirmation page - static/src/css/familylaw_portal.css: full portal/website CSS (EN/ES lang toggle, deadline card color coding, timeline, AI summary box) - static/src/js/fl_calculator.js: FL 61.30 schedule lookup, above- schedule formula, FL 61.30(11)(b) substantial timesharing calculation - static/src/js/fl_timeline.js: deadline timeline widget with filter buttons and mark-complete AJAX - __init__.py: import controllers package - __manifest__.py: add Phase 6 portal view files Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
317 lines
19 KiB
XML
317 lines
19 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!-- Portal templates for fl.case — My Case page (authenticated litigant view)
|
|
URL: /my/cases and /my/cases/<case_id>
|
|
Inherits portal.portal_my_home and portal.portal_layout.
|
|
-->
|
|
<odoo>
|
|
<data>
|
|
|
|
<!-- ══ Portal Home: add "My Cases" card ══════════════════════════════ -->
|
|
<template id="portal_my_home_cases" name="FL Cases — Portal Home Entry"
|
|
inherit_id="portal.portal_my_home" priority="30">
|
|
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
|
|
<t t-if="case_count">
|
|
<div class="o_portal_doc_category">
|
|
<t t-call="portal.portal_docs_entry">
|
|
<t t-set="icon">/activeblue_familylaw/static/src/img/fl_icon.png</t>
|
|
<t t-set="text">My Family Law Cases</t>
|
|
<t t-set="url">/my/cases</t>
|
|
<t t-set="count" t-value="case_count"/>
|
|
</t>
|
|
</div>
|
|
</t>
|
|
</xpath>
|
|
</template>
|
|
|
|
<!-- ══ Case list page ════════════════════════════════════════════════ -->
|
|
<template id="portal_my_cases" name="My Family Law Cases">
|
|
<t t-call="portal.portal_layout">
|
|
<t t-set="breadcrumbs_searchbar" t-value="True"/>
|
|
<t t-call="portal.portal_searchbar">
|
|
<t t-set="title">My Cases</t>
|
|
</t>
|
|
<div class="container fl-portal mt-4">
|
|
<t t-if="not cases">
|
|
<div class="alert alert-info">
|
|
You have no family law cases on file. Contact ActiveBlue to open a new case.
|
|
</div>
|
|
</t>
|
|
<t t-foreach="cases" t-as="case">
|
|
<a t-attf-href="/my/cases/#{case.id}" class="text-decoration-none">
|
|
<div class="fl-deadline-card mb-3">
|
|
<div class="row align-items-center">
|
|
<div class="col-md-7">
|
|
<div class="fl-deadline-type">
|
|
<t t-esc="dict([('dissolution','Dissolution of Marriage'),('paternity','Paternity'),('child_support','Child Support'),('modification','Modification'),('injunction','Injunction')]).get(case.case_type, case.case_type)"/>
|
|
</div>
|
|
<div class="fl-deadline-name">
|
|
<t t-esc="case.name"/>
|
|
</div>
|
|
<div class="fl-deadline-date text-muted" style="font-size:0.85rem;">
|
|
Filed: <t t-esc="case.filing_date or 'Pending'"/>
|
|
| Case No.: <t t-esc="case.court_case_number or 'Pending'"/>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<t t-if="case.overdue_deadline_count">
|
|
<span class="fl-deadline-overdue">
|
|
⚠ <t t-esc="case.overdue_deadline_count"/> overdue deadline(s)
|
|
</span>
|
|
</t>
|
|
</div>
|
|
<div class="col-md-2 text-end">
|
|
<span class="badge bg-secondary">
|
|
<t t-esc="case.stage_id.name if case.stage_id else 'Active'"/>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</t>
|
|
</div>
|
|
</t>
|
|
</template>
|
|
|
|
<!-- ══ Case detail page ══════════════════════════════════════════════ -->
|
|
<template id="portal_case_detail" name="Case Detail — Portal">
|
|
<t t-call="portal.portal_layout">
|
|
<div class="container fl-portal mt-4">
|
|
|
|
<!-- Breadcrumb -->
|
|
<nav aria-label="breadcrumb">
|
|
<ol class="breadcrumb">
|
|
<li class="breadcrumb-item"><a href="/my/home">Home</a></li>
|
|
<li class="breadcrumb-item"><a href="/my/cases">My Cases</a></li>
|
|
<li class="breadcrumb-item active"><t t-esc="case.name"/></li>
|
|
</ol>
|
|
</nav>
|
|
|
|
<!-- Language toggle -->
|
|
<div class="fl-lang-toggle">
|
|
<button class="btn btn-outline-secondary btn-sm fl-lang-btn" data-lang="en">EN</button>
|
|
<button class="btn btn-outline-secondary btn-sm fl-lang-btn" data-lang="es">ES</button>
|
|
</div>
|
|
|
|
<!-- Attorney referral banner (if AI flagged it) -->
|
|
<t t-if="latest_analysis and latest_analysis.attorney_referral_flag">
|
|
<div class="fl-attorney-referral-banner">
|
|
<h5>⚠ Attorney Consultation Recommended</h5>
|
|
<p><t t-esc="latest_analysis.attorney_referral_reason or 'Based on your case details, consulting with an attorney is strongly recommended.'"/></p>
|
|
<p>
|
|
<strong>Free Legal Resources:</strong>
|
|
<a href="https://www.flvlp.org" target="_blank">FL Volunteer Lawyers Project</a> |
|
|
<a href="https://www.fllsc.org" target="_blank">Legal Services of Greater Miami</a> |
|
|
<a href="https://www.flcourts.gov/Resources-Services/Family-Courts" target="_blank">FL Courts Self-Help</a>
|
|
</p>
|
|
</div>
|
|
</t>
|
|
|
|
<!-- DV safety banner -->
|
|
<t t-if="case.domestic_violence_flag">
|
|
<div class="fl-dv-safety-banner">
|
|
<div data-lang="en">
|
|
<h5>🔴 Safety Resources</h5>
|
|
<p>If you are in immediate danger, call <strong>911</strong>.<br/>
|
|
National DV Hotline: <strong>1-800-799-7233</strong> (TTY: 1-800-787-3224)<br/>
|
|
Miami-Dade Safe Space: <strong>(305) 758-2546</strong></p>
|
|
<a href="https://www.google.com" class="fl-dv-safety-escape-link" target="_blank">Quick Exit (Google)</a>
|
|
</div>
|
|
<div data-lang="es" style="display:none;">
|
|
<h5>🔴 Recursos de Seguridad</h5>
|
|
<p>Si está en peligro inmediato, llame al <strong>911</strong>.<br/>
|
|
Línea Nacional de Violencia Doméstica: <strong>1-800-799-7233</strong><br/>
|
|
Miami-Dade Safe Space: <strong>(305) 758-2546</strong></p>
|
|
<a href="https://www.google.com" class="fl-dv-safety-escape-link" target="_blank">Salida Rápida (Google)</a>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
|
|
<!-- Case header -->
|
|
<div class="fl-case-header">
|
|
<div class="d-flex justify-content-between align-items-start">
|
|
<div>
|
|
<h2><t t-esc="case.name"/></h2>
|
|
<div class="fl-case-meta">
|
|
<t t-esc="dict([('dissolution','Dissolution of Marriage'),('paternity','Paternity'),('child_support','Child Support'),('modification','Modification'),('injunction','Injunction / DV')]).get(case.case_type, case.case_type)"/>
|
|
<t t-if="case.court_case_number">
|
|
| Case No. <t t-esc="case.court_case_number"/>
|
|
</t>
|
|
| Filed <t t-esc="case.filing_date or 'Pending'"/>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<span class="badge"><t t-esc="case.stage_id.name if case.stage_id else 'Active'"/></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Stats row -->
|
|
<div class="row g-3 mb-4">
|
|
<div class="col-6 col-md-3">
|
|
<div class="fl-stat-card <t t-if='case.overdue_deadline_count'>danger</t>">
|
|
<div class="fl-stat-number"><t t-esc="case.overdue_deadline_count or 0"/></div>
|
|
<div class="fl-stat-label">Overdue</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-6 col-md-3">
|
|
<div class="fl-stat-card">
|
|
<div class="fl-stat-number"><t t-esc="len(case.deadline_ids.filtered(lambda d: not d.completed))"/></div>
|
|
<div class="fl-stat-label">Open Deadlines</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-6 col-md-3">
|
|
<div class="fl-stat-card">
|
|
<div class="fl-stat-number"><t t-esc="len(case.child_ids.filtered(lambda c: not c.emancipated))"/></div>
|
|
<div class="fl-stat-label">Minor Children</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-6 col-md-3">
|
|
<div class="fl-stat-card <t t-if='case.threshold_met'>success</t>">
|
|
<div class="fl-stat-number" style="font-size:1.2rem;">
|
|
<t t-if="case.threshold_met">✓ Met</t>
|
|
<t t-else="">—</t>
|
|
</div>
|
|
<div class="fl-stat-label">Mod. Threshold</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- AI Summary -->
|
|
<t t-if="latest_analysis and latest_analysis.plain_english_summary">
|
|
<div class="fl-ai-summary">
|
|
<div class="fl-ai-header">🤖 AI Case Summary</div>
|
|
<div class="fl-ai-text" data-lang="en">
|
|
<t t-esc="latest_analysis.plain_english_summary"/>
|
|
</div>
|
|
<div class="fl-ai-text" data-lang="es" style="display:none;">
|
|
<t t-esc="latest_analysis.plain_english_summary_es or latest_analysis.plain_english_summary"/>
|
|
</div>
|
|
<div class="fl-ai-disclaimer">
|
|
This is an AI-generated summary for informational purposes only. It is NOT legal advice.
|
|
Always verify with a licensed Florida attorney.
|
|
</div>
|
|
</div>
|
|
</t>
|
|
|
|
<!-- Deadlines / Timeline -->
|
|
<div class="fl-section-card mb-4">
|
|
<div class="fl-section-header">📅 Deadlines & Timeline</div>
|
|
<div class="fl-section-body">
|
|
<div class="fl-timeline-widget">
|
|
<!-- Filter buttons -->
|
|
<div class="btn-group btn-group-sm mb-3" role="group">
|
|
<button type="button" class="btn btn-primary fl-timeline-filter active" data-filter="pending">Pending</button>
|
|
<button type="button" class="btn btn-outline-secondary fl-timeline-filter" data-filter="overdue">Overdue</button>
|
|
<button type="button" class="btn btn-outline-secondary fl-timeline-filter" data-filter="completed">Completed</button>
|
|
<button type="button" class="btn btn-outline-secondary fl-timeline-filter" data-filter="all">All</button>
|
|
</div>
|
|
<!-- Deadline data for JS -->
|
|
<script type="application/json" id="fl-timeline-data">
|
|
[<t t-foreach="case.deadline_ids" t-as="dl">
|
|
<t t-if="not dl_last">,</t>
|
|
{"id": <t t-esc="dl.id"/>, "name": "<t t-esc="dl.name.replace('"', '').replace('\\', '')"/>", "dueDate": "<t t-esc="dl.due_date"/>", "completed": <t t-if="dl.completed">true</t><t t-else="">false</t>, "statRef": "<t t-esc="dl.statute_reference or ''"/>"}
|
|
</t>]
|
|
</script>
|
|
<div class="fl-timeline">
|
|
<div class="fl-timeline-list">
|
|
<!-- Rendered by fl_timeline.js -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Support Info (if applicable) -->
|
|
<t t-if="case.calculated_support or case.current_order_amount">
|
|
<div class="fl-section-card mb-4">
|
|
<div class="fl-section-header">💰 Child Support</div>
|
|
<div class="fl-section-body">
|
|
<div class="row">
|
|
<div class="col-md-4">
|
|
<div class="text-muted" style="font-size:0.82rem;">CURRENT ORDER</div>
|
|
<div style="font-size:1.3rem;font-weight:700;color:#003366;">
|
|
$<t t-esc="'%,.2f' % case.current_order_amount"/> / mo
|
|
</div>
|
|
</div>
|
|
<t t-if="case.calculated_support">
|
|
<div class="col-md-4">
|
|
<div class="text-muted" style="font-size:0.82rem;">GUIDELINE AMOUNT</div>
|
|
<div style="font-size:1.3rem;font-weight:700;color:#003366;">
|
|
$<t t-esc="'%,.2f' % case.calculated_support"/> / mo
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="text-muted" style="font-size:0.82rem;">THRESHOLD STATUS</div>
|
|
<div style="font-size:1.1rem;font-weight:600;">
|
|
<t t-if="case.threshold_met">
|
|
<span class="text-success">✓ Modification threshold met</span>
|
|
</t>
|
|
<t t-else="">
|
|
<span class="text-muted">Not met yet</span>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</div>
|
|
<div class="mt-3">
|
|
<a href="/my/cases/calculator" class="btn btn-sm btn-outline-primary">
|
|
Open Support Calculator →
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
|
|
<!-- Documents -->
|
|
<t t-if="case.document_ids">
|
|
<div class="fl-section-card mb-4">
|
|
<div class="fl-section-header">📄 Documents</div>
|
|
<div class="fl-section-body p-0">
|
|
<t t-foreach="case.document_ids" t-as="doc">
|
|
<a t-attf-href="/my/cases/#{case.id}/documents/#{doc.id}"
|
|
class="fl-document-item">
|
|
<div class="fl-doc-icon">📄</div>
|
|
<div>
|
|
<div class="fl-doc-name"><t t-esc="doc.name"/></div>
|
|
<div class="fl-doc-type">
|
|
<t t-esc="doc.document_type or 'Document'"/>
|
|
</div>
|
|
</div>
|
|
<span class="fl-doc-badge <t t-if='doc.state == \"filed\"'>filed</t><t t-elif='doc.state == \"draft\"'>draft</t>">
|
|
<t t-esc="(doc.state or 'draft').title()"/>
|
|
</span>
|
|
</a>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
|
|
<!-- Next Hearing -->
|
|
<t t-if="case.next_hearing">
|
|
<div class="fl-section-card mb-4">
|
|
<div class="fl-section-header">🏛 Upcoming Hearing</div>
|
|
<div class="fl-section-body">
|
|
<strong><t t-esc="case.next_hearing.name"/></strong><br/>
|
|
<t t-esc="case.next_hearing.hearing_date"/>
|
|
<t t-if="case.next_hearing.location">
|
|
| <t t-esc="case.next_hearing.location"/>
|
|
</t>
|
|
<div class="mt-2" style="font-size:0.85rem;">
|
|
<t t-if="case.next_hearing.parenting_class_warning">
|
|
<div class="text-warning">⚠ <t t-esc="case.next_hearing.parenting_class_warning"/></div>
|
|
</t>
|
|
<t t-if="case.next_hearing.discovery_cutoff_warning">
|
|
<div class="text-warning">⚠ <t t-esc="case.next_hearing.discovery_cutoff_warning"/></div>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
|
|
</div>
|
|
</t>
|
|
</template>
|
|
|
|
</data>
|
|
</odoo>
|