feat: hide authorizer for rental orders, auto-set sale type
Rental orders no longer show the "Authorizer Required?" question or the Authorizer field. The sale type is automatically set to 'Rentals' when creating or confirming a rental order. Validation logic also skips authorizer checks for rental sale type. Made-with: Cursor
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
|
||||
<!-- Top-level menu under Rental app -->
|
||||
<menuitem id="menu_rental_enhancement_root"
|
||||
name="Rental Enhancement"
|
||||
name="Fusion Rental"
|
||||
parent="sale_renting.rental_menu_root"
|
||||
sequence="30"/>
|
||||
|
||||
|
||||
76
fusion_rental/views/portal_sale_rental_override.xml
Normal file
76
fusion_rental/views/portal_sale_rental_override.xml
Normal file
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- Override portal quotation sidebar buttons for rental orders -->
|
||||
<template id="sale_order_portal_template_rental_override"
|
||||
inherit_id="sale.sale_order_portal_template"
|
||||
name="Rental Portal Override">
|
||||
|
||||
<!-- Sidebar: replace Sign & Pay / Accept & Sign with rental agreement button -->
|
||||
<xpath expr="//div[@id='sale_order_sidebar_button']" position="before">
|
||||
<t t-if="sale_order.is_rental_order and not sale_order.rental_agreement_signed">
|
||||
<div class="d-flex flex-column gap-2 mb-3" id="rental_sidebar_buttons">
|
||||
<a t-if="sale_order.state in ('draft', 'sent')"
|
||||
role="button"
|
||||
class="btn btn-primary"
|
||||
t-attf-href="/rental/confirm-and-sign/#{sale_order.id}?access_token=#{sale_order.access_token}"
|
||||
>
|
||||
<i class="fa fa-check me-1"/>Confirm & Sign Agreement
|
||||
</a>
|
||||
<a t-elif="sale_order.state == 'sale' and sale_order.rental_agreement_token"
|
||||
role="button"
|
||||
class="btn btn-primary"
|
||||
t-attf-href="/rental/agreement/#{sale_order.id}/#{sale_order.rental_agreement_token}"
|
||||
>
|
||||
<i class="fa fa-pencil me-1"/>Sign Rental Agreement
|
||||
</a>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="sale_order.is_rental_order and sale_order.rental_agreement_signed">
|
||||
<div class="d-flex flex-column gap-2 mb-3">
|
||||
<span class="btn btn-success disabled">
|
||||
<i class="fa fa-check me-1"/>Agreement Signed
|
||||
</span>
|
||||
</div>
|
||||
</t>
|
||||
</xpath>
|
||||
|
||||
<!-- Hide standard Sign & Pay sidebar button for rental orders -->
|
||||
<xpath expr="//div[@id='sale_order_sidebar_button']" position="attributes">
|
||||
<attribute name="t-if">not sale_order.is_rental_order</attribute>
|
||||
</xpath>
|
||||
|
||||
<!-- Bottom actions: replace for rental orders -->
|
||||
<xpath expr="//div[@name='sale_order_actions']" position="before">
|
||||
<div t-if="sale_order.is_rental_order and not sale_order.rental_agreement_signed"
|
||||
class="d-flex justify-content-center gap-1 d-print-none">
|
||||
<div class="col-sm-auto mt8">
|
||||
<a t-if="sale_order.state in ('draft', 'sent')"
|
||||
role="button"
|
||||
class="btn btn-primary"
|
||||
t-attf-href="/rental/confirm-and-sign/#{sale_order.id}?access_token=#{sale_order.access_token}">
|
||||
<i class="fa fa-check me-1"/>Confirm & Sign Agreement
|
||||
</a>
|
||||
<a t-elif="sale_order.state == 'sale' and sale_order.rental_agreement_token"
|
||||
role="button"
|
||||
class="btn btn-primary"
|
||||
t-attf-href="/rental/agreement/#{sale_order.id}/#{sale_order.rental_agreement_token}">
|
||||
<i class="fa fa-pencil me-1"/>Sign Rental Agreement
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-sm-auto mt8">
|
||||
<a role="button" class="btn btn-light" href="#discussion">
|
||||
<i class="fa fa-comment me-1"/>Feedback
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
|
||||
<!-- Hide standard bottom actions for rental orders -->
|
||||
<xpath expr="//div[@name='sale_order_actions']" position="attributes">
|
||||
<attribute name="t-if">(sale_order._has_to_be_signed() or sale_order._has_to_be_paid()) and not sale_order.is_rental_order</attribute>
|
||||
</xpath>
|
||||
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
@@ -7,7 +7,7 @@
|
||||
<field name="inherit_id" ref="sale_renting.res_config_settings_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//app[@name='sale_renting']" position="inside">
|
||||
<block title="Rental Enhancement" name="rental_enhancement_settings">
|
||||
<block title="Fusion Rental" name="rental_enhancement_settings">
|
||||
<setting string="Google Review URL"
|
||||
help="Google Review link shown in thank-you emails after rental close.">
|
||||
<div class="content-group">
|
||||
@@ -31,6 +31,62 @@
|
||||
</div>
|
||||
</div>
|
||||
</setting>
|
||||
<setting string="Google Maps API Key"
|
||||
help="API key for address autocomplete on the rental agreement form. If Fusion Claims is installed, its key is used automatically.">
|
||||
<div class="content-group">
|
||||
<div class="mt-2">
|
||||
<field name="rental_google_maps_api_key"
|
||||
placeholder="Enter Google Maps API Key"
|
||||
password="True"/>
|
||||
</div>
|
||||
<div class="text-muted mt-1">
|
||||
Only needed if Fusion Claims is not installed. Enable the
|
||||
Places API and Geocoding API in Google Cloud Console.
|
||||
</div>
|
||||
</div>
|
||||
</setting>
|
||||
</block>
|
||||
<block title="Timing & Short-Term Rentals" name="rental_timing_settings">
|
||||
<setting string="Marketing Email Timing"
|
||||
help="Percentage of rental period after start date to send the purchase offer email.">
|
||||
<div class="content-group">
|
||||
<div class="row mt-2">
|
||||
<label class="col-lg-4 o_light_label" for="rental_marketing_email_pct"/>
|
||||
<field name="rental_marketing_email_pct" class="col-lg-2"/>
|
||||
<span class="col-lg-5 text-muted">% of rental period (default 23% = day 7 of 30)</span>
|
||||
</div>
|
||||
</div>
|
||||
</setting>
|
||||
<setting string="Renewal Reminder Timing"
|
||||
help="Percentage of rental period before renewal date to send the reminder.">
|
||||
<div class="content-group">
|
||||
<div class="row mt-2">
|
||||
<label class="col-lg-4 o_light_label" for="rental_renewal_reminder_pct"/>
|
||||
<field name="rental_renewal_reminder_pct" class="col-lg-2"/>
|
||||
<span class="col-lg-5 text-muted">% of rental period (default 10% = 3 days before on 30-day)</span>
|
||||
</div>
|
||||
</div>
|
||||
</setting>
|
||||
<setting string="Short-Term Rental Threshold"
|
||||
help="Rentals shorter than this are considered short-term. Auto-renewal waits for the grace period.">
|
||||
<div class="content-group">
|
||||
<div class="row mt-2">
|
||||
<label class="col-lg-4 o_light_label" for="rental_short_term_threshold_days"/>
|
||||
<field name="rental_short_term_threshold_days" class="col-lg-2"/>
|
||||
<span class="col-lg-5 text-muted">days (rentals below this get grace period protection)</span>
|
||||
</div>
|
||||
</div>
|
||||
</setting>
|
||||
<setting string="Short-Term Grace Period"
|
||||
help="Time after scheduled return before auto-renewal charges a short-term rental.">
|
||||
<div class="content-group">
|
||||
<div class="row mt-2">
|
||||
<label class="col-lg-4 o_light_label" for="rental_short_term_grace_hours"/>
|
||||
<field name="rental_short_term_grace_hours" class="col-lg-2"/>
|
||||
<span class="col-lg-5 text-muted">hours after return time (default 1 hour)</span>
|
||||
</div>
|
||||
</div>
|
||||
</setting>
|
||||
</block>
|
||||
</xpath>
|
||||
</field>
|
||||
|
||||
@@ -7,6 +7,46 @@
|
||||
<field name="inherit_id" ref="sale_renting.rental_order_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<!-- Smart buttons in button_box -->
|
||||
<div name="button_box" position="inside">
|
||||
<button name="action_view_deposit_invoice"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-shield"
|
||||
invisible="not is_rental_order or rental_deposit_invoice_count == 0">
|
||||
<field name="rental_deposit_invoice_count"
|
||||
widget="statinfo"
|
||||
string="Security Deposit"/>
|
||||
</button>
|
||||
<button name="action_view_rental_charges_invoice"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-file-text-o"
|
||||
invisible="not is_rental_order or rental_charges_invoice_count == 0">
|
||||
<field name="rental_charges_invoice_count"
|
||||
widget="statinfo"
|
||||
string="Rental Invoice"/>
|
||||
</button>
|
||||
<button name="action_view_renewal_invoices"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-refresh"
|
||||
invisible="not is_rental_order or rental_renewal_invoice_count == 0">
|
||||
<field name="rental_renewal_invoice_count"
|
||||
widget="statinfo"
|
||||
string="Renewals"/>
|
||||
</button>
|
||||
<button name="action_view_refund_invoices"
|
||||
type="object"
|
||||
class="oe_stat_button"
|
||||
icon="fa-undo"
|
||||
invisible="not is_rental_order or rental_refund_invoice_count == 0">
|
||||
<field name="rental_refund_invoice_count"
|
||||
widget="statinfo"
|
||||
string="Refunds"/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Header buttons -->
|
||||
<button name="action_open_pickup" position="before">
|
||||
<button name="action_send_rental_agreement"
|
||||
@@ -37,26 +77,12 @@
|
||||
string="Mark Deposit Collected"
|
||||
invisible="not is_rental_order or rental_deposit_status != 'pending'"
|
||||
icon="fa-check-circle"/>
|
||||
<button name="action_refund_deposit"
|
||||
<button name="action_process_deposit"
|
||||
type="object"
|
||||
class="btn-secondary"
|
||||
string="Refund Deposit"
|
||||
invisible="not is_rental_order or rental_deposit_status != 'collected'"
|
||||
confirm="This will initiate the deposit refund hold period. Continue?"
|
||||
icon="fa-undo"/>
|
||||
<button name="action_force_refund_deposit"
|
||||
type="object"
|
||||
class="btn-secondary"
|
||||
string="Process Refund Now"
|
||||
invisible="not is_rental_order or rental_deposit_status != 'refund_hold'"
|
||||
confirm="Skip the hold period and process the refund immediately?"
|
||||
icon="fa-bolt"/>
|
||||
<button name="action_deduct_deposit"
|
||||
type="object"
|
||||
class="btn-danger"
|
||||
string="Deduct Deposit"
|
||||
invisible="not is_rental_order or rental_deposit_status != 'collected'"
|
||||
icon="fa-minus-circle"/>
|
||||
string="Process Deposit"
|
||||
invisible="not is_rental_order or rental_deposit_status not in ('collected', 'refund_hold')"
|
||||
icon="fa-credit-card"/>
|
||||
|
||||
<button name="action_close_rental"
|
||||
type="object"
|
||||
@@ -68,61 +94,109 @@
|
||||
icon="fa-power-off"/>
|
||||
</button>
|
||||
|
||||
<!-- Rental fields -->
|
||||
<!-- Hidden fields (must stay in form, outside notebook) -->
|
||||
<field name="duration_days" position="after">
|
||||
<!-- Renewal settings -->
|
||||
<field name="rental_auto_renew" invisible="not is_rental_order"/>
|
||||
<field name="rental_renewal_count" invisible="not is_rental_order or rental_renewal_count == 0"/>
|
||||
<field name="rental_max_renewals" invisible="not is_rental_order or not rental_auto_renew"/>
|
||||
<field name="rental_payment_token_id" invisible="not is_rental_order"/>
|
||||
<field name="rental_next_renewal_date" invisible="not is_rental_order or not rental_auto_renew"/>
|
||||
<field name="rental_reminder_sent" invisible="1"/>
|
||||
<field name="rental_original_duration" invisible="1"/>
|
||||
<field name="rental_agreement_token" invisible="1"/>
|
||||
|
||||
<!-- Agreement status -->
|
||||
<field name="rental_agreement_signed" invisible="not is_rental_order"
|
||||
widget="boolean_toggle" readonly="1"/>
|
||||
<field name="rental_agreement_signer_name"
|
||||
invisible="not is_rental_order or not rental_agreement_signed" readonly="1"/>
|
||||
<field name="rental_agreement_signed_date"
|
||||
invisible="not is_rental_order or not rental_agreement_signed" readonly="1"/>
|
||||
|
||||
<!-- Rental charges invoice -->
|
||||
<field name="rental_charges_invoice_id"
|
||||
invisible="not is_rental_order or not rental_charges_invoice_id" readonly="1"/>
|
||||
|
||||
<!-- Deposit status -->
|
||||
<field name="rental_deposit_status" invisible="not is_rental_order or not rental_deposit_status"
|
||||
decoration-success="rental_deposit_status == 'refunded'"
|
||||
decoration-warning="rental_deposit_status in ('pending', 'refund_hold', 'collected')"
|
||||
decoration-danger="rental_deposit_status == 'deducted'"
|
||||
widget="badge"/>
|
||||
<field name="rental_deposit_invoice_id"
|
||||
invisible="not is_rental_order or not rental_deposit_invoice_id" readonly="1"/>
|
||||
|
||||
<!-- Inspection status -->
|
||||
<field name="rental_inspection_status"
|
||||
invisible="not is_rental_order or not rental_inspection_status"
|
||||
decoration-success="rental_inspection_status == 'passed'"
|
||||
decoration-danger="rental_inspection_status == 'flagged'"
|
||||
widget="badge"/>
|
||||
|
||||
<!-- Purchase interest -->
|
||||
<field name="rental_purchase_interest"
|
||||
invisible="not is_rental_order or not rental_purchase_interest"
|
||||
widget="boolean_toggle" readonly="1"/>
|
||||
<field name="rental_purchase_coupon_id"
|
||||
invisible="not is_rental_order or not rental_purchase_coupon_id" readonly="1"/>
|
||||
|
||||
<!-- Close status -->
|
||||
<field name="rental_closed"
|
||||
invisible="not is_rental_order or not rental_closed" readonly="1"/>
|
||||
<field name="rental_marketing_email_sent" invisible="1"/>
|
||||
</field>
|
||||
|
||||
<!-- Notebook pages -->
|
||||
<xpath expr="//notebook" position="inside">
|
||||
|
||||
<!-- Rental Management -->
|
||||
<page string="Rental Management"
|
||||
name="rental_management"
|
||||
invisible="not is_rental_order">
|
||||
|
||||
<!-- Row 1: Agreement + Payment -->
|
||||
<group>
|
||||
<group string="Agreement">
|
||||
<field name="rental_agreement_signed"
|
||||
widget="boolean_toggle" readonly="1"/>
|
||||
<field name="rental_agreement_signer_name"
|
||||
invisible="not rental_agreement_signed" readonly="1"/>
|
||||
<field name="rental_agreement_signed_date"
|
||||
invisible="not rental_agreement_signed" readonly="1"/>
|
||||
</group>
|
||||
<group string="Payment">
|
||||
<field name="rental_payment_token_id"/>
|
||||
<div invisible="not is_rental_order or state != 'sale' or rental_closed">
|
||||
<button name="action_send_card_reauthorization"
|
||||
type="object"
|
||||
class="btn btn-outline-secondary btn-sm"
|
||||
string="Reauthorize Card"
|
||||
icon="fa-credit-card"
|
||||
confirm="This will send a card authorization form to the customer. Continue?"/>
|
||||
</div>
|
||||
<field name="rental_charges_invoice_id"
|
||||
invisible="not rental_charges_invoice_id" readonly="1"/>
|
||||
<field name="rental_deposit_invoice_id"
|
||||
invisible="not rental_deposit_invoice_id" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- Row 2: Renewal + Status -->
|
||||
<group>
|
||||
<group string="Renewal">
|
||||
<field name="rental_auto_renew"/>
|
||||
<field name="rental_auto_renew_off_reason"
|
||||
invisible="rental_auto_renew"
|
||||
required="not rental_auto_renew"
|
||||
placeholder="Reason for disabling auto-renewal..."/>
|
||||
<field name="rental_max_renewals"
|
||||
invisible="not rental_auto_renew"/>
|
||||
<field name="rental_next_renewal_date"
|
||||
invisible="not rental_auto_renew"/>
|
||||
<field name="rental_renewal_count"
|
||||
invisible="rental_renewal_count == 0"/>
|
||||
</group>
|
||||
<group string="Status">
|
||||
<field name="rental_deposit_status"
|
||||
invisible="not rental_deposit_status"
|
||||
decoration-success="rental_deposit_status == 'refunded'"
|
||||
decoration-warning="rental_deposit_status in ('pending', 'refund_hold', 'collected')"
|
||||
decoration-danger="rental_deposit_status == 'deducted'"
|
||||
widget="badge"/>
|
||||
<field name="rental_inspection_status"
|
||||
invisible="not rental_inspection_status"
|
||||
decoration-success="rental_inspection_status == 'passed'"
|
||||
decoration-danger="rental_inspection_status == 'flagged'"
|
||||
widget="badge"/>
|
||||
<field name="rental_purchase_interest"
|
||||
invisible="not rental_purchase_interest"
|
||||
widget="boolean_toggle" readonly="1"/>
|
||||
<field name="rental_purchase_coupon_id"
|
||||
invisible="not rental_purchase_coupon_id" readonly="1"/>
|
||||
<field name="rental_closed"
|
||||
invisible="not rental_closed" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- Row 3: Document + Billing (visible after agreement signed) -->
|
||||
<group invisible="not rental_agreement_signed">
|
||||
<group string="Signed Agreement">
|
||||
<div invisible="not rental_agreement_document" class="mb-2">
|
||||
<button name="action_preview_rental_agreement" type="object"
|
||||
class="btn btn-outline-primary"
|
||||
icon="fa-file-pdf-o">
|
||||
Preview Signed Agreement
|
||||
</button>
|
||||
</div>
|
||||
<field name="rental_agreement_document"
|
||||
filename="rental_agreement_document_filename"
|
||||
widget="binary" readonly="1"/>
|
||||
<field name="rental_agreement_document_filename" invisible="1"/>
|
||||
</group>
|
||||
<group string="Billing Details">
|
||||
<field name="rental_billing_address" readonly="1"/>
|
||||
<field name="rental_billing_postal_code" readonly="1"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
|
||||
<!-- Renewal History -->
|
||||
<page string="Renewal History"
|
||||
name="renewal_history"
|
||||
invisible="not is_rental_order or rental_renewal_count == 0">
|
||||
@@ -147,6 +221,8 @@
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
|
||||
<!-- Cancellation Requests -->
|
||||
<page string="Cancellation Requests"
|
||||
name="cancellation_requests"
|
||||
invisible="not is_rental_order"
|
||||
@@ -166,32 +242,37 @@
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
|
||||
<!-- Inspection -->
|
||||
<page string="Inspection"
|
||||
name="inspection"
|
||||
invisible="not is_rental_order or not rental_inspection_status">
|
||||
invisible="not is_rental_order">
|
||||
<group>
|
||||
<group>
|
||||
<field name="rental_inspection_status"/>
|
||||
<field name="rental_inspection_status"
|
||||
decoration-success="rental_inspection_status == 'passed'"
|
||||
decoration-danger="rental_inspection_status == 'flagged'"
|
||||
decoration-info="rental_inspection_status == 'pending'"
|
||||
widget="badge"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="Inspection Notes">
|
||||
<div class="alert alert-secondary" role="alert"
|
||||
invisible="rental_inspection_status">
|
||||
No inspection has been performed yet. Use the
|
||||
<strong>Return</strong> button to process the return
|
||||
and complete the inspection.
|
||||
</div>
|
||||
<group string="Inspection Notes"
|
||||
invisible="not rental_inspection_status">
|
||||
<field name="rental_inspection_notes" nolabel="1"/>
|
||||
</group>
|
||||
<group string="Inspection Photos">
|
||||
<field name="rental_inspection_photo_ids" widget="many2many_binary" nolabel="1"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Agreement"
|
||||
name="agreement_tab"
|
||||
invisible="not is_rental_order or not rental_agreement_signed">
|
||||
<group>
|
||||
<group string="Signature Details">
|
||||
<field name="rental_agreement_signer_name" readonly="1"/>
|
||||
<field name="rental_agreement_signed_date" readonly="1"/>
|
||||
</group>
|
||||
<group string="Signature">
|
||||
<field name="rental_agreement_signature" widget="image" readonly="1"/>
|
||||
</group>
|
||||
<group string="Inspection Photos"
|
||||
invisible="not rental_inspection_status">
|
||||
<field name="rental_inspection_photo_ids"
|
||||
widget="inspection_photos"
|
||||
nolabel="1"
|
||||
class="o_inspection_photos"
|
||||
options="{'accepted_file_extensions': 'image/*'}"/>
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
|
||||
Reference in New Issue
Block a user