X2 Day-before visit reminder email
- New cron 'Fusion Repairs: Day-before visit reminders' (daily at 08:00)
walks repair.order records with at least one linked
fusion.technician.task scheduled for tomorrow and not yet reminded.
- Sends mail.template email_template_visit_day_before to the client.
- New x_fc_day_before_reminder_sent flag (copy=False) so the cron
never re-sends the same reminder.
- Template uses 4px blue accent, 600px max-width, shows the scheduled
date + technician name + equipment, with a 'reply to reschedule' note.
- Verified: cron flagged the test repair x_fc_day_before_reminder_sent=True
after running.
X4 Post-visit NPS / Google review email
- New cron 'Fusion Repairs: Send post-visit NPS emails' (hourly)
finds repairs in state='done' with write_date >= 24h ago and no NPS
email sent. Sends mail.template email_template_post_visit_nps.
- New x_fc_nps_email_sent flag so we never re-pester clients.
- Template uses 4px green accent + 'Leave a Google review' CTA button
linking to res.company.x_fc_google_review_url (or a sensible Google
search fallback when the company hasn't configured a review URL).
M3 Loaner auto-offer for long-running repairs
- Soft-bridges fusion_loaners_management without a hard dep -
cron_offer_loaner_for_long_repairs returns immediately if the
fusion.loaner.checkout model isn't installed.
- Walks repair.order records open longer than
fusion_repairs.loaner_offer_threshold_days (ICP, default 3 days)
with no existing loaner-offer activity.
- Posts a 'Repair: Offer Loaner' activity (new mail.activity.type)
assigned to the repair responsible.
- New x_fc_loaner_offered flag to prevent daily re-posting.
- Manual 'Offer Loaner' button on repair header opens the
fusion.loaner.checkout wizard pre-filled with partner + SO.
- Daily cron runs at 08:30.
Email + ICP + cron wiring:
- 2 new mail.template records (visit_day_before, post_visit_nps)
- 1 new mail.activity.type (loaner_offer)
- 3 new ir.cron records (day-before, NPS, loaner)
- 1 new ir.config_parameter (loaner_offer_threshold_days)
- 1 new header button (Offer Loaner) on repair.order
Verified end-to-end on local westin-v19:
X2 setup repair: RO-202605-12 task: TASK-00045
day-before flag after cron: True (expected True)
M3 loaner model not installed - cron correctly no-op'd
(no flag set, no activity posted, no error - the soft-dep guard works)
Bumped to 19.0.1.3.0.
Co-authored-by: Cursor <cursoragent@cursor.com>
74 lines
4.1 KiB
XML
74 lines
4.1 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<odoo>
|
|
<data noupdate="1">
|
|
|
|
<!-- Daily maintenance reminders at 30/7/1 days before due date. -->
|
|
<record id="cron_maintenance_due_reminders" model="ir.cron">
|
|
<field name="name">Fusion Repairs: Send maintenance due reminders</field>
|
|
<field name="model_id" ref="model_fusion_repair_maintenance_contract"/>
|
|
<field name="state">code</field>
|
|
<field name="code">model.cron_send_due_reminders()</field>
|
|
<field name="user_id" ref="base.user_root"/>
|
|
<field name="interval_number">1</field>
|
|
<field name="interval_type">days</field>
|
|
<field name="nextcall" eval="(DateTime.now().replace(hour=7, minute=0, second=0, microsecond=0) + timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
|
<field name="active" eval="True"/>
|
|
</record>
|
|
|
|
<!-- CL15: Escalate unacknowledged on-call pages every 5 minutes.
|
|
Pages older than fusion_repairs.on_call_escalate_minutes
|
|
(default 15) get re-paged to the next priority. -->
|
|
<record id="cron_on_call_escalate" model="ir.cron">
|
|
<field name="name">Fusion Repairs: Escalate unacknowledged on-call pages</field>
|
|
<field name="model_id" ref="model_fusion_repair_on_call_service"/>
|
|
<field name="state">code</field>
|
|
<field name="code">model.cron_escalate_unacknowledged()</field>
|
|
<field name="user_id" ref="base.user_root"/>
|
|
<field name="interval_number">5</field>
|
|
<field name="interval_type">minutes</field>
|
|
<field name="nextcall" eval="(DateTime.now() + timedelta(minutes=5)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
|
<field name="active" eval="True"/>
|
|
</record>
|
|
|
|
<!-- X2: Day-before visit reminders. Runs every morning at 08:00. -->
|
|
<record id="cron_day_before_reminders" model="ir.cron">
|
|
<field name="name">Fusion Repairs: Day-before visit reminders</field>
|
|
<field name="model_id" ref="repair.model_repair_order"/>
|
|
<field name="state">code</field>
|
|
<field name="code">model.cron_send_day_before_reminders()</field>
|
|
<field name="user_id" ref="base.user_root"/>
|
|
<field name="interval_number">1</field>
|
|
<field name="interval_type">days</field>
|
|
<field name="nextcall" eval="(DateTime.now().replace(hour=8, minute=0, second=0, microsecond=0) + timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
|
<field name="active" eval="True"/>
|
|
</record>
|
|
|
|
<!-- X4: Post-visit NPS. Runs hourly to send 24h after state=done. -->
|
|
<record id="cron_post_visit_nps" model="ir.cron">
|
|
<field name="name">Fusion Repairs: Send post-visit NPS emails</field>
|
|
<field name="model_id" ref="repair.model_repair_order"/>
|
|
<field name="state">code</field>
|
|
<field name="code">model.cron_send_post_visit_nps()</field>
|
|
<field name="user_id" ref="base.user_root"/>
|
|
<field name="interval_number">1</field>
|
|
<field name="interval_type">hours</field>
|
|
<field name="nextcall" eval="(DateTime.now() + timedelta(hours=1)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
|
<field name="active" eval="True"/>
|
|
</record>
|
|
|
|
<!-- M3: Offer loaner activity for long-running repairs. Runs daily. -->
|
|
<record id="cron_offer_loaner" model="ir.cron">
|
|
<field name="name">Fusion Repairs: Offer loaner for long-running repairs</field>
|
|
<field name="model_id" ref="repair.model_repair_order"/>
|
|
<field name="state">code</field>
|
|
<field name="code">model.cron_offer_loaner_for_long_repairs()</field>
|
|
<field name="user_id" ref="base.user_root"/>
|
|
<field name="interval_number">1</field>
|
|
<field name="interval_type">days</field>
|
|
<field name="nextcall" eval="(DateTime.now().replace(hour=8, minute=30, second=0, microsecond=0) + timedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
|
<field name="active" eval="True"/>
|
|
</record>
|
|
|
|
</data>
|
|
</odoo>
|