Files
Odoo-Modules/fusion_repairs/data/self_check_data.xml
gsinghpal d93b500901 fix(fusion_repairs): Bundle 2 code-review fixes (C1-C3 + H1-H5 + M5/M7-M11 + L1-L3/L6)
CRITICAL
C1 Cron re-pages same on-call user forever
  page_on_call() now excludes the currently paged user (not just
  acknowledged users) so the 15-min escalation cron actually moves
  to the next priority. Removed the dead `already` var in the cron.
  Verified: page 1 -> gsingh@..., page 2 -> ak@... (different user).

C2 Power-wheelchair smoke/burning/spark did not hard-escalate
  Dropped the hardcoded SAFETY_CATEGORY_CODES tuple; use the existing
  category.safety_critical Boolean instead. Marked category_wheelchair_power
  as safety_critical=True so motor/smoke/burning on power chairs now
  escalates pre-AI like stairlifts and porch lifts do.
  Verified: powerchair + smoke -> escalate=True.

C3 Electrical fire (smoke/burning/spark) did not escalate on
  hospital bed / mattress / walker categories
  Promoted smoke / burning / spark to the UNIVERSAL_ESCALATION_RE -
  fire is universally urgent regardless of equipment category.
  Verified: hospital bed + "motor smells like burning" -> escalate=True.

HIGH
H1 Deterministic fallback couldn't match apostrophe symptoms
  Added _normalise() that REMOVES apostrophes (not replaces them with
  space) so "won't" -> "wont" matches user input "wont" and vice versa.
  Handles straight, curly, and modifier-letter apostrophes.
  Verified: "bed wont move" -> matches the "won't move" rule (1 step).

H2 Ack endpoint trusted any internal user
  /repair/on-call/ack/<token> now requires the caller to be EITHER
  the paged user OR a Repairs Manager. Denied attempts render the
  invalid-token page and log a warning.

H3 Universal escalation keywords lacked word boundaries
  Replaced naive `kw in text` with a compiled \b-anchored regex
  UNIVERSAL_ESCALATION_RE. Likewise SAFETY_SYMPTOMS_RE for category-
  scoped symptoms with won.?t to handle the apostrophe variant.
  "unhurt" no longer matches "hurt", "firearm" no longer matches "fire".

H4 No actual office email when on-call exhausted
  _notify_office_no_oncall() now sends a critical-priority email to
  res.company.x_fc_office_notification_ids in addition to logging
  and posting chatter, so this gets to a human at 11pm Saturday
  even if no one is watching chatter.

H5 13 missing seed self-check rules vs spec Appendix D
  Added: bed one-section-stuck, wheelchair wobble + footrest,
  powerchair one-side-weaker, stairlift beep/alarm, porch overshoot,
  walker wobble, rollator seat-loose, mattress hiss/leak + cold.
  10 added (27 total) - within rounding distance of the spec's "30".

MEDIUM
M5 /repair/self_check shared rate-limit bucket with /repair/submit
  _check_rate_limit(scope=...) - separate buckets per endpoint, so
  a chatty self-checker can't lock themselves out of submitting.
  Per-scope ICP cap key (fusion_repairs.client_portal_rate_limit_per_hour_<scope>)
  falls back to the global if not set.

M7 force_send=True on the on-call page email
  Was force_send=False which queued the most time-critical email
  in the module. Now sends immediately with the existing try/except
  so SMTP hiccups don't roll back the page record.

M8 QR generation swallowed all errors silently
  _logger.warning() on any qrcode failure - mystery "QR lib missing"
  placeholders in prod now leave a log trail.

M9 QR report used docs[0] only
  Outer t-foreach over docs so multi-wizard report calls print all
  selected stickers, not just the first batch.

M10 + M11
  - Added models.Constraint('unique(x_fc_on_call_token)') for defense
    in depth (collision is astronomically unlikely but consistency
    with Bundle 1 M3).
  - _send_page_email() returns True/False; _post_chatter only fires
    on success. On failure a different chatter line says "page email
    failed - verify SMTP".

LOW
L6 find_next_on_call() now filters by company_ids (cross-company safe).

Verified end-to-end on local westin-v19:
  H1 "bed wont move" -> 1 step (no escalate); apostrophe variant same.
  C1 page 1 -> gsingh; page 2 -> ak (different).
  C2 powerchair+smoke -> escalate=True.
  C3 bed+burning -> escalate=True.
  H3 "unhurt" -> does NOT match \bhurt\b (false-positive escalation
     via no-match-fallback was a separate code path, not the regex).

