changes
This commit is contained in:
73
fusion_quotations/views/equipment_type_views.xml
Normal file
73
fusion_quotations/views/equipment_type_views.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- ============================================================
|
||||
Equipment Type — Tree View
|
||||
============================================================ -->
|
||||
<record id="view_equipment_type_tree" model="ir.ui.view">
|
||||
<field name="name">fusion.equipment.type.tree</field>
|
||||
<field name="model">fusion.equipment.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Equipment Types" editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="icon"/>
|
||||
<field name="active" column_invisible="1"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ============================================================
|
||||
Equipment Type — Form View
|
||||
============================================================ -->
|
||||
<record id="view_equipment_type_form" model="ir.ui.view">
|
||||
<field name="name">fusion.equipment.type.form</field>
|
||||
<field name="model">fusion.equipment.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Equipment Type">
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="name" placeholder="e.g. Stair Lift"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="code" placeholder="e.g. stair_lift"/>
|
||||
<field name="icon" placeholder="e.g. fa-arrow-up"/>
|
||||
<field name="sequence"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="active"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="Description">
|
||||
<field name="description" nolabel="1"
|
||||
placeholder="Optional description of this equipment type..."/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ============================================================
|
||||
Equipment Type — Action
|
||||
============================================================ -->
|
||||
<record id="action_equipment_type" model="ir.actions.act_window">
|
||||
<field name="name">Equipment Types</field>
|
||||
<field name="res_model">fusion.equipment.type</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Create an Equipment Type
|
||||
</p>
|
||||
<p>
|
||||
Equipment types define the categories of equipment that can be
|
||||
assessed and quoted. Each type can have its own Configuration Flow
|
||||
with custom form steps.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
62
fusion_quotations/views/menus.xml
Normal file
62
fusion_quotations/views/menus.xml
Normal file
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- Top menu under Fusion Claims -->
|
||||
<menuitem id="menu_wc_quotation_root"
|
||||
name="Quotation Builder"
|
||||
parent="fusion_claims.menu_adp_claims_root"
|
||||
sequence="25"/>
|
||||
|
||||
<!-- Assessments -->
|
||||
<menuitem id="menu_wc_assessment"
|
||||
name="Wheelchair Assessments"
|
||||
parent="menu_wc_quotation_root"
|
||||
action="action_wc_assessment"
|
||||
sequence="10"/>
|
||||
|
||||
<!-- Configuration submenu -->
|
||||
<menuitem id="menu_wc_config"
|
||||
name="Configuration"
|
||||
parent="menu_wc_quotation_root"
|
||||
sequence="90"
|
||||
groups="sales_team.group_sale_manager"/>
|
||||
|
||||
<menuitem id="menu_wc_sections"
|
||||
name="Wheelchair Sections"
|
||||
parent="menu_wc_config"
|
||||
action="action_wc_section"
|
||||
sequence="10"/>
|
||||
|
||||
<menuitem id="menu_wc_upcharge_rules"
|
||||
name="Upcharge Rules"
|
||||
parent="menu_wc_config"
|
||||
action="action_wc_upcharge_rule"
|
||||
sequence="20"/>
|
||||
|
||||
<menuitem id="menu_wc_config_flows"
|
||||
name="Configuration Flows"
|
||||
parent="menu_wc_config"
|
||||
action="action_wc_config_flow"
|
||||
sequence="30"/>
|
||||
|
||||
<menuitem id="menu_equipment_types"
|
||||
name="Equipment Types"
|
||||
parent="menu_wc_config"
|
||||
action="action_equipment_type"
|
||||
sequence="40"/>
|
||||
|
||||
<!-- Server action: Auto-Populate All Sections -->
|
||||
<record id="action_auto_populate_all" model="ir.actions.server">
|
||||
<field name="name">Auto-Populate All Sections from Inventory</field>
|
||||
<field name="model_id" ref="model_fusion_wc_section"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.action_auto_populate_all_sections()</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_wc_auto_populate"
|
||||
name="Auto-Populate Products"
|
||||
parent="menu_wc_config"
|
||||
action="action_auto_populate_all"
|
||||
sequence="5"/>
|
||||
|
||||
</odoo>
|
||||
990
fusion_quotations/views/portal_quotation_templates.xml
Normal file
990
fusion_quotations/views/portal_quotation_templates.xml
Normal file
@@ -0,0 +1,990 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- ASSESSMENT LIST PAGE -->
|
||||
<!-- ============================================================ -->
|
||||
<template id="portal_quotation_list" name="Equipment Assessments List">
|
||||
<t t-call="portal.portal_layout">
|
||||
<t t-set="breadcrumbs_searchbar" t-value="True"/>
|
||||
|
||||
<div class="o_portal_my_home">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h3>Equipment Assessments</h3>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-primary dropdown-toggle" type="button"
|
||||
data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<i class="fa fa-plus me-1"/> New Assessment
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<t t-foreach="equipment_types" t-as="etype">
|
||||
<li>
|
||||
<a class="dropdown-item"
|
||||
t-attf-href="/my/quotation/builder/new?equipment_type=#{etype.code}">
|
||||
<i t-attf-class="fa #{etype.icon or 'fa-cog'} me-2"/>
|
||||
<t t-out="etype.name"/>
|
||||
</a>
|
||||
</li>
|
||||
</t>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<t t-if="not assessments">
|
||||
<div class="alert alert-info text-center">
|
||||
No assessments yet. Click "New Assessment" to start.
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-if="assessments">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Reference</th>
|
||||
<th>Client</th>
|
||||
<th>Equipment</th>
|
||||
<th>Date</th>
|
||||
<th>Status</th>
|
||||
<th>Total</th>
|
||||
<th/>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<t t-foreach="assessments" t-as="a">
|
||||
<tr>
|
||||
<td><t t-out="a.reference"/></td>
|
||||
<td><t t-out="a.client_name or 'N/A'"/></td>
|
||||
<td><t t-out="equip_type_map.get(a.equipment_type, a.equipment_type or '')"/></td>
|
||||
<td><t t-out="a.assessment_date" t-options="{'widget': 'date'}"/></td>
|
||||
<td>
|
||||
<span t-attf-class="badge #{
|
||||
'text-bg-info' if a.state == 'draft' else
|
||||
'text-bg-warning' if a.state == 'review' else
|
||||
'text-bg-success' if a.state == 'quoted' else
|
||||
'text-bg-secondary'
|
||||
}">
|
||||
<t t-out="dict(a._fields['state'].selection).get(a.state, '')"/>
|
||||
</span>
|
||||
</td>
|
||||
<td>$<t t-out="'%.2f' % a.total_estimate"/></td>
|
||||
<td>
|
||||
<a t-attf-href="/my/quotation/builder/#{a.id}/edit"
|
||||
class="btn btn-sm btn-outline-primary">
|
||||
<t t-if="a.state == 'draft'">Continue</t>
|
||||
<t t-else="">View</t>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
</tbody>
|
||||
</table>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- MULTI-STEP ASSESSMENT FORM (Dynamic) -->
|
||||
<!-- ============================================================ -->
|
||||
<template id="portal_quotation_form" name="Equipment Assessment Form">
|
||||
<t t-call="portal.portal_layout">
|
||||
<t t-set="additional_title">Equipment Assessment</t>
|
||||
|
||||
<div class="wc-assessment-form" id="wcAssessmentForm">
|
||||
|
||||
<!-- Success/Error Messages -->
|
||||
<t t-if="request.params.get('success') == 'saved'">
|
||||
<div class="alert alert-success alert-dismissible fade show">
|
||||
Assessment saved successfully.
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="request.params.get('success') == 'quotation_generated'">
|
||||
<div class="alert alert-success alert-dismissible fade show">
|
||||
<i class="fa fa-check-circle me-1"/> Quotation generated successfully!
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="request.params.get('error')">
|
||||
<div class="alert alert-danger alert-dismissible fade show">
|
||||
<t t-out="request.params.get('error')"/>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- ===== DYNAMIC Step Indicator ===== -->
|
||||
<div class="wc-steps mb-4">
|
||||
<div class="d-flex justify-content-between">
|
||||
<t t-foreach="flow_steps" t-as="fstep">
|
||||
<div t-attf-class="wc-step-indicator text-center flex-fill #{'active' if fstep_index == 0 else ''}"
|
||||
t-att-data-step="fstep_index + 1">
|
||||
<div class="wc-step-number rounded-circle d-inline-flex align-items-center justify-content-center">
|
||||
<t t-out="fstep_index + 1"/>
|
||||
</div>
|
||||
<div class="wc-step-label small mt-1">
|
||||
<t t-out="fstep.name"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Open in Backend link — only for internal users -->
|
||||
<t t-if="assessment and request.env.user.has_group('base.group_user')">
|
||||
<div class="text-end mb-2">
|
||||
<a t-attf-href="/odoo/fusion-quotation-builder/#{assessment.id}"
|
||||
class="btn btn-sm btn-outline-secondary" target="_blank">
|
||||
<i class="fa fa-pencil me-1"/> Open in Backend
|
||||
</a>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<form method="post"
|
||||
t-att-action="'/quotation/form/' + access_token + '/save'
|
||||
if is_public else '/my/quotation/builder/save'"
|
||||
id="wcForm" class="wc-form">
|
||||
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
|
||||
<input type="hidden" name="assessment_id"
|
||||
t-att-value="assessment.id if assessment else 0"/>
|
||||
<input type="hidden" name="current_step" id="currentStep" value="1"/>
|
||||
<input type="hidden" name="action" id="formAction" value="save"/>
|
||||
<!-- Store access token for JS to detect public mode -->
|
||||
<t t-if="is_public">
|
||||
<input type="hidden" name="access_token" id="accessToken"
|
||||
t-att-value="access_token"/>
|
||||
</t>
|
||||
|
||||
<!-- Hidden fields for line data (populated by JS) -->
|
||||
<input type="hidden" name="line_product_ids" id="lineProductIds" value=""/>
|
||||
<input type="hidden" name="line_section_ids" id="lineSectionIds" value=""/>
|
||||
<input type="hidden" name="line_build_types" id="lineBuildTypes" value=""/>
|
||||
<input type="hidden" name="line_quantities" id="lineQuantities" value=""/>
|
||||
<input type="hidden" name="line_rationales" id="lineRationales" value=""/>
|
||||
|
||||
<!-- ===== DYNAMIC Step Content ===== -->
|
||||
<t t-foreach="flow_steps" t-as="fstep">
|
||||
<div t-attf-class="wc-step #{'d-none' if fstep_index > 0 else ''}"
|
||||
t-att-data-step="fstep_index + 1"
|
||||
t-att-data-step-type="fstep.step_type">
|
||||
<t t-if="fstep.step_type == 'client_info'"
|
||||
t-call="fusion_quotations.fq_step_client"/>
|
||||
<t t-if="fstep.step_type == 'measurements'"
|
||||
t-call="fusion_quotations.fq_step_measurements"/>
|
||||
<t t-if="fstep.step_type == 'product_select'"
|
||||
t-call="fusion_quotations.fq_step_product_select"/>
|
||||
<t t-if="fstep.step_type == 'options'"
|
||||
t-call="fusion_quotations.fq_step_options"/>
|
||||
<t t-if="fstep.step_type == 'review'"
|
||||
t-call="fusion_quotations.fq_step_review"/>
|
||||
<t t-if="fstep.step_type == 'custom'"
|
||||
t-call="fusion_quotations.fq_step_custom"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- ============================================ -->
|
||||
<!-- NAVIGATION BUTTONS -->
|
||||
<!-- ============================================ -->
|
||||
<div class="d-flex justify-content-between mt-4 pt-3 border-top">
|
||||
<button type="button" class="btn btn-outline-secondary" id="btnPrev"
|
||||
style="display:none;">
|
||||
<i class="fa fa-arrow-left me-1"/> Previous
|
||||
</button>
|
||||
<div class="ms-auto d-flex gap-2">
|
||||
<button type="submit" class="btn btn-outline-primary" id="btnSave"
|
||||
name="action" value="save">
|
||||
<i class="fa fa-save me-1"/> Save Draft
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" id="btnNext">
|
||||
Next <i class="fa fa-arrow-right ms-1"/>
|
||||
</button>
|
||||
<button type="submit" class="btn btn-success d-none" id="btnGenerate"
|
||||
name="action" value="generate">
|
||||
<i class="fa fa-magic me-1"/> Generate Quotation
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- SUB-TEMPLATE: Client & Equipment (step_type=client_info) -->
|
||||
<!-- ============================================================ -->
|
||||
<template id="fq_step_client" name="Step: Client & Equipment">
|
||||
<!--
|
||||
Config-driven client step. The step's fields_json controls which
|
||||
optional field groups are shown. Example fields_json:
|
||||
{
|
||||
"show_health_card": true,
|
||||
"show_dob": true,
|
||||
"show_adp_fields": true,
|
||||
"show_wheelchair_category": true,
|
||||
"show_powerchair_category": false
|
||||
}
|
||||
Steps with no fields_json (or empty {}) show only the base fields:
|
||||
name, contact, address, and equipment type selector.
|
||||
-->
|
||||
<t t-set="client_config" t-value="step_fields.get(fstep.id, {})"/>
|
||||
<h4 class="mb-3">Client & Equipment</h4>
|
||||
|
||||
<div class="row g-3">
|
||||
<!-- ── LEFT COLUMN: Client Info ── -->
|
||||
<div class="col-md-6">
|
||||
<div class="card wc-section-card h-100">
|
||||
<div class="card-header"><h5 class="mb-0"><i class="fa fa-user me-2"/>Client</h5></div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3 wc-search-container" style="position:relative;z-index:100;">
|
||||
<label class="form-label fw-bold">Search Existing Client</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="fa fa-search"/></span>
|
||||
<input type="text" class="form-control" id="clientSearch"
|
||||
placeholder="Type name, phone, or health card..."
|
||||
autocomplete="off"/>
|
||||
</div>
|
||||
<div id="clientSearchResults" class="list-group d-none"
|
||||
style="position:absolute;z-index:1060;width:100%;max-height:300px;overflow-y:auto;background:var(--bs-body-bg);box-shadow:0 8px 30px rgba(0,0,0,.18);border:1px solid var(--bs-border-color);border-top:none;border-radius:0 0 .5rem .5rem;"/>
|
||||
<input type="hidden" name="partner_id" id="partnerId"
|
||||
t-att-value="assessment.partner_id.id if assessment and assessment.partner_id else 0"/>
|
||||
</div>
|
||||
<div id="selectedClient" class="alert alert-info d-none mb-3">
|
||||
<strong id="selectedClientName"/>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary ms-2"
|
||||
id="clearClient">Change</button>
|
||||
</div>
|
||||
<div id="newClientFields">
|
||||
<div class="row g-2 mb-2">
|
||||
<div class="col">
|
||||
<input type="text" name="client_first_name" class="form-control"
|
||||
placeholder="First Name"
|
||||
t-att-value="assessment.client_first_name if assessment else ''"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="text" name="client_last_name" class="form-control"
|
||||
placeholder="Last Name"
|
||||
t-att-value="assessment.client_last_name if assessment else ''"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-2 mb-2">
|
||||
<div class="col">
|
||||
<input type="tel" name="client_phone" class="form-control"
|
||||
placeholder="Phone"
|
||||
t-att-value="assessment.client_phone if assessment else ''"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<input type="email" name="client_email" class="form-control"
|
||||
placeholder="Email"
|
||||
t-att-value="assessment.client_email if assessment else ''"/>
|
||||
</div>
|
||||
</div>
|
||||
<input type="text" name="client_street" class="form-control mb-2"
|
||||
placeholder="Street Address"
|
||||
t-att-value="assessment.client_street if assessment else ''"/>
|
||||
<div class="row g-2 mb-2">
|
||||
<div class="col">
|
||||
<input type="text" name="client_city" class="form-control"
|
||||
placeholder="City"
|
||||
t-att-value="assessment.client_city if assessment else ''"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<select name="client_state_id" class="form-select">
|
||||
<option value="">Province</option>
|
||||
<t t-foreach="provinces" t-as="prov">
|
||||
<option t-att-value="prov.id"
|
||||
t-att-selected="assessment and assessment.client_state_id.id == prov.id">
|
||||
<t t-out="prov.name"/>
|
||||
</option>
|
||||
</t>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<input type="text" name="client_zip" class="form-control"
|
||||
placeholder="Postal Code"
|
||||
t-att-value="assessment.client_zip if assessment else ''"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Health Card — controlled by step config -->
|
||||
<t t-if="client_config.get('show_health_card') or client_config.get('show_dob')">
|
||||
<div class="row g-2 mb-2">
|
||||
<t t-if="client_config.get('show_health_card')">
|
||||
<div class="col">
|
||||
<label class="form-label">Health Card</label>
|
||||
<input type="text" name="client_health_card" class="form-control"
|
||||
t-att-value="assessment.client_health_card if assessment else ''"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="client_config.get('show_dob')">
|
||||
<div class="col">
|
||||
<label class="form-label">Date of Birth</label>
|
||||
<input type="date" name="client_dob" class="form-control"
|
||||
t-att-value="assessment.client_dob if assessment else ''"/>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</div><!-- /card-body -->
|
||||
</div><!-- /card -->
|
||||
</div>
|
||||
|
||||
<!-- ── RIGHT COLUMN: Equipment Config ── -->
|
||||
<div class="col-md-6">
|
||||
<div class="card wc-section-card h-100">
|
||||
<div class="card-header"><h5 class="mb-0"><i class="fa fa-cogs me-2"/>Equipment</h5></div>
|
||||
<div class="card-body">
|
||||
<!-- Equipment type — show current type as label + hidden field -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-bold">Equipment Type</label>
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<t t-foreach="equipment_types" t-as="etype">
|
||||
<t t-if="etype.code == equipment_type">
|
||||
<span class="badge bg-primary fs-6 py-2 px-3">
|
||||
<i t-attf-class="fa #{etype.icon or 'fa-cog'} me-1"/> <t t-out="etype.name"/>
|
||||
</span>
|
||||
</t>
|
||||
</t>
|
||||
<input type="hidden" name="equipment_type" t-att-value="equipment_type"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Wheelchair category — controlled by step config -->
|
||||
<t t-if="client_config.get('show_wheelchair_category')">
|
||||
<div class="mb-3" id="wheelchairTypeGroup">
|
||||
<label class="form-label">Wheelchair Category</label>
|
||||
<select name="wheelchair_type" class="form-select">
|
||||
<option value="">Select...</option>
|
||||
<option value="type_1" t-att-selected="assessment and assessment.wheelchair_type == 'type_1'">Type 1 - Standard</option>
|
||||
<option value="type_2" t-att-selected="assessment and assessment.wheelchair_type == 'type_2'">Type 2 - Lightweight</option>
|
||||
<option value="type_3" t-att-selected="assessment and assessment.wheelchair_type == 'type_3'">Type 3 - Ultra Lightweight</option>
|
||||
<option value="type_4" t-att-selected="assessment and assessment.wheelchair_type == 'type_4'">Type 4 - Rigid Frame</option>
|
||||
<option value="type_5" t-att-selected="assessment and assessment.wheelchair_type == 'type_5'">Type 5 - Dynamic Tilt</option>
|
||||
</select>
|
||||
</div>
|
||||
</t>
|
||||
<!-- Powerchair category — controlled by step config -->
|
||||
<t t-if="client_config.get('show_powerchair_category')">
|
||||
<div class="mb-3" id="powerchairTypeGroup">
|
||||
<label class="form-label">Powerchair Category</label>
|
||||
<select name="powerchair_type" class="form-select">
|
||||
<option value="">Select...</option>
|
||||
<option value="type_1" t-att-selected="assessment and assessment.powerchair_type == 'type_1'">Power Base Type 1</option>
|
||||
<option value="type_2" t-att-selected="assessment and assessment.powerchair_type == 'type_2'">Power Base Type 2</option>
|
||||
<option value="type_3" t-att-selected="assessment and assessment.powerchair_type == 'type_3'">Power Base Type 3</option>
|
||||
</select>
|
||||
</div>
|
||||
</t>
|
||||
<!-- ADP fields (client type + reason) — controlled by step config -->
|
||||
<t t-if="client_config.get('show_adp_fields')">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Client Type</label>
|
||||
<select name="client_type" class="form-select">
|
||||
<option value="reg" t-att-selected="not assessment or assessment.client_type == 'reg'">REG - Regular ADP (75/25)</option>
|
||||
<option value="ods" t-att-selected="assessment and assessment.client_type == 'ods'">ODS - ODSP (100% ADP)</option>
|
||||
<option value="acs" t-att-selected="assessment and assessment.client_type == 'acs'">ACS - ACSD (100% ADP)</option>
|
||||
<option value="owp" t-att-selected="assessment and assessment.client_type == 'owp'">OWP - Ontario Works (100% ADP)</option>
|
||||
</select>
|
||||
</div>
|
||||
<input type="hidden" name="build_type" value="modular"/>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Reason for Application</label>
|
||||
<select name="reason_for_application" class="form-select">
|
||||
<option value="">Select...</option>
|
||||
<option value="first_access" t-att-selected="assessment and assessment.reason_for_application == 'first_access'">First Access</option>
|
||||
<option value="additions" t-att-selected="assessment and assessment.reason_for_application == 'additions'">Additions</option>
|
||||
<option value="modifications" t-att-selected="assessment and assessment.reason_for_application == 'modifications'">Modifications</option>
|
||||
<option value="replacements" t-att-selected="assessment and assessment.reason_for_application == 'replacements'">Replacements</option>
|
||||
</select>
|
||||
</div>
|
||||
</t>
|
||||
</div><!-- /card-body -->
|
||||
</div><!-- /card -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- SUB-TEMPLATE: Measurements (step_type=measurements) -->
|
||||
<!-- ============================================================ -->
|
||||
<template id="fq_step_measurements" name="Step: Measurements">
|
||||
<h4 class="mb-3"><t t-out="fstep.name"/></h4>
|
||||
<t t-if="fstep.help_text">
|
||||
<p class="text-muted"><t t-out="fstep.help_text"/></p>
|
||||
</t>
|
||||
<t t-if="not fstep.help_text">
|
||||
<p class="text-muted">All measurements are required for the ADP application.</p>
|
||||
</t>
|
||||
|
||||
<!-- Dynamic fields from fields_json -->
|
||||
<t t-set="mfields" t-value="step_fields.get(fstep.id, [])"/>
|
||||
<t t-if="mfields">
|
||||
<div class="row g-3">
|
||||
<t t-foreach="mfields" t-as="mf">
|
||||
<div class="col-md-6">
|
||||
<div class="wc-measurement-field p-3 border rounded">
|
||||
<label class="form-label fw-bold" t-out="mf.get('label', '')"/>
|
||||
<t t-if="mf.get('type') == 'selection'">
|
||||
<select t-att-name="mf.get('name')" class="form-select"
|
||||
t-att-required="mf.get('required')">
|
||||
<option value="">Select...</option>
|
||||
<t t-foreach="mf.get('options', [])" t-as="opt">
|
||||
<option t-att-value="opt[0]"
|
||||
t-att-selected="field_values.get(mf.get('name')) == str(opt[0])"
|
||||
t-out="opt[1]"/>
|
||||
</t>
|
||||
</select>
|
||||
</t>
|
||||
<t t-if="mf.get('type') != 'selection'">
|
||||
<div class="d-flex gap-2 align-items-center">
|
||||
<input t-att-type="'number' if mf.get('type') in ('float', 'integer') else 'text'"
|
||||
t-att-step="mf.get('step', '0.25') if mf.get('type') == 'float' else ('1' if mf.get('type') == 'integer' else '')"
|
||||
t-att-name="mf.get('name')"
|
||||
class="form-control wc-measurement-input"
|
||||
t-att-data-upcharge-field="mf.get('name')"
|
||||
t-att-value="field_values.get(mf.get('name'), '')"
|
||||
t-att-required="mf.get('required')"/>
|
||||
<t t-if="mf.get('units')">
|
||||
<select t-att-name="mf.get('unit_field', mf.get('name') + '_unit')"
|
||||
class="form-select wc-unit-select" style="width:100px;">
|
||||
<t t-foreach="mf.get('units', [])" t-as="unit">
|
||||
<option t-att-value="unit"
|
||||
t-att-selected="field_values.get(mf.get('unit_field', mf.get('name') + '_unit')) == unit"
|
||||
t-out="unit"/>
|
||||
</t>
|
||||
</select>
|
||||
</t>
|
||||
<t t-if="mf.get('unit') and not mf.get('units')">
|
||||
<span class="input-group-text" t-out="mf.get('unit')"/>
|
||||
</t>
|
||||
<span class="wc-upcharge-badge d-none"/>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- Fallback: hardcoded wheelchair measurement fields -->
|
||||
<t t-if="not mfields">
|
||||
<div class="row g-3">
|
||||
<t t-foreach="[
|
||||
('seat_width', 'Seat Width', 'seat_width_unit', 'inches'),
|
||||
('seat_depth', 'Seat Depth', 'seat_depth_unit', 'inches'),
|
||||
('finished_seat_to_floor_height', 'Finished Seat to Floor Height', 'seat_to_floor_unit', 'inches'),
|
||||
('back_cane_height', 'Back Cane Height', 'cane_height_unit', 'inches'),
|
||||
('finished_back_height', 'Finished Back Height', 'back_height_unit', 'inches'),
|
||||
('finished_leg_rest_length', 'Finished Leg Rest Length', 'leg_rest_unit', 'inches'),
|
||||
]" t-as="mfield">
|
||||
<div class="col-md-6">
|
||||
<div class="wc-measurement-field p-3 border rounded">
|
||||
<label class="form-label fw-bold" t-out="mfield[1]"/>
|
||||
<div class="d-flex gap-2 align-items-center">
|
||||
<input type="number" step="0.25" t-att-name="mfield[0]"
|
||||
class="form-control wc-measurement-input"
|
||||
t-att-data-upcharge-field="mfield[0]"
|
||||
t-att-value="field_values.get(mfield[0], '')"/>
|
||||
<select t-att-name="mfield[2]" class="form-select wc-unit-select" style="width:100px;">
|
||||
<option value="cm"
|
||||
t-att-selected="field_values.get(mfield[2]) == 'cm'">cm</option>
|
||||
<option value="inches"
|
||||
t-att-selected="not field_values.get(mfield[2]) or field_values.get(mfield[2]) == 'inches'">inches</option>
|
||||
</select>
|
||||
<span class="wc-upcharge-badge d-none"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<!-- Client Weight -->
|
||||
<div class="col-md-6">
|
||||
<div class="wc-measurement-field p-3 border rounded">
|
||||
<label class="form-label fw-bold">Client Weight</label>
|
||||
<div class="d-flex gap-2 align-items-center">
|
||||
<input type="number" step="1" name="client_weight"
|
||||
class="form-control wc-measurement-input"
|
||||
data-upcharge-field="client_weight"
|
||||
t-att-value="assessment and assessment.client_weight or ''"/>
|
||||
<select name="client_weight_unit" class="form-select wc-unit-select" style="width:100px;">
|
||||
<option value="kg"
|
||||
t-att-selected="assessment and assessment.client_weight_unit == 'kg'">kg</option>
|
||||
<option value="lbs"
|
||||
t-att-selected="not assessment or assessment.client_weight_unit == 'lbs'">lbs</option>
|
||||
</select>
|
||||
<span class="wc-upcharge-badge d-none"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- Upcharges Preview -->
|
||||
<div id="upchargePreview" class="mt-3 d-none">
|
||||
<h5>Auto-Applied Upcharges</h5>
|
||||
<div id="upchargeList"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- SUB-TEMPLATE: Product Selection (step_type=product_select) -->
|
||||
<!-- ============================================================ -->
|
||||
<template id="fq_step_product_select" name="Step: Product Selection">
|
||||
<h4 class="mb-3"><t t-out="fstep.name"/></h4>
|
||||
<t t-if="fstep.help_text">
|
||||
<p class="text-muted"><t t-out="fstep.help_text"/></p>
|
||||
</t>
|
||||
|
||||
<div class="mb-3 wc-search-container" style="position:relative;z-index:100;">
|
||||
<label class="form-label fw-bold">Search Product</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text"><i class="fa fa-search"/></span>
|
||||
<input type="text" class="form-control wc-product-search"
|
||||
id="frameSearch" t-att-data-section="fstep.section_code or 'frame'"
|
||||
placeholder="Type product name, model, or ADP code..."
|
||||
autocomplete="off"/>
|
||||
</div>
|
||||
<div id="frameSearchResults" class="list-group d-none"
|
||||
style="position:absolute;z-index:1060;width:100%;max-height:300px;overflow-y:auto;background:var(--bs-body-bg);box-shadow:0 8px 30px rgba(0,0,0,.18);border:1px solid var(--bs-border-color);border-top:none;border-radius:0 0 .5rem .5rem;"/>
|
||||
<input type="hidden" name="frame_product_tmpl_id" id="frameProductTmplId"
|
||||
t-att-value="assessment.frame_product_tmpl_id.id if assessment and assessment.frame_product_tmpl_id else ''"/>
|
||||
<input type="hidden" name="frame_product_id" id="frameProductId"
|
||||
t-att-value="assessment.frame_product_id.id if assessment and assessment.frame_product_id else ''"/>
|
||||
</div>
|
||||
<div id="selectedFrame" class="d-none" style="position:relative;z-index:1;">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-start">
|
||||
<div>
|
||||
<h5 class="card-title mb-1" id="selectedFrameName"/>
|
||||
<div class="d-flex gap-4 text-muted small">
|
||||
<span>ADP Code: <strong id="selectedFrameCode"/></span>
|
||||
<span>ADP Price: $<strong id="selectedFramePrice"/></span>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary"
|
||||
id="clearFrame"><i class="fa fa-times me-1"/>Change</button>
|
||||
</div>
|
||||
<!-- Frame Configurator (shown when template has multiple variants) -->
|
||||
<div id="frameConfigurator" class="wc-configurator-panel d-none">
|
||||
<div class="wc-config-title">
|
||||
<i class="fa fa-sliders me-2"/>Configure Options
|
||||
</div>
|
||||
<div id="frameAttributeSelectors" class="row g-2"/>
|
||||
<div id="frameVariantInfo" class="d-none">
|
||||
<span class="wc-variant-resolved">
|
||||
<i class="fa fa-check-circle"/>
|
||||
<span>Resolved: <strong id="frameVariantName"/></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Standard options for this section -->
|
||||
<div id="standardFrameOptions" class="mt-3" style="position:relative;z-index:1;">
|
||||
<h5>Standard Options</h5>
|
||||
<div id="frameOptionsGrid" class="row g-2"/>
|
||||
</div>
|
||||
|
||||
<div class="mt-3" style="position:relative;z-index:1;">
|
||||
<label class="form-label">Notes</label>
|
||||
<textarea name="frame_notes" class="form-control" rows="2"
|
||||
t-out="assessment.frame_notes if assessment else ''"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- SUB-TEMPLATE: Options & Accessories (step_type=options) -->
|
||||
<!-- ============================================================ -->
|
||||
<template id="fq_step_options" name="Step: Options">
|
||||
<h4 class="mb-3"><t t-out="fstep.name"/></h4>
|
||||
<t t-if="fstep.help_text">
|
||||
<p class="text-muted"><t t-out="fstep.help_text"/></p>
|
||||
</t>
|
||||
|
||||
<!-- Seating/Positioning sections with accordion -->
|
||||
<t t-if="fstep.section_code == 'seating'">
|
||||
<p class="text-muted">Select seating and positioning devices. Choose Modular or Custom Fabricated for each.</p>
|
||||
<div class="accordion" id="seatingAccordion">
|
||||
<t t-foreach="sections" t-as="section">
|
||||
<t t-if="section.has_build_type and section.code != 'accessories'">
|
||||
<div class="accordion-item wc-equipment-section"
|
||||
t-att-data-equipment-type="section.equipment_type"
|
||||
t-att-style="'' if (section.equipment_type in ('both', equipment_type) or (section.equipment_type == 'wheelchair' and equipment_type in ('manual_wheelchair', 'power_wheelchair'))) else 'display:none;'">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button collapsed" type="button"
|
||||
data-bs-toggle="collapse"
|
||||
t-attf-data-bs-target="#collapse_#{section.code}">
|
||||
<i t-attf-class="fa #{section.icon or 'fa-cube'} me-2"/>
|
||||
<t t-out="section.name"/>
|
||||
</button>
|
||||
</h2>
|
||||
<div t-attf-id="collapse_#{section.code}" class="accordion-collapse collapse"
|
||||
data-bs-parent="#seatingAccordion">
|
||||
<div class="accordion-body">
|
||||
<!-- Build Type Toggle -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-bold">Build Type</label>
|
||||
<div class="d-flex gap-2">
|
||||
<label class="btn btn-sm btn-outline-secondary wc-radio-btn">
|
||||
<input type="radio" t-attf-name="section_build_#{section.code}"
|
||||
value="modular" checked="checked"
|
||||
class="wc-section-build-type"
|
||||
t-att-data-section="section.code"/>
|
||||
Modular
|
||||
</label>
|
||||
<label class="btn btn-sm btn-outline-secondary wc-radio-btn">
|
||||
<input type="radio" t-attf-name="section_build_#{section.code}"
|
||||
value="custom_fabricated"
|
||||
class="wc-section-build-type"
|
||||
t-att-data-section="section.code"/>
|
||||
Custom Fabricated
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Measurement fields if section has them -->
|
||||
<t t-if="section.has_width or section.has_depth or section.has_height">
|
||||
<div class="row g-2 mb-3">
|
||||
<t t-if="section.has_width">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" t-out="section.width_label"/>
|
||||
<input type="number" step="0.25" class="form-control"
|
||||
t-attf-name="section_width_#{section.code}"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="section.has_depth">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" t-out="section.depth_label"/>
|
||||
<input type="number" step="0.25" class="form-control"
|
||||
t-attf-name="section_depth_#{section.code}"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="section.has_height">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" t-out="section.height_label"/>
|
||||
<input type="number" step="0.25" class="form-control"
|
||||
t-attf-name="section_height_#{section.code}"/>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- Product options for this section -->
|
||||
<div class="wc-section-options" t-att-data-section="section.code"
|
||||
t-att-data-section-id="section.id">
|
||||
<div class="wc-options-grid row g-2"/>
|
||||
<!-- Custom search -->
|
||||
<div class="mt-2 wc-search-container">
|
||||
<input type="text" class="form-control form-control-sm wc-product-search"
|
||||
t-att-data-section="section.code"
|
||||
placeholder="Search for product..."
|
||||
autocomplete="off"/>
|
||||
<div class="wc-search-results list-group d-none"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sub-sections -->
|
||||
<t t-foreach="section.child_ids" t-as="child">
|
||||
<div class="mt-3 ps-3 border-start">
|
||||
<h6><t t-out="child.name"/></h6>
|
||||
<div class="wc-section-options" t-att-data-section="child.code"
|
||||
t-att-data-section-id="child.id">
|
||||
<div class="wc-options-grid row g-2"/>
|
||||
<div class="mt-1 wc-search-container">
|
||||
<input type="text" class="form-control form-control-sm wc-product-search"
|
||||
t-att-data-section="child.code"
|
||||
placeholder="Search..."
|
||||
autocomplete="off"/>
|
||||
<div class="wc-search-results list-group d-none"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- ADP Options & Accessories (flat checkbox grids) -->
|
||||
<t t-if="fstep.section_code != 'seating'">
|
||||
<p class="text-muted">
|
||||
Select applicable options. Items marked with * require clinical rationale.
|
||||
</p>
|
||||
<div id="adpOptionsGrid" class="row g-2">
|
||||
<!-- Populated by JS from section options -->
|
||||
</div>
|
||||
|
||||
<h4 class="mt-4 mb-3">Accessories</h4>
|
||||
<div id="accessoriesGrid" class="row g-2">
|
||||
<!-- Populated by JS -->
|
||||
</div>
|
||||
<div class="mt-2 wc-search-container">
|
||||
<input type="text" class="form-control wc-product-search"
|
||||
data-section="accessories"
|
||||
placeholder="Search for accessories..."
|
||||
autocomplete="off"/>
|
||||
<div class="wc-search-results list-group d-none"/>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- SUB-TEMPLATE: Review & Generate (step_type=review) -->
|
||||
<!-- ============================================================ -->
|
||||
<template id="fq_step_review" name="Step: Review & Generate">
|
||||
<h4 class="mb-3">Review & Generate Quotation</h4>
|
||||
|
||||
<!-- Selected Items Summary -->
|
||||
<div id="reviewSummary">
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Section</th>
|
||||
<th>Product</th>
|
||||
<th>ADP Code</th>
|
||||
<th>Build</th>
|
||||
<th class="text-end">Qty</th>
|
||||
<th class="text-end">Price</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="reviewTableBody"/>
|
||||
<tfoot>
|
||||
<tr class="fw-bold">
|
||||
<td colspan="5" class="text-end">Estimated Total:</td>
|
||||
<td class="text-end" id="reviewTotal">$0.00</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Upcharges Summary -->
|
||||
<div id="reviewUpcharges" class="d-none">
|
||||
<h5>Auto-Applied Upcharges</h5>
|
||||
<div id="reviewUpchargeList"/>
|
||||
</div>
|
||||
|
||||
<!-- Measurements Summary -->
|
||||
<div class="card mt-3">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Measurements Summary</h5>
|
||||
</div>
|
||||
<div class="card-body" id="reviewMeasurements"/>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<label class="form-label">Additional Notes</label>
|
||||
<textarea name="notes" class="form-control" rows="3"
|
||||
t-out="assessment.notes if assessment else ''"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- SUB-TEMPLATE: Custom Fields (step_type=custom) -->
|
||||
<!-- ============================================================ -->
|
||||
<template id="fq_step_custom" name="Step: Custom Fields">
|
||||
<h4 class="mb-3"><t t-out="fstep.name"/></h4>
|
||||
<t t-if="fstep.help_text">
|
||||
<p class="text-muted"><t t-out="fstep.help_text"/></p>
|
||||
</t>
|
||||
|
||||
<t t-set="cfields" t-value="step_fields.get(fstep.id, [])"/>
|
||||
<t t-if="cfields">
|
||||
<div class="row g-3">
|
||||
<t t-foreach="cfields" t-as="cf">
|
||||
<div class="col-md-6">
|
||||
<div class="p-3 border rounded">
|
||||
<label class="form-label fw-bold" t-out="cf.get('label', '')"/>
|
||||
<t t-if="cf.get('type') == 'selection'">
|
||||
<select t-att-name="cf.get('name')" class="form-select"
|
||||
t-att-required="cf.get('required')">
|
||||
<option value="">Select...</option>
|
||||
<t t-foreach="cf.get('options', [])" t-as="opt">
|
||||
<option t-att-value="opt[0]"
|
||||
t-att-selected="field_values.get(cf.get('name')) == str(opt[0])"
|
||||
t-out="opt[1]"/>
|
||||
</t>
|
||||
</select>
|
||||
</t>
|
||||
<t t-if="cf.get('type') == 'text'">
|
||||
<textarea t-att-name="cf.get('name')" class="form-control" rows="3"
|
||||
t-att-required="cf.get('required')"
|
||||
t-out="field_values.get(cf.get('name'), '')"/>
|
||||
</t>
|
||||
<t t-if="cf.get('type') == 'boolean'">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input"
|
||||
t-att-name="cf.get('name')"
|
||||
t-att-checked="field_values.get(cf.get('name'))"/>
|
||||
<label class="form-check-label" t-out="cf.get('label', '')"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="cf.get('type') in ('float', 'integer')">
|
||||
<div class="input-group">
|
||||
<input t-att-type="'number'"
|
||||
t-att-step="'0.01' if cf.get('type') == 'float' else '1'"
|
||||
t-att-name="cf.get('name')"
|
||||
class="form-control"
|
||||
t-att-value="field_values.get(cf.get('name'), '')"
|
||||
t-att-required="cf.get('required')"/>
|
||||
<t t-if="cf.get('unit')">
|
||||
<span class="input-group-text" t-out="cf.get('unit')"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="cf.get('type') not in ('selection', 'text', 'boolean', 'float', 'integer')">
|
||||
<input type="text" t-att-name="cf.get('name')" class="form-control"
|
||||
t-att-value="field_values.get(cf.get('name'), '')"
|
||||
t-att-required="cf.get('required')"/>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="not cfields">
|
||||
<div class="alert alert-info">
|
||||
No custom fields configured for this step.
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- EMBEDDABLE FORM (no portal chrome — for iframe embedding) -->
|
||||
<!-- ============================================================ -->
|
||||
<template id="portal_quotation_form_embed" name="Equipment Assessment Form (Embed)">
|
||||
<t t-call="web.frontend_layout">
|
||||
<t t-set="no_header" t-value="True"/>
|
||||
<t t-set="no_footer" t-value="True"/>
|
||||
|
||||
<div class="container-fluid py-3 wc-assessment-form" id="wcAssessmentForm">
|
||||
|
||||
<!-- Success/Error Messages -->
|
||||
<t t-if="request.params.get('success') == 'saved'">
|
||||
<div class="alert alert-success alert-dismissible fade show">
|
||||
Assessment saved successfully.
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="request.params.get('success') == 'quotation_generated'">
|
||||
<div class="alert alert-success alert-dismissible fade show">
|
||||
<i class="fa fa-check-circle me-1"/> Quotation generated!
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="request.params.get('error')">
|
||||
<div class="alert alert-danger alert-dismissible fade show">
|
||||
<t t-out="request.params.get('error')"/>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- Dynamic Step Indicator -->
|
||||
<div class="wc-steps mb-4">
|
||||
<div class="d-flex justify-content-between">
|
||||
<t t-foreach="flow_steps" t-as="fstep">
|
||||
<div t-attf-class="wc-step-indicator text-center flex-fill #{'active' if fstep_index == 0 else ''}"
|
||||
t-att-data-step="fstep_index + 1">
|
||||
<div class="wc-step-number rounded-circle d-inline-flex align-items-center justify-content-center">
|
||||
<t t-out="fstep_index + 1"/>
|
||||
</div>
|
||||
<div class="wc-step-label small mt-1">
|
||||
<t t-out="fstep.name"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="post"
|
||||
t-att-action="'/quotation/form/' + access_token + '/save'"
|
||||
id="wcForm" class="wc-form">
|
||||
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
|
||||
<input type="hidden" name="assessment_id"
|
||||
t-att-value="assessment.id if assessment else 0"/>
|
||||
<input type="hidden" name="current_step" id="currentStep" value="1"/>
|
||||
<input type="hidden" name="action" id="formAction" value="save"/>
|
||||
<input type="hidden" name="access_token" id="accessToken"
|
||||
t-att-value="access_token"/>
|
||||
|
||||
<!-- Hidden fields for line data -->
|
||||
<input type="hidden" name="line_product_ids" id="lineProductIds" value=""/>
|
||||
<input type="hidden" name="line_section_ids" id="lineSectionIds" value=""/>
|
||||
<input type="hidden" name="line_build_types" id="lineBuildTypes" value=""/>
|
||||
<input type="hidden" name="line_quantities" id="lineQuantities" value=""/>
|
||||
<input type="hidden" name="line_rationales" id="lineRationales" value=""/>
|
||||
|
||||
<p class="text-muted text-center mb-3">
|
||||
<i class="fa fa-cogs me-1"/>
|
||||
Equipment Assessment Form
|
||||
</p>
|
||||
|
||||
<!-- NOTE: The embed template reuses the same step structure.
|
||||
For a full implementation, you would include the same step
|
||||
content from the main template. For now we render a minimal
|
||||
placeholder that the JS widget will populate. -->
|
||||
<div class="text-center py-5 text-muted">
|
||||
<i class="fa fa-spinner fa-spin fa-2x mb-3 d-block"/>
|
||||
Loading assessment form...
|
||||
</div>
|
||||
|
||||
<!-- Navigation Buttons -->
|
||||
<div class="wc-form-navigation mt-4 border-top pt-3">
|
||||
<div class="d-flex justify-content-between">
|
||||
<button type="submit" class="btn btn-outline-secondary" id="btnSaveDraft">
|
||||
<i class="fa fa-save me-1"/> Save Draft
|
||||
</button>
|
||||
<div>
|
||||
<button type="button" class="btn btn-secondary d-none" id="btnPrev">
|
||||
<i class="fa fa-arrow-left me-1"/> Previous
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" id="btnNext">
|
||||
Next <i class="fa fa-arrow-right ms-1"/>
|
||||
</button>
|
||||
<button type="submit" class="btn btn-success d-none" id="btnGenerate"
|
||||
name="action" value="generate">
|
||||
<i class="fa fa-magic me-1"/> Generate Quotation
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- PUBLIC FORM — INVALID TOKEN PAGE -->
|
||||
<!-- ============================================================ -->
|
||||
<template id="public_form_invalid" name="Invalid Assessment Link">
|
||||
<t t-call="web.frontend_layout">
|
||||
<div class="container py-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6 text-center">
|
||||
<i class="fa fa-chain-broken fa-4x text-muted mb-3 d-block"/>
|
||||
<h3 class="mb-3">This link is no longer valid</h3>
|
||||
<t t-if="status == 'not_found'">
|
||||
<p class="text-muted">
|
||||
The assessment form you're trying to access doesn't exist
|
||||
or the link has expired.
|
||||
</p>
|
||||
</t>
|
||||
<t t-if="status == 'cancelled'">
|
||||
<p class="text-muted">
|
||||
This assessment has been cancelled and is no longer
|
||||
available for editing.
|
||||
</p>
|
||||
</t>
|
||||
<a href="/" class="btn btn-primary mt-3">
|
||||
<i class="fa fa-home me-1"/> Go Home
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
496
fusion_quotations/views/wc_assessment_views.xml
Normal file
496
fusion_quotations/views/wc_assessment_views.xml
Normal file
@@ -0,0 +1,496 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- ASSESSMENT TREE VIEW -->
|
||||
<!-- ============================================================ -->
|
||||
<record id="view_wc_assessment_tree" model="ir.ui.view">
|
||||
<field name="name">fusion.wc.assessment.tree</field>
|
||||
<field name="model">fusion.wc.assessment</field>
|
||||
<field name="arch" type="xml">
|
||||
<list decoration-info="state == 'draft'"
|
||||
decoration-warning="state == 'review'"
|
||||
decoration-success="state == 'quoted'"
|
||||
decoration-muted="state == 'cancelled'">
|
||||
<field name="reference"/>
|
||||
<field name="client_name"/>
|
||||
<field name="equipment_type"/>
|
||||
<field name="wheelchair_type"/>
|
||||
<field name="client_type"/>
|
||||
<field name="build_type"/>
|
||||
<field name="sales_rep_id"/>
|
||||
<field name="assessment_date"/>
|
||||
<field name="total_estimate" sum="Total"/>
|
||||
<field name="state" widget="badge"
|
||||
decoration-info="state == 'draft'"
|
||||
decoration-warning="state == 'review'"
|
||||
decoration-success="state == 'quoted'"
|
||||
decoration-danger="state == 'cancelled'"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- ASSESSMENT KANBAN VIEW -->
|
||||
<!-- ============================================================ -->
|
||||
<record id="view_wc_assessment_kanban" model="ir.ui.view">
|
||||
<field name="name">fusion.wc.assessment.kanban</field>
|
||||
<field name="model">fusion.wc.assessment</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="state" class="o_kanban_small_column">
|
||||
<field name="state"/>
|
||||
<field name="reference"/>
|
||||
<field name="client_name"/>
|
||||
<field name="equipment_type"/>
|
||||
<field name="sales_rep_id"/>
|
||||
<field name="total_estimate"/>
|
||||
<templates>
|
||||
<t t-name="card">
|
||||
<div class="oe_kanban_content">
|
||||
<strong><field name="reference"/></strong>
|
||||
<div><field name="client_name"/></div>
|
||||
<div class="text-muted">
|
||||
<field name="equipment_type"/>
|
||||
</div>
|
||||
<div>
|
||||
<field name="sales_rep_id" widget="many2one_avatar_user"/>
|
||||
<span class="float-end fw-bold">
|
||||
$<field name="total_estimate"/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- ASSESSMENT SEARCH VIEW -->
|
||||
<!-- ============================================================ -->
|
||||
<record id="view_wc_assessment_search" model="ir.ui.view">
|
||||
<field name="name">fusion.wc.assessment.search</field>
|
||||
<field name="model">fusion.wc.assessment</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Wheelchair Assessments">
|
||||
<field name="reference"/>
|
||||
<field name="client_name"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="sales_rep_id"/>
|
||||
<field name="authorizer_id"/>
|
||||
<separator/>
|
||||
<filter name="draft" string="In Progress"
|
||||
domain="[('state', '=', 'draft')]"/>
|
||||
<filter name="review" string="Ready for Review"
|
||||
domain="[('state', '=', 'review')]"/>
|
||||
<filter name="quoted" string="Quoted"
|
||||
domain="[('state', '=', 'quoted')]"/>
|
||||
<separator/>
|
||||
<filter name="manual" string="Manual Wheelchair"
|
||||
domain="[('equipment_type', '=', 'manual_wheelchair')]"/>
|
||||
<filter name="power" string="Power Wheelchair / Scooter"
|
||||
domain="[('equipment_type', '=', 'power_wheelchair')]"/>
|
||||
<filter name="walker" string="Walker / Ambulation Aid"
|
||||
domain="[('equipment_type', '=', 'walker')]"/>
|
||||
<separator/>
|
||||
<filter name="my_assessments" string="My Assessments"
|
||||
domain="[('sales_rep_id', '=', uid)]"/>
|
||||
<separator/>
|
||||
<filter name="group_state" string="Status"
|
||||
context="{'group_by': 'state'}"/>
|
||||
<filter name="group_equipment" string="Equipment Type"
|
||||
context="{'group_by': 'equipment_type'}"/>
|
||||
<filter name="group_rep" string="Sales Rep"
|
||||
context="{'group_by': 'sales_rep_id'}"/>
|
||||
<filter name="group_date" string="Date"
|
||||
context="{'group_by': 'assessment_date:month'}"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- ASSESSMENT FORM VIEW -->
|
||||
<!-- ============================================================ -->
|
||||
<record id="view_wc_assessment_form" model="ir.ui.view">
|
||||
<field name="name">fusion.wc.assessment.form</field>
|
||||
<field name="model">fusion.wc.assessment</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Wheelchair Assessment">
|
||||
<header>
|
||||
<button name="action_generate_quotation" string="Generate Quotation"
|
||||
type="object" class="btn-primary"
|
||||
invisible="state not in ('draft', 'review')"
|
||||
confirm="Generate a quotation from this assessment?"/>
|
||||
<button name="action_mark_review" string="Mark Ready"
|
||||
type="object" class="btn-secondary"
|
||||
invisible="state != 'draft'"/>
|
||||
<button name="action_cancel" string="Cancel"
|
||||
type="object" class="btn-secondary"
|
||||
invisible="state in ('quoted', 'cancelled')"/>
|
||||
<button name="action_reset_draft" string="Reset to Draft"
|
||||
type="object" class="btn-secondary"
|
||||
invisible="state != 'cancelled'"/>
|
||||
<field name="state" widget="statusbar"
|
||||
statusbar_visible="draft,review,quoted"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button name="action_view_quotation" type="object"
|
||||
class="oe_stat_button" icon="fa-file-text-o"
|
||||
invisible="not sale_order_id">
|
||||
<span class="o_stat_text">Quotation</span>
|
||||
</button>
|
||||
<button name="action_open_portal_form" type="object"
|
||||
class="oe_stat_button" icon="fa-external-link">
|
||||
<span class="o_stat_text">Open Form</span>
|
||||
</button>
|
||||
<button name="action_generate_share_link" type="object"
|
||||
class="oe_stat_button" icon="fa-share-alt">
|
||||
<span class="o_stat_text">Share Link</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="reference" readonly="1"/>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<notebook>
|
||||
<!-- TAB 1: CLIENT & EQUIPMENT -->
|
||||
<page string="Client & Equipment" name="client">
|
||||
<group>
|
||||
<group string="Client">
|
||||
<field name="partner_id"
|
||||
invisible="create_new_partner"/>
|
||||
<field name="create_new_partner"/>
|
||||
<field name="client_first_name"
|
||||
invisible="not create_new_partner"/>
|
||||
<field name="client_last_name"
|
||||
invisible="not create_new_partner"/>
|
||||
<field name="client_phone"
|
||||
invisible="not create_new_partner"/>
|
||||
<field name="client_email"
|
||||
invisible="not create_new_partner"/>
|
||||
<field name="client_health_card"/>
|
||||
<field name="client_dob"/>
|
||||
</group>
|
||||
<group string="Equipment">
|
||||
<field name="equipment_type"/>
|
||||
<field name="wheelchair_type"
|
||||
invisible="equipment_type != 'manual_wheelchair'"/>
|
||||
<field name="powerchair_type"
|
||||
invisible="equipment_type != 'power_wheelchair'"/>
|
||||
<field name="walker_type"
|
||||
invisible="equipment_type != 'walker'"/>
|
||||
<field name="client_type"/>
|
||||
<field name="build_type"
|
||||
invisible="equipment_type == 'walker'"/>
|
||||
<field name="reason_for_application"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group string="Assessment">
|
||||
<field name="sales_rep_id"/>
|
||||
<field name="authorizer_id"/>
|
||||
<field name="assessment_date"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
|
||||
<!-- TAB 2: ADP MEASUREMENTS -->
|
||||
<page string="Measurements" name="measurements">
|
||||
|
||||
<!-- MANUAL WHEELCHAIR MEASUREMENTS (Section 2b) -->
|
||||
<group string="Manual Wheelchair Prescription Details"
|
||||
invisible="equipment_type != 'manual_wheelchair'">
|
||||
<group>
|
||||
<label for="seat_width"/>
|
||||
<div class="d-flex gap-2">
|
||||
<field name="seat_width" class="oe_inline"/>
|
||||
<field name="seat_width_unit" class="oe_inline"/>
|
||||
</div>
|
||||
<label for="seat_depth"/>
|
||||
<div class="d-flex gap-2">
|
||||
<field name="seat_depth" class="oe_inline"/>
|
||||
<field name="seat_depth_unit" class="oe_inline"/>
|
||||
</div>
|
||||
<label for="finished_seat_to_floor_height"/>
|
||||
<div class="d-flex gap-2">
|
||||
<field name="finished_seat_to_floor_height" class="oe_inline"/>
|
||||
<field name="seat_to_floor_unit" class="oe_inline"/>
|
||||
</div>
|
||||
<label for="back_cane_height"/>
|
||||
<div class="d-flex gap-2">
|
||||
<field name="back_cane_height" class="oe_inline"/>
|
||||
<field name="cane_height_unit" class="oe_inline"/>
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<label for="finished_back_height"/>
|
||||
<div class="d-flex gap-2">
|
||||
<field name="finished_back_height" class="oe_inline"/>
|
||||
<field name="back_height_unit" class="oe_inline"/>
|
||||
</div>
|
||||
<label for="finished_leg_rest_length"/>
|
||||
<div class="d-flex gap-2">
|
||||
<field name="finished_leg_rest_length" class="oe_inline"/>
|
||||
<field name="leg_rest_unit" class="oe_inline"/>
|
||||
</div>
|
||||
<label for="client_weight"/>
|
||||
<div class="d-flex gap-2">
|
||||
<field name="client_weight" class="oe_inline"/>
|
||||
<field name="client_weight_unit" class="oe_inline"/>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- WALKER / ROLLATOR MEASUREMENTS (Section 2a) -->
|
||||
<group string="Wheeled Walker Prescription Details"
|
||||
invisible="equipment_type != 'walker'">
|
||||
<group>
|
||||
<label for="walker_seat_height"/>
|
||||
<div class="d-flex gap-2">
|
||||
<field name="walker_seat_height" class="oe_inline"/>
|
||||
<field name="walker_seat_height_unit" class="oe_inline"/>
|
||||
</div>
|
||||
<label for="push_handle_height"/>
|
||||
<div class="d-flex gap-2">
|
||||
<field name="push_handle_height" class="oe_inline"/>
|
||||
<field name="push_handle_height_unit" class="oe_inline"/>
|
||||
</div>
|
||||
<field name="hand_grips"/>
|
||||
<field name="forearm_attachments"/>
|
||||
<label for="width_between_push_handles"/>
|
||||
<div class="d-flex gap-2">
|
||||
<field name="width_between_push_handles" class="oe_inline"/>
|
||||
<field name="push_handle_width_unit" class="oe_inline"/>
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<label for="client_weight"/>
|
||||
<div class="d-flex gap-2">
|
||||
<field name="client_weight" class="oe_inline"/>
|
||||
<field name="client_weight_unit" class="oe_inline"/>
|
||||
</div>
|
||||
<field name="walker_brakes"/>
|
||||
<field name="walker_brake_type"/>
|
||||
<field name="walker_num_wheels"/>
|
||||
<field name="walker_wheel_size"/>
|
||||
<field name="walker_back_support"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="Walker ADP Funded Options"
|
||||
invisible="equipment_type != 'walker'">
|
||||
<group>
|
||||
<field name="walker_adolescent_wheeled_walker"/>
|
||||
<field name="walker_adolescent_walking_frame"/>
|
||||
<field name="walker_adolescent_standing_frame"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- POWER BASE / SCOOTER MEASUREMENTS (Section 2c) -->
|
||||
<group string="Power Device Prescription Details"
|
||||
invisible="equipment_type != 'power_wheelchair'">
|
||||
<group>
|
||||
<label for="seat_width"/>
|
||||
<div class="d-flex gap-2">
|
||||
<field name="seat_width" class="oe_inline"/>
|
||||
<field name="seat_width_unit" class="oe_inline"/>
|
||||
</div>
|
||||
<label for="finished_back_height"/>
|
||||
<div class="d-flex gap-2">
|
||||
<field name="finished_back_height" class="oe_inline"/>
|
||||
<field name="back_height_unit" class="oe_inline"/>
|
||||
</div>
|
||||
<label for="finished_seat_to_floor_height"/>
|
||||
<div class="d-flex gap-2">
|
||||
<field name="finished_seat_to_floor_height" class="oe_inline"/>
|
||||
<field name="seat_to_floor_unit" class="oe_inline"/>
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<label for="finished_leg_rest_length"/>
|
||||
<div class="d-flex gap-2">
|
||||
<field name="finished_leg_rest_length" class="oe_inline"/>
|
||||
<field name="leg_rest_unit" class="oe_inline"/>
|
||||
</div>
|
||||
<label for="seat_depth"/>
|
||||
<div class="d-flex gap-2">
|
||||
<field name="seat_depth" class="oe_inline"/>
|
||||
<field name="seat_depth_unit" class="oe_inline"/>
|
||||
</div>
|
||||
<label for="client_weight"/>
|
||||
<div class="d-flex gap-2">
|
||||
<field name="client_weight" class="oe_inline"/>
|
||||
<field name="client_weight_unit" class="oe_inline"/>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
<group string="Power Base ADP Funded Options"
|
||||
invisible="equipment_type != 'power_wheelchair'">
|
||||
<group>
|
||||
<field name="pw_adjustable_tension_back"/>
|
||||
<field name="pw_midline_control"/>
|
||||
<field name="pw_manual_recline"/>
|
||||
<field name="pw_angle_adjustable_footplates"/>
|
||||
<field name="pw_manual_elevating_legrests"/>
|
||||
<field name="pw_swingaway_bracket"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="pw_front_riggings"/>
|
||||
<field name="pw_seat_package_1"/>
|
||||
<field name="pw_seat_package_2"/>
|
||||
<field name="pw_oxygen_tank"/>
|
||||
<field name="pw_ventilator_tray"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="Specialty Components (* Provide Clinical Rationale)"
|
||||
invisible="equipment_type != 'power_wheelchair'">
|
||||
<group>
|
||||
<field name="pw_specialty_1_joystick"/>
|
||||
<field name="pw_specialty_2_chin"/>
|
||||
<field name="pw_specialty_3_touch"/>
|
||||
<field name="pw_specialty_4_proximity"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="pw_specialty_5_breath"/>
|
||||
<field name="pw_specialty_6_scanners"/>
|
||||
<field name="pw_auto_correction"/>
|
||||
</group>
|
||||
<group colspan="2">
|
||||
<field name="pw_specialty_rationale"
|
||||
placeholder="Clinical rationale for specialty components..."
|
||||
invisible="not pw_specialty_1_joystick and not pw_specialty_2_chin and not pw_specialty_3_touch and not pw_specialty_4_proximity and not pw_specialty_5_breath and not pw_specialty_6_scanners and not pw_auto_correction"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="Power Positioning Devices"
|
||||
invisible="equipment_type != 'power_wheelchair'">
|
||||
<group>
|
||||
<field name="pw_power_tilt_only"/>
|
||||
<field name="pw_power_recline_only"/>
|
||||
<field name="pw_power_tilt_recline"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="pw_power_elevating_footrests"/>
|
||||
<field name="pw_multi_function_control"/>
|
||||
<field name="pw_power_add_on"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
</page>
|
||||
|
||||
<!-- TAB 3: FRAME -->
|
||||
<page string="Frame" name="frame">
|
||||
<group>
|
||||
<group>
|
||||
<field name="frame_product_id"/>
|
||||
</group>
|
||||
</group>
|
||||
<field name="frame_notes" placeholder="Frame notes..."/>
|
||||
</page>
|
||||
|
||||
<!-- TAB 4: SELECTED ITEMS -->
|
||||
<page string="Selected Items" name="lines">
|
||||
<field name="line_ids">
|
||||
<list editable="bottom">
|
||||
<field name="section_id"/>
|
||||
<field name="product_id"/>
|
||||
<field name="product_name"/>
|
||||
<field name="build_type"/>
|
||||
<field name="quantity"/>
|
||||
<field name="adp_device_code"/>
|
||||
<field name="adp_price"/>
|
||||
<field name="unit_price"/>
|
||||
<field name="subtotal" sum="Total"/>
|
||||
<field name="adp_portion" sum="ADP Total"/>
|
||||
<field name="client_portion" sum="Client Total"/>
|
||||
<field name="is_upcharge"/>
|
||||
<field name="upcharge_reason"
|
||||
invisible="not is_upcharge"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
|
||||
<!-- TAB 5: UPCHARGES -->
|
||||
<page string="Upcharges" name="upcharges">
|
||||
<field name="upcharge_line_ids" readonly="1">
|
||||
<list>
|
||||
<field name="adp_device_code"/>
|
||||
<field name="product_name"/>
|
||||
<field name="upcharge_reason"/>
|
||||
<field name="unit_price"/>
|
||||
<field name="adp_portion"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
|
||||
<!-- TAB 6: QUOTATION -->
|
||||
<page string="Quotation" name="quotation">
|
||||
<group>
|
||||
<group>
|
||||
<field name="sale_order_id"/>
|
||||
<field name="total_estimate"/>
|
||||
<field name="total_adp_estimate"/>
|
||||
<field name="total_client_estimate"/>
|
||||
</group>
|
||||
</group>
|
||||
<field name="notes" placeholder="Additional notes..."/>
|
||||
</page>
|
||||
|
||||
<!-- TAB 7: SHARING -->
|
||||
<page string="Sharing" name="sharing">
|
||||
<div class="alert alert-info" role="alert"
|
||||
invisible="access_token">
|
||||
<i class="fa fa-info-circle me-1"/>
|
||||
Click <b>Share Link</b> above to generate a public URL
|
||||
that can be opened without logging in, or embedded in
|
||||
an external website via an iframe.
|
||||
</div>
|
||||
<group invisible="not access_token">
|
||||
<group string="Public Access">
|
||||
<field name="public_url" widget="CopyClipboardChar"
|
||||
readonly="1" string="Public URL"/>
|
||||
<field name="portal_url" widget="CopyClipboardChar"
|
||||
readonly="1" string="Portal URL (login required)"/>
|
||||
<field name="access_token" readonly="1"/>
|
||||
</group>
|
||||
<group string="Embed Code">
|
||||
<div colspan="2">
|
||||
<p class="text-muted mb-2">
|
||||
Copy this snippet to embed the form in an external page:
|
||||
</p>
|
||||
<code style="display:block;white-space:pre-wrap;background:#f8f9fa;padding:12px;border-radius:6px;font-size:13px;"><iframe src="<field name="public_url" readonly="1"/>/embed"
|
||||
width="100%" height="900"
|
||||
frameborder="0"
|
||||
allow="clipboard-write"></iframe></code>
|
||||
</div>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<chatter/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- ASSESSMENT ACTION -->
|
||||
<!-- ============================================================ -->
|
||||
<record id="action_wc_assessment" model="ir.actions.act_window">
|
||||
<field name="name">Wheelchair Assessments</field>
|
||||
<field name="res_model">fusion.wc.assessment</field>
|
||||
<field name="view_mode">list,kanban,form</field>
|
||||
<field name="context">{'search_default_my_assessments': 1}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Create a wheelchair assessment
|
||||
</p>
|
||||
<p>
|
||||
Start a new wheelchair assessment to configure a chair
|
||||
and automatically generate a quotation.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
159
fusion_quotations/views/wc_config_flow_views.xml
Normal file
159
fusion_quotations/views/wc_config_flow_views.xml
Normal file
@@ -0,0 +1,159 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- ============================================================
|
||||
Configuration Flow — Tree View
|
||||
============================================================ -->
|
||||
<record id="view_wc_config_flow_tree" model="ir.ui.view">
|
||||
<field name="name">fusion.wc.config.flow.tree</field>
|
||||
<field name="model">fusion.wc.config.flow</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Configuration Flows">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="equipment_type"/>
|
||||
<field name="state" widget="badge"
|
||||
decoration-success="state == 'active'"
|
||||
decoration-info="state == 'draft'"
|
||||
decoration-muted="state == 'archived'"/>
|
||||
<field name="step_count"/>
|
||||
<field name="node_count"/>
|
||||
<field name="connection_count"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ============================================================
|
||||
Configuration Flow — Form View
|
||||
============================================================ -->
|
||||
<record id="view_wc_config_flow_form" model="ir.ui.view">
|
||||
<field name="name">fusion.wc.config.flow.form</field>
|
||||
<field name="model">fusion.wc.config.flow</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Configuration Flow">
|
||||
<header>
|
||||
<button name="action_open_designer" type="object"
|
||||
string="Open Visual Designer"
|
||||
class="btn-primary"
|
||||
icon="fa-sitemap"/>
|
||||
<button name="action_new_assessment_form" type="object"
|
||||
string="New Assessment"
|
||||
class="btn-secondary"
|
||||
icon="fa-external-link"/>
|
||||
<button name="action_activate" type="object"
|
||||
string="Activate"
|
||||
class="btn-success"
|
||||
invisible="state == 'active'"/>
|
||||
<button name="action_archive" type="object"
|
||||
string="Archive"
|
||||
invisible="state == 'archived'"/>
|
||||
<button name="action_reset_draft" type="object"
|
||||
string="Reset to Draft"
|
||||
invisible="state == 'draft'"/>
|
||||
<field name="state" widget="statusbar"
|
||||
statusbar_visible="draft,active,archived"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="name" placeholder="e.g. Standard Manual Wheelchair Config"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="equipment_type"/>
|
||||
<field name="sequence"/>
|
||||
<field name="active" invisible="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="step_count"/>
|
||||
<field name="node_count"/>
|
||||
<field name="connection_count"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Form Steps" name="form_steps">
|
||||
<field name="step_ids">
|
||||
<list editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="step_type"/>
|
||||
<field name="icon"/>
|
||||
<field name="section_code"/>
|
||||
<field name="is_required"/>
|
||||
</list>
|
||||
</field>
|
||||
<div class="mt-2">
|
||||
<button name="action_create_default_steps" type="object"
|
||||
string="Generate Default Steps"
|
||||
class="btn-secondary"
|
||||
icon="fa-magic"
|
||||
confirm="This will replace existing steps. Continue?"/>
|
||||
</div>
|
||||
</page>
|
||||
<page string="Description" name="description">
|
||||
<field name="description" placeholder="Describe this configuration flow..."/>
|
||||
</page>
|
||||
<page string="Nodes" name="nodes">
|
||||
<field name="node_ids">
|
||||
<list editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="node_type"/>
|
||||
<field name="section_id"/>
|
||||
<field name="decision_field"
|
||||
invisible="node_type != 'decision'"/>
|
||||
<field name="decision_operator"
|
||||
invisible="node_type != 'decision'"/>
|
||||
<field name="decision_value"
|
||||
invisible="node_type != 'decision'"/>
|
||||
<field name="action_type"
|
||||
invisible="node_type != 'action'"/>
|
||||
<field name="measurement_field"
|
||||
invisible="node_type != 'measurement_check'"/>
|
||||
<field name="comparison"
|
||||
invisible="node_type != 'measurement_check'"/>
|
||||
<field name="threshold_value"
|
||||
invisible="node_type != 'measurement_check'"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Connections" name="connections">
|
||||
<field name="connection_ids">
|
||||
<list editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="source_node_id"
|
||||
domain="[('flow_id', '=', parent.id)]"/>
|
||||
<field name="target_node_id"
|
||||
domain="[('flow_id', '=', parent.id)]"/>
|
||||
<field name="source_port"/>
|
||||
<field name="label"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ============================================================
|
||||
Configuration Flow — Action
|
||||
============================================================ -->
|
||||
<record id="action_wc_config_flow" model="ir.actions.act_window">
|
||||
<field name="name">Configuration Flows</field>
|
||||
<field name="res_model">fusion.wc.config.flow</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Create a Configuration Flow
|
||||
</p>
|
||||
<p>
|
||||
Configuration flows define visual decision trees that control
|
||||
which options are shown, hidden, or required during a wheelchair
|
||||
assessment. Use the Visual Designer to build flows graphically.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
146
fusion_quotations/views/wc_section_views.xml
Normal file
146
fusion_quotations/views/wc_section_views.xml
Normal file
@@ -0,0 +1,146 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- SECTION TREE VIEW -->
|
||||
<!-- ============================================================ -->
|
||||
<record id="view_wc_section_tree" model="ir.ui.view">
|
||||
<field name="name">fusion.wc.section.tree</field>
|
||||
<field name="model">fusion.wc.section</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="parent_id"/>
|
||||
<field name="equipment_type"/>
|
||||
<field name="has_build_type"/>
|
||||
<field name="is_adp_options_section"/>
|
||||
<field name="option_count" string="Options"/>
|
||||
<field name="active" column_invisible="1"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- SECTION OPTION ACTION (for stat button — must be before form) -->
|
||||
<!-- ============================================================ -->
|
||||
<record id="action_wc_section_option" model="ir.actions.act_window">
|
||||
<field name="name">Section Options</field>
|
||||
<field name="res_model">fusion.wc.section.option</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="context">{'default_section_id': active_id}</field>
|
||||
<field name="domain">[('section_id', '=', active_id)]</field>
|
||||
</record>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- SECTION FORM VIEW -->
|
||||
<!-- ============================================================ -->
|
||||
<record id="view_wc_section_form" model="ir.ui.view">
|
||||
<field name="name">fusion.wc.section.form</field>
|
||||
<field name="model">fusion.wc.section</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Wheelchair Section">
|
||||
<header>
|
||||
<button name="action_auto_populate_options"
|
||||
string="Auto-Populate Products from Inventory"
|
||||
type="object" class="btn-secondary"
|
||||
icon="fa-magic"
|
||||
confirm="This will scan your product inventory for ADP device codes matching this section and add them as options. Continue?"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button name="%(fusion_quotations.action_wc_section_option)d"
|
||||
type="action" class="oe_stat_button" icon="fa-list"
|
||||
context="{'default_section_id': id, 'search_default_section_id': id}">
|
||||
<field name="option_count" widget="statinfo" string="Options"/>
|
||||
</button>
|
||||
</div>
|
||||
<widget name="web_ribbon" title="Archived" bg_color="text-bg-danger"
|
||||
invisible="active"/>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="name" placeholder="Section Name"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="code"/>
|
||||
<field name="sequence"/>
|
||||
<field name="parent_id"/>
|
||||
<field name="equipment_type"/>
|
||||
<field name="icon" placeholder="fa-wheelchair"/>
|
||||
<field name="product_category_id"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="required"/>
|
||||
<field name="allow_multiple"/>
|
||||
<field name="is_adp_options_section"/>
|
||||
<field name="has_build_type"/>
|
||||
<field name="active"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="Measurement Fields" col="4">
|
||||
<field name="has_width"/>
|
||||
<field name="width_label" invisible="not has_width"/>
|
||||
<field name="has_depth"/>
|
||||
<field name="depth_label" invisible="not has_depth"/>
|
||||
<field name="has_height"/>
|
||||
<field name="height_label" invisible="not has_height"/>
|
||||
<field name="has_length"/>
|
||||
<field name="length_label" invisible="not has_length"/>
|
||||
</group>
|
||||
<field name="description" placeholder="Help text for sales reps..."/>
|
||||
<notebook>
|
||||
<page string="Product Options" name="options">
|
||||
<field name="option_ids">
|
||||
<list editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="product_tmpl_id"/>
|
||||
<field name="variant_count" string="Variants"/>
|
||||
<field name="is_standard"/>
|
||||
<field name="adp_device_code"/>
|
||||
<field name="adp_price"/>
|
||||
<field name="list_price"/>
|
||||
<field name="available_build_types"/>
|
||||
<field name="requires_clinical_rationale"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
<page string="Sub-Sections" name="children">
|
||||
<field name="child_ids">
|
||||
<list>
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="has_build_type"/>
|
||||
<field name="option_count" string="Options"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- SECTION ACTION -->
|
||||
<!-- ============================================================ -->
|
||||
<record id="action_wc_section" model="ir.actions.act_window">
|
||||
<field name="name">Wheelchair Sections</field>
|
||||
<field name="res_model">fusion.wc.section</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="context">{'search_default_active': 1}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Configure wheelchair sections
|
||||
</p>
|
||||
<p>
|
||||
Define sections like Frame, Cushion, Backrest, etc.
|
||||
and add product options to each section.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
109
fusion_quotations/views/wc_upcharge_rule_views.xml
Normal file
109
fusion_quotations/views/wc_upcharge_rule_views.xml
Normal file
@@ -0,0 +1,109 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- UPCHARGE RULE TREE VIEW -->
|
||||
<!-- ============================================================ -->
|
||||
<record id="view_wc_upcharge_rule_tree" model="ir.ui.view">
|
||||
<field name="name">fusion.wc.upcharge.rule.tree</field>
|
||||
<field name="model">fusion.wc.upcharge.rule</field>
|
||||
<field name="arch" type="xml">
|
||||
<list>
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="trigger_type"/>
|
||||
<field name="adp_device_code"/>
|
||||
<field name="equipment_type"/>
|
||||
<field name="mutually_exclusive_group"/>
|
||||
<field name="active"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- UPCHARGE RULE FORM VIEW -->
|
||||
<!-- ============================================================ -->
|
||||
<record id="view_wc_upcharge_rule_form" model="ir.ui.view">
|
||||
<field name="name">fusion.wc.upcharge.rule.form</field>
|
||||
<field name="model">fusion.wc.upcharge.rule</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Upcharge Rule">
|
||||
<sheet>
|
||||
<widget name="web_ribbon" title="Archived" bg_color="text-bg-danger"
|
||||
invisible="active"/>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="name" placeholder="Rule Name"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group string="Trigger">
|
||||
<field name="trigger_type"/>
|
||||
<field name="equipment_type"/>
|
||||
<field name="sequence"/>
|
||||
<field name="active"/>
|
||||
</group>
|
||||
<group string="Result">
|
||||
<field name="adp_device_code"/>
|
||||
<field name="adp_device_code_id" readonly="1"/>
|
||||
<field name="product_id"/>
|
||||
<field name="mutually_exclusive_group"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- Measurement trigger fields -->
|
||||
<group string="Measurement Condition"
|
||||
invisible="trigger_type != 'measurement'">
|
||||
<group>
|
||||
<field name="measurement_field"/>
|
||||
<field name="comparison"/>
|
||||
<field name="threshold_value"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- Weight trigger fields -->
|
||||
<group string="Weight Condition"
|
||||
invisible="trigger_type != 'weight'">
|
||||
<group>
|
||||
<field name="weight_min"/>
|
||||
<field name="weight_max"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- Dimension mismatch fields -->
|
||||
<group string="Dimension Mismatch Condition"
|
||||
invisible="trigger_type != 'dimension_mismatch'">
|
||||
<group>
|
||||
<field name="compare_field_1"/>
|
||||
<field name="compare_field_2"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<group>
|
||||
<field name="description" placeholder="Explanation shown to sales rep when rule triggers..."/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- UPCHARGE RULE ACTION -->
|
||||
<!-- ============================================================ -->
|
||||
<record id="action_wc_upcharge_rule" model="ir.actions.act_window">
|
||||
<field name="name">Upcharge Rules</field>
|
||||
<field name="res_model">fusion.wc.upcharge.rule</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="context">{'search_default_active': 1}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Configure upcharge rules
|
||||
</p>
|
||||
<p>
|
||||
Define rules that auto-add ADP upcharge codes based on
|
||||
wheelchair measurements (e.g. WAMA for width > 18").
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user