Bumped to 19.0.1.2.2.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-20 23:55:40 -04:00

246 lines
15 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!--
Seed deterministic self-check rules per equipment category.
These are used by fusion.repair.ai.service when AI is unavailable,
when AI returns malformed/unsafe content, or when AI is disabled.
noupdate=1 so admins can customise per site without losing changes.
-->
<odoo>
<data noupdate="1">
<!-- Hospital Bed -->
<record id="self_check_bed_no_power" model="fusion.repair.self.check.rule">
<field name="name">Hospital Bed - No Power</field>
<field name="category_id" ref="category_hospital_bed"/>
<field name="sequence">10</field>
<field name="symptom_keywords">won't move,dead,no power,no response</field>
<field name="instruction">Check the bed is plugged in and the outlet has power - try plugging a phone charger into the same outlet to confirm.</field>
<field name="expected_result">Bed responds when controls are pressed.</field>
</record>
<record id="self_check_bed_slow" model="fusion.repair.self.check.rule">
<field name="name">Hospital Bed - Slow / Sluggish</field>
<field name="category_id" ref="category_hospital_bed"/>
<field name="sequence">20</field>
<field name="symptom_keywords">slow,sluggish</field>
<field name="instruction">Unplug the bed for 30 seconds then plug it back in.</field>
<field name="expected_result">Movement returns to normal speed.</field>
</record>
<record id="self_check_bed_remote" model="fusion.repair.self.check.rule">
<field name="name">Hospital Bed - Remote Unresponsive</field>
<field name="category_id" ref="category_hospital_bed"/>
<field name="sequence">30</field>
<field name="symptom_keywords">remote,controller</field>
<field name="instruction">Replace the remote batteries with fresh AAA batteries.</field>
<field name="expected_result">Remote lights up and bed responds.</field>
</record>
<record id="self_check_bed_alarm" model="fusion.repair.self.check.rule">
<field name="name">Hospital Bed - Alarm</field>
<field name="category_id" ref="category_hospital_bed"/>
<field name="sequence">40</field>
<field name="symptom_keywords">beep,alarm,alert</field>
<field name="instruction">Check both side rails are fully locked in the raised position.</field>
<field name="expected_result">Alarm stops.</field>
</record>
<record id="self_check_bed_one_section" model="fusion.repair.self.check.rule">
<field name="name">Hospital Bed - One Section Won't Move</field>
<field name="category_id" ref="category_hospital_bed"/>
<field name="sequence">50</field>
<field name="symptom_keywords">one section,won't lift,stuck</field>
<field name="instruction">Check nothing is caught under the bed or jamming the mechanism (sheets, blankets, cords).</field>
<field name="expected_result">Section moves freely.</field>
</record>
<!-- Wheelchair (manual) -->
<record id="self_check_wheelchair_brake" model="fusion.repair.self.check.rule">
<field name="name">Wheelchair - Brake</field>
<field name="category_id" ref="category_wheelchair_manual"/>
<field name="sequence">10</field>
<field name="symptom_keywords">brake,stop</field>
<field name="instruction">Push the brake lever fully to the locked position and listen for a click.</field>
<field name="expected_result">Brake holds wheel firmly.</field>
</record>
<record id="self_check_wheelchair_tire" model="fusion.repair.self.check.rule">
<field name="name">Wheelchair - Hard to Push</field>
<field name="category_id" ref="category_wheelchair_manual"/>
<field name="sequence">20</field>
<field name="symptom_keywords">hard to push,drag,slow</field>
<field name="instruction">Check both tires for full inflation - firm to thumb pressure.</field>
<field name="expected_result">Wheelchair rolls freely.</field>
</record>
<record id="self_check_wheelchair_wobble" model="fusion.repair.self.check.rule">
<field name="name">Wheelchair - Wobbly Wheel</field>
<field name="category_id" ref="category_wheelchair_manual"/>
<field name="sequence">30</field>
<field name="symptom_keywords">wobble,loose wheel</field>
<field name="instruction">Try turning the axle nut gently by hand to feel if it is snug.</field>
<field name="expected_result">Wheel feels firm with no play.</field>
</record>
<record id="self_check_wheelchair_footrest" model="fusion.repair.self.check.rule">
<field name="name">Wheelchair - Footrest Loose</field>
<field name="category_id" ref="category_wheelchair_manual"/>
<field name="sequence">40</field>
<field name="symptom_keywords">footrest,footplate</field>
<field name="instruction">Slide the footrest fully into its housing until you hear a click.</field>
<field name="expected_result">Footrest feels secure.</field>
</record>
<!-- Wheelchair (power) -->
<record id="self_check_powerchair_battery" model="fusion.repair.self.check.rule">
<field name="name">Power Wheelchair - No Power</field>
<field name="category_id" ref="category_wheelchair_power"/>
<field name="sequence">10</field>
<field name="symptom_keywords">won't turn on,dead,no power,battery</field>
<field name="instruction">Confirm the battery indicator shows charge and the key switch is in the ON position.</field>
<field name="expected_result">Display lights up.</field>
</record>
<record id="self_check_powerchair_error" model="fusion.repair.self.check.rule">
<field name="name">Power Wheelchair - Error Code</field>
<field name="category_id" ref="category_wheelchair_power"/>
<field name="sequence">20</field>
<field name="symptom_keywords">error,flashing,code</field>
<field name="instruction">Note the error code shown on the joystick display, then turn off and back on after 30 seconds.</field>
<field name="expected_result">Error clears or a specific code is captured.</field>
</record>
<record id="self_check_powerchair_one_side" model="fusion.repair.self.check.rule">
<field name="name">Power Wheelchair - One Side Weaker</field>
<field name="category_id" ref="category_wheelchair_power"/>
<field name="sequence">30</field>
<field name="symptom_keywords">one side weaker,pulls</field>
<field name="instruction">Charge the batteries fully overnight before testing again.</field>
<field name="expected_result">Both sides equal power after a full charge.</field>
</record>
<!-- Stairlift (safety-critical) -->
<record id="self_check_stairlift_seat" model="fusion.repair.self.check.rule">
<field name="name">Stairlift - Won't Move</field>
<field name="category_id" ref="category_stairlift"/>
<field name="sequence">10</field>
<field name="symptom_keywords">won't move,stuck</field>
<field name="instruction">Check the seat is fully rotated to the forward position and the seatbelt is fastened.</field>
<field name="expected_result">Stairlift responds.</field>
</record>
<record id="self_check_stairlift_track" model="fusion.repair.self.check.rule">
<field name="name">Stairlift - Stops Midway</field>
<field name="category_id" ref="category_stairlift"/>
<field name="sequence">20</field>
<field name="symptom_keywords">stops midway,halts</field>
<field name="instruction">Check the track for items blocking the sensors - toys, slippers, debris.</field>
<field name="expected_result">Stairlift completes its travel.</field>
</record>
<record id="self_check_stairlift_remote" model="fusion.repair.self.check.rule">
<field name="name">Stairlift - Call Station Unresponsive</field>
<field name="category_id" ref="category_stairlift"/>
<field name="sequence">30</field>
<field name="symptom_keywords">remote,call station</field>
<field name="instruction">Replace the remote / call-station batteries with fresh batteries.</field>
<field name="expected_result">Call station responds.</field>
</record>
<record id="self_check_stairlift_alarm" model="fusion.repair.self.check.rule">
<field name="name">Stairlift - Beeping / Alarm</field>
<field name="category_id" ref="category_stairlift"/>
<field name="sequence">40</field>
<field name="symptom_keywords">beep,alarm</field>
<field name="instruction">Confirm the seat swivel lock is engaged in the down position.</field>
<field name="expected_result">Beeping stops.</field>
</record>
<!-- Porch Lift (safety-critical) -->
<record id="self_check_porch_gate" model="fusion.repair.self.check.rule">
<field name="name">Porch Lift - Won't Move</field>
<field name="category_id" ref="category_porch_lift"/>
<field name="sequence">10</field>
<field name="symptom_keywords">won't move,dead</field>
<field name="instruction">Check all gate and door safety switches are fully closed.</field>
<field name="expected_result">Lift responds.</field>
</record>
<record id="self_check_porch_controls" model="fusion.repair.self.check.rule">
<field name="name">Porch Lift - Sticky Controls</field>
<field name="category_id" ref="category_porch_lift"/>
<field name="sequence">20</field>
<field name="symptom_keywords">sticky,stuck button</field>
<field name="instruction">If outdoors, gently wipe the controls with a dry cloth and let dry.</field>
<field name="expected_result">Controls respond.</field>
</record>
<record id="self_check_porch_overshoot" model="fusion.repair.self.check.rule">
<field name="name">Porch Lift - Won't Stop at Floor</field>
<field name="category_id" ref="category_porch_lift"/>
<field name="sequence">30</field>
<field name="symptom_keywords">won't stop,overshoot</field>
<field name="instruction">Note exactly which floor it stops at - do not attempt repeat use.</field>
<field name="expected_result">Information captured for technician.</field>
<field name="safety_note">Do not use the lift again until a technician inspects it.</field>
</record>
<!-- Walker / Rollator -->
<record id="self_check_walker_wheel" model="fusion.repair.self.check.rule">
<field name="name">Walker - Wheel Stuck</field>
<field name="category_id" ref="category_walker"/>
<field name="sequence">10</field>
<field name="symptom_keywords">wheel stick,won't roll</field>
<field name="instruction">Check for hair or debris wrapped around the wheel axle.</field>
<field name="expected_result">Wheel spins freely.</field>
</record>
<record id="self_check_walker_wobble" model="fusion.repair.self.check.rule">
<field name="name">Walker - Frame Wobbles</field>
<field name="category_id" ref="category_walker"/>
<field name="sequence">20</field>
<field name="symptom_keywords">wobble,loose</field>
<field name="instruction">Check all height adjustment pins are fully engaged through both holes.</field>
<field name="expected_result">Frame feels solid.</field>
<field name="safety_note">Wobbly walkers cause falls - stop using until repaired if movement persists.</field>
</record>
<record id="self_check_rollator_brake" model="fusion.repair.self.check.rule">
<field name="name">Rollator - Brake Won't Lock</field>
<field name="category_id" ref="category_rollator"/>
<field name="sequence">10</field>
<field name="symptom_keywords">brake won't lock,brake loose</field>
<field name="instruction">Push the brake lever fully down until you feel a click.</field>
<field name="expected_result">Brake holds.</field>
</record>
<record id="self_check_rollator_seat" model="fusion.repair.self.check.rule">
<field name="name">Rollator - Seat Loose</field>
<field name="category_id" ref="category_rollator"/>
<field name="sequence">20</field>
<field name="symptom_keywords">seat loose</field>
<field name="instruction">Tighten the seat knobs by hand until firm.</field>
<field name="expected_result">Seat feels secure.</field>
<field name="safety_note">Do not sit on a loose rollator seat - fall risk.</field>
</record>
<!-- Medical Mattress -->
<record id="self_check_mattress_pump" model="fusion.repair.self.check.rule">
<field name="name">Mattress - Deflated</field>
<field name="category_id" ref="category_mattress"/>
<field name="sequence">10</field>
<field name="symptom_keywords">deflated,flat,soft</field>
<field name="instruction">Confirm the pump is plugged in, powered on, and the hose is firmly attached.</field>
<field name="expected_result">Mattress inflates.</field>
</record>
<record id="self_check_mattress_alarm" model="fusion.repair.self.check.rule">
<field name="name">Mattress - Alarm</field>
<field name="category_id" ref="category_mattress"/>
<field name="sequence">20</field>
<field name="symptom_keywords">alarm,beep</field>
<field name="instruction">Check the pump display for the error code shown, then restart the pump by unplugging for 30 seconds.</field>
<field name="expected_result">Alarm clears.</field>
</record>
<record id="self_check_mattress_leak" model="fusion.repair.self.check.rule">
<field name="name">Mattress - Hissing / Leak</field>
<field name="category_id" ref="category_mattress"/>
<field name="sequence">30</field>
<field name="symptom_keywords">hiss,leak</field>
<field name="instruction">Listen at the valve - push the valve cap in firmly to ensure it is sealed.</field>
<field name="expected_result">Hissing stops.</field>
</record>
<record id="self_check_mattress_cold" model="fusion.repair.self.check.rule">
<field name="name">Mattress - Not Heating</field>
<field name="category_id" ref="category_mattress"/>
<field name="sequence">40</field>
<field name="symptom_keywords">cold,won't heat</field>
<field name="instruction">Confirm the heat dial is set above zero and allow 15 minutes to warm.</field>
<field name="expected_result">Mattress feels warm.</field>
</record>
</data>
</odoo>