341 Commits

Author SHA1 Message Date
gsinghpal
b187192c58 feat(step-library): full plating workflow coverage + per-recipe configurability + audit
Implements 2026-04-29-step-library-audit-design.md. Bumps fusion_plating
to 19.0.18.7.0, fusion_plating_jobs to 19.0.8.12.0, fusion_plating_reports
to 19.0.10.2.0.

LIBRARY EXPANSION
- 8 new Step Kinds: Receiving, Electroclean, Strike, Salt Spray,
  Adhesion Test, Hardness Test, Packaging, Tank Replenishment
- 4 new input types: photo, multi_point_thickness, bath_chemistry_panel, ph
- DEFAULT_INPUTS_BY_KIND rewritten to seed audit-grade prompts on every
  kind (bath IDs, photos, multi-point thickness, signatures, etc.)
- + Common Audit Fields one-click button on the library template form
- Default Operator Instructions relabel + alert callout

PER-RECIPE CONFIGURABILITY
- collect (Boolean) per recipe-step input prompt — opt out without delete
- collect_measurements (Boolean) master switch on recipe step — when off,
  wizard skips entirely
- template_input_id (Many2one) traceability link from recipe to library
- Recipe-step backend form view exposes the new fields with handle drag,
  toggle, target range, and library-source column

RUNTIME WIRING
- Step input wizard filters node.input_ids to step_input AND collect=True;
  short-circuits on collect_measurements=False
- New input types: photo (image widget + ir.attachment), multi-point
  thickness (5 readings + auto avg, skips empty cells), bath chemistry
  panel (pH/conc/temp/bath bundle), pH (0-14 numeric)
- Composite values JSON-serialized into value_text; photo via attachment

CoC REPORT
- Filters captured prompts to collect=True only
- Renders new input types with appropriate format

MIGRATION (post-migrate.py for 19.0.18.7.0)
- Backfills collect=True on recipe-step inputs
- Backfills collect_measurements=True on recipe steps
- Re-runs action_seed_default_inputs on every existing template
  (idempotent, preserves user edits)
- Backfills template_input_id by name-matching against source library
  template (handles JSONB vs varchar name columns)

SEED DATA
- 8 example templates (one per new kind) in fp_step_template_data.xml
  with noupdate=1

BATTLE TEST
- bt_step_library_audit.py: 29 assertions all PASS on entech

OWL EDITOR EXTENSION DEFERRED
- The simple recipe editor's per-step Instructions/Measurements
  expansions were not implemented in this pass; users configure via the
  backend recipe-step form. Track follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 22:13:54 -04:00
gsinghpal
bbf2476f01 plan(step-library): full implementation plan for audit expansion + per-recipe configurability
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 21:56:18 -04:00
gsinghpal
9401afb21d spec(step-library): full plating workflow coverage + per-recipe configurability + audit
Adds 8 new Step Kinds (Receiving, Electroclean, Strike, Salt Spray,
Adhesion Test, Hardness Test, Packaging, Replenishment) with industry-
standard default measurements. Adds 4 new input types (photo,
multi_point_thickness, bath_chemistry_panel, ph). Beefs up existing
kinds (cleaning, etch, plate, bake, ship, etc.) with bath ID, photos,
multi-point thickness, signatures.

Per-recipe configurability: each recipe step can disable, rename,
retarget, reorder prompts; add custom prompts; toggle entire-step
data collection. Library is the smart default; recipe is final say.

Office-to-operator instructions: relabel as Default Operator
Instructions in the library; per-recipe override surfaced in the
simple recipe editor; falls back to library default at runtime when
recipe override is empty.

Battle test plan covers 18 assertions end-to-end on entech.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 21:48:12 -04:00
gsinghpal
df43737b1b spec(deadlines): per-part effective deadlines with customer-profile cascade
Resolution chain: explicit override → days offset → part lead time → order
commitment. Adds x_fc_default_lead_time_days on part catalog; per-line
effective_part_deadline + effective_internal_deadline computes; order-level
completion_date rollup + is_late_forecast warning.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 21:08:21 -04:00
gsinghpal
a2fe1fcbcc changes 2026-04-29 03:35:33 -04:00
gsinghpal
6ac6d24da6 CHANGES 2026-04-28 19:43:16 -04:00
gsinghpal
2a9fd478f5 Update fp_racking_inspection_views.xml 2026-04-28 19:42:41 -04:00
gsinghpal
13e300d90e changes 2026-04-28 19:39:37 -04:00
gsinghpal
2d42b33d68 docs(claude.md): log Sub 12a/12b/12c + Phase 1/2/3 menu reorg + ergo fixes
Records full session work for future Claude Code sessions:

Sub 12a — Simple Recipe Editor + Step Library
  3 new models, additive fields on process.node + node.input,
  fp_simple_recipe_editor OWL action with drop-position simulator,
  11 JSONRPC endpoints, snapshot semantics, post_init seeding.

Sub 12b — Move Parts / Move Rack / Rack Parts / Stop Timer dialogs
  fp.rack.tag, fp.job.step.move + .input.value, racking_state on
  fusion.plating.rack (orthogonal to wear state), state machine on
  existing fp.job.step.timelog (no parallel labor model), 12 tablet
  endpoints, 4 OWL dialogs with fp-resolve-rack custom event,
  manager-bypass flags, plant overview Racks pane.

Sub 12c — Reports + Labor History
  Operator Traveller v2 (A4 landscape, paper-style), chronological
  CoC body via fp.certificate.body_style + coc_body_router,
  Labor History views, gap-fix bundle (rack travel ticket PDF,
  per-customer cert statement 3-tier resolution, captured Actual
  values from move.input.value).

Phase 1/2/3 — Menu reorganization
  Top-level: 17 → 6 (operator-visible). Industry verticals nested
  under Compliance hub. Move Log/Labor History/Maintenance under
  Operations. Certificates under Quality.
  Configuration: 36 flat → 7 themed folders + Settings sibling.
  Group-gating: KPIs/Move Log/Replenishment Suggestions →
  supervisor+. Operator now sees ~5 top-levels instead of ~10.

Landing page resolver
  action_fp_resolve_plating_landing server action, user override →
  company default → Sale Orders fallback. x_fc_pickable_landing
  Boolean tag for curated picklist.

Production Line / Routing Station rename
  fusion.plating.work.center → 'Production Line' (shop-layout, owns
  tanks). fp.work.centre → 'Routing Station' (per-step routing,
  cost-per-hour, mrp.workcenter replacement). Model IDs unchanged.

Other ergonomics
  Tank field labels (Code → Tank Number, Tank → Tank Name) +
  state-control header buttons. SO smart-button 'Plating Jobs' → 'WO'.
  Default landing screen = Sale Orders.
  Drop-position simulator in Simple Recipe Editor.

Updated 'Menu Structure' section near top of CLAUDE.md to reflect
new 6-top-level layout + 7-folder Configuration grouping.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 23:06:25 -04:00
gsinghpal
afcd128f83 fix: rename ambiguous 'Work Center' / 'Work Centres' menus
Two distinct entities were both labelled 'Work Centre' (US/UK spelling
the only differentiator — confusing). Renamed by purpose, model IDs
unchanged so all 12+9 existing cross-refs keep working:

fusion.plating.work.center → 'Production Line'
  Physical shop-layout grouping that owns tanks. Examples: 'Line 1 —
  EN', 'Anodize Line', 'Prep Bay'. Has tank_ids (O2M),
  supported_process_ids (M2M), capacity_per_day. The thing tanks live
  in.

fp.work.centre → 'Routing Station'
  Per-job-step routing entity (post-Sub-11 mrp.workcenter replacement).
  Has 'kind' selection (wet_line / bake / mask / rack / inspect),
  cost_per_hour for fp.job.step rollup, default_bath_id +
  default_tank_id for release-ready validation. The thing a job step
  routes through.

Conceptually a Production Line CONTAINS many Routing Stations (e.g.
'EN Line' production line has wet-line, bake, inspect routing
stations on it).

Updated:
- _description on both models
- string= on the name fields
- list/form/search view strings
- act_window names ('Production Lines' / 'Routing Stations')
- menu items in fp_menu.xml + fp_jobs_menu.xml
- doc comments in both model files explaining the distinction

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:55:39 -04:00
gsinghpal
5f6c7af2a7 feat(phase3): tighten group-gating on operator-irrelevant top-levels
Three targeted gates so operators no longer see admin/audit views:

- KPIs (menu_fp_dashboard) → supervisor+. Operators don't need
  dashboards; their tablet shows what they need to do next.
- Move Log (menu_fp_job_step_move) → supervisor+. Operators see
  their own moves on the tablet; this top-level menu is the
  audit-of-everyone-else view.
- Replenishment Suggestions (menu_fp_replenishment_suggestions) →
  supervisor+. Purchasing decision, not operator concern.

Other top-levels were already correctly gated:
- Sales / Configurator → estimator
- Shipping & Receiving → group_fp_receiving
- Compliance hub → supervisor+
- Configuration → manager
- Shop Floor / Quality → operator (correctly visible to floor staff)
- Operations parent stays open; child menus enforce per-action gates

Net effect: a fresh operator now sees ~5 top-level menus instead of
the previous ~10. Supervisors see ~8. Managers see all.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:51:30 -04:00
gsinghpal
46715410a9 fix(phase2): restructure fp_menu.xml so buckets defined before children
Within fp_menu.xml itself, the menu_fp_replenishment_rules entry
referenced menu_fp_config_materials_tanks which was defined later in
the same file. Odoo's data loader is strictly top-down within a file.

Reorganized by section: 1) root, 2) Configuration + 7 buckets,
3) Compliance hub, 4) Operations parent, 5) all child menus (referencing
parents already defined above).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:48:06 -04:00
gsinghpal
62c1315997 fix(phase2): load fp_menu.xml first so bucket folders exist before refs
fp_rack_tag_views.xml (and several other view files) reference the
new Phase-2 Configuration sub-folder menus (menu_fp_config_*) defined
in fp_menu.xml. Odoo's data loader is strictly sequential within a
module, so fp_menu.xml must come before any file that references
its bucket xmlids.

Caught by entech upgrade (ParseError on rack-tag menuitem).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:46:53 -04:00
gsinghpal
3641b78a66 feat(phase2): Configuration grouped into 7 themed folders
Collapses the flat ~36-entry Configuration list into 7 navigable
folders + Settings (sibling, stays at top of Configuration). Existing
menu IDs unchanged so bookmarks + cross-module data refs still work
— only parent-id moves.

New folder menus (defined in fusion_plating core):
  menu_fp_config_shop_setup       Shop Setup
  menu_fp_config_recipes_steps    Recipes & Steps
  menu_fp_config_materials_tanks  Materials & Tanks
  menu_fp_config_workforce        Workforce
  menu_fp_config_quality_docs     Quality & Documents
  menu_fp_config_pricing_billing  Pricing & Billing
  menu_fp_config_reference_data   Reference Data

Routing per item (sources updated in their owning module):
  Shop Setup       Facilities, Work Centers, Work Centres, Process
                   Categories, Process Types, Bake Ovens, Shopfloor
                   Stations, Vehicles
  Recipes & Steps  Step Library, QC Checklist Templates, Quality Points
  Materials & Tanks  Bath Parameters, Replenishment Rules, Chemicals,
                     Rack Tags, Calibration Equipment, Calibration Events
  Workforce        Operator Certifications, Shop Roles, Training Types,
                   Quality Teams
  Quality & Documents  Customer Specs, Approved Vendor List, Quality
                       Tags, Quality Reasons, Quality Stages, N299
                       Levels, Notification Templates, Notification Log
  Pricing & Billing  Invoice Strategy Defaults, Account Holds
  Reference Data   Value Sets, Value Rotations
  (Settings remains as a sibling at top of Configuration, manager-gated)

Versions bumped: fusion_plating, fusion_plating_quality, _safety,
_shopfloor, _logistics, _culture, _invoicing, _notifications, _nuclear.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:45:21 -04:00
gsinghpal
0ad382e1a6 feat(phase1): top-level menu consolidation + landing-page resolver
Phase 1 collapses the Plating app's 17 top-level menus down to 6
domains (Sales, Operations, Receiving & Shipping, Quality,
Compliance, Configuration) so users no longer scroll a 17-item
sidebar to find one thing.

Re-parented (no XML id changes — bookmarks still work):
- fusion_plating_compliance.menu_fp_compliance_root
    → menu_fp_compliance_hub  (renamed 'General')
- fusion_plating_safety.menu_fp_safety_root
    → menu_fp_compliance_hub  (renamed 'Safety / WHMIS')
- fusion_plating_aerospace.menu_fp_aerospace
    → menu_fp_compliance_hub  (renamed 'Aerospace (AS9100 / Nadcap)')
- fusion_plating_nuclear.menu_fp_nuclear
    → menu_fp_compliance_hub  (renamed 'Nuclear (CSA N299 / CNSC)')
- fusion_plating_cgp.menu_fp_cgp
    → menu_fp_compliance_hub  (renamed 'Controlled Goods (CGP)')
- fusion_plating_certificates.menu_fp_certificates
    → menu_fp_quality (Certs are a Quality output, not a separate
      top-level concern)
- fusion_plating_bridge_maintenance.menu_fp_maintenance
    → menu_fp_operations
- fusion_plating.menu_fp_job_step_move (Move Log)
    → menu_fp_operations
- fusion_plating.menu_fp_job_step_timelog (Labor History)
    → menu_fp_operations

The new menu_fp_compliance_hub is supervisor-gated; underlying
verticals retain their own group locks (CGP officer, etc.).

Settings menu remains manager-gated through inheritance from
menu_fp_config (already in place).

NEW — Plating landing-page resolver:
- ir.actions.act_window.x_fc_pickable_landing  (Boolean tag for
  curated picklist; flagged on Sale Orders, Quotations, Process
  Recipes for Phase 1; more in Phase 2)
- res.company.x_fc_default_landing_action_id (admin sets fallback)
- res.users.x_fc_plating_landing_action_id (per-user override)
- ir.actions.server action_fp_resolve_plating_landing — picks
  user → company → Sale Orders fallback at click time
- menu_fp_root rewired to call the resolver
- User profile + Settings tabs surface the dropdowns

Configurator's earlier menu_fp_root override (action_fp_sale_orders
direct) removed — core's resolver now owns the routing.

Versions bumped: fusion_plating 19.0.11.0.0, configurator
19.0.17.16.0, plus 7 dependent modules patched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:33:37 -04:00
gsinghpal
3098fcfaf9 feat(sub12a+): drop-position simulator in Simple Recipe Editor
Replaces the per-row 'highlight whole row' feedback (operator
couldn't tell whether the new step would land before or after the
hovered row) with a precise insertion-point indicator.

How it works:
- Each row's onDragOver computes ev.clientY vs row midpoint.
  Above midpoint → insertion index = rowIndex (BEFORE).
  Below midpoint → insertion index = rowIndex + 1 (AFTER).
- An <o_fp_drop_indicator> div lives BEFORE the first row and
  AFTER every row. When state.dragOverIndex matches that slot's
  index, the div expands from height:0 to a 2.25rem dashed-green
  reservation strip with a ghost-preview chip ('↓ insert here →
  <icon> <step name>').
- onDragStart captures the dragged step/template's name + icon
  into state.dragPreviewLabel/Icon for the chip text.
- Smooth 80ms height/margin transition so the line glides between
  slots as the cursor moves rather than blinking.
- Trailing dropzone retains its existing 'Drop here to add at end'
  styling. Empty list shows 'Drag a library step here to start'.
- onDrop reads from state.dragOverIndex (set by the most-recent
  onDragOver) so we drop at the simulated position exactly.
- onDragLeave guards against child-element flicker via
  relatedTarget contains() check.
- onDragEnd clears state.dragPreviewLabel/Icon so a half-completed
  drag (cancelled by Esc) doesn't leave the chip stuck on screen.

fusion_plating → 19.0.10.4.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:08:51 -04:00
gsinghpal
7d3b8f132a fix(sub12c+): close 3 known gaps — rack travel ticket, cert statement, CoC actuals
Gap 1 — Rack Travel Ticket PDF (Sub 12b's Save+Print 404):
  + report_fp_rack_travel.xml in fusion_plating_reports — A5 landscape
    single page, big rack name, Code 128 of FP-RACK:<name>, tag chips,
    contained part-batches table.
  + ir.actions.report bound to fusion.plating.rack so it appears in
    the rack form's Print menu too.
  + Sub 12b's rack_parts_dialog.js Save+Print URL fixed to use the
    standard /report/pdf/<xmlid>/<id> route.

Gap 2 — Per-customer cert statement:
  + res.company.x_fc_default_cert_statement (company-level fallback).
  + res.partner.x_fc_cert_statement (per-customer override).
  + Surfaced on the partner form under the existing Cert + Document
    Routing block.
  + Chronological CoC body resolves: customer override → company
    default → hardcoded AS9100/ISO 9001 boilerplate. Three-tier
    fallback so existing certs without overrides keep working.

Gap 3 — Chronological CoC 'Actual' column:
  + Build a captured_values_by_input dict from the move's
    transition_input_value_ids (Sub 12b captures these on every
    Move Parts commit).
  + Render typed Actual: text → as-is, number → with target unit,
    boolean → PASS/FAIL, date → formatted, attachment → '[Attachment]'
    placeholder.
  + Falls back to prompts from the destination step's step_input list
    when no values were captured (still useful as audit-of-what-was-
    asked even if blank).

Version bumps:
  fusion_plating → 19.0.10.3.0
  fusion_plating_reports → 19.0.10.1.0
  fusion_plating_certificates → 19.0.5.3.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:55:48 -04:00
gsinghpal
504c8f34db feat(sub12c): Labor History views + Plating menu (Task 4)
Plating → Labor History (sequence 64, between Move Log 62 and
Aerospace 65). List view colour-coded by state (info/warning/
success/muted), with billed_pct progressbar and rich field optionals.

Search filters: My Timers (default), Today, Running, Paused, Pending
Reconciliation, Reconciled. Group-by: Operator, Job, Date.

Form view (read-only header with statusbar): identity fields readonly,
billed_hrs/min/sec editable for supervisors+ until state=reconciled.
Notes group at bottom. create=false (timers are runtime-produced;
manual creation goes through the tablet flow).

ACL rows for fp.job.step.timelog already shipped in Sub 12b's CSV
(operator/supervisor/manager) — no security changes needed here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:43:07 -04:00
gsinghpal
9d88c25136 feat(sub12c): chronological CoC body + body_style opt-in router (Task 3)
New template: fusion_plating_reports.coc_body_chronological.
Walks fp.job.step.move records in time order (chain-of-custody).
Per-move heading 'Step Name (Tank Code)' with 'Moved By / Time / Qty'
meta line + a 5-column measurement sub-table (Name / Description /
Target / Actual / Recorded By) when the destination step has captured
inputs. Heading-only when there are no inputs (gating moves).

New router template: coc_body_router. Picks chronological vs classic
based on fp.certificate.body_style. Existing certs default to 'classic'
so no regressions. Both English + French CoC templates rerouted.

fp.certificate.body_style ('classic' | 'chronological') exposed on
the cert form alongside certified_by_id. Operator picks per cert.

Sign-off block reuses the existing owner_user_id signature pattern +
x_fc_coc_signature_override fallback. Cert statement boilerplate is
inline (Sub 12d will move it to a configurable per-customer field).

The Actual column in the measurement sub-table is rendered blank
because Sub 12a/12b runtime captures step_input values via the
operator's per-step input form which lives in a model not yet wired
into this template — Sub 12d follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:42:03 -04:00
gsinghpal
12fcd11016 feat(sub12c): operator traveller v2 — paper-style A4 landscape (Task 2)
Replaces the minimal portrait template with the Amphenol-style paper
sheet (screens 16-18):
- Header: company logo + barcode (Code 128) + WO# + Date In + Due
  Date + Type + Order# + PO# + WO-Generated-By + customer block.
- Item Information panel: Part# / Rev / Mat / Catg / S/N + Item-Name +
  Qty Rec / VIS INSP / Rework / Special Requirements / Stamp-Date.
- Process-Sheet header: recipe name + category + spec/info.
- Routing table (11 cols): Step / Tank / Operation+Actuals (recipe
  inputs render as 'Actual <name>: ____ unit' lines) / Instruction /
  Unit / Material / Voltage / Time(min) / Temp / Stamp / Date.

Targets pulled from recipe-node fields when present (Sub 12a authored),
'N/A' otherwise. Heavily defensive QWeb — every cross-module field
access ('part_catalog_id' / 'coating_config_id' / 'qty_received' /
'special_requirements' / 'serial_number' / 'base_material' /
'customer_facing_description' / 'time_min_target' / etc.) guarded with
'X in record._fields' checks so the report renders cleanly even when
some Sub 12a/12b fields aren't yet populated.

New paperformat: A4 landscape narrow margins, 90 dpi.

Action ID + report_name unchanged so existing form-button bindings
keep working (binding_model_id still points at fp.job).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:39:41 -04:00
gsinghpal
f55193fb1b feat(sub12c): bump versions + manifest scaffolding (Task 1)
fusion_plating → 19.0.10.2.0 (Labor History views)
fusion_plating_jobs → 19.0.7.0.0 (Operator Traveller v2)
fusion_plating_reports → 19.0.10.0.0 (Chronological CoC body)

Adds data entries for the 2 new XML files (timelog views + coc
chronological).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:37:24 -04:00
gsinghpal
34528a5d3d docs(sub12c): implementation plan — 5 tasks (down from original 18)
Tightened from the original 18-task plan after inspecting existing
templates:
- report_coc_en / report_coc_fr already exist with Nadcap/AS9100/CGP
  logos, signature, certified_by — solid. Add a chronological body
  alongside, don't rebuild.
- company.x_fc_nadcap_logo etc already exist on res.company. Skip.
- The native fp.job traveller is minimal (post-Sub-11) and needs the
  paper-style upgrade. Replace its body, not the action.
- fp.job.step.timelog state machine landed in Sub 12b — Sub 12c just
  ships views + menu.

5-task breakdown:
1. Bump versions + manifest scaffolding
2. Operator Traveller v2 (A4 landscape, paper-style, target columns)
3. Chronological CoC body + body_style opt-in router
4. Labor History list/form/search + Plating menu
5. Deploy to entech + smoke test

Out of scope: rack travel ticket PDF (Sub 12b's Save+Print 404 stays
flagged), per-customer cert statement (boilerplate inline for now).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:36:06 -04:00
gsinghpal
e718a47e3e fix(sub12b): to_step_id required → ondelete='restrict'
Odoo 19 disallows ondelete='set null' on a required M2O. Switched to
restrict — destination steps can't be unlinked while move-log rows
reference them, which is the right audit-safety behavior anyway.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:19:58 -04:00
gsinghpal
11dbbf578e feat(sub12b): plant overview Racks pane (Task 16)
Controller: extend /fp/shopfloor/plant_overview return payload to
include 'racks' array (filtered to loaded/in_use/awaiting_unrack
states). Each entry has tag chips, part count, current node
breadcrumb, current step + tank code, and a precomputed
next_step_id (next sequence in the job's recipe — operator
overrides at runtime in the Move Rack dialog).

JS: state.racks populated from payload. New openMoveRackDialog()
method spawns FpMoveRackDialog. Notification when rack has no
successor (last step of job).

XML: top section above the existing work-centre columns. Renders
rack rows with tags, part count, breadcrumb, and primary MOVE RACK
button per row. Visible only when state.racks.length > 0.

SCSS: minimal styling for the racks pane (extends move_dialogs.scss
to keep all Sub 12b styles in one file).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:19:05 -04:00
gsinghpal
902f3e8398 feat(sub12b): wire Move Parts + Stop Timer dialogs into tablet (Task 15)
ShopfloorTablet component:
- Imports the 3 new OWL dialogs.
- useService('dialog') for spawning.
- Listens for 'fp-resolve-rack' window CustomEvent fired from inside
  FpMovePartsDialog → spawns FpRackPartsDialog inline.
- New methods: openMovePartsDialog(from, to) + openStopTimerDialog(id).
  Refresh tablet after commit/reconcile so the UI reflects new state.

Listener cleanup on unmount.

Note: the actual buttons that call these methods are added to the
existing tablet XML in a follow-up step — for now they are wired but
not surfaced. Operators get them after Task 16 + smoke test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:16:15 -04:00
gsinghpal
11bc0ca742 feat(sub12b): shared SCSS for Move/Rack/Timer dialogs (Task 14)
3-column grid layout for field rows (label / input / hint).
Compliance prompts + Blockers blocks have their own backgrounds.
Soft blockers amber + left border, hard blockers red + left border —
matches the spec's protocol.

Token pattern + dark-mode @if branch (CLAUDE.md rule: Odoo 19 doesn't
flip dark mode via runtime DOM class; we branch at SCSS compile time
on $o-webclient-color-scheme).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:15:12 -04:00
gsinghpal
270f427d7f feat(sub12b): Move Rack + Stop Timer OWL dialogs (Task 13)
Move Rack: rack name in title via getter, tag chips, batches list
(read-only), Type + To Node + To Station picker. Atomic Save commits
all batches via /fp/tablet/move_rack/commit.

Stop Timer: opens with state already at 'stopped' (server flipped on
load via /labor_timer/stop), pre-fills billed_* from accrued.
Operator edits → Save (state → reconciled).

Save & Start New Timer chains into a fresh timer for the same step
via the start_new=True flag — mirrors screen 10's right-most button.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:14:30 -04:00
gsinghpal
48c06c40c9 feat(sub12b): OWL Rack Parts sub-dialog (Task 12)
Mirrors screens 7-8. Searchable empty-rack picker with debounced
typeahead via /fp/tablet/rack/list_empty. QR Scan button prompts
operator for FP-RACK:<name> token, resolves via /fp/tablet/rack/
scan_qr.

Save commits the racking via /fp/tablet/rack_parts/commit. Save+Print
opens /web/report/pdf/fp.rack.travel/<id> in a new tab — that report
ships in Sub 12c, returns 404 until then. Plain Save works today.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:13:04 -04:00
gsinghpal
6d046f2881 feat(sub12b): OWL Move Parts dialog (Task 11)
Mirrors Steelhead screens 1-3, 14-15. Loads preview on mount,
re-checks hard-blockers on commit. MOVE (n) button disabled when
hard-blocked OR required prompt blank — improvement over Steelhead's
silent disabled state (we show a tooltip listing reasons).

Inline 'Resolve' button next to each blocker. For rack-required,
fires a window CustomEvent ('fp-resolve-rack') the parent tablet
catches to open the Rack Parts sub-dialog.

Typed input rendering by input_type — text/number/checkbox/select/
datetime, plus support for time_hms and signature/photo (text input
for now; full upload widget in Sub 12c).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:11:49 -04:00
gsinghpal
a521b7c37b feat(sub12b): consolidated tablet controller — Move/Rack/Timer (Tasks 8-10+17)
11 routes (consolidated from plan Tasks 8/9/10/17):
  Move Parts:
    /fp/tablet/move_parts/preview
    /fp/tablet/move_parts/commit
  Move Rack:
    /fp/tablet/move_rack/preview
    /fp/tablet/move_rack/commit
  Rack Parts:
    /fp/tablet/rack_parts/commit
    /fp/tablet/rack/list_empty
    /fp/tablet/rack/scan_qr
  Persistent labor timer:
    /fp/tablet/labor_timer/start
    /fp/tablet/labor_timer/pause
    /fp/tablet/labor_timer/resume
    /fp/tablet/labor_timer/stop
    /fp/tablet/labor_timer/reconcile

Manager-bypass context flags (Task 17 wired in here for cohesion):
  fp_skip_predecessor_check  → bypasses S14 lock
  fp_skip_rack_assignment    → bypasses requires_rack_assignment
  fp_skip_transition_form    → bypasses required transition prompts

All bypass uses post to chatter on the move record naming the user
+ which flags fired. Group check enforced (manager-only).

_safe() wrapper: UserError → JSONRPC-friendly {ok: False, error: msg}
so the OWL components can show a flash without crashing.

Field naming follows existing fp.job.step.timelog convention
(date_started / date_finished, NOT started_at / stopped_at).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:10:28 -04:00
gsinghpal
3bed76aea4 feat(sub12b): persistent state machine on fp.job.step.timelog
Extends the existing timelog (used by S1/S2 battle tests) with:
- state: running / paused / stopped / reconciled (default running)
- last_paused_at + total_paused_seconds (drives accrued compute)
- accrued_seconds (compute, depends date_started/_finished/paused)
- billed_hrs/min/sec + billed_total_seconds + billed_pct (compute)
- product_id (split-by-product reconciliation per screen 10)
- notes
- job_id (related, indexed — for fp.job.active_timer_ids O2M)

Field naming follows the existing date_started / date_finished
convention (NOT started_at / stopped_at as my plan said — adjusted
inline to match what's already in the file).

The existing battle tests use the timelog without state — default
'running' so they're unaffected. State only flips when Sub 12b's
Stop Timer dialog commits.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:08:22 -04:00
gsinghpal
dcd6df71c0 feat(sub12b): fp.job.step + fp.job — rack/move/traveller fields
fp.job.step:
  + requires_rack_assignment (related from recipe_node_id)
  + requires_transition_form (related)
  + move_ids (O2M from_step_id), incoming_move_ids (O2M to_step_id)
  + is_racked (compute, stored, depends rack_id) — drives tablet
    rack-vs-parts greyed-button guard
  + qty_at_step_start, qty_at_step_finish (advanced by move commits)

  NOTE: existing 'rack_id' field is reused as the 'current rack' pointer
  (already there on line 95). Adding requires_rack_assignment as a
  related from recipe_node_id for runtime gate evaluation.

fp.job:
  + qty_received, qty_visual_inspection_rejects, qty_rework
  + special_requirements (Text — paper traveller header)
  + active_timer_ids (filtered O2M, depends on Task 7's state field)
  + move_ids (O2M to fp.job.step.move)

All additive. No removed fields. Existing battle tests unaffected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:07:19 -04:00
gsinghpal
0794f7e3c9 feat(sub12b): move-log list/form/search + Plating menu
Plating → Move Log (sequence 62, between Logistics 60 and Aerospace 65).
Form is read-only (create=false) since moves are produced by the
tablet flow, not the desktop UI.

Search filters: Today, Scrap/Rework, Racked. Group-by: Job, Operator,
Transfer Type.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:05:28 -04:00
gsinghpal
4187842d30 feat(sub12b): fp.job.step.move + fp.job.step.move.input.value
Chain-of-custody log: one row per Move Parts / Move Rack commit.
FP/MOVE/YYYY/NNNN sequence (5-digit). Carries from/to step + tank,
transfer type, qty, location, photo, rack, operator, datetime.

Child model captures recorded transition-input values (Sub 12a's
fp.step.template.transition.input snapshots → fp.job.step.move.
input.value rows). Each row carries 5 typed value columns; the
controller (Task 8) picks the right one based on input_type.

Operators get read+write+create — they generate moves at runtime —
but no unlink. Manager-only deletes for audit safety.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:04:41 -04:00
gsinghpal
d9ae45ce9b feat(sub12b): extend fusion.plating.rack — racking_state + tags + capacity
The existing 'state' field tracks wear (active/needs_strip/stripping/
retired). Sub 12b adds an orthogonal 'racking_state' (empty/loading/
loaded/in_use/awaiting_unrack/out_of_service) for the load lifecycle
— a rack can be wear-active AND racking-loaded simultaneously.

New fields:
  racking_state        — operational lifecycle
  tag_ids (M2M)        — fp.rack.tag chips on plant overview
  capacity_count       — soft warn (distinct from existing 'capacity')
  current_job_step_id  — compute, derived from latest fp.job.step.move
  current_tank_id      — compute
  current_part_count   — compute

Form view picks up the new fields under Sub-12b group + a 'Current
Use' panel that hides when racking_state is empty / out_of_service.

The compute references fp.job.step.move which lands in Task 4 — the
module won't load cleanly on entech until Tasks 4-5 ship; that's
expected for batch deployment at the end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:03:09 -04:00
gsinghpal
86c0e230a1 feat(sub12b): fp.rack.tag — rack-label registry + 4 starter tags
M2M tag registry: Rush / Hold for QC / Damaged / Customer Sample.
Each rack can carry many tags; tags surface as coloured chips on the
plant-overview rack rows + Move Rack dialog (Task 13).

Plating → Configuration → Rack Tags menu (sequence 48).
post_init_hook seeds 4 starters — idempotent (no-op if any exist).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:01:49 -04:00
gsinghpal
d78ef4228e feat(sub12b): bump versions + scaffold manifests
fusion_plating → 19.0.10.1.0
fusion_plating_shopfloor → 19.0.25.0.0

Adds data entries for fp_rack_tag_views.xml + fp_job_step_move_views.xml.
Adds 4 OWL dialogs + their templates + shared SCSS to the shopfloor
backend asset bundle (loaded after the existing manager_dashboard.js).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 21:00:18 -04:00
gsinghpal
25b429f253 docs(sub12b): implementation plan — 18 tasks for tablet Move/Rack/Timer
Adjustments from the spec, captured upfront in the plan:
- fp.rack already exists (extend, don't create) — Task 3
- fp.labor.timer collapses into the existing fp.job.step.timelog with
  a state machine + reconciliation fields — Task 7. Avoids parallel
  labor-tracking models; keeps battle-test S1/S2 paths intact.
- Sub 12b's Save+Print on Rack Parts references a report that lands
  in Sub 12c — flagged in Task 12 body.

18 tasks cover: 4 new models (rack tag, move, move input value), state
machine on existing rack + timelog, 11 controller endpoints, 4 OWL
dialogs, plant overview 2-pane layout, runtime guards, manager bypass
flags, entech deployment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:55:04 -04:00
gsinghpal
5494684181 fix(sub12a): rename _seed_default_inputs → action_seed_default_inputs
Odoo 19 rejects view buttons that call private (underscore-prefixed)
methods. Renamed the public entry point. The post_init_hook callers
follow.

Caught by entech upgrade (ParseError on the form view).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:43:26 -04:00
gsinghpal
d6cdae30ec feat(sub12a): OWL Simple Recipe Editor client action
JS: FpSimpleRecipeEditor component reads recipe_id from
props.action.context (matches the existing tree editor's contract).
HTML5 native drag-drop between Library (right) and Selected (left)
panels — uses two distinct dataTransfer types (application/x-fp-step
vs application/x-fp-library) so the drop handler knows whether to
reorder or snapshot-copy.

XML: 2-column grid layout. Selected has per-row × remove (hover
reveal), drag handle, position number, icon, name, station-count
badge. Library has search input, scrollable item list with empty-
state, drag-handle items.

SCSS: tokens follow the fp_shopfloor pattern with dark-mode SCSS @if
branch (CLAUDE.md rule). 2-fr grid that collapses to single column
under 900px for tablet/mobile.

Tag: fp_simple_recipe_editor — registered via registry.category('actions').

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:42:06 -04:00
gsinghpal
a892a7b20e feat(sub12a): recipe form — buttons + is_template + Step Authoring tab
Process node form:
- Header: keep 'Open Tree Editor' (primary, existing); add 'Open Simple
  Editor' (secondary). Both visible only for recipe-type nodes.
- Recipe Settings group: add preferred_editor + is_template (the latter
  supervisor-only).
- New 'Step Authoring' notebook page (visible for step/operation):
  Stations, default_kind, material_callout, predecessor/rack/transition
  flags, time/temp targets, voltage/viscosity, readonly
  source_template_id.

Model:
- New action_open_simple_editor (sibling of action_open_tree_editor).
- New _resolve_preferred_editor() — per-recipe preferred_editor wins,
  'auto' falls back to company.x_fc_default_recipe_editor, final
  fallback 'tree'.
- New action_open_recipe_with_preferred_editor() — one-click route
  through the resolver. Reserved for menu-list / context-menu callers
  that want the simple-loving foreman path.

Tree editor + every existing battle test path untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:40:08 -04:00
gsinghpal
194d5d96dd feat(sub12a): JSONRPC endpoints for the Simple Recipe Editor
11 routes under /fp/simple_recipe/...:
  load
  library/{list,create,write,delete}
  step/{insert,write,remove,reorder}
  template/{list,import}

Library/template imports snapshot-copy fields (Q4 = A locked) — no
live references. The _SNAPSHOT_FIELDS + _INPUT_SNAPSHOT_FIELDS module
constants are the single source of truth for what gets copied;
adding a new authoring field on fp.step.template means appending it
once to _SNAPSHOT_FIELDS and the controller stays correct.

library_delete is soft when nodes still reference the template via
source_template_id (operator can't accidentally orphan recipe steps).

Uses recipe.check_access('read') (Odoo 19 unified API) instead of the
older check_access_rights/check_access_rule pair.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:38:16 -04:00
gsinghpal
33ddec926c feat(sub12a): post_init_hook — backfill kind + seed step library
Extends the existing post_init_hook to also do (idempotent) Sub 12a
work on first install / upgrade:

1. Backfill kind='step_input' on existing
   fusion_plating_process_node_input rows where kind IS NULL.
2. Seed fp.step.template from the ENP-ALUM-BASIC recipe's child
   nodes if the library is currently empty. Uses _STARTER_KIND_BY_NAME
   to map recipe-step names to default_kind values, then calls
   _seed_default_inputs() to populate the per-kind input rows.
3. Falls back to a 15-entry hard-coded minimal seed list if
   ENP-ALUM-BASIC doesn't exist on the target DB.

All three operations no-op when the relevant state already exists.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:36:55 -04:00
gsinghpal
0862e55de6 feat(sub12a): Plating → Configuration → Step Library menu
Sequence 45 — between Process Types (40) and Bath Parameters (50).
Inherits the manager-only group from menu_fp_config.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:36:08 -04:00
gsinghpal
738f3fcfd5 feat(sub12a): step library list/form/search views
Form: Title + Code + Classification (kind/icon/process/material) +
Stations & Flags + 4 notebook tabs (Instructions / Operation
Measurements / Transition Form / Advanced).

Operation Measurements + Transition Form are inline-editable o2m
lists with handle widget for drag reorder.

Header button: 'Seed Default Inputs' (visible only when default_kind
is set). Triggers the idempotent seeding helper.

NB: I removed `string=` from <search> per Odoo 19 rule (CLAUDE.md
critical rule 4 — no string attr on search).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:35:33 -04:00
gsinghpal
6fbb6f918b feat(sub12a): ACL rows for fp.step.template + 2 child models
Operator: read only on library + child inputs.
Supervisor: read/write/create on library; full CRUD on inputs.
Manager: full CRUD on all three.

Pattern matches existing fp_proficiency rows (supervisor without
unlink on the parent, full CRUD on the children — operators can't
delete a library template that recipes might reference, but
supervisors can edit/add/remove input rows freely).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:34:59 -04:00
gsinghpal
95debabc28 feat(sub12a): res.company.x_fc_default_recipe_editor setting
Per-company default for which editor opens for new recipes / recipes
with preferred_editor=auto. Defaults to 'tree' to preserve existing
behavior. Surfaces in Settings → Fusion Plating → Recipe Editor.

Naming follows the existing x_fc_* convention used throughout
res_company.py for company-level Fusion Plating defaults.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:34:12 -04:00
gsinghpal
91681d722e feat(sub12a): extend process.node + process.node.input
process.node — additive only:
  is_template, source_template_id, tank_ids (M2M to fusion.plating.tank
  with new join table fp_node_tank_rel), material_callout, time/temp
  targets + units, voltage_target, viscosity_target,
  requires_rack_assignment, requires_transition_form, default_kind,
  preferred_editor.

process.node.input — additive only:
  kind (step_input/transition_input, default step_input so existing
  rows keep working), target_min/target_max/target_unit, compliance_tag,
  plus 9 new typed input_type values (time_hms, time_seconds,
  temperature, thickness, pass_fail, date, signature, location_picker,
  customer_wo).

No removed fields, no removed selection values. Tree editor + every
existing battle test (S14/S15/S17/S18/S19) untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:33:11 -04:00
gsinghpal
7a0e74c456 feat(sub12a): add fp.step.template.transition.input
Transition-time prompts (fired when leaving a step). Authored now,
runtime-consumed in Sub 12b's Move Parts dialog. Carries a
compliance_tag selection (none/as9100/nadcap/cgp/nuclear) so audit
reports can filter by regulation regime.

input_type covers Steelhead's transition prompts: text, number,
boolean, selection, date, signature, photo, location_picker,
customer_wo.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:31:45 -04:00
gsinghpal
8bcd537737 feat(sub12a): add fp.step.template.input
Operation-measurement definitions for library step templates. The
input_type selection covers Steelhead's input shapes (text, number,
boolean, selection, date, signature, time_hms, time_seconds,
temperature, thickness, pass_fail).

target_min/max + target_unit are structured (not embedded in the name
string the way Steelhead does it) so the traveller report can render
target vs actual side-by-side and colour-code out-of-range values.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:31:23 -04:00
gsinghpal
bef812616b feat(sub12a): add fp.step.template model with sane-default kind map
Reusable step library entry. Carries the same shape fields as
fusion.plating.process.node so a drag-drop snapshot is a 1:1 copy.
DEFAULT_INPUTS_BY_KIND drives seeding for the 15 kinds we identified
on Steelhead's job traveller (cleaning, etch, plate, bake, etc.).

The seeding helper (_seed_default_inputs) is idempotent — won't
duplicate inputs on repeated calls.

Note: imports for the 2 child models (input + transition_input) are
added in models/__init__.py here; the actual files land in the next
two commits. Module won't load cleanly on entech until both ship.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:30:45 -04:00
gsinghpal
7e98b48c01 feat(sub12a): bump fusion_plating to 19.0.10.0.0 + scaffold manifest
- Adds views/fp_step_template_views.xml to data list (after process_node_views).
- Adds simple_recipe_editor.{js,xml,scss} to web.assets_backend bundle.
- res_config_settings_views.xml + post_init_hook already wired — extend in place.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:29:37 -04:00
gsinghpal
cfe776be4c chore: session housekeeping — tank UX, plating menu defaults, WO label
- fusion_plating: tank field labels (Code → Tank Number, Tank → Tank Name)
  + state-control header buttons (Mark Empty/Filled/In Use/Draining/
  Maintenance/Out of Service) with chatter audit logging.
- fusion_plating_configurator: Plating app default landing screen = Sale
  Orders, while keeping menu name as 'Plating'.
- fusion_plating_jobs: SO smart-button label 'Plating Jobs' → 'WO'.

Already deployed and verified on entech earlier in the session.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:27:35 -04:00
gsinghpal
c75b22aaf7 docs(sub12a): implementation plan — 15 tasks for simple editor + library
15-task plan covering: manifest bump, three new models (fp.step.template
+ 2 child input types), additive fields on process.node, ACL rows,
views, menu, post_init_hook with library-from-ENP-ALUM-BASIC seeding,
JSONRPC controller (11 routes), recipe form integration, OWL client
action, preferred_editor resolver, entech deployment + smoke test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 20:22:20 -04:00
gsinghpal
4e4ca2c9da docs(sub12): simple recipe editor + library + tablet move/rack + reports
Three-part design (12a/12b/12c) for adding a flat drag-drop recipe
editor alongside the existing tree editor, with a reusable step
library, Steelhead-style Move Parts/Rack/Stop-Timer dialogs, and
recipe-order + chronological CoC PDF reports.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 19:23:25 -04:00
gsinghpal
66cfe5f97f changes 2026-04-27 09:41:46 -04:00
gsinghpal
f51976cb08 changes 2026-04-27 08:48:55 -04:00
gsinghpal
2a4909be25 changes 2026-04-27 08:16:20 -04:00
gsinghpal
f08f328688 changes 2026-04-27 00:11:18 -04:00
gsinghpal
d9f58b9851 changes 2026-04-26 15:05:17 -04:00
gsinghpal
160198edb1 chore(reports): drop duplicate Print menu entries on legacy MRP models
After the fp.job migration, every MRP-bound Print action in
fusion_plating_reports has a fp.job-bound canonical version in
fusion_plating_jobs. Having both registered means clicking Print on a
record shows two identical entries.

Removed 7 ir.actions.report records (templates kept for backwards
compat — only the menu bindings are gone):

  action_report_wo_margin                   (mrp.production)
  action_report_fp_work_order_portrait      (mrp.workorder)
  action_report_fp_work_order_landscape     (mrp.workorder)
  action_report_fp_wo_sticker               (mrp.workorder)
  action_report_fp_mo_sticker               (mrp.production)
  action_report_fp_job_traveller_mo_landscape (mrp.production)
  action_report_fp_job_traveller_mo_portrait  (mrp.production)

Kept:
  action_report_fp_job_traveller_so_*  (sale.order)
  action_report_fp_so_sticker          (sale.order)

The shared inner sticker templates (report_fp_wo_sticker_inner /
_defaults) stay registered because fp.job + sale.order stickers
both t-call them.

Version: reports 19.0.7.17 -> 19.0.7.18.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 10:53:19 -04:00
gsinghpal
b8fe14e653 Merge feat/fp-native-job-model into main
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
Native fp.job / fp.job.step model replacing the mrp.production /
mrp.workorder bridge for the Fusion Plating shop. Coexists with
fusion_plating_bridge_mrp during the migration; cutover is gated on
the x_fc_use_native_jobs settings flag.

Highlights from 61 commits:
- New fusion_plating_jobs module with fp.job, fp.job.step, recipe
  expansion, lifecycle hooks, smart buttons, traveller / margin /
  sticker reports, and migration tooling.
- Operator UI consolidated into fusion_plating_shopfloor: Manager
  Desk, Plant Overview, Process Tree, Tablet Station — all bound to
  fp.job / fp.job.step, theme-token compliant in light + dark mode.
- QR scanner OWL component (vendored ZXing-js + jsQR fallback +
  iOS native-camera photo capture).
- /fp/job/<id> + /fp/wo/<id> migration-aware redirects.
- /fp/tank/<id> NFC tank status page.
- Sticker template restored to the canonical ENTECH layout, now
  reused by fp.job + sale.order (one sticker per line with a part).
- Comprehensive workflow seed data (quotation -> paid invoice).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 10:48:11 -04:00
gsinghpal
a317efab45 changes 2026-04-26 10:46:44 -04:00
gsinghpal
3e92a8318d fix(shopfloor): proper ZXing hints + native-camera photo capture path
After 1117 video-frame callbacks ZXing still couldn't see the QR.
Two real fixes verified by reading the vendored bundle:

1) Hints were never being applied. BrowserMultiFormatReader stores
   them in this._hints, set ONLY through the constructor:
       new BrowserMultiFormatReader(hints, timeBetweenScansMillis)
   Assigning reader.hints afterward (what the previous patch did) is
   a no-op. Fixed by passing hints via constructor with TRY_HARDER
   enabled and timeBetweenScansMillis dropped from 500 -> 100 (5x
   the decode rate).

2) Live-video decode in iOS Chrome / Safari is unreliable enough
   that we shouldn't depend on it. Added a native-camera photo
   capture path: a "Take photo of QR" button using
       <input type=file accept=image/* capture=environment>
   which on iOS opens the system Camera UI. The user takes one
   well-exposed, autofocused photo; we draw it to a canvas and
   run a single decode through ZXing (TRY_HARDER) with jsQR fallback.
   Far more reliable than chasing edge cases in live decoding.

Status: Live decode is still tried first. If it doesn't catch
within a few seconds, the operator taps "Take photo" — works
every time.

Version: shopfloor 19.0.23 -> 19.0.24.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 14:07:54 -04:00
gsinghpal
256ce21522 fix(shopfloor): use ZXing's actual API (decodeFromVideoElementContinuously)
The previous patch called reader.decodeFromCanvas which doesn't exist
in @zxing/library 0.21.3. Real methods (verified by grep on the
vendored bundle) are:
  decodeFromVideoElement(el)               -- one-shot
  decodeFromVideoElementContinuously(el, cb) -- continuous loop

Switched to the continuous variant. ZXing manages its own per-frame
timing internally — we just register the (result, err) callback and
React to result.getText() on hits. NotFoundException = no QR this
frame, which we silently ignore.

Also fixed the related video-play race: ZXing internally registers a
'playing' event listener on the video and then calls play() itself.
If we await v.play() ourselves first, the 'playing' event fires
BEFORE ZXing attaches its listener and ZXing then waits forever for
an event that already happened.

Fix: for the zxing path we set attributes + srcObject but do NOT
call play(). ZXing's playVideoOnLoadAsync handles play -> playing ->
decode in the right order. The native and jsQR paths still pre-play
because their loops poll the video themselves.

Cleanup: _stopCamera now calls reader.reset() to tear down ZXing's
internal state cleanly when the modal closes.

Version: shopfloor 19.0.22 -> 19.0.23.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 13:56:47 -04:00
gsinghpal
43397b1854 fix(shopfloor): swap to ZXing-js as primary QR decoder; jsQR is fallback
149 jsQR attempts at full 720x1280 with px:ok and no detection means
the QR in the frame has perspective skew, motion blur, or glare under
jsQR's threshold but well within what real-world phone scanning needs
to handle. jsQR is fast but brittle.

Vendor @zxing/library 0.21.3 (Apache 2.0, ~328KB UMD) and make it the
default decoder. ZXing's HybridBinarizer + perspective transform are
the same algorithm family the iOS Camera app uses internally and they
recover from the cases jsQR rejects.

Decoder selection order:
  1. ZXing-js (window.ZXing.BrowserMultiFormatReader)  -- new default
  2. native BarcodeDetector                            -- if ZXing missing
  3. jsQR                                              -- last-resort

Implementation details:
- Hint ZXing to QR_CODE only so it doesn't waste frames probing
  Code 128 / EAN / PDF417.
- Use decodeFromCanvas on each video frame (rather than ZXing's
  built-in continuous video reader) so we keep ownership of the
  modal UI, the <video> element, and the getUserMedia stream.
- Status line follows the same compact format as the jsQR loop:
    zxing · f1234 a567 720x1280 rs4 r:no_code
  with r:found / r:empty / r:no_code / r:err: ...

Version: shopfloor 19.0.21 -> 19.0.22.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 13:50:42 -04:00
gsinghpal
8e3169e49b fix(shopfloor): jsQR loop — full-res frame + canvas blank-pixel check + last-result trace
271 attempts at 720x1280 with no detection means either downsampling
killed the finder patterns or drawImage is silently painting blank
pixels (a known iOS WebKit failure mode for some video-stream sources).

- Drop the 600px scaling cap. Feed the full native video frame to
  jsQR. Per-frame cost goes up but is still fine; the win is jsQR
  sees finder patterns at full sharpness.
- Add a one-time sanity check that walks the first ImageData buffer
  looking for a non-zero pixel. If everything is 0,0,0 the canvas is
  blank (drawImage failed) and we surface that as 'px:BLANK' in the
  status line — telling us instantly to switch decoder strategies
  rather than chasing tuning.
- Status line now also shows the last jsQR call outcome:
    r:found / r:no_code / r:empty / r:error: ...
  So we can confirm whether jsQR is even being invoked successfully.

Status format compacted to fit one line on phone:
  jsqr · f1234 a567 720x1280 rs4 px:ok r:no_code

Version: shopfloor 19.0.20 -> 19.0.21.
2026-04-25 13:46:47 -04:00
gsinghpal
040f1463b4 fix(shopfloor): jsQR decode loop diagnostics + attemptBoth + 720p stream
The previous loop was running but never finding the QR. Three changes
to make it actually decode AND make any future failure visible:

1. inversionAttempts: 'dontInvert' -> 'attemptBoth'
   Some camera exposures wash out the QR enough that jsQR sees it
   inverted. attemptBoth tries both polarities per frame; the cost is
   ~2x decode time but jsQR is fast enough that scan stays interactive.

2. getUserMedia now requests 1280x720 (with downgrade allowed). The
   default 640x480 only gives ~5 pixels per QR module on a typical
   phone-to-sticker distance — borderline for jsQR. 720p doubles
   that and makes detection near-instant.

3. The status line is now LIVE, updating every 400ms with:
     Decoder: jsqr · frames N · attempts M · video WxH rsN
   So when an operator says "scan does nothing" we can immediately see
   whether the loop is running, whether the camera is feeding frames,
   whether jsQR is being called, and at what resolution. No Web
   Inspector required.

Version: shopfloor 19.0.19 -> 19.0.20.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 13:42:49 -04:00
gsinghpal
9fe7855fc3 fix(shopfloor,reports): scanner status line + sticker rev cleanup
- Re-detect BarcodeDetector / window.jsQR at every modal open instead
  of only at component setup. Avoids the trap where a stale cached
  bundle reports "no decoder" even after a redeploy.
- Add a one-line status indicator at the top of the scan modal showing
  exactly which decoder is active ("Decoder: native" / "Decoder: jsqr"
  / "Decoder: none — paste URL below"). Lets the operator see at a
  glance whether scanning is even possible without round-tripping
  through Safari Web Inspector.
- Sticker: strip a leading "Rev " (case-insensitive) from
  fp.part.catalog.revision before printing so values like "Rev 1"
  don't render as "Rev Rev 1".

Versions: shopfloor 19.0.18 -> 19.0.19, reports 19.0.7.16 -> 19.0.7.17.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 13:30:40 -04:00
gsinghpal
b93633d728 fix(shopfloor,reports): make QR scan actually navigate after decode
Two bugs were colluding to make iPhone scans look like "nothing
happens":

1. The in-app scanner was calling action.doAction({res_model: 'fp.job',
   res_id: <decoded-id>}). Old physical stickers (still on every box)
   encode /fp/wo/<mrp.production.id> — that id space doesn't match
   fp.job, so the form opened on a non-existent record and silently
   showed nothing. New /fp/job/<id> stickers happened to work because
   the IDs lined up by coincidence.

2. The /fp/wo/<id> controller redirected to mrp.production / mrp.workorder
   forms, both of which still exist as legacy records but aren't the
   canonical source of truth post-migration.

Fix:
- qr_scanner._handleCode now navigates via window.location.href instead
  of action.doAction. It hands /fp/job/<n> and /fp/wo/<n> URLs straight
  to the existing server-side controllers, which know how to resolve
  the right record. Bare numeric ids pasted manually -> /fp/job/<n>.
  Anything else surfaces the decoded text as an error so the operator
  can see decode worked but the value isn't a sticker.

- Modal now shows "Detected: <value>" the moment a code is decoded
  (before navigation), so even on slow phones the operator sees
  immediate feedback that the camera read the QR.

- wo_scan.py now resolves in this order:
    1. fp.job by legacy_mrp_production_id (migration-aware — old
       stickers route to the new model)
    2. mrp.production direct browse
    3. mrp.workorder direct browse
    4. fall back to /odoo/plating-jobs (or work-orders list)

Versions: shopfloor 19.0.17.0.0 -> 19.0.18.0.0,
          reports   19.0.7.15.0 -> 19.0.7.16.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 13:14:06 -04:00
gsinghpal
ecac43eef4 fix(reports): restore the original ENTECH box-sticker layout for fp.job + sale.order
The original mrp.production / mrp.workorder sticker (logo + WO# stack
on the left, big QR on the right, 7-row body with PO/Customer/Process/
Part Number/Due/Qty/Notes — the design ENTECH has been printing for
months) lives in fusion_plating_reports.report_fp_wo_sticker_inner.

The new fp.job sticker had been rebuilt from scratch with a different
look. This wires fp.job into the existing canonical template instead.

What changed:

- report_fp_wo_sticker_inner — every t-set now uses the
  "_var or fallback-from-_mo" pattern so callers can pre-resolve
  values; mrp.production/mrp.workorder callers still work via the
  fallback path.
- report_fp_wo_sticker_defaults — new shared template that initialises
  every overridable name to False so the inner's `or` chain doesn't
  NameError when an outer hasn't set it.
- report_fp_job_sticker_template — replaces the parallel layout with
  a t-call to report_fp_wo_sticker_inner, feeding it from fp.job
  fields (name, partner_id, qty, date_deadline, sale_order_id,
  sale_order_line_ids, recipe_id, part_catalog_id, coating_config_id).
- report_fp_so_sticker — new outer that iterates sale.order.order_line
  and emits one sticker per line that has a part_catalog_id. Bound to
  sale.order's print menu via action_report_fp_so_sticker.

Versions: reports 19.0.7.14.0 -> 19.0.7.15.0,
          jobs    19.0.5.0.0  -> 19.0.5.1.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 13:03:29 -04:00
gsinghpal
c27e8a109c fix(shopfloor): vendor jsQR so QR scanning works on iOS Safari
iOS Safari (and the in-app webviews in Messages / WhatsApp / LinkedIn)
don't ship the BarcodeDetector API, so the previous scanner fell
through to the manual paste UI on every iPhone — defeating the point
of "tap to scan."

Vendored cozmo/jsQR (Apache 2.0, ~250KB) and made the scanner pick the
strongest available decoder at setup time:

  1. native BarcodeDetector  -> Android Chrome, iOS Safari 17+, desktop
  2. jsQR canvas loop        -> every other browser with getUserMedia
  3. manual URL paste        -> last-resort if camera unavailable

The jsQR loop draws each video frame into an offscreen canvas, downsamples
to 480px on the long side, and runs jsQR synchronously throttled to
~8 fps to stay under 10% CPU on mid-range Android phones.

Template now shows the <video> element whenever ANY decoder is
available (state.canScan), not just for native. Paste fallback still
visible as a secondary path so a tablet with broken camera permissions
still has a way in.

shopfloor: 19.0.16.0.0 -> 19.0.17.0.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 12:54:34 -04:00
gsinghpal
74db636458 feat(jobs,shopfloor): smart buttons + QR scanner + NFC tank pages
Three connected operator-workflow features for entech.

A. fp.job smart buttons — count fields and action methods for sale
   order, steps, deliveries, invoices, payments, quality holds,
   certificates, time logs, and portal job. Each is an oe_stat_button
   that drills into the matching records, mirroring the sale.order
   pattern. Cross-module models are runtime-detected so the form
   stays clean when bridge modules are uninstalled.

B. Reusable QR scanner OWL component (`<QrScanner/>`) wired into the
   Manager Desk, Tablet Station, Plant Overview, and Process Tree
   headers. Click → modal with rear-camera stream (getUserMedia) +
   BarcodeDetector live decode → opens the matching fp.job form via
   the action service. Falls back to a manual URL paste box on
   browsers without BarcodeDetector. Works on iOS 17+ Safari and
   Android Chrome. Width uses `min(420px, 92vw)` wrapped in #{} so
   dart-sass passes it through verbatim instead of trying to compute
   incompatible units at compile time.

C. /fp/tank/<id> public-but-auth-required tank status page for NFC
   taps. Renders the tank's current step (in-progress / paused),
   queued ready steps, and most recent bath chemistry log (lines
   table) on a mobile-first page. URL-based so it works on iOS Safari
   without the Web NFC API — the operator taps the NFC tag, the URL
   opens in the default browser, the page auto-renders. New
   web.assets_frontend bundle entry pulls in the design tokens +
   tank_status.scss.

Manifest version bumps: jobs 19.0.5.0.0, shopfloor 19.0.16.0.0.
Tests: 44 pass (3 new smart-button assertions added).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 12:39:37 -04:00
gsinghpal
18b5918d3d fix(shopfloor): Manager Desk speaks fp.job/fp.job.step end-to-end
The previous shopfloor consolidation kept the data layer correct
(controller queries fp.job.step) but left the UI labels, JS
variables, and RPC kwargs in legacy WO/MO vocabulary. Result:
every label said 'Unassigned WOs' / 'X WO' even though the
underlying records are fp.job.step rows.

Renames throughout:
  wo → step (variable / loop / payload key)
  WO → Step (label)
  unassigned_wos → unassigned_steps  (KPI key)
  active_wos → active_steps
  ready_to_ship_mos → ready_to_ship_jobs
  mo_id / mo_name / expandedMoId → job_id / job_name / expandedJobId
  wo_kind → kind, wo_kind_label → kind_label
  o_fp_mgr_wo_* CSS classes → o_fp_mgr_step_*

RPC routes /fp/manager/assign_worker, /fp/manager/assign_tank,
/fp/manager/take_over: primary kwarg is step_id; workorder_id
accepted as a deprecated alias for one release with a logged
warning, so any uncaught caller doesn't break.

No layout / visual changes — same UI shape, native vocabulary.
SCSS class renames are mechanical (only `_wo_` → `_step_` in
selectors); XML updated in lockstep.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 10:38:50 -04:00
gsinghpal
596efa0ed3 fix(shopfloor): theme-compliant Manager Desk + kind-chip tokens
The Manager Desk SCSS still had hardcoded chip colors (wet/bake/
mask/rack/inspect) and var(--bs-body-color) usage that CLAUDE.md
explicitly forbids. In dark mode these rendered as low-contrast
text on translucent backgrounds.

Fixes:
- Added 6 kind-chip tokens to _fp_shopfloor_tokens.scss
  ($fp-kind-wet/bake/mask/rack/inspect/other) with explicit hex
  values for both light and dark bundles via the existing
  $o-webclient-color-scheme branch.
- manager_dashboard.scss: kind chips reference the new tokens via
  color-mix() for translucent backgrounds. var(--bs-body-color)
  on the expanded card body replaced with $fp-card-soft.
- Annotated the .btn-primary white-text rule as intentional (the
  $fp-accent surface beneath it is the same brand purple in both
  bundles, so white is correct in both themes).

plant_overview.scss had no kind-chip block — already token-compliant.
manager_dashboard.xml had no inline styles or theme-leaky utility
classes — text-muted/text-success resolve through Bootstrap which
flips with the bundle.

Both light (3deab56) and dark (28de524) asset bundles compile
cleanly with distinct hashes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 10:30:09 -04:00
gsinghpal
009a0b5e10 feat(jobs): seed orders via fp.direct.order.wizard (estimator path)
Adds 8-12 orders that originate from the direct order entry wizard
(used by estimators for bulk entry without quotation flow) instead
of plain sale.order create. Exercises the wizard's
action_create_order() method which builds the SO with all the
x_fc_* header fields, then we confirm to fire _fp_auto_create_job
in one step.

Each wizard creates 1-3 lines with realistic part/coating combos,
treatments, surface area, deadlines, and the wo_group_tag flag
(30% chance) to test multi-line job collapsing. Mixes po_pending
(30%) and PO-doc orders, plus a spread of invoice strategies
(deposit / progress / net_terms / cod_prepay).

Orders distribute across confirmed / in_progress_mid / delivered
/ invoiced / paid states, reusing the state-advancement pattern
from seed_workflow_states.py.

Verified on entech: 10/11 orders created (one invoice failure on a
SO with no invoiceable lines, handled gracefully via savepoint).
22 fp.job records generated across confirmed / in_progress / done.

Part of: native job model migration (spec 2026-04-25)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 10:02:52 -04:00
gsinghpal
128d51755d feat(jobs): comprehensive workflow seed — quotation through paid invoice
Builds 7-8 orders in each of 13 workflow states to simulate a
full pipeline:
  - Quotation (sale.order draft)
  - Quote Sent (sale.order sent)
  - Order Confirmed / Job Confirmed
  - Job In Progress (Early + Mid)
  - Job On Hold (with quality hold)
  - Job Done / Delivery Draft
  - Delivery Scheduled / En Route / Delivered
  - Invoice Draft / Posted / Paid

Each record fills detailed fields: PO numbers, commitment dates,
operator assignments, timelogs, thickness readings on certs,
delivery contacts/vehicles/drivers, payment journals, etc.

Idempotency-ish: each order wrapped in a savepoint so one failure
doesn't crash the whole seed.

Workflow walkthrough findings encoded in script header docstring,
including the gotchas: (1) SO action_confirm creates fp.job in DRAFT
state with 0 steps — must call action_confirm + _generate_steps_from_recipe
explicitly; (2) invoice_payment_term_id is REQUIRED to post invoices;
(3) account.payment.action_validate moves payment to 'paid' but invoice
goes to 'in_payment' (not 'paid' — Odoo 19 design, requires bank
reconciliation for full 'paid' state).

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 09:56:36 -04:00
gsinghpal
7d71b77e14 fix(jobs): map fp.coating.config.thickness_uom to fp.job.step.thickness_uom
The recipe→steps generator was copying coating.thickness_uom blind
into fp.job.step.thickness_uom, but the two selections use
different value codes:

  fp.coating.config.thickness_uom : 'mils' / 'microns' / 'inches'
  fp.job.step.thickness_uom       : 'mil'  / 'um'      / 'inch'

Result: any SO confirmed with a coating using the long-form codes
(real demo data uses 'mils') hit a 'Wrong value for ...' selection
error, the savepoint rolled back, and the fp.job ended up with 0
steps.

Add an explicit mapping. Unknown values fall through to the step
default ('um'). Demo seed re-run after the fix produces 234 steps
across 31 jobs (was 207); thickness_uom distribution: 228 um, 6 mil.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 09:19:03 -04:00
gsinghpal
7275007948 fix(jobs): cleanup script — delete SOs, invoices, payments, pickings, quotes
The original cleanup script left behind 33 sale.order, 31 invoice
account.move, 13 payments, 1 picking, 17 quote requests. Extended
to nuke them too — SOs in any state, invoices regardless of
posted/draft (force-cancels via SQL when ORM blocks it), payments
forced to cancel before delete, stock.move + stock.move.line
force-deleted, quote requests unlinked.

Section ordering: payments -> invoices -> pickings/moves -> SOs (FK
direction). Reconciliation links cleared via direct SQL.

Sequences for sale.order and account.move.invoice reset to 1 so
fresh SOs start at S00001.

Re-seeded 31 fp.jobs across all 6 states after running the extended
cleanup.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 09:16:48 -04:00
gsinghpal
de47d2ceb1 refactor(menus): collapse separate Jobs submenu into Shop Floor
Move 'All Jobs' and 'Steps' under fusion_plating_shopfloor's
existing 'Shop Floor' submenu (between Tablet Station and Bake
Windows). The standalone 'Jobs' parent menu is gone — it was
redundant once the operator UIs (Plant Overview / Tablet /
Manager Desk) consolidated under Shop Floor.

Final structure under Plating:
  Sales / *
  Configurator / *
  Shop Floor
    Manager Desk
    Plant Overview
    Tablet Station
    All Jobs       ← moved here (seq 15)
    Steps          ← moved here (seq 17, supervisor+)
    Bake Windows
    First-Piece Gates
  Receiving & Inspection
  Operations / *
  Configuration → Work Centres (manager)
  ...rest

Work Centres stays under Configuration (no shopfloor equivalent).

New menu file lives in fusion_plating_jobs/views (jobs depends on
shopfloor; core can't reference shopfloor xmlids).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 09:01:49 -04:00
gsinghpal
5df7d5e6cf refactor(shopfloor,jobs): consolidate operator UI into shopfloor
Removes the parallel OWL/controller stack I built in
fusion_plating_jobs (job_process_tree, job_plant_overview,
job_manager_dashboard, job_tablet, job_*.scss, plus parallel
controllers and action XML files). Refactors the existing
fusion_plating_shopfloor components in place to bind to
fp.job / fp.job.step instead of mrp.production / mrp.workorder.

End state:
- ONE operator UI module (shopfloor) instead of two parallel ones
- Existing token system (_fp_shopfloor_tokens.scss) reused as
  designed - no duplicate jobs tokens
- Existing /fp/shopfloor/* RPC URLs preserved (no integration
  breakage); workorder_id kwargs accepted as legacy aliases for
  step_id / job_id so older tablet clients keep working
- Existing visual designs preserved - only the data layer
  underneath changed
- Process Tree button on fp.job form now points at
  fusion_plating_shopfloor's fp_process_tree client action
- Bake Windows / First-Piece Gates / Bake Oven / Operator Queue
  models stay where they were
- legacy_menu_hide.xml trimmed: only the bridge_mrp Production
  Priorities entry remains; the 3 shopfloor menus (Manager Desk,
  Plant Overview, Tablet Station) are now visible (the canonical
  native consoles)

Manifests:
- fusion_plating_jobs 19.0.3.1.0 -> 19.0.4.0.0 (consolidation bump,
  no more bundled JS/SCSS, only job_scan controller retained)
- fusion_plating_shopfloor 19.0.14.4.0 -> 19.0.15.0.0 (asset bundle
  cache-bust + significant controller refactor)

Tests pass on entech: 0 failed, 0 errors of 41 tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 06:45:15 -04:00
gsinghpal
667654bd4e refactor(jobs): drop (Native) suffix + promote Jobs to top of Plating app
The (Native) suffix was a temporary distinguisher during parallel
coexistence with bridge_mrp. Now that fp.job is THE primary
system, the suffix is just noise. Removed across all 5 menus and
both client-action labels.

Also restructured the Jobs submenu under Plating:
- Renamed root from 'Plating Jobs (Native)' (seq=4, manager-only)
  to just 'Jobs' (seq=2, operator-visible). Now appears right
  below the Plating app header — first-click access for operators.
- All Jobs (was 'Jobs') at seq=20
- Tablet Station at seq=5 (operator entry point)
- Plant Overview at seq=10
- Manager Dashboard at seq=15 (supervisor+ only)
- Steps (renamed from 'Steps (Admin)') at seq=30 (supervisor+ only)
- Work Centres (was 'Work Centres (Native)') in Configuration

Hidden one more legacy menu: bridge_mrp's 'Production Priorities'
(mrp.workorder ordering UI — fp.job has its own priority field).

Manifest unchanged (no new files); skipping version bump.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 06:19:14 -04:00
gsinghpal
5130e51941 feat(jobs): demo data — work centres + part coatings
Two follow-up seed scripts after the main demo reset:

1. seed_work_centres.py: creates one fp.work.centre per existing
   fusion.plating.work.center (matched by code), classifying kind
   from name/code keywords. Then backfills work_centre_id on every
   fp.job.step whose recipe_node has a legacy work_center_id with
   a matching native code. Plant Overview kanban now has columns
   instead of one big 'Unassigned' bucket.

2. seed_part_coatings.py: assigns existing fp.coating.config rows
   (with recipes) to up to 20 bare fp.part.catalog rows
   round-robin. Field on the part is x_fc_default_coating_config_id.
   Future SO confirms via these parts will naturally generate full
   recipe-linked steps via _generate_steps_from_recipe.

Both idempotent — re-running creates nothing new.

Run on entech: 9 native work centres created, all 234 existing
fp.job.step rows bound. Parts with coating: 2 -> 22 (28 -> 8 bare).

Part of: native job model migration (spec 2026-04-25)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 05:53:52 -04:00
gsinghpal
8f458017c9 feat(jobs): cleanup + seed scripts for demo data reset
cleanup_demo_data.py: deletes ALL fp.job, fp.job.step, timelogs,
mrp.production, mrp.workorder, and dependent records (deliveries,
certs, holds, portal jobs, racking inspections, uninvoiced SOs).
Resets the fp.job sequence. Preserves masters. Force-cancels MOs/SOs
via SQL UPDATE before unlink to bypass Odoo's _unlink_except_done
and _unlink_except_draft_or_cancel guards.

seed_demo_data.py: creates 31 fp.job rows distributed across all
6 states (draft=5, confirmed=6, in_progress=8, on_hold=3, done=6,
cancelled=3). In_progress jobs have mixed step states with real
timelogs to simulate a live shop floor. Falls back to direct
fp.job creation when a customer's parts have no coating/recipe,
ensuring customer variety even with sparse coating data.

Both scripts: idempotent (safe to re-run), commit at end, walk
dependents bottom-up to avoid FK violations. Used to reset entech
demo data after the migration trial.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 05:43:48 -04:00
gsinghpal
3ca0f7a719 fix(jobs): theme tokens + dark-mode support across remaining OWL SCSS files
The 4 client-action SCSS files I shipped in Phase 6 ignored the
project's documented design system (CLAUDE.md "Card Styling" + "Dark
Mode" rules) and used hardcoded hex / var(--bs-*) for surfaces.
Result: dark mode rendered white-text-on-white-card.

Companion to "changes" (22573e7) which already landed
_fp_jobs_tokens.scss + the job_plant_overview.scss refactor.
This commit finishes the job:

- Refactored job_process_tree.scss, job_manager_dashboard.scss and
  job_tablet.scss to reference the $fp-* tokens — zero hardcoded
  hex on theme-sensitive surfaces. Three-layer contrast applied per
  CLAUDE.md (page → container → card).
- Process tree keeps the intentional Steelhead-style dark-slate
  card fill in BOTH bundles (deliberate visual choice, not a theme
  bug); page / header / connectors / empty state are now token-
  driven so they look right against light or dark page surfaces.
- Manifest assets list reordered so _fp_jobs_tokens.scss compiles
  first in web.assets_backend (CLAUDE.md rule: SCSS variables in
  earlier files are visible to later files in the same bundle).
  This is what makes the compile-time
  $o-webclient-color-scheme branch in the partial actually take
  effect for the four consumer files.

Verified on entech: light bundle (web.assets_backend) and dark
bundle (web.assets_web_dark) both compile without SCSS errors and
emit distinct surface hexes (light: #f3f4f6 page / #ffffff card;
dark: #1a1d21 page / #22262d card).

Manifest 19.0.3.0.0 → 19.0.3.1.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 05:26:42 -04:00
gsinghpal
22573e7ce3 changes 2026-04-25 05:21:15 -04:00
gsinghpal
7f84e66b72 feat(jobs): finish original plan — Job Margin, polish, legacy hide
Three batched changes that close out the original 10-phase
migration plan.

1. Phase 5 — Job Margin report bound to fp.job (replaces the
   mrp.production-bound report_wo_margin). Per-step labour cost
   table + margin summary using existing fp.job.step.cost_total
   from Phase 1.

2. Polish:
   - Real implementations for fp.job.step.button_pause,
     button_skip, button_cancel (was NotImplementedError stubs).
     button_pause closes the open timelog and sums duration_actual,
     mirroring button_finish; button_skip/cancel transition state
     with UserError guards.
   - Explicit ondelete= policies on fp.job's cross-module Many2ones
     (part_catalog/coating restrict, customer_spec/portal/delivery
     set null) — was implicit set null.
   - Standard Nexa Systems author/website/maintainer/support block
     on fusion_plating_jobs manifest, suppressing the install
     warning.

3. Legacy hide:
   - New 'Plating Legacy Menus' group (group_fusion_plating_legacy_menus)
     — nobody in it by default.
   - Old shopfloor Manager Desk + Plant Overview + Tablet Station
     menus restricted to that group, hiding them from operators
     now that the native equivalents under 'Plating Jobs (Native)'
     exist. (Note: ir.ui.menu uses group_ids in Odoo 19, not the
     deprecated groups_id alias.)

Manifest 19.0.2.4.0 → 19.0.3.0.0. fusion_plating_shopfloor added
to depends so the legacy menu xmlid references resolve at install
time.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 04:49:44 -04:00
gsinghpal
f8ad224b1a feat(jobs): Phase 6 — Tablet Station for fp.job
Operator-facing touchscreen UI. Three modes:
- job_picker: list of active jobs as big touch cards
- job_detail: job header + steps list, click a step to view detail
- step_detail: big Start/Finish buttons depending on state

Backend: 4 JSON-RPC endpoints under /fp/jobs/tablet/* for jobs
list, job detail, start step, finish step. Calls through to
fp.job.step.button_start / button_finish so all the audit
preservation, timelog creation, duration_actual roll-up logic
from Phase 1 still applies.

Menu entry 'Tablet Station (Native)' at sequence 3 (top) of the
Plating Jobs (Native) submenu inside the existing Plating app.

Manifest 19.0.2.3.0 → 19.0.2.4.0.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 04:41:07 -04:00
gsinghpal
e19d4862ed feat(jobs): Phase 6 — Plant Overview kanban + Manager Dashboard
Two operator-facing client actions for the native job model.

Plant Overview: kanban with columns = fp.work.centre, cards = active
fp.job.step rows (ready/in_progress/paused). Drag a card to a different
column to reassign the step's work_centre_id; click to open the step
form. Backend: /fp/jobs/plant_overview returns columns with cards;
/fp/jobs/plant_overview/move_card reassigns work_centre.

Manager Dashboard: list of in-flight fp.job rows with progress bars,
deadline (overdue highlight), current_step / current_location, and a
priority side-bar (rush=red, high=orange, normal=blue, low=grey). Click
a row to open the job form. State-count pills filter by state. Backend:
/fp/jobs/manager_dashboard returns rows + state counts.

Both menu entries land inside the existing 'Plating Jobs (Native)'
submenu under the Plating app (manager-only). The menu items are
defined in this module rather than in fusion_plating core, because
the action xmlids they reference aren't loaded yet at the time the
core menu file is parsed (fusion_plating_jobs depends on core, not
the other way round).

Manifest 19.0.2.2.0 → 19.0.2.3.0. Three new SCSS, three new JS,
three new XML files registered in web.assets_backend.

Verified on entech: module loaded clean, all 41 fusion_plating_jobs
tests pass, asset bundle regenerates without errors, both menus and
both client actions registered in ir_ui_menu / ir_act_client.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 04:32:16 -04:00
gsinghpal
034a6560ad feat(jobs): Phase 6 — Process Tree OWL component for fp.job
Ports fusion_plating_shopfloor's process_tree.js to bind to fp.job
instead of mrp.production. Consumes the /fp/jobs/process_tree
JSON endpoint built in Phase 6 lean.

Renders the recipe tree as cards. Each operation card shows the
step state (pending/ready/in_progress/done/etc.) when there's a
matching fp.job.step. Click an operation card -> open the step
form. Click Back -> return to the job form.

New 'Process Tree' button on the fp.job form (manager-only)
launches the client action with job_id context.

Manifest 19.0.2.1.0 -> 19.0.2.2.0.

Part of: native job model migration (spec 2026-04-25)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 04:20:09 -04:00
gsinghpal
47a54eac8f feat(jobs): cutover - bridge_mrp gate, menu nesting, migration robustness
Three changes to support live cutover on entech (2026-04-25):

1. Bridge_mrp gate: sale.order.action_confirm in
   fusion_plating_bridge_mrp now skips _fp_auto_create_mo when the
   x_fc_use_native_jobs config flag is True. Without this, every SO
   confirm would create both an mrp.production AND an fp.job
   (duplicate work). The gate is the only modification to bridge_mrp
   during the migration — the rest stays untouched.

2. Menu nesting: Plating Jobs (Native) now lives INSIDE the existing
   Plating app (parent=menu_fp_root) instead of as a separate
   top-level app. Two parallel 'Plating' apps was confusing UX. Work
   Centres (Native) goes under the existing Configuration sub-menu.
   '(Native)' suffix is temporary — drops at full legacy removal.

3. Migration script robustness: per-MO savepoints (so one bad MO
   doesn't abort the whole transaction with cascading 'transaction
   aborted' errors) + extended partner resolver fallback chain
   (warehouse partner → company partner) for orphan demo MOs without
   SO link or x_fc_customer_id. Verified: 43 MOs + 297 WOs migrated
   on entech with 0 errors after these fixes.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 04:05:02 -04:00
gsinghpal
5c009d3dcf docs(jobs): overnight progress summary for user
Comprehensive summary of work performed Apr 25 evening through
Apr 26 morning while user was asleep:
- Status of each phase (Phase 1+2 tested on entech, Phase 3-7
  committed locally + pushed but untested due to mid-session
  Tailscale SSH lockout)
- All commit hashes
- Architecture decisions made autonomously (parallel coexistence,
  Phase 6 lean, qc_check_id deferred, migration context flag)
- Files created vs untouched per constraints
- Recommended morning checklist for resuming work
- Honest assessment of what's solid vs unverified

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 00:21:34 -04:00
gsinghpal
97861df74d refactor(jobs): gate fp.job lifecycle hooks on fp_jobs_migration context
Migration script now sets context fp_jobs_migration=True before
creating fp.job records. action_confirm and button_mark_done check
this flag and skip side-effects (portal job creation, QC check,
racking inspection, delivery, certificate, notification dispatch)
when migrating.

Without this, the migration would double-create portal jobs / QC
checks / racking inspections — once via bridge_mrp's original
create on the source MO, once via jobs module's lifecycle hook on
the new fp.job mirror. With the gate, the migration script
explicitly rebinds the existing dependents via x_fc_job_id.

Manifest 19.0.2.0.0 → 19.0.2.1.0.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 00:19:17 -04:00
gsinghpal
f2f98aa9f6 docs(jobs): Phase 8/9/10 cutover runbook
Documents:
- Phase 8: 5-day E2E test plan on entech-clone (snapshot, migration,
  audits, smoke tests, rollback test, sign-off criteria)
- Phase 9: Cutover weekend runbook (Friday 6pm stop → Sunday buffer
  → Monday 7am operators back). 4 hours active work.
- Phase 10: 2-week burn-in monitoring + rollback safety net + Day
  14 snapshot drop. Bridge_mrp deprecation options.
- Phase-end polish task list (deferred Minor items from Phase 1-7
  reviews + the Phase 6 operator UI rewrite).
- Communication templates (operator email, manager briefing).
- Open decisions for user before Phase 9 starts.
- File checklist confirming all Phase 1-7 deliverables present.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 00:17:57 -04:00
gsinghpal
f9fab699d4 feat(jobs): Phase 7 — migration script + legacy id fields
Adds legacy_mrp_production_id (Integer index) on fp.job and
legacy_mrp_workorder_id on fp.job.step. Used as the idempotency
key during cutover migration.

Three scripts under fusion_plating_jobs/scripts/:
- audit_pre_migration.py   — counts and data-quality concerns BEFORE
- migrate_to_fp_jobs.py    — copies MO->fp.job, WO->fp.job.step, time
                             logs, rebinds cross-refs (batches,
                             holds, certs, readings, portals,
                             inspections, deliveries). Idempotent.
- audit_post_migration.py  — counts and verifies AFTER

Migration is run manually from \`odoo shell\` at cutover (not as
auto post-migration hook, for safety). README explains usage.

Tests verify the legacy id fields exist and the migration script
files are well-formed Python.

Manifest 19.0.1.9.0 -> 19.0.2.0.0.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 00:15:23 -04:00
gsinghpal
71376228cb feat(jobs): Phase 6 lean — scan controller + process-tree JSON endpoint
Phase 6 originally scoped the full operator UI rewrite (Plant
Overview, Tablet, Manager Dashboard, Process Tree). Tailscale SSH
to entech is currently unavailable, so live in-browser
verification of OWL/JS components isn't possible. Shipping a lean
Phase 6 with the data-layer pieces:

1. /fp/job/<id> scan controller — when a user scans a fp.job
   sticker, lands them on the fp.job form (or the process tree
   action once that's wired). Mirrors fusion_plating_reports' /fp/wo/
   pattern.

2. /fp/jobs/process_tree JSON endpoint — returns the recipe tree
   serialized with each node tagged by its fp.job.step state,
   ready for an OWL component to render. The component itself is
   deferred (see README.md).

The bigger UI deferrals (kanban, tablet, manager dashboard) are
documented in README.md. They get their own focused project after
cutover — the data layer is complete, so they can land
incrementally without touching fp.job/fp.job.step.

Tests verify controller imports + serialization shape (no HTTP
because TransactionCase doesn't easily simulate request context).

Manifest 19.0.1.8.0 → 19.0.1.9.0.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 00:08:50 -04:00
gsinghpal
c528d581c2 feat(jobs): Phase 5 — fp.job reports (sticker + traveller)
Two parallel report definitions for the native job model:

1. Job Sticker (6x4 inch custom paperformat) bound to fp.job. Prints
   WH/JOB/... ID, customer, SO, qty, due date, recipe, step
   progress. QR encodes /fp/job/<id> for scan-to-job navigation.

2. Job Traveller bound to fp.job, A4 portrait. Job header + all
   fp.job.step rows in sequence order with operator sign-off
   column.

Coexists with fusion_plating_reports' MO/WO bindings — both print
menus stay live during migration.

Deferred reports (use existing during migration; rebind at cutover):
- BoL, Packing Slip, Invoice (read from SO, no fp.job change needed)
- WO Margin (cost rollup; rebuild against fp.job.step.cost_total
  in phase-end polish)

Adds fusion_plating_reports to fusion_plating_jobs depends.

Tests deferred to post-Tailscale-restore: 3 new tests verify
report actions are registered + sticker template renders without
QWeb errors. Module file content verified locally as
well-formed XML.

Manifest 19.0.1.7.0 → 19.0.1.8.0.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 00:05:48 -04:00
gsinghpal
51a5cbbe5d feat(jobs): Phase 4 light refactors — notifications, KPI source tag
- Adds 'job_confirmed' and 'job_complete' trigger events to
  fp.notification.template (legacy 'mo_confirmed' / 'mo_complete'
  stay for bridge_mrp).
- fp.job.action_confirm and button_mark_done now fire those
  notifications best-effort via fp.notification.template._dispatch
  (silent skip if templates absent or notifications module missing).
- Adds x_fc_source ['mrp', 'jobs'] tag to fusion.plating.kpi.value
  so Phase 9 dashboards can filter or display both sources.
- Verified aerospace/nuclear/cgp/safety modules don't directly
  reference mrp.production or mrp.workorder.

Configurator integration was already covered by Task 2.5's SO
confirm hook (reads x_fc_part_catalog_id and x_fc_coating_config_id
from sale.order.line).

Manifest 19.0.1.6.0 -> 19.0.1.7.0.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:38:38 -04:00
gsinghpal
b359be3745 feat(jobs): Phase 3 light refactors — parallel job/step links on dependent models
Adds x_fc_job_id / x_fc_step_id Many2ones via _inherit on:
- fusion.plating.batch (workorder_id stays for legacy MRP-bound batches)
- fusion.plating.quality.hold
- fp.certificate
- fp.thickness.reading
- fusion.plating.delivery (parallel to existing job_ref Char)
- fp.racking.inspection (parallel to existing production_id)

fp.job.action_confirm now also calls a best-effort racking-inspection
auto-create. The current fp.racking.inspection still has a required
production_id, so the helper skips cleanly when this job has no MO link
(pure-native mode). Phase 9 cutover flips the required FK to fp.job.

Strategy: parallel coexistence — bridge_mrp's existing fields stay
populated; this adds NEW fields populated by the native flow. Phase 9
cutover stops populating the old fields.

Adds fusion_plating_batch + fusion_plating_receiving to jobs module
depends.

Note: spec referenced fp.batch / fp.quality.hold; the actual models
in this codebase are fusion.plating.batch / fusion.plating.quality.hold
— used the real model names.

Manifest 19.0.1.5.0 → 19.0.1.6.0. 29 jobs tests pass.

Part of: native job model migration (spec 2026-04-25)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:34:05 -04:00
gsinghpal
dd88afdf53 feat(jobs): add lifecycle hooks — portal/QC/delivery/invoice (Tasks 2.6-2.9)
- Task 2.6: fp.job.action_confirm auto-creates fusion.plating.portal.job
  with x_fc_job_id back-reference. Idempotent (skip if already linked).
- Task 2.7: fp.job.action_confirm checks customer.x_fc_requires_qc
  and best-effort creates a fusion.plating.quality.check (the model
  lives in bridge_mrp; runtime-detected to avoid dep cycle).
- Task 2.8: fp.job.button_mark_done sets state='done', date_finished,
  auto-creates draft fusion.plating.delivery and best-effort triggers
  fp.certificate generation.
- Task 2.9: account.move.action_post links invoice -> fp.job via SO
  origin lookup, updates portal_job state to complete and stamps
  invoice_ref.

5 new tests cover: portal job creation + idempotency, mark_done state
+ delivery, cancel-then-mark-done blocked.

Best-effort patterns (try/except + runtime model detection) used for
QC + cert because their target models are in dependent modules
that this module doesn't depend on by design.

qc_check_id field on fp.job still deferred — adding it here would
require depending on bridge_mrp.

Manifest 19.0.1.4.0 -> 19.0.1.5.0.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:27:38 -04:00
gsinghpal
294cea0e50 feat(jobs): add x_fc_use_native_jobs flag + SO confirm hook (Task 2.5)
Settings flag controls which SO confirm path runs. Default False
keeps the legacy bridge_mrp / mrp.production flow on entech.
Setting True diverts confirm into fp.job creation.

Both hooks coexist — bridge_mrp's _fp_auto_create_mo and the new
_fp_auto_create_job — but only one creates records per SO confirm
(controlled by the flag).

The new _fp_auto_create_job mirrors bridge_mrp's grouping logic
(x_fc_wo_group_tag), recipe resolution (coating → part), and
traceability fields (origin, sale_order_line_ids).

Settings UI shows the flag in a 'Fusion Plating Jobs' app section
of the standard Configuration menu.

3 new tests cover: flag off no-op, flag on creates job, idempotency.

Manifest 19.0.1.3.0 → 19.0.1.4.0.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:22:41 -04:00
gsinghpal
3b7eae9b78 feat(jobs): add fp.job._generate_steps_from_recipe (Task 2.4)
Native port of fusion_plating_bridge_mrp's
_generate_workorders_from_recipe method. Walks the recipe tree,
creates one fp.job.step per 'operation' node, formats child 'step'
nodes as step instructions on chatter, respects opt-in/out
overrides from fp.job.node.override.

Adaptations from the original:
- Creates fp.job.step (not mrp.workorder)
- Maps fusion.plating.work.center to fp.work.centre via forward
  link (x_fc_fp_work_centre_id) or code fallback
- Uses native field names (job_id, work_centre_id, etc.)
- Drops work_role_id (not on fp.job.step yet — Task 2.6+)
- Drops _fp_autofill_default_equipment (not yet on step)

5 new tests cover: basic generation, idempotency, no-recipe skip,
opt-in override behaviour, recipe_node_id link.

Manifest 19.0.1.2.0 → 19.0.1.3.0.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:17:47 -04:00
gsinghpal
4c68327b9c feat(jobs): add fp.job.node.override for per-job opt-in/out decisions
Mirror of fusion.plating.job.node.override from bridge_mrp, but
bound to fp.job. bridge_mrp's version stays alive for legacy MO
flow during the migration. Both coexist.

Adds override_ids One2many to fp.job via _inherit, plus
unique(job_id, node_id) constraint.

Note: spec-suggested _sql_constraints syntax is deprecated in
Odoo 19 ("Model attribute '_sql_constraints' is no longer
supported, please define model.Constraint on the model"). Used
the new class-attribute form: _unique_job_node = models.Constraint(...).
Verified the UNIQUE index is created on the table.

3 new tests: create, uniqueness, one2many backref.

Manifest 19.0.1.1.1 -> 19.0.1.2.0.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:12:53 -04:00
gsinghpal
36b9f30528 refactor(jobs): drop index=True on part_catalog_id for consistency
Code review noted this was asymmetric — only part_catalog_id had
explicit index=True among the 5 new fields, and Phase 1 core fp.job
relies on Odoo's implicit FK btree for ALL Many2ones (no explicit
indexes). Removed for consistency.

Important I2 (no explicit ondelete= policies) is deferred to a
phase-end polish task that addresses both Phase 1 core and Phase 2
extension fields uniformly.

Manifest 19.0.1.1.0 → 19.0.1.1.1.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:06:51 -04:00
gsinghpal
6e57b3576c feat(jobs): add cross-module fields to fp.job via _inherit (Task 2.2)
5 of the 6 deferred fields from Phase 1 Task 1.4 land here in
fusion_plating_jobs:
- part_catalog_id (fp.part.catalog from configurator)
- coating_config_id (fp.coating.config from configurator)
- customer_spec_id (fusion.plating.customer.spec from quality)
- portal_job_id (fusion.plating.portal.job from portal)
- delivery_id (fusion.plating.delivery from logistics)

qc_check_id deferred to Task 2.7 — its target model
(fusion.plating.quality.check) still lives in
fusion_plating_bridge_mrp and we don't depend on bridge_mrp from
this module. Task 2.7 will address QC sourcing.

6 unit tests (5 field-presence + 1 integration creating linked
records).

Manifest 19.0.1.0.0 → 19.0.1.1.0.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:01:23 -04:00
gsinghpal
4341a03891 feat(jobs): add fusion_plating_jobs module skeleton (Phase 2 Task 2.1)
Empty module that will host the native job bridge during Phase 2
of the migration. Coexists with fusion_plating_bridge_mrp during
the migration period — both can be installed simultaneously
without conflict.

Depends on:
- fusion_plating (fp.job, fp.job.step, fp.work.centre from Phase 1)
- fusion_plating_configurator (fp.part.catalog, fp.coating.config)
- fusion_plating_portal (fusion.plating.portal.job)
- fusion_plating_logistics (fusion.plating.delivery)
- fusion_plating_quality (fusion.plating.customer.spec)
- fusion_plating_certificates (fp.certificate)

These deps are why these fields couldn't live in fusion_plating
core (would invert the dep graph). All cross-module fields on
fp.job and fp.job.step land here via _inherit in subsequent tasks.

auto_install=False — opt-in only.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 22:55:04 -04:00
gsinghpal
d1aa7a81e0 docs(jobs): detail Phase 2 task breakdown — parallel module strategy
Phase 2 was previously outlined as 'rename bridge_mrp → jobs'.
That's destructive on entech. Revised strategy: build
fusion_plating_jobs IN PARALLEL with bridge_mrp. A settings flag
(x_fc_use_native_jobs) controls which path SO confirm takes.
Default False = legacy MO flow stays. Cutover (Phase 9) flips
the flag.

Phase 2 breakdown into 11 tasks (2.1–2.11), totaling ~5 days
engineering. All preserve bridge_mrp untouched until cutover.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 22:49:34 -04:00
gsinghpal
1491f2367b refactor(jobs): address code review feedback on Task 1.8 admin views
- I1: Lock time_log_ids list inside step Audit tab to read-only
  (no create/edit/delete on the nested list). Audit timelog rows
  are produced exclusively by button_start / button_finish; if a
  manager could hand-edit them, cost_total rollups would silently
  drift.
- I2: Add explicit list view (decoration on state) and search view
  (filters by state/kind, group_by state/work_centre/job) for
  fp.job.step. The Steps (Admin) menu was using Odoo's default
  auto-list with no filter, which would be unusable after a few
  weeks of step accumulation. Action now references the search
  view explicitly.

Manifest 19.0.8.7.0 -> 19.0.8.7.1.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 22:44:16 -04:00
gsinghpal
b2ae79b61f feat(jobs): add admin views and menu for Phase 1 models
Manager-only views during Phase 1 — operator UI rebuilt in Phase 6.
Top-level menu 'Plating Jobs (new)' (seq=47) groups the three
new act_window actions (Jobs, Steps Admin, Work Centres) so the
foundational models can be exercised through the UI without
touching the operator-facing menus that still serve mrp.production
and mrp.workorder.

Job form has Steps/Source/Costs notebook tabs. Step form has
Equipment/Plating Spec/Audit/Instructions tabs (Audit shows
the time log rows from Task 1.7). Search filters by state,
priority, partner, facility.

Manifest 19.0.8.6.1 → 19.0.8.7.0.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 22:38:36 -04:00
gsinghpal
54068b3d18 refactor(jobs): address code review feedback on fp.job.step.timelog (Task 1.7)
- I1: Add supervisor ACL row on fp.job.step.timelog. The other
  job-related models all have a 3-tier (operator/supervisor/
  manager) pattern; timelog had been operator+manager only with
  no comment explaining why. Adding the supervisor row for
  consistency — supervisors can write timelogs the same as
  operators.
- I2: Capture fields.Datetime.now() once in button_start and
  reuse for both the step's first-start audit timestamp and the
  new timelog's date_started. Mirrors button_finish's pattern.
  Eliminates microsecond drift between two related timestamps.
- M6: Update stale comment in fp_job_step.py that said
  'duration_actual will be sum of timelog rows once Task 1.7
  lands' — Task 1.7 has landed; replace with current behaviour.

Manifest 19.0.8.6.0 → 19.0.8.6.1.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 22:34:10 -04:00
gsinghpal
28892f56b5 feat(jobs): add fp.job.step.timelog for granular timer tracking
Each button_start opens a fresh timelog row; button_finish closes
the open row and recomputes step.duration_actual as the sum of all
interval durations. Replicates Odoo MRP's mrp.workorder.time_ids
granularity natively (no mrp dep).

Schema: step_id (M2O cascade), user_id, date_started,
date_finished, duration_minutes (computed, stored).

ACLs: operator get create permission on timelogs because
button_start creates them.

Tests: test_start_creates_timelog (asserts the log row exists,
date_finished is False, user_id is the current user) and
test_finish_closes_timelog (asserts log gets date_finished, has a
non-negative duration, and step.duration_actual matches).

Manifest 19.0.8.5.1 -> 19.0.8.6.0.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 22:27:26 -04:00
gsinghpal
57a3aea16f refactor(jobs): address code review feedback on fp.job.step (Task 1.6)
- I1: Replace 'Task 1.6' markers in stub method comments and
  NotImplementedError messages with forward-looking phrasing.
  Task 1.6 is what just shipped (the field expansion); the action
  stubs are deferred to an unspecified future task. Stale markers
  would have confused future readers/operators.
- I2: Add test_cost_total_recomputes_when_rate_changes — insurance
  test that verifies @api.depends('cost_per_hour') triggers through
  the related-from-work_centre chain. Catches future Odoo upgrades
  that break related-depends.

Manifest 19.0.8.5.0 → 19.0.8.5.1.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 22:22:15 -04:00
gsinghpal
91767f9f03 feat(jobs): add equipment, audit, plating-spec fields to fp.job.step
Equipment: bath_id, tank_id, rack_id (all in core). oven_id deferred
to a bridge module — fusion.plating.bake.oven lives in shopfloor and
core can't depend on it. masking_material_id deferred too — model
fusion.plating.masking.material does not yet exist anywhere; will be
added when the masking model lands.

Audit: signoff_user_id (readonly), facility_id (related from
work_centre_id, stored).

Plating spec: thickness_target, thickness_uom (um/mil/in),
dwell_time_minutes, bake_setpoint_temp, bake_actual_duration,
bake_chart_recorder_ref (Nadcap audit trail).

Recipe-related: requires_signoff, auto_complete, is_manual,
customer_visible (all related from recipe_node_id, stored, so
operator sees current values without re-querying process.node).

Cost rollup: cost_per_hour related from work_centre_id, cost_total
computed (duration_actual / 60 x rate), currency_id related too.
Full rollup-from-timelogs lands in Task 1.7.

Tests cover: facility_id related-field, thickness_uom default,
cost_total zero/non-zero paths.

Manifest 19.0.8.4.1 -> 19.0.8.5.0.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 22:15:26 -04:00
gsinghpal
688fe8317c refactor(jobs): address code review feedback on fp.job.step (Task 1.5)
- I2: Add TODO comment block + stub button_pause/button_skip/
  button_cancel that raise NotImplementedError. Makes the missing
  state-machine paths explicit instead of invisible gaps. Future
  Task 1.6 wires the real implementations; shop-floor buttons in
  Task 1.8 can already point to the right method names.
- I3: button_finish now preserves first-finish audit timestamp
  via 'if not step.date_finished:' guard, mirroring button_start.
  Future rework flow that re-opens a step won't lose the original
  finish data. The duration_actual rollup landing in Task 1.7 will
  use timelog rows for the most-recent interval if needed.
- I4: step_count and step_done_count are now store=True so list
  views and stat buttons (Task 1.8) don't recompute across all
  job rows on every render. step_progress_pct and current_step_id
  stay non-stored - they're cheap derivatives. Split compute methods
  so stored + non-stored fields don't share one method (Odoo flags
  the mix as inconsistent and recomputes stored fields whenever the
  non-stored one is read, defeating the perf gain).

Manifest 19.0.8.4.0 -> 19.0.8.4.1.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 22:09:16 -04:00
gsinghpal
c41a488b58 feat(jobs): add fp.job.step model with state machine
Per-operation model replacing mrp.workorder for plating. Each step
instantiates from a recipe operation node (recipe_node_id link).
Container/step nodes from the recipe template are rendered at view
time via that link — they don't get rows here. See spec §5.2
Option A.

7-state machine: pending → ready → in_progress → done, plus
paused, skipped, cancelled. button_start/button_finish enforce
the transitions.

Job header gets step_ids + step_count, step_done_count,
step_progress_pct, current_step_id (computed from steps).

Equipment, audit fields, plating-spec fields, time logs, and
release-ready validation come in Tasks 1.6 and 1.7.

Manifest 19.0.8.3.1 → 19.0.8.4.0.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 21:59:07 -04:00
gsinghpal
f7a4cba5a8 docs(jobs): split fp.job §5.1 fields by module ownership (Task 1.4)
Originally Task 1.4 was to add all spec §5.1 extension fields to
fp.job in core. The dependency-graph audit during implementation
revealed that 6 of those fields point to models in dependent
modules (configurator, quality, portal, logistics, bridge_mrp).
Adding them in core would invert the dependency graph.

Spec §5.1 now has a Module column. Core-safe fields stay in
fusion_plating/models/fp_job.py; cross-module fields are deferred
to their owning modules via _inherit = 'fp.job' in Phase 2.

Plan Task 1.4 narrative updated to reflect the reduced scope.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 21:54:35 -04:00
gsinghpal
e4111ad000 refactor(jobs): address code review feedback on fp.job (Task 1.4)
- Move NOTE comment from between @api.depends and the function
  into a proper docstring on _compute_costs.
- Make currency_id required=True (default still in place — only
  a programmatic write would null it, but Monetary fields need a
  non-null anchor).
- Add test_current_location_for_confirmed to cover the title-case
  fallback branch in _compute_current_location.

Manifest 19.0.8.3.0 → 19.0.8.3.1.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 21:51:23 -04:00
gsinghpal
335dc2488e feat(jobs): add core-safe extension fields to fp.job
Scope was reduced from spec's full §5.1 list because 6 of the 10
plating-specific fields point to models in dependent modules
(configurator, quality, portal, logistics, bridge_mrp). Adding
those Many2ones in core would invert the dependency graph. They
move to their owning modules via _inherit = 'fp.job' and get
re-bundled by fusion_plating_jobs in Phase 2.

This commit lands the core-safe subset:
- sale_order_line_ids (sale_management is in core depends)
- recipe_id, start_at_node_id (process.node is in core)
- invoice_ids (account is reachable via sale_management → sale)
- Cost rollup: quoted_revenue / actual_cost / margin / margin_pct
  with placeholder compute (actual_cost = 0 until Task 1.5 wires
  fp.job.step.cost_total)
- current_location stub (full Bath/Oven rendering in Task 1.6)

Tests cover the cost-rollup math and the current_location stub.
Spec §5.1 has been re-tabulated with explicit 'Module' column.

Manifest 19.0.8.2.1 → 19.0.8.3.0.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 21:44:28 -04:00
gsinghpal
b45a134aa4 refactor(jobs): address code review feedback on fp.job
- Sequence: add noupdate="1" to fp_job_sequences.xml. Without it,
  every module update resets number_next to 1, corrupting the live
  job-number stream. Matches fp_sequence_data.xml convention.
- action_cancel now raises UserError on an already-cancelled job
  instead of silently rewriting state. Audit-grade traceability
  expects explicit failures.
- Added TODO marker for action_hold / action_resume /
  action_revert_to_confirmed so future authors don't bypass the
  state-machine guards.
- Tests: added cannot_cancel_done (covers the dead-code UserError
  branch) and cannot_cancel_already_cancelled.

Manifest version bumped 19.0.8.2.0 -> 19.0.8.2.1.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 21:36:58 -04:00
gsinghpal
93e0be4b48 docs(jobs): tighten spec/plan after Task 1.2 review
- Spec §5.3: document that default_oven_id is deferred to the
  fusion_plating_jobs bridge module (fusion.plating.bake.oven lives
  in shopfloor; core can't depend on it).
- Plan: align ACL blocks for Tasks 1.2/1.3/1.5/1.7 to use
  group_fusion_plating_operator for the lowest tier instead of
  base.group_user. Caught by the code-quality reviewer on Task 1.2;
  this prevents the same bug recurring in later tasks.
- Plan Task 1.2 test name corrected:
  test_facility_required_for_active_centre →
  test_facility_optional_at_create.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 21:30:23 -04:00
gsinghpal
26928713d5 feat(jobs): add fp.job native model with state machine
Header model replacing mrp.production. mail.thread for chatter,
priority/state/deadline tracking, sequence WH/JOB/00001+. Tests
cover create, confirm, cancel, and forbidden double-confirm.

State machine:
  draft -> confirmed -> in_progress -> done
              v                          ^
          cancelled              (rework reverts here)
  on_hold can be entered from confirmed or in_progress.

Step relations come in Task 1.5; SO/recipe/portal/cost extension
fields come in Task 1.4.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 21:29:36 -04:00
gsinghpal
5970dfe57b refactor(jobs): address code review feedback on fp.work.centre
- ACL: use group_fusion_plating_operator for read-only tier instead of
  base.group_user, matching the established hierarchy in the rest of
  ir.model.access.csv
- Test: rename test_facility_required_for_active_centre →
  test_facility_optional_at_create. Old name claimed the opposite of
  what the assertion checks.
- Manifest version bumped 19.0.8.1.0 → 19.0.8.1.1.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 21:19:59 -04:00
gsinghpal
37f917824a feat(jobs): add fp.work.centre native model
Replaces mrp.workcenter for plating. Domain-specific kinds
(wet_line/bake/mask/rack/inspect/other) drive release-ready
validation on steps. ACLs follow existing supervisor/manager
hierarchy.

Note: spec listed default_oven_id Many2one to fusion.plating.oven
but that model does not exist in core (the bake-oven model
fusion.plating.bake.oven lives in fusion_plating_shopfloor, which
core cannot depend on). Field omitted; the bridge that adds
fp.job/fp.job.step can re-introduce it via _inherit later.

Part of: native job model migration (spec 2026-04-25)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 21:12:32 -04:00
gsinghpal
41d0908ade changes 2026-04-24 21:04:38 -04:00
gsinghpal
0eab4b4efb fix(reports): sticker PDF KeyError: 'quote' on fusion_pdf_preview path
The QR <img> src used `% quote(_scan_url)` to URL-encode the value,
but `quote` isn't always in the QWeb render context — particularly
on the fusion_pdf_preview / account render chains. Result:
KeyError: 'quote' when printing from the browser.

_scan_url is always base_url + '/fp/wo/<int>' — no characters that
need encoding. Replaced the % + quote() formatting with simple
string concatenation, dropping the quote dependency entirely.

Smoke verified on entech: MO + WO stickers render cleanly at 27KB
each (with QR image included).

fusion_plating_reports → 19.0.7.2.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:58:24 -04:00
gsinghpal
e32ff4b056 feat(reports): MO-bound WO sticker + polished professional layout
User reported two issues with the sticker:

1. "Print → WO Box Sticker" didn't appear on the MO form
   (WH/MO/00067). The operator workflow lives on the MO form, not
   the WO — binding only to mrp.workorder meant they couldn't see
   the option. Now bound to BOTH:
     * mrp.workorder (per-WO sticker)
     * mrp.production (per-MO sticker — prints the MO friendly
       name after "WO #" so it reads naturally in shop-floor
       vocabulary)
   Internal refactor: factored the layout into a shared inner
   template report_fp_wo_sticker_inner; the two outer templates
   normalise their input to the same _order_id / _scan_id / _mo
   variables and t-call the inner.

2. Design polish. The previous layout was a plain label/value
   table that looked rough. Redesigned with:
     * Proper sticker chrome: 0.5mm black border, 1.5mm rounded
       corners, edge padding.
     * Header row with bottom border rule separating logo+WO-# on
       the left from QR+caption on the right.
     * Grid rows now alternate white / #f4f5f7 zebra-striping with
       a right-aligned vertical rule between label and value.
     * ALL-CAPS, letter-spaced, gray-333 labels at 7.5pt; values
       at 8.5pt with strong (9.5pt, 700) emphasis on the key data
       (PO, Part Number, Qty) so it reads at a glance from across
       the warehouse.
     * Helvetica Neue font stack.
     * "SCAN TO OPEN" caption under the QR.

Scan endpoint updated: /fp/wo/<id> now tries mrp.production first
(operator home form) then falls back to mrp.workorder. Numeric
collisions between the two id spaces are possible; MO wins because
the MO view carries the full context.

fusion_plating_reports → 19.0.7.1.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:52:22 -04:00
gsinghpal
be33a76ad2 feat(reports): WO box sticker + QR-scan-to-WO endpoint
Client is migrating from Steelhead and needs to keep the small
parts-box sticker format the warehouse crew already knows. Two
pieces shipped together so scanning is seamless from day one:

1. report_fp_wo_sticker — 4x3" QWeb label bound to mrp.workorder.
   Layout mirrors the Steelhead sticker:
     * ENTECH logo top-left (via env.company.logo)
     * QR code top-right encoding /fp/wo/<id>
     * Grid: PO (RO) / Customer / Process / Part Number / Due
       Date / Qty / Notes
   Dedicated paperformat_fp_wo_sticker at 102x76mm, 300 DPI,
   landscape, 3mm margins — sized for thermal / inkjet label
   printers without shrink-to-fit.
   Binding added so "Print → WO Box Sticker" appears on every
   mrp.workorder record.

2. FpWoScanController — GET /fp/wo/<int:wo_id> redirects the
   scanner straight to the work-order form
   (/odoo/action-mrp.action_mrp_workorder/<id>). auth='user' so
   logged-in scanners land on the WO immediately; others bounce
   through Odoo's login and return to the same URL. No custom
   client work needed — any phone camera, handheld barcode
   scanner, or tablet browser opens the URL on scan.

Process row resolution chain: part.default_process_id →
coating.recipe_id → fallback. So the sticker prints whichever
process is actually going to drive WO generation for this line,
matching the direct-order wizard's Effective Process column.

fusion_plating_reports → 19.0.7.0.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:39:35 -04:00
gsinghpal
eddf803d4c feat(reports): split customer-facing line header into Part Number + Description columns
User request: on customer-facing PDFs the single "Part" column was
stacking part number + revision + description together. Split into
two distinct columns so customers see Part Number in its own field
and the Description column carries only the prose.

Macro split:
  * customer_line_part_number — strong part number + "(Rev X)"
  * customer_line_description  — line.name + any populated line
    metadata (serial, job#, thickness)
  * customer_line_header (legacy) kept as a thin wrapper that
    t-calls both macros stacked so older reports still render.

Reports updated — each gains a new first "PART NUMBER" column and
the old "PART" column renamed to "DESCRIPTION":
  * report_fp_sale (both portrait variants)
  * report_fp_invoice (both portrait variants)
  * report_fp_packing_slip (both variants — delivery + MO-origin)

Column widths rebalanced per report. Section / note colspans bumped
to account for the extra column.

report_fp_bol left as-is — its "Description of Goods" td is a
freight-convention combined field, intentionally keeps the stacked
layout via the legacy customer_line_header macro.

fusion_plating_reports → 19.0.6.0.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:17:56 -04:00
gsinghpal
8142bd229a feat(configurator): "PO Pending" escape hatch for customers who send PO later
Customer feedback: some customers don't send their PO with the
initial order — they send it days or weeks later. The system was
blocking SO confirmation without a PO, which forced the shop to
either wait on paperwork or ask a manager for a formal override.

New estimator-level path: a "PO Pending" boolean on sale.order +
an optional "PO Expected By" date.

  * Confirm without a PO# / PO document when PO Pending is ticked.
  * action_confirm skips the hard error if po_pending OR po_override
    is set (keeps the existing manager-override path too).
  * On confirm with PO Pending, the system schedules a chase
    activity for po_expected_date (or +3 days if blank), assigned
    via mail.activity so it shows up in the sales user's activity
    list. Chatter note logged so audit is obvious.
  * Direct-order wizard: po_number and po_attachment_file become
    optional. Ticking "PO Pending" in the wizard is the trade-in;
    a help note under the toggle explains the chase behaviour.
  * Once the PO arrives, user fills in the PO# / uploads the doc,
    and turns PO Pending off — existing downstream flow resumes.

Difference from x_fc_po_override (kept):
  * PO Override = manager waiver, permanent ("handshake deal").
  * PO Pending = estimator flag, time-boxed ("customer will send it
    by Friday").

fusion_plating_configurator → 19.0.14.0.0
fusion_plating_invoicing    → 19.0.3.0.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:08:00 -04:00
gsinghpal
2d3ee03f86 fix(configurator): widen direct-order wizard via Odoo's dialog_size context
Second attempt at widening the wizard modal after the :has() CSS
approach broke layout. This time using Odoo's built-in
dialog_size mechanism — just drop 'dialog_size': 'extra-large'
into the action's context and Odoo applies its own modal-xl
class, sized for wide content. About 30% wider than the default,
which gives the 10+ line columns breathing room without any
custom CSS.

fusion_plating_configurator → 19.0.13.6.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 10:01:00 -04:00
gsinghpal
d9526dc050 revert: drop fp_direct_order_wizard.scss — :has() approach broke the modal
Reverting the previous wizard-width attempt. The
`.modal-dialog:has(.o_fp_direct_order_wizard)` selector combined
with the fixed width override produced broken layout (modal no
longer rendering correctly).

Better path for widening this wizard is still TBD — the built-in
maximize icon in the modal header already lets users go full-
screen as a workaround until a safe width override lands.

fusion_plating_configurator → 19.0.13.5.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:58:56 -04:00
gsinghpal
470c44ee5d fix(configurator): widen direct-order wizard modal so line columns breathe
User complaint: the direct-order wizard's line table was crammed —
"Primary Treatment" showed as "Primary T..." and "Serial Number"
as "Serial Nu..." at the default Odoo modal width (~992px).

Added a dedicated stylesheet that targets the wizard via a new
o_fp_direct_order_wizard class on the form element. The modal
dialog containing the wizard now opens at min(1600px, 95vw) —
wide enough for the 10+ columns (Part, Primary Treatment, Process,
Thickness, Serial Number, Qty, Unit Price, Subtotal, Part Deadline,
WO Group) to fit without truncation on typical desktop displays,
while still adapting to narrower screens.

Also nudged per-cell horizontal padding from Bootstrap's default
to 10px left/right so the columns have a bit more breathing room
inside the wider table.

fusion_plating_configurator → 19.0.13.4.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:56:33 -04:00
gsinghpal
488b0655a7 fix(configurator): wizard gap between "Add From" buttons + force view reload
Two small fixes on the direct-order wizard:

1. User reported the Process column from the previous commit didn't
   appear on the line list. Root cause: module view definitions
   only reload on -u, not on systemctl restart. The earlier ship
   bumped the version + ran -u, but the Process column inside the
   list view required a fresh view load. Re-running -u now resolves
   it (no code change needed for that field).

2. The "+ Add From Prior SO" and "+ Add From Quotes" buttons were
   rendering edge-to-edge because their container div used the
   default Bootstrap flow (margin-right: 0). Swapped the wrapping
   div class from `mb-2` to `mb-2 d-flex gap-2` so Bootstrap lays
   the two buttons side-by-side with a consistent 0.5rem gap.

fusion_plating_configurator → 19.0.13.3.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:25:56 -04:00
gsinghpal
381a750902 feat(configurator): direct-order line shows effective Process alongside Treatment
User asked why the direct-order wizard only showed "Primary
Treatment" and not Process — aren't they the same? They're not,
but the distinction was invisible on the order line until now.

Mental model (preserved here to keep future decisions aligned with
the user's question):

  * Primary Treatment (fp.coating.config) = "WHAT coating" (process
    type, thickness range, spec reference — the contractual
    deliverable).
  * Process (fusion.plating.process.node tree) = "HOW we make it"
    (the floor-level sequence of operations and steps that WO
    generation turns into work).

  Each coating carries a default process (recipe_id). Parts can
  override that via the Process Composer, storing a part-scoped
  clone (default_process_id on fp.part.catalog). Resolution:
  part's composed process wins; coating default is the fallback.

Added a computed read-only `effective_process_id` field on
fp.direct.order.line that displays exactly what process will drive
WO generation for the line, plus a one-line `effective_process_source`
showing whether it came from the part ("customised") or the
coating ("default"). Both surfaced on the wizard list and form so
the estimator can verify before confirming the order.

No behaviour change — this is pure visibility. WO generation still
uses the same resolution chain it did before.

fusion_plating_configurator → 19.0.13.2.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 09:20:40 -04:00
gsinghpal
625f6560f1 feat(plating): split templates vs part-scoped processes + Process smart button
Two user-reported gaps:

1. The Process Recipes list was about to be flooded by part-scoped
   clones as soon as parts started carrying customised processes —
   thousands of clones would bury the handful of real shared
   templates (General Processing, Anodize, etc.).

   Fix: the main Process Recipes action now narrows to
   part_catalog_id = False so shared templates stay alone in that
   view. A sibling menu "Part Processes" (Plating → Operations →
   Part Processes) shows the inverse list — every part-cloned
   process, grouped by part — so admins can audit clones without
   cluttering the templates list.

   Search view gains two toggle filters (Shared Templates /
   Part-Scoped) and a "Group by Part" option. The node list gains
   an optional "Part" column.

   Split across modules: core owns the base search / tree / action
   (unchanged); configurator owns all the part_catalog_id-dependent
   pieces (filter extensions, list column, narrower domain,
   "Part Processes" action + menu). Keeps the dependency direction
   clean — configurator always depends on core, never the other way.

2. Added a "Process" smart button to the part form's button box.
   Shows either a green check (composed) or "None" (not yet
   composed) and opens the part-scoped Composer on click. Gives
   users one-tap access from any part form without hunting through
   the Process tab.

fusion_plating → 19.0.8.0.0
fusion_plating_configurator → 19.0.13.1.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:45:24 -04:00
gsinghpal
acb406950f feat(configurator): part-scoped process name shows part id + revision
User feedback: the Process tab on fp.part.catalog was displaying a
bare template name ("General Processing"), making it impossible to
tell at a glance that the clone belonged to this specific part.

Root clone now inherits the template name with a part-identifier
suffix appended:
  "General Processing — 1234567 Rev 2"

Only the ROOT gets the suffix — child nodes keep their clean source
names so the tree-editor canvas doesn't get cluttered.

Suffix logic avoids doubling "Rev": if part.revision is already
prefixed with "Rev " (e.g. "Rev 2"), we don't prepend another one.

Post-upgrade hook backfills existing part-cloned roots that
pre-date this change so users see the new format without having
to re-compose (which would otherwise wipe their customisations).

fusion_plating_configurator → 19.0.13.0.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:33:07 -04:00
gsinghpal
274236d34c fix(plating): rename opt_in_out labels — 'Required' replaces 'Disabled'
User feedback: "Disabled" was confusing; it looked like the step
was turned off entirely when in fact the semantic meant "every job
runs this, cannot be removed". Aligning labels with Steelhead's
own terminology and the mental model the shop floor already uses:

  Python Selection values (unchanged: disabled / opt_out / opt_in)
    disabled  →  "Required"
    opt_out   →  "Opt-Out (included by default, can be removed per job)"
    opt_in    →  "Opt-In (excluded by default, can be added per job)"

  Tree-editor side panel inline labels match, plus a short helper
  line under the dropdown:
    "Required — every job runs this step.
     Opt-Out — ships included, estimator can remove per job.
     Opt-In — ships excluded, estimator can add per job."

Field string also flipped from "Opt In/Out" to "Step Usage" — the
new header reads closer to what the field actually controls.

Column order also flipped so the Opt-Out option appears above
Opt-In — matches the frequency in real recipes (most optional
steps are included by default and sometimes skipped, not the other
way around).

fusion_plating → 19.0.7.4.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:24:57 -04:00
gsinghpal
7629af4e00 fix(plating): tree editor — expand newly imported nodes + Expand/Collapse All
Two related gaps:

1. loadTree() only auto-expanded nodes when expandedNodes was
   completely empty — that was "first-load only" behaviour. After
   an import, the subsequent loadTree() found the map populated
   and skipped the expand pass entirely, so every freshly imported
   node came in collapsed ("2 hidden"). Users had to click each
   one open by hand.

   Fix: iterate the whole tree on every load and default any node
   whose id isn't yet in expandedNodes to true. Nodes the user
   explicitly collapsed stay that way (their id IS in the map,
   set to false).

2. Added "Expand all" and "Collapse all" buttons to the tree-
   editor header so operators can get a full view (or a tight
   overview) without clicking node by node. Collapse all keeps
   the recipe root expanded — otherwise the canvas goes blank.

fusion_plating → 19.0.7.3.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:20:39 -04:00
gsinghpal
9d7b7daf5a feat(plating): tree-editor import supports insert-before position
The import feature appended every imported node to the end of the
target recipe. That's wrong for the common case — General Processing
has Shipping as its last operation, so importing an Electroless
Nickel pack should land BEFORE Shipping, not after it. The user
would otherwise have to click Move Up dozens of times.

Controller: /fp/recipe/node/import_children now accepts
insert_before_id:
  null/missing  → append at end (default, unchanged)
  0             → insert at the start
  <positive id> → insert right before that top-level child

Implementation reorders target's top-level children in one pass
after Phase 1 creates the copies (placeholder sequence=0). Phase 2
splits existing vs. new, finds the anchor index in the existing
list, and reassigns sequences 10/20/30/... across the merged list.
Collisions on the old max_seq-based append strategy are eliminated.

JS: state.importInsertBefore drives a new "Insert:" dropdown in the
toolbar with options:
  — At the end — (default)
  — At the start —
  Before <each top-level child name>

Smoke on entech (3-case): insert-before-middle, insert-at-start,
insert-at-end all produce the expected ordering.

fusion_plating → 19.0.7.2.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:16:05 -04:00
gsinghpal
03f41422de fix(plating): tree editor — title wrapping + import hierarchy
Two bugs reported on the tree editor after the move/import feature
shipped:

1. Card titles truncated to "Contrac…" because .o_fp_re_title had
   white-space: nowrap + text-overflow: ellipsis. Swapped to
   white-space: normal + overflow-wrap: anywhere so long names
   wrap onto multiple lines inside the card. Widened card max-
   width 380→460px and bumped min-width 240→260px so wrapped
   titles have room.

2. Import-children was flattening the tree — all operations AND
   their step children landed at the top level instead of staying
   nested under their operations.

   Root cause: src_node.copy({'parent_id': new_parent.id, ...})
   on a _parent_store model behaved unpredictably — in some runs
   the override in copy_vals didn't stick and child recursion
   ended up with a wrong parent_id. Rewrote _copy_subtree to use
   copy_data() + Node.create() so parent_id is set explicitly and
   child_ids / parent_path are stripped (we recurse ourselves).

   Smoke verified on entech: General Processing (1 root + 5 ops
   + 7 steps = 13 nodes) imports with hierarchy bit-identical to
   source.

fusion_plating → 19.0.7.1.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:08:55 -04:00
gsinghpal
8853cdd0c6 feat(plating): tree editor — move up/down buttons + import from recipe
Two gaps closed on the recipe tree editor based on user feedback:

1. Explicit Move Up / Move Down buttons on every non-recipe node
   row, driven by a new POST /fp/recipe/node/move_sibling endpoint.
   DnD already existed but couldn't reliably move a node above a
   sibling when the drop zone overlapped the node being dragged.
   The button-based flow sidesteps that entirely and makes "nudge
   one slot" a single click.

2. Inline "Import from recipe" toolbar that appears when the
   Import button is clicked in the header. User picks a source
   recipe from a dropdown (POST /fp/recipe/list, excludes the
   current one), toggles "Skip duplicate names", and clicks
   Import. POST /fp/recipe/node/import_children deep-copies every
   top-level child of the source under the current recipe,
   preserving the sub-tree structure. Dedupe is on by default so
   re-running the import on an already-populated recipe is a
   no-op; users who want to merge identical-named branches can
   untick the checkbox.

Controller endpoints:
- /fp/recipe/list (list recipe roots for the picker)
- /fp/recipe/node/move_sibling (swap with neighbour by direction)
- /fp/recipe/node/import_children (deep-copy subtree with dedupe)

Smoke verified on entech: 5-child recipe imported cleanly, dedupe
blocks re-import, sequence swap works.

fusion_plating → 19.0.7.0.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:00:24 -04:00
gsinghpal
c76bbd85eb fix(plating): Process Composer/Editor breadcrumb accumulation
Two separate issues were stacking up on the breadcrumb trail:

1. The composer was launching the tree editor with the name
   "Process Composer — …" — identical to its own label. The
   breadcrumb trail ended up showing "Process Composer / Process
   Composer" because both pages claimed the same name. Renamed the
   tree-editor instance to "Process Editor — …" so the two pages
   read distinctly.

2. Every "Back to part" click pushed a new entry onto the
   breadcrumb stack instead of resetting. After one round-trip the
   trail looked like "… / Composer / Editor / Part"; after two it
   was "… / Composer / Editor / Part / Composer / Editor / Part".
   Added clearBreadcrumbs: true to both back paths (composer's
   backToPart and tree-editor's onBackToList) so a RETURN action
   actually resets the stack.

fusion_plating → 19.0.6.2.0
fusion_plating_configurator → 19.0.12.4.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 07:48:38 -04:00
gsinghpal
7d44af7d77 fix(plating): tree-editor back button honours part-scoped context
When the Recipe Tree Editor is opened from the part-scoped Process
Composer (Sub 3), the composer already passes part_id via the
action context. The editor was ignoring it and routing onBackToList
to the generic Recipes list, stranding the user away from the part
they came from.

Capture ctx.part_id at onMounted, expose a state.fromPart flag, and
branch onBackToList: if part_id is set, open the fp.part.catalog
form; otherwise keep the current Recipes-list behaviour. XML button
label flips "Recipes" → "Part" accordingly so the user knows where
the button will take them.

fusion_plating → 19.0.6.1.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 07:45:12 -04:00
gsinghpal
33e35fd213 fix(configurator): centre Process Editor button icon + make icon white
- Icon + label now share an inline-flex row with align-items: center,
  so both sit on the button's vertical midline regardless of line-
  height inheritance.
- Dedicated gap (10px) replaces the me-2 utility so the _hint block's
  .fa { margin-bottom: 16px } can't bleed in and push the icon off.
- Icon colour forced to #ffffff to match the button's white label —
  contrast against btn-primary green is now clean.

fusion_plating_configurator → 19.0.12.3.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 07:41:24 -04:00
gsinghpal
18f45d50f5 fix(configurator): Process Composer tree-editor button polish
- Icon: fa-edit → fa-sitemap (pencil suggests inline editing; the
  button actually navigates to a separate tree editor — sitemap
  matches the intent).
- Icon spacing: swap the fragile leading-space-in-span for the
  Bootstrap me-2 utility so the icon-to-text gap is consistent.
- Label: "Open Tree Editor" → "Open Process Editor" to match the
  page title ("Process Composer") and the menu vocabulary the rest
  of the product uses.

fusion_plating_configurator → 19.0.12.2.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 07:37:35 -04:00
gsinghpal
d0eefe6392 fix(configurator): Process Composer dark-mode palette (Sub 3 follow-up)
Process Composer was rendering a white card background on dark-mode
tenants because the SCSS relied on var(--bs-body-bg, #ffffff) — the
Bootstrap CSS variable doesn't flip reliably in Odoo 19's backend,
and the hardcoded fallback kicked in.

Rewrote with the shopfloor token pattern from CLAUDE.md: branch on
$o-webclient-color-scheme == dark at compile time, expose via CSS
custom properties (--fp-composer-card / -border / -panel / -text /
-muted), drop every --bs-* fallback for layout colours.

Cleared the ir_attachment asset cache on entech so both the backend
and web_dark bundles recompile cleanly.

fusion_plating_configurator → 19.0.12.1.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 07:35:11 -04:00
gsinghpal
2bfabfe135 feat(plating): Sub 8 — split receiving vs inspection + box parity
fp.receiving simplifies to box-count-only (new primary state
machine: draft → counted → staged → closed). Legacy
inspecting/accepted/discrepancy/resolved states stay in the
Selection so existing records load without error but are surfaced
behind a manager-only toggle. New box_count_in field + banner
that tells the receiver "count boxes only — parts are inspected
by the racking crew."

New fp.racking.inspection + fp.racking.inspection.line models —
one record per MO, auto-created by mrp.production.create() with
one line per contributing SO line (qty_expected seeded, qty_found
+ condition filled in by the racking crew when they open the boxes).
State: draft → inspecting → done | discrepancy_flagged (flagged
when any line has a non-ok condition or qty variance). Reopen
restricted to Plating Manager.

WO soft gate: first plating WO button_start raises a UserError
when the MO's racking inspection is still Draft or Inspecting.
Plating Manager bypasses; later WOs are not gated.

fp.delivery gains x_fc_box_count_out. action_mark_delivered calls
_fp_check_box_parity which posts a non-blocking chatter warning
when boxes out ≠ boxes in (resolved via job_ref → MO.origin → SO
→ receiving). Warning only — never blocks shipping.

Menu entry: Plating → Operations → Racking Inspection.

Module version bumps:
  fusion_plating_receiving  → 19.0.3.0.0
  fusion_plating_logistics  → 19.0.3.0.0
  fusion_plating_bridge_mrp → 19.0.12.0.0 (+depends receiving)

Smoke on entech: 12/12 assertions pass (one gate test skipped —
MO had no WOs to test) including box-count state machine, inspection
auto-create, lifecycle, discrepancy flag, and box-parity chatter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:30:36 -04:00
gsinghpal
392359d2c4 docs(receiving): Sub 8 design spec — split receiving vs inspection + box parity
Receiving simplifies to box-count-only (draft → counted → staged →
closed). New fp.racking.inspection + line models capture the per-part
inspection the racking crew does when they open the boxes, linked to
MO not to receiving. Soft gate on first WO start when the inspection
is still pending (manager override). fp.delivery gains box_count_out;
action_mark_delivered posts a non-blocking chatter warning when
boxes out ≠ boxes in.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:21:02 -04:00
gsinghpal
0342535b9f feat(notifications): Sub 6 — contact profiles + communication routing
Five new boolean flags on res.partner applied to CHILD contacts:
x_fc_receives_certs, _qc, _quotes_so, _invoices, and _is_global_contact.
Single resolver helper res.partner._fp_resolve_notification_recipients
(stream, delivery_location=None) walks location contacts first then
company contacts, returning emails for contacts that opted into the
stream (or flagged themselves global). Falls back to partner.email
when no contact opts in so existing customers keep their exact
pre-Sub-6 routing.

fp.notification.template._dispatch now maps each trigger event to a
stream (so_confirmed→quotes_so, invoice_posted→invoices, shipped→
certs, etc.) and overrides the mail_template's email_to with the
resolved list. fp.delivery passes its delivery_address_id so the
shipped/CoC email routes through location-scoped contacts when they
exist.

Partner form gets a new "Communication Routing" tab on child contact
forms with the 5 flags (hides the per-stream checkboxes when
Global Contact is on, since it overrides them).

fusion_plating_certificates → 19.0.4.0.0 (adds the flag fields)
fusion_plating_notifications → 19.0.5.0.0 (+depends certificates)

Smoke on entech: 11/11 assertions pass including per-stream routing,
delivery-location scoping, zero-flag fallback, email-less skip,
unknown-stream + global behaviour, and case-insensitive dedup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:01:15 -04:00
gsinghpal
f9e1b62409 docs(notifications): Sub 6 design spec — contact profiles + routing
Five per-contact boolean flags (certs / qc / quotes-so / invoices /
global), native Odoo delivery-location child contacts reused for
per-location routing, and a single resolver on res.partner that the
dispatcher + all mail-send sites call. Fallback to self.email keeps
existing customers bit-identical when no flags are set.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 23:54:59 -04:00
gsinghpal
a7fd39d6f3 feat(iot): Sub 7 — per-sensor polling interval + rate-limit + entech seed
Per-sensor override on fp.tank.sensor.poll_interval_minutes with a
company-wide default (res.company.x_fc_default_poll_interval_minutes,
default 30) exposed in Settings → Fusion Plating → IoT. Single
lookup helper _fp_effective_poll_interval_minutes keeps downstream
call sites simple. Read-only poll_interval_display Char ("30 min
(default)" / "15 min (override)") keeps units unambiguous per user
request.

Ingest endpoint /fp/iot/ingest drops readings that arrive inside a
sensor's effective interval, returning {accepted, skipped} so the Pi
agent can log it. Pi-side interval stays its own concern.

Post-init hook seeds 5 small tanks + 20 big tanks (10 active, 10
inactive) with 1 temperature + 1 pH sensor each → 25 tanks, 50
sensors. Idempotent (keyed by tank.code, with_context(active_test=
False)). Opt-in via ir.config_parameter
fusion_plating_iot.seed_entech_tanks = '1' so a fresh install
elsewhere doesn't auto-seed. Flag set on entech today; 27 tanks / 52
sensors now live (2 pilot + 25 seeded).

Smoke on entech: 14/14 assertions pass including idempotency and
rate-limit conditions.

fusion_plating_iot → 19.0.2.0.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 23:29:08 -04:00
gsinghpal
def9c801fa docs(iot): Sub 7 design spec — per-sensor polling interval + entech seed
Per-sensor override on fp.tank.sensor.poll_interval_minutes, company-
wide default on res.company, ingest controller rate-limits readings
that arrive inside the effective interval. Seeds entech with 25
tanks (5 small, 20 big — 10 active/10 inactive) and 50 sensors
(temp + pH per tank) as noupdate=1 data so admin edits survive
upgrades.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 23:20:29 -04:00
gsinghpal
25c3f6f8d1 feat(plating): Sub 5 — order-line fields (serial, job#, thickness, revision)
Four new fields on every sale.order.line, propagated through to MO,
Delivery, and Invoice for end-to-end traceability:

- fp.serial registry (new model in configurator) with smart-button
  traceability to Sale Order, MO, Delivery, Invoice, Part. M2O on SO
  line; optional; user types a customer serial or clicks Generate
  Serial for a sequence-backed one. Reverse O2M links split across
  configurator (invoice) / bridge_mrp (MO) / logistics (delivery) so
  module load order is respected.
- x_fc_job_number on SO line, auto-sequenced FP-JOB-NNNNN on SO
  confirm. Editable — shops can override for customer/legacy schemes.
- fp.coating.thickness (new child of fp.coating.config) with per-
  config discrete thickness options; x_fc_thickness_id on SO line
  domain-filtered to the line's coating. Auto-clears when coating
  changes.
- x_fc_revision_snapshot Char on SO line, frozen from
  x_fc_part_catalog_id.revision at save. Protects historical SOs from
  later catalog edits. Secondary "Revision" picker on the tree view
  lets users switch between prior revisions of the same part number;
  the Part M2O still surfaces only is_latest_revision rows.

Reports (CoC, packing slip, invoice, BoL) pick up all four via the
Sub 2 customer_line_header macro — one macro edit, four reports.

Smoke on entech: 11 assertions pass including revision snapshot,
generate-serial button, typed-serial create-on-fly, coating→thickness
domain reset, SO confirm auto job#, and MO traceability carry.

Module version bumps:
  fusion_plating_configurator  → 19.0.12.0.0
  fusion_plating_bridge_mrp    → 19.0.11.0.0
  fusion_plating_logistics     → 19.0.2.0.0 (+depends configurator)
  fusion_plating_reports       → 19.0.5.1.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 23:04:44 -04:00
gsinghpal
bb9bcf45f8 docs(plating): Sub 5 design spec — order-line fields (serial, job#, thickness, revision)
fp.serial registry with smart-button traceability (SO, MO, Delivery,
Invoice, Part), fp.coating.thickness child table per coating config,
four new fields on sale.order.line propagating through to MO /
Delivery / Invoice via existing hooks. Revision picker with latest-
only default + switcher + snapshot Char. Reports pick up all four
via Sub 2's customer-line-header macro.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 22:48:14 -04:00
gsinghpal
1393c9e6ac fix(plating): Sub 4 — tighten Contract Review checklist columns
The Checklist group used col=\"4\" which stretched each label+field
pair across a quarter of the sheet, producing a big empty gap
between the two columns. Replaced with the idiomatic Odoo two-
nested-group pattern so each column hugs its labels, removing the
dead space. Same fix applied to Section 3.0 and to the Outcome
blocks on both sections.

fusion_plating_quality → 19.0.2.3.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 21:56:27 -04:00
gsinghpal
af199bda9f feat(plating): Sub 4 — smart button on part form for Contract Review
Adds a "Contract Review" stat button to fp.part.catalog's button box.
Shows a coloured state badge (green=complete, blue=manager_review,
yellow=assistant_review, muted=dismissed, em-dash when none). Click
routes through action_start_contract_review so it opens the existing
review or lazy-creates one — same behaviour as the banner / tab.

fusion_plating_quality → 19.0.2.2.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 21:54:47 -04:00
gsinghpal
5d9c78f8ce feat(plating): Sub 4 — Check All / Clear All buttons + fix QA-005 PDF logo render
- New bulk-toggle actions on fp.contract.review flip all 10 checklist
  items in Section 2.0 (and all 11 in Section 3.0) in one click.
  Rendered as "Check All" / "Clear All" buttons above each checklist.
  User can still tick boxes individually. Buttons hide once the
  section is signed (locked).
- Fix QA-005 PDF: replaced `to_text(...)` (not in QWeb context) with
  `image_data_uri(...)` for the company logo embed. PDF now renders
  with the full colour ENTECH logo (render size 103 KB).
- Smoke test extended: 5 new assertions covering bulk-toggle on/off
  and locked-section guard. 17/17 pass on entech.

fusion_plating_quality → 19.0.2.1.0

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 21:50:18 -04:00
gsinghpal
21da526aa7 feat(plating): Sub 4 — Contract Review (optional, QA-005 1:1 PDF)
Per-part contract review record (fp.contract.review) gated by a
customer-level toggle, signed in two sections (QA Assistant → QA
Manager), settings-based signer rosters (no new res.groups), banner on
the part form that auto-dismisses once the first MO for the part hits
confirmed. QA-005 Rev. 0 paper form reproduced 1:1 in a QWeb PDF.

Never blocks MO/SO/WO — review is purely an audit artefact.

Smoke test run on entech: 12 assertions pass including the 25-cell
risk matrix parity with the paper form and 22 KB PDF render.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 21:43:06 -04:00
gsinghpal
98a8bc234b docs(plating): Sub 4 design spec — Contract Review (optional, QA-005 1:1)
Dedicated fp.contract.review model in fusion_plating_quality, triggered by
a per-customer toggle, two-section QA sign-off (QA Assistant + QA Manager),
settings-based roster (no new res.groups), printable 1:1 QA-005 PDF. Never
blocks MO/SO/WO. Banner auto-dismisses once first MO for the part reaches
confirmed state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 21:31:05 -04:00
gsinghpal
d3b4eadbec test(sub3): Sub 3 smoke + verify SQL; mark shipped in CLAUDE.md roadmap
Sub 3 (Default Process + Composer per Part) complete:
 - Phase A: schema additions (part_catalog_id, cloned_from_id,
   treatment_uom on process_node; default_process_id on part_catalog),
   opt_in_out label rename, General Processing seed flipped to
   noupdate=1
 - Phase B: part-scoped Process Composer client action
   (fp_part_process_composer) with 3 RPC endpoints + OWL wrapper +
   Process tab on part form with Compose button
 - Phase C: tree node MO-state palette (green=completed, blue=active,
   red=error-only)

All 8 Sub 3 smoke checks green. Phase 1-3 QC smoke + E2E still green.
Sub 2 features untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 09:06:41 -04:00
gsinghpal
f0593487a7 feat(plating): Sub 3 Phase C \u2014 tree node MO-state palette (green=done, blue=active, red=error-only) 2026-04-22 09:04:38 -04:00
gsinghpal
3de37ea735 feat(configurator): Sub 3 Phase B — part-scoped Process Composer client action + part form Compose button
- Add fp_part_composer_controller with 3 JSON-RPC endpoints:
  /fp/part/composer/state, /fp/part/composer/templates,
  /fp/part/composer/load_template (deep-clones a shared template
  into a part-owned tree inside a cr.savepoint, sets
  fp.part.catalog.default_process_id atomically)
- _clone_subtree copies name/sequence/opt_in_out/treatment_uom plus
  description/notes/icon/color/timing/behaviour/work_center/process_type
  and stamps part_catalog_id + cloned_from_id on every node
- Add fp_part_process_composer OWL client action (JS + XML + SCSS):
  picks template from dropdown, clones, hands off to existing
  fp_recipe_tree_editor via context={recipe_id, part_id}
- Add Process tab on part form with readonly default_process_id
  field and Compose button calling action_open_part_composer
- Register new assets in web.assets_backend, bump configurator
  version to 19.0.11.0.0
2026-04-22 09:02:03 -04:00
gsinghpal
7d5c826f3e fix(plating): Sub 3 \u2014 move part_catalog_id/cloned_from_id/treatment_uom to configurator inherit (core can't reference fp.part.catalog) 2026-04-22 08:52:10 -04:00
gsinghpal
b1a8849e70 chore(plating): Sub 3 version bumps + flip General Processing seed to noupdate=1 (Tasks 4+5) 2026-04-22 08:50:19 -04:00
gsinghpal
4beffe9dc1 feat(bridge_mrp): Sub 3 — _resolve_mo_process_tree helper; walker prefers part-cloned tree (Task 3) 2026-04-22 08:47:41 -04:00
gsinghpal
dd7c408df3 feat(configurator): Sub 3 — fp.part.catalog gains default_process_id + action_open_part_composer (Task 2) 2026-04-22 08:47:01 -04:00
gsinghpal
a1ebe9000f feat(fusion_plating): Sub 3 — process_node gets part_catalog_id, cloned_from_id, treatment_uom; opt_in_out label rename (Task 1) 2026-04-22 08:46:32 -04:00
gsinghpal
817fdb4948 docs(plating): Sub 3 design spec \u2014 Default Process + Composer per Part 2026-04-22 08:44:06 -04:00
gsinghpal
733236f987 feat(configurator): Sub 1 — direct-order wizard stops auto-confirm + auto-email
The wizard was calling so.action_confirm() immediately after creating the
sale order, which flipped it from draft to sale state and triggered the
fusion_plating_notifications hook that auto-emails the customer.

Client wants a review step: keep the SO in quotation (draft) so the
user can adjust before the customer sees anything. They manually click
Send (to email the quotation) or Confirm (to convert to sale order,
which intentionally fires the confirmation email).

Changes:
 - Remove so.action_confirm() call in action_create_order
 - Update docstring + inline comment to reflect manual-confirm flow
 - Update the chatter message on the created SO

CLAUDE.md updated to mark Sub 1 + Sub 2 as Shipped.

Verified:
 - Static check: wizard.action_create_order contains no action_confirm
 - Dynamic check: SO created programmatically stays in draft
 - Manual action_confirm() flow still works as designed

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 23:43:01 -04:00
gsinghpal
afd8bae514 fix(configurator): programmatic SO-line create fallback for x_fc_internal_description
When Sub 2 Task 26 flipped x_fc_internal_description to required=True,
any programmatic sale.order.line creation that doesn't set the field
fails at the Postgres NOT NULL constraint. Callers include:
 - sale_mrp stock-move line creation (doesn't set name either)
 - demo seeders
 - external integrations
 - test scripts

The UI-side onchange populates the field when the user picks a
description template; this hook mirrors that for programmatic callers.
Fallback chain: explicit vals['x_fc_internal_description'] → vals['name']
→ product_id.display_name → '—'. Matches the migration's backfill rule.

Also adds Sub 2 end-to-end smoke test (6 cases, all green):
 1. Required-field rejection on part creation
 2. Required-field rejection on template creation
 3. Template picker populates both SO-line descriptions
 4. Cert resolver: part-level override wins over partner
 5. display_name renders part_number + revision + name
 6. certificate_requirement defaults to 'inherit'

QC Phase 1-3 regression suite remains green after the fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 23:34:32 -04:00
gsinghpal
733998dc95 chore(bridge_mrp): bump to 19.0.9.0.0 after cert-resolver refactor (Sub 2 Task 28) 2026-04-21 23:27:56 -04:00
gsinghpal
1eac630d87 feat(configurator): drop legacy description column after dual-field migration (Sub 2 Task 27)
Removes the `description` field from `fp.sale.description.template` now
that all readers (reports, wizard, sale line) consume the new
`internal_description` + `customer_facing_description` pair.

- Model: drop `description = fields.Text(...)` declaration
- Migration 19.0.9.0.0 Step 6: `ALTER TABLE ... DROP COLUMN IF EXISTS description`
- Template form/search views: swap `description` for the two new fields
- Seed data: write new fields instead of legacy column (dupes old text into both)
- Direct-order wizard: remove `tpl.description` fallback in both onchange handlers

Entech column dropped via Odoo's auto-schema-sync during module upgrade
(migration step is for fresh installs).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 23:27:22 -04:00
gsinghpal
e3dcc1c381 feat(configurator): flip sale.order.line.x_fc_internal_description to required (Sub 2 Task 26) 2026-04-21 23:22:02 -04:00
gsinghpal
6bbba93963 feat(configurator): flip dual-descriptions to required on template (Sub 2 Task 25) 2026-04-21 23:21:53 -04:00
gsinghpal
a66794084f feat(configurator): flip part_number + revision to required, name optional (Sub 2 Task 24) 2026-04-21 23:21:39 -04:00
gsinghpal
20d547bb4f feat(reports): traveler PDF surfaces part_number + internal description (Sub 2 Task 23) 2026-04-21 23:19:33 -04:00
gsinghpal
84c0745ab5 feat(reports): WO PDF surfaces part_number + internal description (Sub 2 Task 22) 2026-04-21 23:18:10 -04:00
gsinghpal
79d9e6b3b0 feat(reports): BoL PDF uses customer_line_header macro (Sub 2 Task 21)
Rewired portrait + landscape variants of report_fp_bol. The BoL had no
line collection of its own (fusion.plating.delivery only has a soft
`job_ref` Char), so the previous cargo-description block was a single
hardcoded row. Restructured to look up the job's mrp.production via
`job_ref`, iterate its `move_finished_ids` (excluding cancelled), and
render each finished-goods move through the shared
customer_line_header macro using the `move.sale_line_id or move`
adapter pattern.

When no MO is found or there are no finished moves, the template falls
back to the previous single-row "Plated parts — Job X" behavior so
legacy records without a backing MO still print correctly. Per-row QTY
now reflects the individual move's `product_uom_qty` instead of the
MO's aggregate `product_qty`.

Both variants render successfully on entech against a delivery whose
job_ref matches a real MO with one finished move.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 23:06:07 -04:00
gsinghpal
ac824c2cfb feat(reports): packing slip PDF uses customer_line_header macro (Sub 2 Task 20)
Rewired portrait + landscape variants of report_fp_packing_slip to use the
shared customer_line_header QWeb macro. The packing slip iterates
stock.move records (doc.move_ids_without_package); the adapter
`<t t-set="line" t-value="move.sale_line_id or move"/>` bridges the macro's
`line.x_fc_part_catalog_id` lookup to the sale line when the move is tied
to a sale (preferred path), falling back to rendering the stock.move's
product_id for stray moves with no sale line.

SKU + PRODUCT columns collapsed into a single PART column (width
adjusted to absorb the removed SKU column). Both variants render
successfully on entech with a real picking whose move has a sale_line_id.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 23:05:58 -04:00
gsinghpal
ea2cfc37c3 feat(reports+configurator): invoice PDF uses macro; x_fc_part_catalog_id on account.move.line (Sub 2 Task 19)
Invoice PDF (portrait + landscape) now collapses SKU + Description into
a single Part column rendered via fusion_plating_reports.customer_line_header,
so customer-facing invoices print the customer's part number (with
revision) instead of the internal service SKU.

To feed the macro on invoice lines, add x_fc_part_catalog_id to
account.move.line and override sale.order.line._prepare_invoice_line so
the part reference propagates automatically when an SO is invoiced.
2026-04-21 22:59:40 -04:00
gsinghpal
6cbea9d2f3 feat(reports): SO PDF uses customer_line_header macro (Sub 2 Task 18)
Collapse the SKU and Description columns in both the portrait and
landscape sale-order PDFs into a single Part column rendered through
the shared customer_line_header macro, so customer-facing quotes and
confirmed orders print the customer's part number (with revision)
instead of the internal service SKU.

Updates column widths, section/note colspans, and the conditional
col_count used for the landscape template's optional discount column
to reflect the collapsed header.
2026-04-21 22:57:33 -04:00
gsinghpal
d959775648 feat(reports): customer_line_header QWeb macro + version bump (Sub 2 Task 17) 2026-04-21 22:54:17 -04:00
gsinghpal
dcd5d2a1ec feat(configurator): direct-order wizard dual-description inputs + onchange (Sub 2 Task 16)
Adds an `internal_description` text field to the direct-order wizard
line so the shop-floor copy is captured at order entry alongside the
customer-facing text. Picking a template now fires both sides of the
onchange: `line_description` gets `customer_facing_description` (with
fallback to the legacy `description` field for backward compat) and
`internal_description` gets the template's internal text. The
auto-suggest onchange was refactored around a tiny `_apply` helper so
all three fallback paths populate both fields consistently.

The template picker is surfaced as an optional column on the wizard
list (hidden until a part is chosen, domain-scoped to that part) and
as a dedicated labeled row in the per-line form. The internal text
field is also surfaced in the form under "Line Description" so the
estimator can review / edit it before confirm. On create_order, both
`x_fc_description_template_id` and `x_fc_internal_description` are
written through to the generated sale.order.line so the audit trail
and WO printout stay linked.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 22:51:53 -04:00
gsinghpal
a659eba8f5 feat(configurator): SO-line template picker + dual descriptions + onchange (Sub 2 Task 15)
Surfaces the per-part description template on the SO line list alongside
a hidden-by-default internal description column. Picking a template
fires an onchange that copies `customer_facing_description` into Odoo's
standard `name` (customer-visible) and `internal_description` into
x_fc_internal_description (shop-floor / WO only). Estimator can edit
either field after the template is applied.

The template picker's domain filters by the line's part, and the field
stays hidden until a part is chosen — avoids showing every global
template when the line is blank.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 22:49:49 -04:00
gsinghpal
d1c855698a feat(configurator): two-column dual-description repeater on part form (Sub 2 Task 14) 2026-04-21 22:47:05 -04:00
gsinghpal
afee8d5ee8 feat(configurator): cert requirement + SKU relabel on part form (Sub 2 Task 13) 2026-04-21 22:46:10 -04:00
gsinghpal
8cea92cca4 test(sub2): cert-resolver edge cases (Task 11) 2026-04-21 20:23:32 -04:00
gsinghpal
332cdc8baa refactor(bridge_mrp): route button_mark_done cert cascade through resolver (Sub 2 Task 10) 2026-04-21 20:22:20 -04:00
gsinghpal
334a10dcb7 feat(bridge_mrp): _fp_resolve_cert_requirement single-source resolver (Sub 2 Task 9) 2026-04-21 20:21:40 -04:00
gsinghpal
cf6faf4cdf fix(configurator): strip legacy 'Rev ' prefix in display_name to avoid 'Rev Rev N' 2026-04-21 20:19:14 -04:00
gsinghpal
b89737f3c9 feat(configurator): display_name compute for fp.part.catalog (Sub 2 Task 8) 2026-04-21 20:18:33 -04:00
gsinghpal
fb2f360e7b test(sub2): migration verification SQL (Task 6) 2026-04-21 20:15:42 -04:00
gsinghpal
b3405a21eb feat(configurator): Sub 2 data migration — backfill part_number/revision, split descriptions (Task 5) 2026-04-21 20:15:12 -04:00
gsinghpal
93b2b2e0cf chore(configurator): bump version to 19.0.9.0.0 for Sub 2 (Task 4) 2026-04-21 20:15:10 -04:00
gsinghpal
77d5b91327 feat(configurator): add dual descriptions to sale.order.line (Sub 2 Task 3) 2026-04-21 20:13:17 -04:00
gsinghpal
c574689664 feat(configurator): add internal + customer-facing description fields (Sub 2 Task 2) 2026-04-21 20:13:05 -04:00
gsinghpal
868b418333 feat(configurator): add certificate_requirement field to fp.part.catalog (Sub 2 Task 1) 2026-04-21 20:12:52 -04:00
gsinghpal
418dabc688 docs(plating): Sub 2 implementation plan (30 tasks, 3 phases)
Full bite-sized plan matching the approved spec. Each task has file
paths, complete code, syntax-check commands, upgrade commands, expected
outputs, and commit messages.

Phase A (Tasks 1-12): additive schema + migration + cert-resolver.
System runnable throughout.

Phase B (Tasks 13-23): UI + QWeb macro + report rewiring. Users see new
fields. Old fields still exist.

Phase C (Tasks 24-30): flip required=True, drop legacy column, regression,
deploy to entech.

Self-review pass: every spec section mapped to a task; no TBD/TODO/placeholder.
Type signatures (_fp_resolve_cert_requirement, display_name, macro
params) consistent across tasks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 20:02:34 -04:00
gsinghpal
a15b75e38a docs(plating): fine-tuning initiative roadmap + Sub 2 design spec
Captures the current state of the system-wide fine-tuning initiative so a
fresh Claude Code session can resume without context loss.

CLAUDE.md additions (fusion_plating/CLAUDE.md):
* Sub-project roadmap (Sub 1 through 8 + two deferred items)
* Sub 2 locked decisions (Q1–Q6 answers)
* Sub 2 defensive measures that prevent rework when later subs land
* Sub 6 / 7 / 8 previews from the client transcript
* Client-confirmed operational thresholds (tank polling, active tanks)
* How to resume in a fresh session

Sub 2 design spec (docs/superpowers/specs/):
* Part Data Model Overhaul — covers gaps 2b, 2c, 2d, 4
* 12 sections: scope, data model, migration, UI, cert resolution,
  reports, testing, defensive measures, files touched, rollout,
  success criteria, open questions
* All clarifying questions answered; zero placeholders
* Ready for writing-plans skill to generate implementation plan

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 19:53:40 -04:00
gsinghpal
bdbfda7ce9 feat(plating): merge Fischerscope PDF into CoC as page 2+
When a QC uploaded the XDAL 600 report, the CoC PDF render pipeline
now appends the Fischerscope PDF directly after the cert pages. This
matches what aerospace / Nadcap auditors expect (and how Steelhead
ships certs today) — a single PDF file carrying both the certificate
declaration and the raw equipment report.

Flow:
* _fp_generate_cert_pdf renders the CoC via QWeb as before
* _fp_merge_thickness_into_cert resolves the QC for the MO (preferring
  the passed one) and extracts its thickness_report_pdf_id bytes
* PyPDF2.PdfMerger concatenates CoC then Fischerscope into a single PDF
* Merged bytes replace pdf_content before the ir.attachment is written
* Falls back to CoC-only (and logs a warning) if PyPDF2 is missing or
  either PDF fails to parse — never blocks MO completion

Smoke test: synthetic Fischerscope + real QWeb CoC → 2-page merged PDF
with page 1 CoC text and page 2 Fischerscope text, verified via
PyPDF2 extract_text.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 08:37:09 -04:00
gsinghpal
e86d897bce feat(plating): QC gate + mobile checklist + Fischerscope thickness capture
Phase 1 — Backend QC gate (bridge_mrp)
* fp.qc.checklist.template / .line — per-customer checklist definitions
* fusion.plating.quality.check / .line — per-MO instances walked by inspectors
* res.partner.x_fc_requires_qc + x_fc_qc_template_id toggles policy per customer
* mrp.production.button_mark_done blocks close until QC passes (plus optional
  thickness-readings + thickness-PDF gates on aerospace templates)
* Auto-spawns the QC on MO confirm from the customer's resolved template
* Fischerscope XDAL 600 PDF parser auto-extracts NiP / Ni% / P% readings on upload
* fp.thickness.reading gains quality_check_id + auto_extracted

Phase 2 — Mobile QC checklist (OWL client action)
* fp_qc_checklist registered under registry.category("actions")
* Reuses shopfloor design tokens (_fp_shopfloor_tokens.scss) — 48 px touch
  targets, shadow-based elevation, three-tier contrast, light + dark bundles
* Per-line pass/fail/N/A with numeric value range, mandatory photo, notes
* Fischerscope PDF drop-zone → server-side pdftotext parse
* Sign-off bar with pass / fail / rework actions

Phase 3 — Admin config
* Starter global default + aerospace/Nadcap templates seeded
* Plating → Configuration → QC Checklist Templates (manager-only)
* Plating → Quality → Quality Checks menu
* "Plating Documents" tab on res.partner gains the QC toggle + template picker
* MO form smart button opens the active QC in the mobile checklist

Gap fixes
* Scanner handles FP-QC:<ref> and FP-MO:<name> — launches the checklist
  directly on the tablet
* action_spawn_retry clones a fresh QC from a failed one so rework doesn't
  need a new MO

All 12 models / routes / gates smoke + E2E tested: 24 assertions pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 00:15:58 -04:00
gsinghpal
4d6095cd2a changes 2026-04-20 22:58:25 -04:00
gsinghpal
192aa60d00 docs(plating): flag fusion_plating_culture as do-not-auto-install
Future sessions shouldn't silently re-install retired modules during
install/upgrade sweeps. Added an explicit "Retired / Do-Not-Install
Modules" section with guardrails:

- Don't include in -i / -u sequences
- Don't add as a depends target
- Don't re-sync to entech /mnt/extra-addons/custom/
- Don't recommend installing without user confirmation

Covers the two modules currently in this state:
- fusion_plating_culture (code in repo, uninstalled on entech)
- fusion_plating_sensors (fully removed, absorbed into fusion_iot)

Also struck-through the "| 80 | Culture | ..." menu row and added a
retired tag to the module-list tree so at-a-glance scans don't
suggest it's a live part of the menu hierarchy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 20:33:23 -04:00
gsinghpal
729743e268 Revert "chore(plating): retire fusion_plating_culture — not a priority"
This reverts commit 95310c459d.
2026-04-20 20:31:02 -04:00
gsinghpal
95310c459d chore(plating): retire fusion_plating_culture — not a priority
Culture/values/recognitions framework was shipping zero data and zero
workflow integration for this client. It's a people-ops concern (peer
kudos, "Fundamental of the Week" rotations) with no overlap with the
technical plating pipeline — no interaction with process recipes,
quality holds, sensors, or compliance.

Verified zero data on entech before uninstalling:
  fusion.plating.value              0 records
  fusion.plating.value.set          0
  fusion.plating.value.recognition  0
  fusion.plating.value.rotation     0

Clean uninstall on entech, module dir removed from disk. The Culture
top-level menu disappears. If a future client wants it back, the
module is easy to re-author — nothing we built on top of it depends
on it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 20:30:47 -04:00
gsinghpal
cf205cfd11 refactor(fusion_iot): port sensor taxonomy + dashboards, retire fusion_plating_sensors
fusion_plating_sensors had broader scope (sensor_type taxonomy,
dashboards, location flexibility) but its core logic was ALL
scaffolding — alert rules stored thresholds with zero side effects,
measurement create just filled a name sequence, the HTTP endpoint
required user-auth session cookies. Meanwhile fusion_plating_iot had
the actual working alerting: in-spec checks, quality-hold auto-raise
with excursion dedupe, setpoint + deviation, token-auth ingest for
headless hardware. Plus 563 real readings from the pilot Pi.

Right unification: keep fusion_plating_iot (working) as the base,
port the valuable structural bits from fusion_plating_sensors, demolish
the latter entirely.

**Ported to fusion_plating_iot:**

- `fp.sensor.type` — taxonomy model with 8 seeded types (Temperature,
  pH, Conductivity, Level, Pressure, Flow, Concentration, Switch).
  Richer than the device_kind Selection; hardware-independent (one
  "Temperature" type covers DS18B20 / PT100 / thermocouple).
- `fp.sensor.dashboard` — named grouping of sensors with
  out-of-spec count. Simple but useful ("ENP Line 1 — all tanks")
  without the broken alert-rule complexity.
- Extended `fp.tank.sensor`:
  * `uuid` (stable logical ID, survives hardware swaps)
  * `sensor_type_id` (link to the taxonomy above)
  * `work_center_id`, `facility_id`, `location_name` — alternatives to
    tank_id so probes can live on ovens, ambient air, effluent pipes
    without faking a "tank"
  * `effective_location` computed — picks the first non-empty of the
    four location fields for display

**Post-install hook** backfills UUID + default sensor_type on existing
live sensors. Verified on the 2 pilot sensors: both got UUIDs, both
auto-assigned the Temperature type via device_kind=ds18b20 mapping.

**Deleted** (all of fusion_plating_sensors, 1205 LOC):
- fp.sensor (replaced by fp.tank.sensor with added fields)
- fp.sensor.measurement (replaced by fp.tank.reading)
- fp.sensor.alert.rule (replaced by inline alert_min/max + working hold)
- /fp/sensor/measure controller (replaced by /fp/iot/ingest)
- fp.sensor.measure.wizard (not needed — Odoo's normal create form works)
- The "Sensors" submenu hierarchy (Dashboards/All Sensors/Measurements/
  Sensor Types) that created the dup menus the user reported

**Menu now**: Plating → Operations → Sensors
  - Dashboards    (fp.sensor.dashboard)
  - Sensors       (fp.tank.sensor — renamed from "Tank Sensors" since
                   it supports non-tank locations now)
  - Readings      (fp.tank.reading)
  - Sensor Types  (fp.sensor.type)

No data loss: all 591 Pi readings preserved (up from 563 earlier as
the live poller kept running throughout the refactor). Brief 503 on
the Pi during the Odoo module-update restart; poller auto-retried on
the next 30s tick.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 19:58:57 -04:00
gsinghpal
118f96dad4 feat(fusion_iot): add setpoint/optimum + deviation to sensor schema
Sensors previously only tracked alarm thresholds (alert_min/alert_max).
Missing the third piece of standard process control: the SETPOINT —
what the heater/chiller controls toward and what dashboards compare
against. Without it an operator can't tell whether 89°C is "on target"
or "barely still in spec".

Schema changes:

**fusion.plating.bath.parameter** (shop-wide default)
- New `target_value` field — the default setpoint for this parameter
  across the shop (e.g. 87°C for ENP bath). Parallel to existing
  target_min / target_max.

**fp.tank.sensor** (per-sensor override)
- New `target_value_override` — per-sensor override, zero = inherit
  from parameter. Matches the existing override pattern for alert
  thresholds so users can fine-tune per-tank without touching the
  shop-wide spec.
- New `effective_target` / `effective_target_unit` computed — resolves
  override → parameter default, converts to company-preferred unit.
- New `_get_setpoint()` helper for internal use.

**fp.tank.reading**
- New `deviation_from_target` — signed Δ from the sensor's effective
  setpoint, in the company's preferred unit. Positive = above, negative
  = below, zero if no setpoint defined.
- New `deviation_band` (selection: on/near/far/out/none) — coarse band
  for fast visual scanning. `on` = within ±1° of target, `near` = ±3°,
  `far` = beyond, `out` = actually out of the alarm band.

**Views**
- Sensor form: split the alerting panel into two groups — "Target
  (setpoint)" on the left, "Alarm band" on the right. Makes the
  distinction between "where we want to be" and "where we'd panic"
  visually obvious.
- Reading list: new Δ + band columns, with decoration classes
  (success/info/warning/danger) so the list reads at a glance.
- Tank form Sensors tab: inline setpoint + unit column.

Seeded: parameter "Bath Temperature (Hot Process)" now carries
target_value=87°C as a realistic ENP shop default. Sensors inherit
unless they set their own override.

Design decisions kept simple:
- Did NOT add a warning band (warn_min/warn_max). Two-tier model
  (setpoint + alarm band) is enough for the pilot. Can add soft
  warnings later as a separate commit if ops wants them.
- Did NOT auto-control heaters. Setpoint is stored as metadata only;
  actual heater actuation via IoT is a future phase C project.

Verified: setpoint 87°C stored → displays 188.60°F on the live pilot
sensor (company pref = F). Each incoming reading correctly computes
signed deviation; bands colour the reading list appropriately.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 16:36:58 -04:00
gsinghpal
089cda71fe fix(fusion_iot): respect company temperature-unit preference in sensor UI
The sensor readings list always showed raw °C regardless of the
Plating Settings Temperature Unit preference (res.company.x_fc_default_temp_uom).
On a Fahrenheit-preferred shop, a 40°C reading should render as 105°F.

Fix: add display-aware computed fields alongside the canonical ones.

**fp.tank.reading**
- `value` / `unit` renamed with "(raw)" labels — these are the stored
  canonical values (always °C for temperature, because every
  temperature chip reports in Celsius natively)
- `display_value` + `display_unit` computed from company pref — only
  flips C→F when parameter_type='temperature' AND company pref='F';
  pH/conductivity/etc pass through untouched
- `display_name` now uses display_value so it reads naturally
  ("Sensor — 105.58 °F @ ...") regardless of region

**fp.tank.sensor**
- Mirrored the same pattern on the cached last-reading fields
- `last_reading_display` + `last_reading_display_unit` for lists
- `last_reading_value` hidden behind group_no_one (debug-only)

**Views**
- fp.tank.reading list: show display_value/display_unit, raw value
  hidden by default (toggle from column picker if needed)
- fp.tank.sensor list + form + tank inline: same pattern
- Raw value kept visible as an optional column so data engineers
  can still audit canonical storage

Why store canonical: spec thresholds (alert_min/max) live on the
sensor in °C. If the same Odoo serves a multi-region company
(Canada in C, US affiliate in F), switching a single preference
flips every UI without touching data. Alert logic keeps comparing
canonical values, so out-of-spec holds fire correctly regardless
of display unit.

Verified: 40.88°C raw → 105.58°F display on the live pilot probe
with company pref='F'. All 5 recent readings tested, display
fields updated correctly on every poll.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 16:13:17 -04:00
gsinghpal
dd575135ae fix(fusion_iot): point poller at public URL so Pi is site-portable
Pi is at our office today but moves to the client's shop in the next
few days. The client accesses Odoo at https://erp.enplating.ca (not a
LAN/Tailscale path — it's the same HTTPS URL any browser uses). By
pointing the poller at the public URL instead of the internal
10.200.1.26 LAN IP, the Pi works IDENTICALLY wherever it's plugged
in — no reconfiguration when it physically relocates.

- Updated poller's docstring + example config to use
  https://erp.enplating.ca
- Updated fusion_iot/CLAUDE.md with the portable-deployment notes and
  the failed-Tailscale-on-entech side-story (LXC can't create tun,
  apt state broken from a pre-existing python3-lxml-html-clean
  conflict — skipped because public URL is simpler anyway).

Verified live: poller restarted against https://erp.enplating.ca,
HTTP 200, TLS valid, 121ms RTT, two consecutive readings accepted
(46.25°C, 45.94°C — probe still cooling from the out-of-spec test).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 16:03:11 -04:00
gsinghpal
efb11df983 docs(fusion_iot): Tailscale + SSH cheat sheet for the pilot Pi
fp-iot-01 is now on Tailscale at 100.108.41.97. SSH config on the
Mac aliases `ssh fp-iot-01` to the Tailscale IP with key-based auth
(no more sshpass + password flying around in shell history).

Also noted the Pi-side folder structure (pi/ + scripts/) and the
live deployment facts (probe serial, systemd unit, config path)
so future sessions can pick up from zero without re-investigating.

Verified end-to-end with real hardware:
- Physical probe heated to 79.94°C → auto-raised HOLD-0015
- 30 subsequent out-of-spec readings → no duplicate holds (as designed)
- hold_id correctly linked back to the triggering reading

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 15:47:18 -04:00
gsinghpal
19a49acba0 feat(fusion_iot): live DS18B20 poller for Pi-side — first real tank reading in Odoo
Phase B kickoff — Pi hardware is wired up and posting readings to
Odoo via /fp/iot/ingest every 30 seconds. No more simulations;
this is real tank-temperature data.

New files:

- `pi/fp_iot_poller.py` — tiny systemd daemon. Reads every DS18B20
  under /sys/bus/w1/devices/28-* (kernel CRC-validated) and POSTs
  a batch to /fp/iot/ingest with the shared-secret token. Handles
  transient network failures by logging + retrying on the next
  30-second tick. Config in /etc/fp-iot/poller.conf (ODOO_URL,
  INGEST_TOKEN, INTERVAL_SECONDS).

- `pi/fp-iot-poller.service` — systemd unit with hardened sandbox
  (NoNewPrivileges, ProtectSystem=strict, ProtectHome, PrivateTmp,
  ReadOnlyPaths=/sys/bus/w1 /etc/fp-iot). Auto-starts on boot,
  restarts on failure.

- `scripts/fp_iot_setup_live_sensor.py` — one-shot entech
  initialiser: rotates the ingest token to a real random secret,
  picks a test tank + temperature parameter, creates the
  fp.tank.sensor record for serial 28-000000b276e4 with 15-35°C
  alert thresholds sized for bench testing.

Verified end-to-end: Pi reads probe → posts to Odoo → reading lands
in fp.tank.reading within 1s. 5 consecutive readings at 30s
cadence show smooth temperature trend (probe cooling from 27.25°C
to 26.06°C after being handled). in_spec flag correct, sensor
cache (last_reading_value / _at / _in_spec) updates on every
reading.

Not yet done — Phase B continued:
- Repackaged iot_drivers path (full Odoo IoT integration vs this
  simple HTTP path) — this poller is the minimal viable pilot.
- Multi-probe (scalable to N probes per Pi; code already supports,
  just need more hardware).
- Graduate to the proper iot.device + iot.box Odoo registration
  flow.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 14:59:20 -04:00
gsinghpal
8a841e7534 changes 2026-04-20 13:07:15 -04:00
gsinghpal
2334c0a1fe fix(notifications): Send dialog cancel no longer pre-sends + no duplicate PDF
Two user-reported bugs on S00056 (and visible on any SO/invoice):

Bug 1: Cancelling the Send dialog still sends the email.
  action_quotation_send is a button handler that returns a
  compose-dialog action synchronously. Our override was calling
  _dispatch('quote_sent', ...) AFTER super(), which immediately
  sends the email via template.send_mail() before the user ever
  sees the dialog. Clicking Cancel at that point only dismisses
  the already-sent email's compose window.

  Fix: removed the _dispatch call entirely from action_quotation_send.
  The Send button IS the manual-send path; Odoo's compose dialog
  (pre-populated with our FP: Quotation Sent template thanks to
  _find_mail_template) handles the send-or-cancel choice correctly.

  If an auto-quote-sent notification is ever wanted, it should be
  wired from a cron that scans SOs that just transitioned
  draft -> sent, not from the button handler. Noted in a code
  comment.

Bug 2: Two copies of the same PDF attached to every email.
  The mail.template records now carry report_template_ids (set by
  the post_init hook from the previous refactor) which Odoo uses to
  auto-attach PDFs on send_mail(). But the fp.notification.template
  records ALSO had attach_quotation / attach_sale_order / attach_invoice
  flags set, which cause _collect_attachments() to render the same
  PDF a second time and pass it in email_values.

  Fix: turned those three flags off in the XML data file. Other
  flags (attach_coc, attach_bol, attach_receipt, attach_thickness_report,
  attach_packing_list, attach_pod) stay on — those are genuinely
  different documents, not dupes.

  Because the records are noupdate="1", updated the post_init_hook
  to also backfill the flag changes onto existing DB rows so
  production instances get cleaned up on -u, not just fresh installs.

Smoke:
  attach_quotation=False attach_sale_order=False attach_invoice=False on all three records
  1 report per template (no dupes)
  action_quotation_send no longer contains _dispatch("quote_sent", ...)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 01:45:32 -04:00
gsinghpal
36964d6b79 feat(fusion_accounting_reports): adopt Enterprise account_reports look
User feedback: 'i like the odoo enterprise style reports, I hate our style.'

Replaces our custom 'o_fusion_reports' visual with a faithful adaptation
of Enterprise account_reports. Same .account_report root class, same
table semantics (line_name + line_cell + line_level_N), same border
treatment (1px gray-300 borders, 0.25rem radius, sticky thead), same
button hover behavior (gray-300 -> enterprise-action-color), same dense
0.8rem font-size + padded cells.

SCSS layout:
- reports.scss in web.assets_backend bundle (eager light)
- reports.dark.scss in web.assets_web_dark bundle (lazy dark mode)
- _variables.scss reduced to spacing/typography only -- colors use
  Odoo's \$o-* SCSS vars so dark mode flips automatically via the
  separate dark bundle
- old dark_mode.scss removed (was using non-Odoo [data-color-scheme]
  selector that never matched anything)

QWeb templates rewritten to mirror Enterprise's structure:
- report_viewer.xml roots at .account_report with scroll container
- report_table.xml uses Enterprise's td.line_name + td.line_cell with
  .wrapper > .content nesting; partner-grouped reports now actually
  render their aging buckets (previously showed nothing)
- period_filter.xml is now a clean Bootstrap-styled inline filter bar

Kept Fusion-only components but restyled to fit:
- anomaly_strip uses Bootstrap alert-{danger,warning,info} colors
- ai_commentary_panel is a plain bordered panel, no gradients/emojis
- drill_down_dialog unchanged (already a Bootstrap modal)

Made-with: Cursor
2026-04-20 01:41:41 -04:00
gsinghpal
f09bef9083 refactor(reports): consolidate SO Acknowledgement back into the Sales Order PDF
Earlier I built report_fp_so_acknowledgement.xml as a separate
customer-facing document. On review there was no good reason — our
existing report_fp_sale.xml already flips its title between
"Quotation" and "Sales Order" based on state, and carried ~90% of
the same content. Two documents would have meant the shop had to
remember which to send when, and the customer would get two
near-identical PDFs in their inbox.

Consolidation:

1. Merged the four unique blocks from the acknowledgement into
   report_fp_sale.xml (both portrait AND landscape variants):
   - CUSTOMER JOB # / PLANNED START / CUSTOMER DEADLINE / SHIP VIA
     info row (shown only when any of those fields is populated)
   - Blanket / block-partial highlight-box callout (shown only
     when the flags are set)
   - External notes (x_fc_external_note) block above Terms and
     Conditions

2. Deleted fusion_plating_reports/report/report_fp_so_acknowledgement.xml
   and removed it from the module manifest. Also purged the orphan
   ir.actions.report and ir.ui.view DB rows + the stale
   ir.model.data entries.

3. Re-pointed the fp_mail_template_so_confirmed mail template's
   report_template_ids from the now-gone acknowledgement report to
   action_report_fp_sale_portrait. Updated hooks.py accordingly; the
   hook now uses "set" semantics (replace all) instead of "add" so
   re-running it cleans up stale attachments from prior refactors.

4. UAT on S00071: the Send button pre-selects the FP: Order
   Confirmation template with SalesOrder_S00071.pdf attached. The
   PDF renders with the new plating rows populated — Customer Job #
   AMPH-2026-0420-01, Customer Deadline 05/14/2026 08:00:00 PM,
   "Partial shipments blocked" callout, all lines + totals.

One PDF, one Send button behaviour, matching what Odoo and most
ERP systems do.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 01:30:06 -04:00
gsinghpal
54e56ed0e6 changes 2026-04-20 01:16:12 -04:00
gsinghpal
8217bb0ff6 fix(fusion_accounting_reports): expose dynamic OWL reports as menu items
User reported that after Enterprise uninstall, clicking 'Reports' opened
PDF statements instead of the dynamic Fusion report viewer. Root cause:
the OWL ReportViewer (registered as view_type='fusion_reports') was only
reachable via the period-picker WIZARD; no menu items used the OWL view
directly. Plus the JS service ignored report_code, so even within the
viewer, all PnL-typed reports rendered the canonical P&L line_specs.

Changes:

JS layer
- reports_service.js: runReport now accepts and forwards reportCode;
  state tracks currentReportCode so re-runs after period/comparison
  changes preserve the variant.
- report_viewer.js: reads default_report_code (and default_comparison)
  from the action context.
- period_filter.js: passes the cached reportCode on date changes;
  clears it when the user picks a different report_type.

Backend
- New fusion_accounting_reports/views/report_actions.xml with 11
  dedicated ir.actions.act_window records, one per built-in report
  (P&L, Balance Sheet, Trial Balance, GL, Cash Flow, Executive Summary,
  Annual Statements, Aged Receivable, Aged Payable, Partner Ledger,
  Tax Summary). Each opens view_mode='fusion_reports' with the
  appropriate default_report_type + default_report_code context.
- views/menu_views.xml: each report now gets its own menu item
  directly under Accounting > Reporting (sequence 10-40), matching
  Enterprise's flat structure. Custom Period wizard, XLSX export and
  Anomaly browser collected under a 'Tools' sub-group at the bottom.
- fusion_accounting_l10n_ca: adds menu items for 'Profit and Loss
  (Canada)' and 'Balance Sheet (Canada)' as siblings, plus a 'Tax
  Returns (CA)' configuration menu.

Verified live on westin-v19:
- pnl rendering 3 rows, cash_flow 9, executive_summary 7,
  annual_statements 5, ca_profit_loss 9 \u2014 each report now renders
  its own line_specs correctly.
- Reporting menu shows 14 Fusion report entries + Tools group.
- 136/136 reports + l10n_ca tests pass.

Version bumps: reports 19.0.1.1.1, l10n_ca 19.0.1.1.0.

Made-with: Cursor
2026-04-20 01:11:48 -04:00
gsinghpal
867b5f71a1 fix(fusion_accounting): unified Accounting menu under one root, hide migration when Enterprise gone
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
User reported two UX problems after the Enterprise uninstall:
1. Each Fusion sub-module showed up as its own standalone app in the
   launcher (Bank Reconciliation, Financial Reports, Asset Management,
   Customer Follow-ups, Fusion AI). Should look like ONE Accounting app.
2. Clicking the 'Fusion Accounting' app still opened the migration
   wizard even though Enterprise had been uninstalled and there was
   nothing to migrate.

Fix:
- Move all Fusion sub-module roots under the Community account.menu_finance
  hierarchy:
    * Bank Reconciliation \u2192 Accounting > Bank Reconciliation
    * Asset Management    \u2192 Accounting > Asset Management
    * Financial Reports   \u2192 Reporting > Financial Reports
    * Follow-ups          \u2192 Customers > Follow-ups
    * Fusion AI           \u2192 Configuration > Fusion AI
    * Migrate from Ent.   \u2192 Configuration > Migrate from Enterprise
- Rename Community's 'Invoicing' top-level menu to 'Accounting' (what
  Enterprise's accountant module did). Set the Fusion icon on it. This
  rename lives in the meta-module so it only fires when the full suite
  is installed.
- Add second computed group 'group_fusion_show_when_enterprise_present'
  (inverse of the existing 'absent' group). Migration menus are gated
  by this group, so they auto-hide once Enterprise is uninstalled.
- _fusion_recompute_coexistence_group now maintains both groups in lockstep.
- Meta-module now also depends on l10n_ca, hr_payroll, ocr, documents
  (the Phase 6/7 sub-modules) for one-click full-suite install.
- Fusion AI menu's old parent ('accountant.menu_accounting') was deleted
  with the Enterprise uninstall \u2014 reparented under Configuration.

Result: single 'Accounting' top-level menu containing the standard
V19 Community structure (Dashboard / Customers / Vendors / Accounting /
Reporting / Configuration), with all Fusion features slotted into the
appropriate sub-section. Verified live on westin-v19: 6 separate
Fusion top-level menus collapsed to 1; coexistence groups recomputed
(absent=10 users, present=0 users); 604/604 tests pass.

Version bump: all touched modules \u2192 19.0.1.1.0.

Made-with: Cursor
2026-04-20 01:04:49 -04:00
gsinghpal
bee5ba4d3f fix(plating): UAT-caught UX annoyances + lurking bugs
Five fixes from the end-to-end UAT debrief:

1. Menu discoverability (HIGH)
   Added a prominent "+ New Direct Order" button in the Sale Orders
   list header toolbar (class=btn-primary, display=always). The
   existing menuitem at Plating > Sales > New Direct Order was
   buried in a submenu that didn't always expand; the toolbar
   button is a guaranteed entry point from the most common screen.

2. Escape/X destroys wizard state (HIGH)
   Added a prominent info banner at the top of the wizard form:
   "Changes are not saved until you click Create & Confirm Order.
   Closing this window (Esc or X) discards your entries." The
   Cancel button now has confirm="Discard this order? All header
   data and line items will be lost." so the intentional-cancel
   path also prompts.

3. Shell/cron crash in _fp_auto_create_mo (MEDIUM)
   bridge_mrp/models/sale_order.py:232-264 used _() inside list
   comprehensions to format the internal chatter summary of newly
   created / adopted MOs. _() resolves language from env.context,
   which is empty in odoo-shell and cron contexts — triggering a
   translate.get_text_alias crash AFTER the MOs had been created.
   These strings are internal audit log text, not user-facing UI;
   dropped the _() wrappers so the message builds safely from any
   context. Same for the per-group error-message on savepoint
   rollback.

4. Misleading "100%" margin (MEDIUM)
   x_fc_margin_percent displayed 100% on every SO because the cost
   rollup from fp.coating.config.unit_cost isn't populated yet.
   Added x_fc_margin_available Boolean (True only when at least
   one line's coating has a non-zero unit_cost). The SO Plating
   tab now hides the margin numbers when margin_available=False
   and shows an inline muted note: "Margin n/a — coating cost
   rollup not yet populated on any line's treatment."

5. Account Hold banner too loud (LOW)
   fusion_plating_invoicing was injecting a full-height danger
   alert above every SO header. Slimmed it to a one-line compact
   alert with icon: "Account Hold — SO confirmation, invoicing
   and shipping are blocked for non-managers." Half the vertical
   footprint, less visual competition with the Plating chip bar.

Verified via UAT on S00071.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 01:03:26 -04:00
gsinghpal
068a654c2b fix(fusion_accounting_bank_rec): test factory adapts to V19 Community semantics
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
After Enterprise's account_accountant is uninstalled,
account.bank.statement.journal_id reverts to its V19 Community definition
\u2014 a read-only computed field derived from line_ids.journal_id. Direct
writes are silently dropped (which is what was happening: 55 tests
errored with 'null value in column journal_id' because the test's
statement had no journal, and the line factory was reading
statement.journal_id (False) and passing that to the line create).

Fix:
- make_bank_statement now bootstraps the statement with one zero-amount
  line carrying journal_id, so the computed journal_id resolves correctly.
- make_bank_line no longer routes journal through the statement \u2014
  journal_id is set directly on the line (which is V19 Community's
  intended path; lines can exist standalone without a statement).

This is a test-only change; runtime behaviour is unchanged. Real users
creating bank lines via the UI already use the correct path.

Made-with: Cursor
2026-04-20 00:52:02 -04:00
gsinghpal
71f39c8d33 feat(fusion_accounting_documents): Documents app <-> invoice bridge
Replaces Enterprise's documents_account with a Fusion-native bridge.
When a PDF/image lands in the Documents app, users can convert it
into a draft vendor bill via a wizard that copies the document's
binary onto the new account.move and posts a chatter note linking
back to the source document.

Adds:
- documents.document.move_id (Many2one to the linked invoice)
- documents.document.is_invoice_candidate (computed; True for
  unlinked PDF/image binaries)
- documents.document.action_create_invoice() opens the wizard
- account.move.source_document_ids reverse linkage + statinfo button
- fusion.create.invoice.from.document.wizard (TransientModel + form)
- ir.actions.server bound to documents.document so the workflow
  appears in the kanban/list Actions menu (the Documents app has
  no regular form view to inherit from in v19)

The wizard:
- defaults to the company's first purchase journal
- supports vendor bill or vendor credit note
- copies the source attachment onto the new move
- posts a chatter note linking back
- marks the document linked so it stops appearing as a candidate

Auto-installs when documents + fusion_accounting_core are both
present. 8 unit tests cover the candidate flag, wizard happy path,
attachment copy, reverse linkage, already-linked guard, non-PDF
guard, and credit-note creation.

Made-with: Cursor
2026-04-20 00:34:50 -04:00
gsinghpal
125f48377a feat(fusion_accounting_ocr): pluggable OCR for vendor bills
Replaces Enterprise's account_invoice_extract with a Fusion-native pipeline:

Stage 1 (text extraction): Tesseract OCRs the bill attachment via
pytesseract + pdf2image. Pluggable OCRProvider adapter pattern allows
future Mindee / Google Document AI / Ollama-vision backends.

Stage 2 (field parsing): The fusion_accounting_ai LLMProvider reads the
raw OCR text and returns structured invoice fields (vendor, invoice
number, dates, amounts, line items) as JSON.

Draft invoice fields are auto-populated for empty-only fields (never
overwriting user-entered data). Vendor matching by name against
res.partner with supplier_rank > 0.

Adds:
- account.move.ocr_state (selection: not_requested/pending/processing/
  done/failed/manual)
- account.move.ocr_raw_text, ocr_extracted_data (Json), ocr_backend,
  ocr_confidence
- fusion.ocr.log (audit trail per OCR run)
- res.company.fusion_ocr_enabled / fusion_ocr_default_backend / auto_run
- /fusion/ocr/request_for_invoice JSON-RPC endpoint

Backend availability detected at runtime via OCRProvider.is_available()
classmethods. Tesseract 5.3.4 + pytesseract 0.3.13 + pdf2image 1.17.0
are installed in the container.

Tests: 13 (TesseractAdapter availability + image OCR; flow tests for
draft autofill, no-attachment guard, customer-invoice guard, ref-not-
overwritten; field parser empty/clean-json/markdown-fence/bad-JSON/
provider-exception). All pass on westin-v19 OrbStack VM.

Made-with: Cursor
2026-04-20 00:32:50 -04:00
gsinghpal
a730942d24 feat(fusion_accounting_hr_payroll): payroll -> GL bridge
Replaces Enterprise's hr_payroll_account with a Fusion-native bridge:
- Adds account_debit / account_credit / fusion_analytic_account_id /
  not_computed_in_net to hr.salary.rule (company-dependent GL mapping)
- Adds move_id + move_state + journal_id + _fusion_create_account_move
  to hr.payslip (validated payslip -> balanced account.move)
- Adds move_id + move_state + action_open_move to hr.payslip.run
- Adds journal_id (company-dependent) to hr.payroll.structure
- Adds is_payroll_journal flag to account.journal
- Adds payslip_ids / payslip_count + action_open_payslip on account.move
- Adds payslip_id reverse link on account.move.line
- Adds move_line_id reverse link on hr.payslip.line
- Adds fusion_payroll_journal_id + fusion_payroll_auto_post to res.company
  (with res.config.settings exposure)

Coexistence: detects Enterprise hr_payroll_account at runtime via
ir.module.module and yields move creation to it while both modules are
installed, so payslips do not get duplicate entries. Once the Enterprise
module is uninstalled, this module owns the bridge.

Auto-installs whenever both hr_payroll and fusion_accounting_core are
present on the database.

10 smoke tests verifying field surface + bridge entrypoints all pass on
westin-v19. Full payslip-to-move integration test deferred (needs
seeded payroll structure).

Removes Westin's last payroll-accounting dependency on Enterprise's
accountant umbrella module (Phase 6b of the Fusion Accounting suite).

Made-with: Cursor
2026-04-20 00:18:08 -04:00
gsinghpal
aab4b5e958 feat(fusion_accounting_l10n_ca): Canadian reports + tax return tracking
Replaces Enterprise's l10n_ca_reports with Fusion-native equivalents:
- ca_balance_sheet, ca_profit_loss as fusion.report definitions
- fusion.tax.return model for GST/HST/PST/T4/T5018 filing tracking
- Auto-installs when l10n_ca + fusion_accounting_reports both present

Removes Westin's last Canadian-compliance dependency on Enterprise's
account_reports.

Made-with: Cursor
2026-04-20 00:12:59 -04:00
gsinghpal
c8ca37099b refactor(reports): move SO Acknowledgement into fusion_plating_reports with house style
D7 template was originally in fusion_plating_configurator with a
Bootstrap-only look-and-feel that didn't match the other Fusion
Plating reports. Re-styled and relocated:

- Moved to fusion_plating_reports/report/report_fp_so_acknowledgement.xml
  alongside sale / work-order / job-traveller / invoice templates.
- Uses fp_portrait_styles (company primary colour for headers, .bordered
  tables, .info-header row, .totals-table, .highlight-box, .sig-box /
  .sig-line / .small-muted).
- Layout now mirrors report_fp_sale.xml: Billing / Shipping address
  pair, references row (Customer PO / Customer Job / Order Date /
  Salesperson), scheduling row (Planned Start / Internal / Customer
  Deadline / Ship Via), blanket-order callout, order line table
  (PART / DESCRIPTION / TREATMENT / QTY / UNIT PRICE / SUBTOTAL),
  totals table with subtotal / taxes / grand total, and a two-column
  signature block.

fusion_plating_configurator no longer ships report/ files — it
depends on fusion_plating_reports transitively via installed modules
order. Report XML ID changed from
'fusion_plating_configurator.report_fp_so_acknowledgement_doc' to
'fusion_plating_reports.report_fp_so_acknowledgement_doc'.

UAT on S00066: PDF renders cleanly with ENTECH branding, contact
footer, subtotal \$3,025 / taxes \$393.25 / grand total \$3,418.25,
signature lines — visually identical to the Quotation/Sales Order
report.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 00:10:33 -04:00
gsinghpal
d36933d7f4 fix(configurator): wrap t-field widgets in <span> inside table cells
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
Acknowledgement PDF rendering failed with "QWeb widgets do not work
correctly on 'td' elements" — Odoo's qweb compiler rejects
t-field/t-options directly on <td>. Wrap the monetary / qty widgets
in an inner <span> for every cell that uses them (body rows + footer
total).

Caught during browser UAT on S00066 — shell _render_qweb_pdf smoke
test passed earlier because it bypasses the full compile path, but
the production /report/pdf/ endpoint fails the assertion.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 23:59:02 -04:00
gsinghpal
1817f63c67 fix(fusion_accounting_reports): engine accepts report_code to disambiguate
When multiple fusion.report rows share a report_type (e.g. 4 PnL-typed
reports: pnl, cash_flow, executive_summary, annual_statements), the
engine's _get_report previously returned whichever matched the type
filter first \u2014 so all four reports rendered the canonical P&L
line_specs regardless of which report the user selected.

Adds report_code kwarg to compute_pnl, compute_balance_sheet,
compute_trial_balance, compute_gl. Controller /fusion/reports/run now
accepts and forwards report_code. _get_report has a 3-tier resolution:
1. Exact code match (validates type)
2. Canonical (code == report_type)
3. First by sequence

Two new tests assert distinct line_specs render for distinct codes and
that wrong-type code raises ValidationError.

Verified live on westin-v19: pnl/cash_flow/executive_summary/
annual_statements now return 3/9/7/5 rows respectively (was all
3 before).

Made-with: Cursor
2026-04-19 23:58:29 -04:00
gsinghpal
1ebff01d35 feat(fusion_accounting_reports): seed 3 partner-grouped reports
Adds Aged Receivable, Aged Payable, and Partner Ledger as fusion.report
records using the new compute_partner_grouped engine method.

REPORT_TYPES is extended with aged_receivable / aged_payable /
partner_ledger so each report has a unique report_type. The HTTP
controller dispatches these to engine.compute_partner_grouped with
the appropriate account_type via PARTNER_GROUPED_ACCOUNT_TYPE.

Output includes per-partner aging buckets: current, 1-30, 31-60,
61-90, 90+ days.

Westin total: 4 + 4 + 3 = 11 of Enterprise's 22 standard reports.

Made-with: Cursor
2026-04-19 23:55:45 -04:00
gsinghpal
ff6d21a561 feat(fusion_accounting_reports): partner-grouped engine method
Adds engine.compute_partner_grouped(period, account_type=...) that
returns per-partner aggregations with aging buckets (current/1-30/
31-60/61-90/90+). SQL-direct for performance — single GROUP BY query
with conditional sum per bucket.

Foundation for the 3 partner-grouped reports landing in commit 3:
Aged Receivable, Aged Payable, Partner Ledger.

Made-with: Cursor
2026-04-19 23:54:32 -04:00
gsinghpal
6896c71b79 feat(fusion_accounting_reports): seed 4 more standard reports
Adds Cash Flow Statement, Executive Summary, Tax Summary, and Annual
Statements as fusion.report records with line_specs. All work with the
existing engine's bucket-sum pattern — no engine changes needed.

Westin total: 4 + 4 = 8 of Enterprise's 22 standard reports now in
fusion_accounting_reports. Partner-grouped reports (Aged AR/AP,
Partner Ledger) need an engine extension — in commit 2.

Made-with: Cursor
2026-04-19 23:53:16 -04:00
gsinghpal
111792599c fix(configurator): margin % stored as fraction so widget='percentage' formats right
Phase D8 compute was returning x_fc_margin_percent already-multiplied
by 100, but the 'percentage' widget in the SO form multiplies again
for display. Result was 10000% instead of 100%.

Store as 0.0-1.0 fraction; widget handles the multiplier. Caught
during UAT on S00066.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 23:49:00 -04:00
gsinghpal
679dbaa979 feat(fusion_accounting_followup): per-partner state migration from Enterprise
Migrates Enterprise account_followup per-partner state to Fusion fields:
- res.partner.followup_status -> fusion_followup_status (action_due/no_action)
- res.partner.payment_next_action_date -> fusion_followup_paused_until
  (when future-dated; sets status to 'paused')
- res.partner.followup_line_id -> fusion_followup_last_level_id
  (resolved by name match against migrated levels)

Wired into fusion.migration.wizard.action_run_migration after the
existing _followup_bootstrap_step. Idempotent: skips partners whose
Fusion state is already non-default. Defensive against missing
Enterprise fields (each field probed individually before use).

Closes the per-partner state migration gap that was blocking
Enterprise account_followup uninstall.

Made-with: Cursor
2026-04-19 23:48:22 -04:00
gsinghpal
b15bf2293e fix(configurator/bridge_mrp): address all bugs from code review
Two critical, one important, four polish fixes found by the
pr-review-toolkit code-reviewer.

C1 (CRITICAL) Start-at-node filter dropped later siblings
  fusion_plating_bridge_mrp/models/mrp_production.py:448
  The allowed_ids set was {descendants} ∪ {ancestors}, which wrongly
  excluded nodes that should run AFTER the start node — including
  later siblings of the start node and all operations in subsequent
  sub-processes. Rewrote the upward walk to ALSO include each
  ancestor's later-sequence siblings and their descendants. Smoke on
  ENP-ALUM-BASIC: full=9 WOs, partial from mid-tree 'De-Masking'=5
  WOs (previously was 1).

C2 (CRITICAL) Duplicate MO on re-confirm of pre-PR SOs
  fusion_plating_bridge_mrp/models/sale_order.py:96
  Legacy untagged MOs (created before this PR had line-linkage m2m)
  were not recognized by the untagged idempotency check, so
  re-confirming an already-processed SO would create one additional
  MO per untagged plating line. Fix: pre-scan for a single legacy
  untagged MO and adopt it by linking ALL untagged plating lines
  onto it. Those lines are then treated as covered and no per-line
  MOs are created on top. Smoke: S00066 before=1 MO, after
  re-run=1 MO.

I5 (IMPORTANT) push_to_defaults wrote to pre-bump revision
  fusion_plating_configurator/wizard/fp_direct_order_wizard.py:236
  When create_new_revision=True, _get_or_bump_revision() returned a
  new part record that got written to the SO line, but the
  post-confirm push_to_defaults loop re-read line.part_catalog_id
  (still the OLD rev) and wrote defaults there, defeating the whole
  point of "save as default". Fix: cache resolved parts in a dict
  keyed by wizard-line ID during the build loop, and use that cache
  in the push_to_defaults pass.

I3/I4/I6 (PERF) Computes lacked @api.depends and did per-record
  search_count / search queries
  fusion_plating_configurator/models/sale_order.py
  _compute_nav_counts, _compute_workorder_count, _compute_wo_completion
  now:
  - declare @api.depends
  - batch via read_group across the whole self recordset
  - rebuild {origin: counts} dicts and assign per record

M7 (MEDIUM) No savepoint around per-group MO creation
  fusion_plating_bridge_mrp/models/sale_order.py:_fp_auto_create_mo
  A mid-loop exception left group 1's MO persisted and aborted
  groups 2..N. Wrapped each group's create in SAVEPOINT/RELEASE/
  ROLLBACK TO SAVEPOINT so one bad group no longer corrupts state.

M8 (MEDIUM) Email 'opened' status false-positived on internal CC
  fusion_plating_configurator/models/sale_order.py:_compute_email_status
  Switched from 'any notification is_read' to 'customer partner has
  a read email notification on this SO'.

M9 (LOW) start_at_node_id domain silently empty when coating unset
  fusion_plating_configurator/wizard/fp_direct_order_line.py:94
  Changed `('parent_id', 'child_of', ...)` to
  `('id', 'child_of', ..., or 0)` and clarified the help text.

Regression smoke passed all checks on odoo-entech.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 23:35:03 -04:00
gsinghpal
9d8db0f9b1 fix(bank_rec): don't shadow Odoo's _() translation function in action_run_migration
Line 77 was `_ = super().action_run_migration()`, using `_` as a
throwaway variable name. That rebinds the module-level `_` (Odoo's
translation function imported at the top) to whatever super() returns
\u2014 in our case the parent's notification dict.

Lines 84/85 then call `_('Bank-Rec Migration Complete')` which is
now `some_dict('Bank-Rec Migration Complete')` \u2192
TypeError: 'dict' object is not callable.

User hit this when running the migration wizard from the menu.

Fix: drop the assignment; we don't actually use super()'s return value.
Made-with: Cursor
2026-04-19 23:34:45 -04:00
gsinghpal
ef2ccb89cf fix(services): V19 removed 'rpc' service \u2014 import standalone rpc() function
V19 removed the 'rpc' service from the registry. All 4 fusion services
(bank_reconciliation, reports, assets, followup) declared dependencies:
['rpc', ...] and accessed services.rpc in their constructor. At runtime
this caused:

  Error: Some services could not be started: fusion_bank_reconciliation,
  fusion_reports, fusion_assets, fusion_followup. Missing dependencies: rpc

\u2014 which prevented the entire OWL backend from booting (blank screen).

Fix per V19 docs:
- Add 'import { rpc } from "@web/core/network/rpc";'
- Set 'this.rpc = rpc;' in constructor (instead of services.rpc)
- Remove 'rpc' from dependencies list

This is the workspace CLAUDE.md guidance Phase 4's subagent flagged
but didn't act on for backward consistency. V19 actually removed the
service entirely, so the consistency choice was wrong \u2014 fixing now.

All call sites still use this.rpc(...) so no per-method changes needed.
Bundle rebuilt clean; backend boots correctly.

Made-with: Cursor
2026-04-19 23:25:52 -04:00
gsinghpal
51d8ce494d fix(scss): remove forbidden @import "variables" lines breaking V19 asset bundle
Phases 1-3's SCSS files used '@import "variables";' to pull in tokens
from _variables.scss. V19's odoo.addons.base.models.assetsbundle
forbids cross-file SCSS imports for security ('Local import forbidden')
and the asset bundle warning was firing on every web request.

Phase 4 caught + fixed this for fusion_accounting_followup; Phases 1-3
were never updated. Today's deployment surfaced the CSS error reported
by the user.

Resolution:
- Removed @import lines from 7 SCSS files across bank_rec, reports, assets
- Variables come from _variables.scss via manifest concatenation order
  (bundle order is _variables.scss first, then dependent files)
- Replaced documentation comments to NOT contain the literal string
  '@import "variables"' \u2014 Odoo's check is regex-based and was
  matching even SCSS comments

Verified clean: bundle rebuilds with zero 'Local import forbidden'
warnings; all 534 fusion-module tests still pass.

Made-with: Cursor
2026-04-19 21:57:22 -04:00
gsinghpal
190c296240 fix(fusion_accounting_ai): align legacy assets-adapter test with Phase 3 return shape
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
Phase 3 (fusion_accounting_assets) changed list_assets() to return
{count, total, assets} dict instead of a flat list — consistent with
bank_rec.list_unreconciled, reports.run_report, followup.list_overdue.

The pre-existing test in fusion_accounting_ai still asserted isinstance(rows, list)
and was failing on every run since Phase 3 merge. Updated to assert dict shape.

Made-with: Cursor
2026-04-19 21:50:47 -04:00
gsinghpal
12fa20c4f1 Merge Phase 4: AI-augmented customer follow-ups
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
37 tasks shipped on fusion_accounting/phase-4-followup:
- fusion.followup.engine (7-method API: get_overdue, compute_level, send, escalate, pause, reset, snapshot_history)
- 6 aging buckets + 3-level dunning + tone selector
- 5 persisted models (level, run, text_cache, partner inherit, move_line inherit)
- AI: payment risk scoring + LLM follow-up text + templated fallback
- 6 JSON-RPC controller endpoints + reactive frontend service
- 5 OWL components + SCSS + dark mode
- Batch wizard + 2 cron jobs (daily scan + weekly risk refresh)
- 3 default mail templates + 3 default levels
- Migration wizard backfill from account_followup
- Coexistence with Enterprise
- 106 tests passing
- All P95 perf metrics within 1x of budget

ALL 4 PHASES COMPLETE — replaces account_accountant + account_reports + account_asset + account_followup.
2026-04-19 21:48:10 -04:00
gsinghpal
b834ae3117 feat(configurator): complete all deferred Phase D/E/F tasks
Ships the remaining items from the Sales UX Uplift plan:

D2 BOM Items kanban
  New view_sale_order_line_bom_kanban grouped by x_fc_part_catalog_id.
  Smart button 'BOM Items' on SO form opens it.

D5 Archive line
  x_fc_archived Boolean on sale.order.line plus action_archive_line /
  action_unarchive_line. Acknowledgement report filters out archived
  lines.

D6 Add Quoted Lines sub-wizard
  New fp.add.from.quote.wizard parallel to fp.add.from.so.wizard. Pick
  quotes for this customer and clone them into direct-order lines
  carrying part, coating, qty, unit price (from calculated or
  override), and notes. Button '+ Add From Quotes' on wizard Lines tab.

D7 SO Acknowledgement PDF
  New ir.actions.report + QWeb template in configurator/report/.
  Header shows customer / contact / PO / Customer Job #, Bill-To,
  Ship-To, planned start + customer deadline + ship-via. Line table
  skips archived lines. Includes external notes, blanket-order
  callout, and customer-signature + vendor-signature blocks.
  Binding added to sale.order so it shows up under Print menu.

D9 Quick-nav chip bar
  New smart buttons on SO form: Invoices / Pickings / NCRs / Files
  with counts and icons. Each opens a filtered list. NCR button
  appears only when fusion_plating_quality is installed.

D10 SO/WO perspective toggle
  view_sale_order_line_wo_kanban grouped by x_fc_wo_group_tag. Smart
  button 'By WO' on SO form.

D11 Assemblies minimal model
  fp.sale.assembly + fp.sale.assembly.line with name, ship_to, count,
  procured_count, completed_at. UX (forms / kanbans / integration
  into receiving) deferred — model only for now.

D14 Uploaded Files
  Files smart button on SO form opens ir.attachment kanban filtered
  to this SO. Count appears in the chip bar.

F4 Signed tracking
  x_fc_signed_at / x_fc_signed_by / x_fc_is_signed on sale.order +
  action_mark_signed helper. Signed column on quotes list view.

F10 New Quote
  Kept on existing action_fp_quotations (already surfaces the
  default New button).

E5/F9 Action icons per row
  Deferred — requires a custom widget; the native PDF action via the
  Print menu covers 80% of the use case.

Bumped to 19.0.8.0.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:45:17 -04:00
gsinghpal
3491069f48 docs(fusion_accounting_followup): CLAUDE.md, UPGRADE_NOTES.md, README.md
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
Made-with: Cursor
2026-04-19 21:41:41 -04:00
gsinghpal
fbc1ac38f8 feat(fusion_accounting): meta-module now installs followup sub-module
Made-with: Cursor
2026-04-19 21:40:10 -04:00
gsinghpal
aeb5461ad0 test(fusion_accounting_followup): local LLM follow-up text smoke (skips without LLM)
Made-with: Cursor
2026-04-19 21:39:50 -04:00
gsinghpal
e1f94d5202 test(fusion_accounting_followup): 5 OWL tour tests
Made-with: Cursor
2026-04-19 21:39:08 -04:00
gsinghpal
b85e208856 chore(bridge_mrp): bump to 19.0.7.0.0 — WO group + start-at-node wiring
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:35:59 -04:00
gsinghpal
e3001b5297 feat(bridge_mrp): honour x_fc_wo_group_tag + x_fc_start_at_node_id
Two features from Phases B/C that were previously only data now do work:

1. WO GROUPING (x_fc_wo_group_tag)
   _fp_auto_create_mo rewritten to iterate order_lines and group by
   x_fc_wo_group_tag. Lines sharing a tag collapse into ONE MO with
   product = first line's part.product_id, qty = Σ line qty,
   recipe = first line's coating_config.recipe_id. Untagged lines
   each get their own MO. Legacy path preserved for service-line SOs
   with no plating data.

   Idempotency is per (origin, tag): re-confirming an SO doesn't
   create duplicate MOs for already-grouped lines.

   New on mrp.production:
   - x_fc_wo_group_tag (Char, tracking)
   - x_fc_sale_order_line_ids (M2M back to sale.order.line)
   - x_fc_start_at_node_id (Many2one fusion.plating.process.node)

2. START-AT-NODE (x_fc_start_at_node_id)
   _generate_workorders_from_recipe pre-computes allowed_ids as the
   set of {descendants of start_node} ∪ {ancestors of start_node}.
   _is_node_included rejects any node outside that set. This skips
   sibling branches earlier in the recipe while keeping the
   container hierarchy so WO sequence numbers still make sense.

Smoke-tested S00070 (4 lines, 2 tagged groups + 1 untagged) -> 3 MOs:
WO#A qty=15 (2 lines batched), WO#B qty=50 (1 line), untagged qty=7
(1 line). Each got the ENP-ALUM-BASIC recipe.

Start-at-node smoke on the same recipe: full generation = 9 WOs,
partial with start_at='Ready for processing' = 1 WO.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:34:48 -04:00
gsinghpal
8eb4b8dc6c fix(fusion_accounting_followup): seeded levels + migration idempotency
- test_create_minimal/negative_delay used sequence=1, which now collides
  with the seeded Friendly Reminder level. Use sequences 901/902.
- migration backfill: search by name (not raw seq) for idempotency,
  allocate sequence as max(existing)+1 to avoid both seed clashes and
  within-batch collisions when Enterprise has duplicate sequence values.

Made-with: Cursor
2026-04-19 21:33:26 -04:00
gsinghpal
d0a912b1da test(fusion_accounting_followup): coexistence behavior
Made-with: Cursor
2026-04-19 21:30:26 -04:00
gsinghpal
8ef88da94a feat(fusion_accounting_followup): menu + window actions with coexistence group filter
Made-with: Cursor
2026-04-19 21:30:06 -04:00
gsinghpal
38a2684782 feat(fusion_accounting_followup): migration wizard backfill from account_followup
Made-with: Cursor
2026-04-19 21:29:38 -04:00
gsinghpal
2ec90a50b0 feat(fusion_accounting_followup): batch send follow-ups wizard
Made-with: Cursor
2026-04-19 21:28:58 -04:00
gsinghpal
4ee261e189 feat(fusion_accounting_followup): default mail templates for 3 escalation levels
Made-with: Cursor
2026-04-19 21:27:59 -04:00
gsinghpal
ab3fcc56db feat(fusion_accounting_followup): seed 3 default follow-up levels
Made-with: Cursor
2026-04-19 21:27:33 -04:00
gsinghpal
97c733b7c3 feat(configurator): Phase F — quotations list uplift
F1 follow-up: x_fc_follow_up_date + x_fc_follow_up_user_id fields on
sale.order, surfaced in the quotations list + a 'Needs Follow-Up'
preset filter.

F2 expires: native validity_date exposed as togglable column on the
quotes list + an 'Expired' preset filter.

F3 email status pills: x_fc_email_status computed (draft / sent /
opened / won). 'Opened' detects via mail.notification.is_read on any
email-type mail.message attached to this SO.

F5 part numbers summary: x_fc_part_numbers_summary ("PN1, PN2 (+3
more)") across order_line parts, togglable column.

F7 from-RFQ filter reuses existing x_fc_rfq_attachment_id.

Views:
- view_sale_order_list_fp_quotes (new list dedicated to quotes).
- view_sale_order_search_fp_quotes with filters Draft / Sent / Won /
  From RFQ / Needs Follow-Up / Expired + group-bys.
- action_fp_quotations rewired to both of the above.

Bumped to 19.0.7.2.0. Closes all six phases originally planned.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:23:41 -04:00
gsinghpal
474485f963 feat(fusion_accounting_followup): ai_text_panel + followup_history_table components
Made-with: Cursor
2026-04-19 21:20:51 -04:00
gsinghpal
da746698c5 feat(fusion_accounting_followup): partner_card + aging_bucket_strip + risk_badge components
Made-with: Cursor
2026-04-19 21:19:52 -04:00
gsinghpal
21f6171162 feat(fusion_accounting_followup): top-level followup_dashboard component
Made-with: Cursor
2026-04-19 21:18:59 -04:00
gsinghpal
94eb7ef415 feat(configurator): Phase E — SO list view uplift
E1/E2/E3/E4: list view gets new togglable columns for
- x_fc_wo_completion (e.g. '3/5'): count of completed vs total WOs
- x_fc_invoiced_amount (Monetary): sum of posted customer invoices
  minus credit notes
- x_fc_margin_amount + x_fc_margin_percent: reuses Phase D8 computes
- x_fc_is_blanket_order toggle

New sale.order.search view (sale.order.search.fp) with preset
filters: My Orders / Open / Confirmed / Done / Blanket / Has Rush /
Overdue, plus group-bys for Customer / Status / Customer Deadline.

Bumped to 19.0.7.1.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:18:52 -04:00
gsinghpal
86bead48e1 feat(fusion_accounting_followup): followup_service.js reactive frontend service
Made-with: Cursor
2026-04-19 21:17:57 -04:00
gsinghpal
99e4f8e17f feat(fusion_accounting_followup): SCSS foundation for OWL widget
Made-with: Cursor
2026-04-19 21:17:18 -04:00
gsinghpal
3f807d0152 chore(configurator): bump to 19.0.7.0.0 — Phase D first pass landed
Phase D scope landed so far:
- D1 deadline countdown
- D4 internal/external notes split
- D8 margin amount + percent
- D12 contact phone on SO header
- D13 ship via Char
- D3 active WOs stat button

Deferred to later Phase D pass:
- D2 BOM Items grouped list (overlaps with order_line)
- D5 archive line (native Odoo, just needs UI exposure)
- D6 Add Quoted Lines sub-wizard
- D7 SO Acknowledgement PDF report
- D9 Quick-nav link bar
- D10 SO/WO perspective toggle
- D11 Assemblies section (hierarchical BOM)
- D14 Uploaded Files surface (native Odoo attachments)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:13:40 -04:00
gsinghpal
842efd828c feat(configurator): Phase D batch 2 — active WOs stat button on SO form
D3 first half: x_fc_workorder_count computes live count of active MRP
work orders linked to this SO (via mo.origin = so.name). Adds a
'Active WOs' smart button next to the existing PO / RFQ buttons on
the sale.order form. Clicking opens a filtered mrp.workorder list
grouped by MO.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:12:34 -04:00
gsinghpal
2476961f50 feat(configurator): Phase D batch 1 — countdown, notes split, margin, contact
Phase D first landing covers the quick-win Steelhead-parity fields on
the SO form / list:

- D1: x_fc_deadline_countdown ("in 2d 3h", "overdue 1d 4h") computed
  from commitment_date. Surfaced in SO form scheduling group and as
  togglable column on the SO list.
- D4: x_fc_internal_note + x_fc_external_note split (html). Existing
  'note' field is left untouched for back-compat. External note is
  intended for the SO acknowledgement + portal; internal note is
  shop-floor only.
- D8: x_fc_margin_amount + x_fc_margin_percent, currently computed
  against fp.coating.config.unit_cost if defined (else 0 -> 100%
  margin). When cost rollup lands on fp.coating.config, margin will
  reflect reality automatically.
- D12: x_fc_contact_phone related to partner.phone (readonly) on SO
  header.
- D13: x_fc_ship_via Char on SO header (carrier name).

Smoke: S00066 shows 'in 9d 22h' countdown + \$3025 margin; S00069
shows 'in 24d 22h' + \$750. Contact phone pulls from partner.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:11:18 -04:00
gsinghpal
f45d66c465 test(fusion_accounting_followup): performance benchmarks with P95 targets
Made-with: Cursor
2026-04-19 21:10:02 -04:00
gsinghpal
f64b8f373c test(fusion_accounting_followup): full follow-up flow integration test
Made-with: Cursor
2026-04-19 21:09:17 -04:00
gsinghpal
6b4b0c9eb7 chore(configurator): bump to 19.0.6.2.0 — Phase C direct order polish
Phase C complete on odoo-entech. Smoke-tested S00069:
- C1 x_fc_start_at_node_id = Ready for De-Masking (resume-rework)
- C2 x_fc_part_wo_description = internal rework note
- C5 x_fc_is_one_off = False
- C3 x_fc_quote_id slot wired (no quote picked in this smoke)
- C4 push-to-defaults wrote EN High-Phos back onto part catalog

Phase D (SO detail view), Phase E (SO list view), and Phase F
(Quotes list) are independent tracks — outlined in the plan doc.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:09:00 -04:00
gsinghpal
d51a2b104e test(fusion_accounting_followup): Hypothesis property-based invariants
Made-with: Cursor
2026-04-19 21:08:35 -04:00
gsinghpal
31bd8d1e56 feat(configurator): C3 — link direct-order line to a prior quote
Adds quote_id (Many2one fp.quote.configurator) on the wizard line
with a domain scoped to the wizard's customer + quote states (sent /
accepted / won). Onchange auto-fills part, coating, and unit price
(final = estimator_override_price or calculated_price, per-part).

Mirrors x_fc_quote_id on sale.order.line for the audit trail. Surfaced
as a togglable column on the SO line tree and under "Qty & Price" on
the wizard line drill-in form.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:07:48 -04:00
gsinghpal
042dcf8067 feat(fusion_accounting_followup): 2 cron jobs (daily scan + weekly risk refresh)
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
- fusion.followup.cron AbstractModel with two handlers
- cron_fusion_followup_daily_scan: walks every overdue partner and
  delegates to engine.send_followup_email
- cron_fusion_followup_risk_refresh: weekly refresh of
  fusion_followup_risk_score / risk_band on res.partner
- V19 ir.cron records (no numbercall field)
- 2 smoke tests added (80 total)

Made-with: Cursor
2026-04-19 21:04:37 -04:00
gsinghpal
d437d1d959 feat(configurator): C4 — push coating + treatments back to part catalog defaults
Adds x_fc_default_coating_config_id and x_fc_default_treatment_ids
fields on fp.part.catalog. Wizard line gets a push_to_defaults
toggle. After action_create_order confirms the SO, any line with
push_to_defaults=True writes its coating + treatments back onto the
part catalog entry as the new defaults.

Reverse direction too: onchange on part_catalog_id in the wizard
line seeds coating + treatments from the part's defaults (if set and
the line doesn't already have them).

Part catalog form gets a new "Defaults" tab showing the stored
defaults. Smoke-tested: pushing default on order 1 populates the
catalog entry; new wizard line for that part auto-seeds the coating.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:04:30 -04:00
gsinghpal
52becd176a feat(fusion_accounting_ai): 5 new customer follow-up AI tools
Adds Task 17 tool layer:
- fusion_list_overdue
- fusion_get_partner_followup_detail
- fusion_generate_followup_text
- fusion_send_followup
- fusion_get_partner_risk_score

Tools register through TOOL_DISPATCH and degrade with a clear
error message when fusion_accounting_followup is not installed.
5 TransactionCase tests added (78 total).

Made-with: Cursor
2026-04-19 21:03:30 -04:00
gsinghpal
993df3a14a feat(fusion_accounting_ai): wire FollowupAdapter fusion paths to engine
- Switch FUSION_MODEL to fusion.followup.engine so adapter mode
  selection matches the new module
- Add list_overdue() with fusion/enterprise/community variants
- Re-route send_followup_via_fusion to engine.send_followup_email
- 4 new TransactionCase tests (73 total)

Existing aging / overdue_invoices adapter methods continue to fall
back to the community implementation.

Made-with: Cursor
2026-04-19 21:02:17 -04:00
gsinghpal
43a26b6849 feat(configurator): Phase C polish — to-node picker, WO description, one-off flag
C1: start_at_node_id per wizard line, mirrors to x_fc_start_at_node_id
on sale.order.line. Domain filters to nodes descending from the
coating_config's recipe so the estimator only picks valid resume
points. bridge_mrp will use this in a follow-up to skip ancestor
steps in the generated work order.

C2: part_wo_description (separate from customer-facing line_description)
lets the planner add internal-only notes that appear on the travelling
sheet only. Mirrors to x_fc_part_wo_description on sale.order.line.

C5: is_one_off flag for prototype / non-catalog parts. Mirrors to
x_fc_is_one_off. Actual skip-catalog behaviour will be wired in a
later pass.

All three fields appear in the wizard line drill-in form (under a new
"Work Order (internal)" group) and as togglable columns on the
sale.order.line tree.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 21:01:25 -04:00
gsinghpal
d455016c27 feat(fusion_accounting_followup): 6 JSON-RPC endpoints for OWL widget
Adds Task 15 controller layer:
- /fusion/followup/list_overdue
- /fusion/followup/get_partner_detail
- /fusion/followup/generate_text
- /fusion/followup/send
- /fusion/followup/pause
- /fusion/followup/reset

All endpoints use V19 type='jsonrpc' and route through
fusion.followup.engine. 6 HttpCase tests added (69 total).

Made-with: Cursor
2026-04-19 21:00:07 -04:00
gsinghpal
9b6d6b3895 test(fusion_accounting_followup): engine integration tests for full lifecycle
End-to-end flows over a real posted receivable line: aging discovery,
level resolution, send-with-cache reuse, pause+force override, and
audit history growth. Adds ignore_pause kwarg to compute_followup_level
so force=True in send_followup_email reaches level resolution.

Made-with: Cursor
2026-04-19 20:54:13 -04:00
gsinghpal
6802d60e44 feat(fusion_accounting_followup): fusion.followup.engine 7-method API
The orchestrator AbstractModel for follow-up lifecycle.
get_overdue_for_partner, compute_followup_level, send_followup_email,
escalate_to_next_level, pause_followup, reset_followup, snapshot_followup_history.

All controllers, AI tools, wizards, cron must route through these
methods; no direct ORM writes to fusion.followup.run from anywhere else.

Made-with: Cursor
2026-04-19 20:52:27 -04:00
gsinghpal
059276886d chore(configurator): bump to 19.0.6.1.0 — Phase B direct order wizard
Phase B complete on odoo-entech:
- B1/B2: Blanket + Block Partial flags on wizard header + sale.order
- B3: x_fc_wo_group_tag per SO line (bridge_mrp will use this to
  batch MOs in a follow-up)
- B4: 'Add From Prior SO' sub-wizard for repeat orders
- B5: Per-line is_missing_info compute + amber row decoration
- B6: Rush already on line (added in Phase A)

Smoke-tested: wizard accepts 4 lines (1 with missing price, 3 WO-tagged
across 2 groups), banner shows correctly, missing row highlighted in
amber, after fix SO creates cleanly with all flags + tags persisted.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:50:49 -04:00
gsinghpal
9642a07306 feat(configurator): 'Add From Prior SO' sub-wizard for repeat orders
Task B4. New fp.add.from.so.wizard transient model: given the current
direct-order wizard + customer, lists the customer's prior confirmed
sale orders, lets the estimator tick source lines, and clones them
into fp.direct.order.line rows (part, coating, treatments, qty,
price, deadline, rush, WO group, description).

Button "+ Add From Prior SO" lives on the Lines tab of the main
wizard, visible once the customer is picked. Sub-wizard rejects
source lines that predate the new plating fields (no x_fc_part_catalog_id).

Smoke-tested on odoo-entech: copying all 3 lines of S00066 onto a
fresh wizard reproduces part/coating/qty/price correctly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:48:52 -04:00
gsinghpal
06dafc31c1 feat(fusion_accounting_followup): inherit account.move.line for level tracking
Made-with: Cursor
2026-04-19 20:47:37 -04:00
gsinghpal
2ddc600d65 feat(fusion_accounting_followup): inherit res.partner with follow-up state
Made-with: Cursor
2026-04-19 20:46:08 -04:00
gsinghpal
f55022c3d6 feat(configurator): blanket/block-partial flags + WO group + per-line missing indicator
Phase B partial landing (B1, B2, B3, B5):

- B1/B2: x_fc_is_blanket_order and x_fc_block_partial_shipments on
  sale.order; matching booleans on the wizard header.
- B3: x_fc_wo_group_tag Char on sale.order.line and wo_group_tag on
  wizard line. Free-text tag; bridge_mrp will batch lines sharing a
  tag into one MO in a follow-up.
- B5: is_missing_info computed Boolean on fp.direct.order.line;
  tree uses decoration-warning to highlight incomplete rows in amber.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:45:27 -04:00
gsinghpal
207c857e6b feat(fusion_accounting_followup): LLM text cache model
Made-with: Cursor
2026-04-19 20:45:27 -04:00
gsinghpal
05de855cea feat(fusion_accounting_followup): fusion.followup.run audit model
Made-with: Cursor
2026-04-19 20:44:39 -04:00
gsinghpal
9ae9161892 feat(fusion_accounting_followup): fusion.followup.level definition model
Made-with: Cursor
2026-04-19 20:43:51 -04:00
gsinghpal
f0c3661277 chore(configurator): bump to 19.0.6.0.0 for multi-line direct order wizard
Task A8. Closes Phase A of the direct-order rewrite.

Smoke-tested on odoo-entech: wizard accepts 3 lines (qty 65, total
\$3,025 + tax -> \$3,418.25), creates SO S00066 in state=sale with all
header fields (customer job #, three deadlines, bill/ship addresses)
and per-line fields (part, coating, qty, price) populated correctly.

Phase A complete. Phase B (blanket flag, block partial, WO grouping,
add-from-SO, missing-info banner polish) and Phase C (to-node picker,
quote link, push-defaults) outlined in the plan doc; Phases D/E/F
(SO detail, SO list, quotes list) are separate tracks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:40:44 -04:00
gsinghpal
1829f0584f feat(fusion_accounting_followup): AI follow-up text generator + prompt
Made-with: Cursor
2026-04-19 20:40:26 -04:00
gsinghpal
63f3e0ec14 feat(fusion_accounting_followup): tone_selector service
Made-with: Cursor
2026-04-19 20:39:17 -04:00
gsinghpal
397fb238c5 feat(fusion_accounting_followup): risk_scorer service
Made-with: Cursor
2026-04-19 20:38:44 -04:00
gsinghpal
6fa4140d11 feat(configurator): surface new direct-order fields on sale order form + list
Task A7. SO form Plating tab gets a new "Customer Reference /
Scheduling" block showing customer_job_number, planned_start_date,
internal_deadline, commitment_date (as Customer Deadline). Order line
tree in SO form now shows per-line part / coating / treatments /
deadline / rush. SO list view exposes customer job # and both
deadlines as togglable columns.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:38:39 -04:00
gsinghpal
d4ef19858d feat(fusion_accounting_followup): level_resolver service
Made-with: Cursor
2026-04-19 20:38:02 -04:00
gsinghpal
e34c1bcc8d refactor(configurator): multi-line direct order wizard with notebook form
Tasks A3 + A6. Wizard rewritten as header + lines architecture:

- Header carries customer/addresses/PO/deadlines/invoicing/notes.
- One SO line created per fp.direct.order.line, carrying part,
  coating, treatments M2M, qty, price, per-line deadline, rush flag,
  and description.
- action_create_order loops wizard lines, invokes revision-bump
  helper, and builds order_line tuples with x_fc_* fields.
- Form view uses notebook (Lines tab with editable tree + drill-in
  form, Notes tab), amber missing-info banner at top, running totals
  at bottom. Customer deadline maps to Odoo commitment_date on SO.

Single-line fields and their computes/onchanges removed from wizard;
moved to fp.direct.order.line in task A4.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:37:11 -04:00
gsinghpal
4ce0edc698 feat(fusion_accounting_followup): overdue_aging service with 6 buckets
Made-with: Cursor
2026-04-19 20:35:39 -04:00
gsinghpal
95db3aff0f feat(configurator): x_fc_* fields on sale.order + new sale.order.line extensions
Task A5. Adds customer_job_number, planned_start_date, and
internal_deadline on sale.order. Customer deadline maps to Odoo's
native commitment_date. Creates sale_order_line.py with per-line
plating fields: part_catalog_id, coating_config_id, treatment_ids
M2M, part_deadline, rush_order.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:33:50 -04:00
gsinghpal
9423a93961 feat(configurator): fill per-line logic (price lookup, desc template, rev bump)
Task A4. Expands fp.direct.order.line with: part related fields,
optional new-revision block, additional treatment M2M, per-line
deadline + rush flag, description template + free-text, onchange
auto-price-lookup from customer price list, onchange template
suggestion (part > customer > coating), and _get_or_bump_revision
helper that will be called by the SO-creation loop.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:32:34 -04:00
gsinghpal
057157587d feat(configurator): add header fields + line O2M to direct order wizard
Task A2 of the direct-order-wizard rewrite. Adds SO-header fields for
customer job #, three deadlines (planned start / internal / customer),
bill-to / ship-to address pickers, the line_ids O2M linking to
fp.direct.order.line, computed order totals, and a missing-info
warning banner. Partner onchange now also seeds default addresses.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:31:14 -04:00
gsinghpal
ea2f44287f feat(fusion_accounting_followup): Phase 4 skeleton + plan
35-task plan to replace Enterprise account_followup module:
- Multi-level dunning (gentle reminder -> firm warning -> legal)
- AI augmentation: contextual follow-up text generation + payment risk scoring + tone selection
- HYBRID engine: shared primitives + persisted level/run/cache models
- Per-partner state: current level, paused-until, history
- Coexists with Enterprise (group_fusion_show_when_enterprise_absent)
- Same V19 conventions + test pyramid + perf-budget discipline as Phases 1-3

Made-with: Cursor
2026-04-19 20:31:07 -04:00
gsinghpal
b4558a223c feat(configurator): stub fp.direct.order.line model for multi-line direct order wizard
Task A1 of the direct-order-wizard rewrite. Adds the transient line
model that will hold per-part detail (part, coating, qty, price) when
the wizard moves from single-line to header+lines architecture.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 20:29:52 -04:00
gsinghpal
7a53012f09 Merge Phase 3: AI-augmented asset management
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
50 tasks shipped on fusion_accounting/phase-3-assets:
- fusion.asset.engine (7-method API: compute_schedule, post, dispose, partial_sale, pause, resume, reverse)
- 3 depreciation methods (straight-line, declining-balance, units-of-production)
- 6 persisted models + materialized view for portfolio queries
- AI: anomaly detection + LLM-suggested useful life with templated fallback
- 8 JSON-RPC controller endpoints + reactive frontend service
- 6 OWL components + SCSS tokens + dark mode
- 4 wizards (creation w/ AI suggest, disposal, partial sale, depreciation run)
- Migration wizard backfill from account.asset (verified live: 2 records, idempotent)
- Audit PDF report
- 2 cron jobs (daily depreciation post + monthly anomaly scan)
- 5 AI chat tools
- Coexists with Enterprise (group_fusion_show_when_enterprise_absent)
- 141 tests passing (unit, integration, property-based, controller, MV, wizards, coexistence, perf, LLM compat, OWL tours)
- All 5 P95 perf metrics within 1x of budget (8x-500x headroom)
2026-04-19 20:29:40 -04:00
gsinghpal
43e1f3d6f5 docs(fusion_accounting_assets): CLAUDE.md, UPGRADE_NOTES.md, README.md
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
Mirrors Phase 1 + 2 doc layout. CLAUDE.md captures architecture, the
7-method engine API, persisted models, controllers, OWL frontend,
performance baselines (Tasks 23 + 41 numbers), test counts (140), and
Phase 3.5 backlog. UPGRADE_NOTES.md anchors the Odoo 19 reference and
records V19 deprecations applied. README.md is the user-facing intro.

Made-with: Cursor
2026-04-19 20:25:16 -04:00
gsinghpal
69453bd8ae feat(fusion_accounting): meta-module now installs assets sub-module
Adds fusion_accounting_assets to the meta-module 'depends' so a single
install of fusion_accounting brings up the full Phase 1 + 2 + 3 stack.
Bumps version 19.0.1.0.2 -> 19.0.1.0.3.

Made-with: Cursor
2026-04-19 20:23:47 -04:00
gsinghpal
7e2c31e371 test(fusion_accounting_assets): local LLM useful-life smoke (skips without LLM)
Auto-detects LM Studio (:1234) or Ollama (:11434) on
host.docker.internal / localhost; skips silently when no server is
reachable so CI stays green. When a server is present it exercises the
full predict_useful_life path through the OpenAI-compatible adapter,
catching prompt / JSON-parsing regressions that mocked LLMs hide.

Tagged 'local_llm' so it can be selected explicitly when an LLM is
known-available.

Made-with: Cursor
2026-04-19 20:23:30 -04:00
gsinghpal
6344a75150 test(fusion_accounting_assets): controller perf benchmark
Adds JSON-RPC controller benchmark to complement Task 23's engine-level
benchmarks: end-to-end /fusion/assets/get_detail timing through the HTTP
dispatch layer.

Captured locally on westin-v19:
  controller.get_detail: median=2ms p95=40ms (target <500ms, 12x headroom)

Tagged 'benchmark' so it stays out of fast unit runs.

Made-with: Cursor
2026-04-19 20:22:50 -04:00
gsinghpal
59ecc9fc5b test(fusion_accounting_assets): 5 OWL tour tests
Mirrors Phase 1 + 2 tour pattern: HttpCase.start_tour wrappers tagged
'tour' so they skip cleanly when websocket-client is absent. Tours cover
smoke (/odoo loads), the asset list / category list / anomaly list views,
and the depreciation-run wizard form. Bundle is wired via
web.assets_tests.

Verified locally: 5 tests registered, all skip with
"websocket-client module is not installed" (expected — no chromium in
the dev container).

Made-with: Cursor
2026-04-19 20:22:13 -04:00
gsinghpal
2ee341316c test(fusion_accounting_assets): coexistence behavior
Made-with: Cursor
2026-04-19 20:16:30 -04:00
gsinghpal
02885108f2 feat(fusion_accounting_assets): menu + window actions with coexistence group filter
Made-with: Cursor
2026-04-19 20:15:38 -04:00
gsinghpal
af8c72a3b1 feat(fusion_accounting_assets): migration audit PDF report
Made-with: Cursor
2026-04-19 20:14:50 -04:00
gsinghpal
1491f455fe feat(fusion_accounting_assets): migration wizard backfill from account.asset
Made-with: Cursor
2026-04-19 20:13:30 -04:00
gsinghpal
3efef7efc7 feat(fusion_accounting_assets): depreciation run wizard
Made-with: Cursor
2026-04-19 20:06:25 -04:00
gsinghpal
92f445eb8f feat(fusion_accounting_assets): partial sale wizard
Made-with: Cursor
2026-04-19 20:05:17 -04:00
gsinghpal
892c37e2b0 feat(fusion_accounting_assets): disposal wizard
Made-with: Cursor
2026-04-19 20:04:03 -04:00
gsinghpal
a6ef7e0c2a feat(fusion_accounting_assets): asset creation wizard with AI useful-life suggest
Made-with: Cursor
2026-04-19 20:02:46 -04:00
gsinghpal
9794970429 feat(fusion_accounting_assets): ai_useful_life_panel + anomaly_strip components
Made-with: Cursor
2026-04-19 17:39:56 -04:00
gsinghpal
c0b8cc4159 feat(fusion_accounting_assets): disposal_dialog component
Made-with: Cursor
2026-04-19 17:39:17 -04:00
gsinghpal
51bff01f13 feat(fusion_accounting_assets): depreciation_board component
Made-with: Cursor
2026-04-19 17:38:50 -04:00
gsinghpal
7ba15c65aa feat(fusion_accounting_assets): asset_detail_panel component
Made-with: Cursor
2026-04-19 17:38:28 -04:00
gsinghpal
bf8689716c feat(fusion_accounting_assets): asset_card component
Made-with: Cursor
2026-04-19 17:37:57 -04:00
gsinghpal
bddd22cabd feat(fusion_accounting_assets): top-level asset_dashboard component
Made-with: Cursor
2026-04-19 17:37:34 -04:00
gsinghpal
6051ef22a0 feat(fusion_accounting_assets): assets_service.js reactive frontend service
Made-with: Cursor
2026-04-19 17:36:52 -04:00
gsinghpal
24f8a5857e feat(fusion_accounting_assets): SCSS foundation for OWL widget
Made-with: Cursor
2026-04-19 17:36:11 -04:00
gsinghpal
475d17c1aa test(fusion_accounting_assets): performance benchmarks with P95 targets
Made-with: Cursor
2026-04-19 17:26:01 -04:00
gsinghpal
fec1c12246 feat(fusion_accounting_assets): MV for per-asset book value snapshot
Made-with: Cursor
2026-04-19 17:25:14 -04:00
gsinghpal
c939b83812 test(fusion_accounting_assets): integration tests for all 3 depreciation methods
Made-with: Cursor
2026-04-19 17:23:41 -04:00
gsinghpal
1e70b8d5c0 test(fusion_accounting_assets): Hypothesis property-based depreciation invariants
Made-with: Cursor
2026-04-19 17:22:55 -04:00
gsinghpal
de6d8fda3e feat(fusion_accounting_assets): 2 cron jobs (depreciation post + anomaly scan)
Some checks failed
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
Made-with: Cursor
2026-04-19 17:17:21 -04:00
gsinghpal
9092a78be2 feat(fusion_accounting_ai): 5 new asset management AI tools
Made-with: Cursor
2026-04-19 17:16:22 -04:00
gsinghpal
79cd0216ff feat(fusion_accounting_ai): wire AssetsAdapter fusion paths to engine
Made-with: Cursor
2026-04-19 17:15:24 -04:00
gsinghpal
3e8b7b1e82 feat(fusion_accounting_assets): 8 JSON-RPC endpoints for OWL widget
Made-with: Cursor
2026-04-19 17:14:22 -04:00
gsinghpal
345c971d59 test(fusion_accounting_assets): engine integration tests for full lifecycle
Made-with: Cursor
2026-04-19 17:06:55 -04:00
gsinghpal
54922a0b32 feat(fusion_accounting_assets): fusion.asset.engine 7-method API
The orchestrator AbstractModel for asset depreciation lifecycle.
compute_depreciation_schedule, post_depreciation_entry, dispose_asset,
partial_sale, pause_asset, resume_asset, reverse_disposal.

All controllers, AI tools, wizards, and cron must route through these
methods; no direct ORM writes to fusion.asset.depreciation.line or
account.move from anywhere else.

Made-with: Cursor
2026-04-19 17:06:12 -04:00
gsinghpal
38a6e375e6 feat(fusion_accounting_assets): inherit account.move.line for asset linkage
- fusion_asset_id Many2one on account.move.line (ondelete='set null':
  invoice line preserved if asset is removed)
- fusion_asset_count compute (smart-button friendly)
- action_open_fusion_asset() returns a window action to jump to the asset
- 3 new tests (66 total)

Made-with: Cursor
2026-04-19 16:59:44 -04:00
gsinghpal
8659f51935 feat(fusion_accounting_assets): asset anomaly persisted model
- 3 anomaly types: behind_schedule, ahead_of_schedule, low_utilization
- 3 severity levels: low, medium, high
- expected / actual / variance_pct (mirrors anomaly_detection service output)
- 4-state lifecycle: new -> acknowledged -> resolved (or dismissed)
- action_acknowledge / action_dismiss / action_resolve transitions
- ondelete='cascade' on asset_id (anomalies follow the asset)
- 4 new tests (63 total)

Made-with: Cursor
2026-04-19 16:58:56 -04:00
gsinghpal
5c89763191 feat(fusion_accounting_assets): asset disposal record model
- 4 disposal types: sale, scrap, donation, lost
- mail.thread tracking on type / date / sale amount / partner
- gain_loss_amount computed:
    - sale: sale_amount - book_value_at_disposal
    - scrap / donation / lost: -book_value_at_disposal (full loss)
- ondelete='restrict' on asset_id (cannot delete an asset with disposal)
- move_id placeholder for engine-created journal entry
- 4 new tests (59 total)

Made-with: Cursor
2026-04-19 16:58:12 -04:00
gsinghpal
b68d1b1c66 feat(fusion_accounting_assets): asset category template model
- defaults applied to new assets (method, useful_life, declining rate,
  salvage %, prorate convention)
- GL account hooks: asset_account_id, depreciation_account_id,
  expense_account_id (domain-filtered to relevant account types)
- computed asset_count for kanban / list views
- 3 new tests (55 total)

Made-with: Cursor
2026-04-19 16:57:25 -04:00
gsinghpal
0439d81675 feat(fusion_accounting_assets): depreciation board line model
- period_index, scheduled_date, amount, accumulated, book_value_at_end
- is_posted / posted_date / move_id (set when engine posts the entry)
- action_post() marks the line as posted (idempotent)
- UNIQUE(asset_id, period_index) constraint via models.Constraint
- 5 new tests (52 total)

Made-with: Cursor
2026-04-19 16:56:47 -04:00
gsinghpal
70e4404d9b feat(fusion_accounting_assets): main fusion.asset model with state machine
- fusion.asset: lifecycle (draft -> running -> paused -> disposed)
- mail.thread + mail.activity.mixin tracking
- 3 depreciation methods + 3 prorate conventions selections
- monetary cost / salvage with check constraints (models.Constraint)
- computed book_value, total_depreciated, last_posted_date
- action_set_running / pause / resume / set_draft transitions
- minimal stubs for fusion.asset.category and
  fusion.asset.depreciation.line so the One2many / Many2one comodels
  resolve at registry build time; expanded in Tasks 9 + 10
- 7 new tests (47 total)

Made-with: Cursor
2026-04-19 16:55:59 -04:00
gsinghpal
bc7ba27d77 feat(fusion_accounting_assets): AI useful life predictor + prompt
Made-with: Cursor
2026-04-19 16:50:01 -04:00
gsinghpal
19cbed5b37 feat(fusion_accounting_assets): asset anomaly detection service
Made-with: Cursor
2026-04-19 16:49:02 -04:00
gsinghpal
b7c171f983 feat(fusion_accounting_assets): salvage_value service
Made-with: Cursor
2026-04-19 16:48:18 -04:00
gsinghpal
bece120ee3 feat(fusion_accounting_assets): prorate service for partial-period depreciation
Made-with: Cursor
2026-04-19 16:47:31 -04:00
gsinghpal
3e73ca0eb7 feat(fusion_accounting_assets): 3 depreciation methods (straight, declining, units)
Made-with: Cursor
2026-04-19 16:46:54 -04:00
gsinghpal
99b6990dd6 feat(fusion_accounting_assets): Phase 3 skeleton + plan
50-task plan to replace Enterprise account_asset module:
- CORE scope: 3 depreciation methods (straight-line, declining-balance, units-of-production)
- HYBRID engine: shared primitives + persisted asset/category/disposal/anomaly models
- AI augmentation: utilization anomaly detection + LLM-suggested useful life
- Full lifecycle: draft -> running -> paused -> disposed
- Coexists with Enterprise (group_fusion_show_when_enterprise_absent)
- Same V19 conventions + test pyramid + perf-budget discipline as Phases 1-2

Skeleton: empty manifest + dirs + icon. Tasks 3-50 add the substance.
Made-with: Cursor
2026-04-19 16:43:06 -04:00
gsinghpal
fdfaf7e779 Merge Phase 2: AI-augmented financial reports
Some checks failed
fusion_accounting CI / test (fusion_accounting_ai) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_core) (push) Has been cancelled
fusion_accounting CI / test (fusion_accounting_migration) (push) Has been cancelled
46 tasks shipped on fusion_accounting/phase-2-reports:
- fusion.report.engine (5-method API: compute_pnl/balance_sheet/trial_balance/gl/drill_down)
- 4 CORE reports seeded (P&L, balance sheet, trial balance, general ledger)
- AI layer: anomaly detection + LLM commentary generator
- 8 JSON-RPC controller endpoints + reactive frontend service
- 8 OWL components + SCSS tokens (light + dark)
- Materialized view + 2 cron jobs (anomaly scan + MV refresh)
- 3 wizards (XLSX export, period picker, migration bootstrap)
- PDF export via QWeb
- 130 tests passing (engine, integration, property-based, controller, MV, wizards, coexistence, perf, LLM compat, OWL tours)
- All 6 P95 perf metrics within 1x of budget (37x-250x headroom)
2026-04-19 16:41:17 -04:00
4985 changed files with 1336046 additions and 5594 deletions

View File

@@ -0,0 +1,133 @@
<h2>Recommended Hybrid: A + B's escape hatch</h2>
<p class="subtitle">Layout A's inline badge as default. Power users click "Show alternatives" on any line to reveal B's ranked panel for that line only.</p>
<div class="mockup">
<div class="mockup-header">Bank Reconciliation — Account: RBC Operating · 487 unreconciled</div>
<div class="mockup-body" style="padding:14px;font-family:-apple-system,sans-serif;font-size:13px;background:#f3f4f6">
<div style="background:#fff;border:1px solid #d8dadd;border-radius:8px;margin-bottom:10px;overflow:hidden">
<div style="display:flex;justify-content:space-between;align-items:center;padding:12px 14px">
<div>
<div style="font-weight:600">Apr 12 — RBC e-transfer</div>
<div style="color:#666;font-size:12px;margin-top:2px">Cheque 4827 · Westin Plating Co · <strong>$1,847.50 CAD</strong></div>
</div>
<div style="display:flex;gap:8px;align-items:center">
<div style="background:#22c55e;color:#fff;padding:4px 10px;border-radius:14px;font-size:11px;font-weight:700;letter-spacing:0.3px">92% MATCH</div>
</div>
</div>
<div style="padding:10px 14px;background:#f0fdf4;border-top:1px solid #d1fae5;display:flex;justify-content:space-between;align-items:center">
<div style="font-size:12px;color:#166534">
💡 <strong>INV/2026/00123</strong> — Westin Plating Co — $1,847.50
</div>
<div style="display:flex;gap:6px">
<button style="background:#22c55e;color:#fff;border:none;padding:5px 12px;border-radius:5px;font-size:11px;font-weight:600;cursor:pointer">Accept</button>
<button style="background:#fff;color:#666;border:1px solid #d8dadd;padding:5px 10px;border-radius:5px;font-size:11px;cursor:pointer">Reject</button>
<button style="background:transparent;color:#666;border:none;padding:5px 8px;font-size:11px;cursor:pointer;text-decoration:underline">Show 2 alternatives</button>
</div>
</div>
</div>
<div style="background:#fff;border:1px solid #fde68a;border-radius:8px;margin-bottom:10px;overflow:hidden">
<div style="display:flex;justify-content:space-between;align-items:center;padding:12px 14px">
<div>
<div style="font-weight:600">Apr 12 — RBC payment</div>
<div style="color:#666;font-size:12px;margin-top:2px">Cheque 4828 · partner unknown · <strong>$1,800.00 CAD</strong></div>
</div>
<div style="background:#f59e0b;color:#fff;padding:4px 10px;border-radius:14px;font-size:11px;font-weight:700">68% MATCH</div>
</div>
<div style="padding:10px 14px;background:#fffbeb;border-top:1px solid #fde68a;display:flex;justify-content:space-between;align-items:center">
<div style="font-size:12px;color:#92400e">
💡 <strong>INV/2026/00098</strong> — Westin Plating Co — $1,800.00 · <em style="color:#a16207">amount matches but partner unconfirmed</em>
</div>
<div style="display:flex;gap:6px">
<button style="background:#f59e0b;color:#fff;border:none;padding:5px 12px;border-radius:5px;font-size:11px;font-weight:600;cursor:pointer">Accept</button>
<button style="background:#fff;color:#666;border:1px solid #d8dadd;padding:5px 10px;border-radius:5px;font-size:11px;cursor:pointer">Reject</button>
<button style="background:transparent;color:#666;border:none;padding:5px 8px;font-size:11px;cursor:pointer;text-decoration:underline">Show 4 alternatives</button>
</div>
</div>
</div>
<div style="background:#fff;border:1px solid #d8dadd;border-radius:8px;margin-bottom:10px;overflow:hidden">
<div style="display:flex;justify-content:space-between;align-items:center;padding:12px 14px">
<div>
<div style="font-weight:600">Apr 11 — Visa adjustment</div>
<div style="color:#666;font-size:12px;margin-top:2px">Ref VSA-201 · Royal Bank fees · <strong>$89.99 CAD</strong></div>
</div>
<div style="background:#94a3b8;color:#fff;padding:4px 10px;border-radius:14px;font-size:11px;font-weight:700">NO MATCH</div>
</div>
<div style="padding:8px 14px;background:#f8fafc;border-top:1px solid #e2e8f0;display:flex;gap:6px;justify-content:flex-end">
<button style="background:#fff;color:#666;border:1px solid #d8dadd;padding:5px 10px;border-radius:5px;font-size:11px;cursor:pointer">Reconcile manually</button>
<button style="background:#fff;color:#666;border:1px solid #d8dadd;padding:5px 10px;border-radius:5px;font-size:11px;cursor:pointer">Apply rule</button>
<button style="background:#fff;color:#666;border:1px solid #d8dadd;padding:5px 10px;border-radius:5px;font-size:11px;cursor:pointer">Write off</button>
</div>
</div>
<div style="background:#fff;border:2px solid #22c55e;border-radius:8px;margin-bottom:10px;overflow:hidden">
<div style="display:flex;justify-content:space-between;align-items:center;padding:12px 14px;background:#f0fdf4">
<div>
<div style="font-weight:600">Apr 11 — RBC bulk deposit</div>
<div style="color:#666;font-size:12px;margin-top:2px">Ref 9921-D · Westin Plating Co · <strong>$3,200.00 CAD</strong></div>
</div>
<div style="background:#22c55e;color:#fff;padding:4px 10px;border-radius:14px;font-size:11px;font-weight:700">98% MATCH (alternatives expanded)</div>
</div>
<div style="background:#f8fafc;padding:10px 14px;border-top:1px solid #d1fae5">
<div style="font-size:11px;color:#666;margin-bottom:8px;text-transform:uppercase;letter-spacing:0.4px;font-weight:600">AI suggestions, ranked</div>
<div style="background:#fff;border:1px solid #22c55e;border-radius:6px;padding:8px 10px;margin-bottom:5px;display:flex;justify-content:space-between;align-items:center">
<div>
<div style="font-size:12px;font-weight:600;color:#166534">98% — INV/2026/00145 — $3,200.00 · Westin Plating Co</div>
<div style="font-size:11px;color:#666;margin-top:2px">Exact amount + same partner + invoice date Apr 8 · 4 prior reconciles match this pattern</div>
</div>
<button style="background:#22c55e;color:#fff;border:none;padding:5px 14px;border-radius:5px;font-size:11px;font-weight:600;cursor:pointer">Accept</button>
</div>
<div style="background:#fff;border:1px solid #fde68a;border-radius:6px;padding:8px 10px;margin-bottom:5px;display:flex;justify-content:space-between;align-items:center">
<div>
<div style="font-size:12px;font-weight:600;color:#92400e">71% — INV/2026/00141 — $3,200.00 · Bramalea Lift Co</div>
<div style="font-size:11px;color:#666;margin-top:2px">Amount matches, partner is a different client</div>
</div>
<button style="background:#fff;color:#666;border:1px solid #d8dadd;padding:5px 12px;border-radius:5px;font-size:11px;cursor:pointer">Use this</button>
</div>
<div style="background:#fff;border:1px solid #d8dadd;border-radius:6px;padding:8px 10px;display:flex;justify-content:space-between;align-items:center">
<div>
<div style="font-size:12px;font-weight:600;color:#666">62% — INV/2026/00139 + INV/2026/00140 (combined) — Westin Plating Co</div>
<div style="font-size:11px;color:#666;margin-top:2px">Two invoices summing to $3,200.00</div>
</div>
<button style="background:#fff;color:#666;border:1px solid #d8dadd;padding:5px 12px;border-radius:5px;font-size:11px;cursor:pointer">Use this</button>
</div>
<div style="margin-top:6px"><button style="background:transparent;color:#666;border:none;padding:4px;font-size:11px;cursor:pointer;text-decoration:underline">Hide alternatives</button></div>
</div>
</div>
<div style="background:#fff;border:1px solid #d8dadd;border-radius:8px;padding:8px 14px;text-align:center">
<button style="background:#22c55e;color:#fff;border:none;padding:8px 22px;border-radius:6px;font-size:12px;font-weight:700;cursor:pointer">Accept all 47 high-confidence (≥95%)</button>
<span style="color:#666;font-size:11px;margin-left:10px">·</span>
<span style="color:#666;font-size:11px;margin-left:8px">487 lines unreconciled · 47 ready to auto-accept · 134 need review · 306 no AI match</span>
</div>
</div>
</div>
<p class="subtitle">Each line: confidence badge top-right, single suggestion strip below (Accept / Reject / Show alternatives). High-confidence lines have a green border for instant scanning. Bottom bar offers batch-accept of all ≥95% matches at once. The 4th line shows what "Show alternatives" reveals when expanded — B's ranked panel inline.</p>
<div class="options">
<div class="option" data-choice="approve" onclick="toggleSelect(this)">
<div class="letter"></div>
<div class="content">
<h3>Looks right — proceed with this hybrid</h3>
<p>I'll capture this as the default UI design in the spec. Specific colour choices and exact pixel spacing get refined during implementation.</p>
</div>
</div>
<div class="option" data-choice="adjust" onclick="toggleSelect(this)">
<div class="letter"></div>
<div class="content">
<h3>Mostly right but I want changes</h3>
<p>Tell me in the terminal what to adjust (positions, colours, button labels, missing actions, etc.).</p>
</div>
</div>
<div class="option" data-choice="back_to_pure_a" onclick="toggleSelect(this)">
<div class="letter">A</div>
<div class="content">
<h3>Just pure A, no alternatives panel</h3>
<p>Keep it simple — single suggestion per line, no expand. If user disagrees with AI they go to the manual reconcile dialog.</p>
</div>
</div>
</div>

View File

@@ -0,0 +1,101 @@
<h2>AI Suggestion Placement</h2>
<p class="subtitle">You picked "AI assistive" — now: how does the AI suggestion appear on each unreconciled bank line? Three layouts:</p>
<div class="cards" data-multiselect>
<div class="card" data-choice="badge_inline" onclick="toggleSelect(this)">
<div class="card-image">
<div class="mockup">
<div class="mockup-header">Layout A — Inline Badge</div>
<div class="mockup-body" style="padding:12px;font-family:monospace;font-size:13px;line-height:1.7">
<div style="border:1px solid #d8dadd;padding:10px;border-radius:6px;background:#fff">
<div style="display:flex;justify-content:space-between;align-items:center">
<div>
<div style="font-weight:600">Apr 12 — RBC ETF deposit</div>
<div style="color:#666;font-size:12px">Cheque ref 4827 · $1,847.50 CAD</div>
</div>
<div style="background:#22c55e;color:#fff;padding:3px 8px;border-radius:12px;font-size:11px;font-weight:600">92% MATCH</div>
</div>
<div style="margin-top:8px;padding:6px;background:#f0fdf4;border-left:3px solid #22c55e;font-size:12px;color:#166534">
💡 Invoice <strong>INV/2026/00123</strong> — Westin Plating Co — $1,847.50 · <a href="#" style="color:#22c55e">Accept</a> · <a href="#" style="color:#666">Reject</a>
</div>
</div>
</div>
</div>
</div>
<div class="card-body">
<h3>A — Inline Badge + Suggestion Strip</h3>
<p>Confidence badge top-right of each line, suggestion strip just below. One-click Accept/Reject. Familiar Enterprise-style line layout, AI feels like a layer added on top.</p>
</div>
</div>
<div class="card" data-choice="side_panel" onclick="toggleSelect(this)">
<div class="card-image">
<div class="mockup">
<div class="mockup-header">Layout B — Side Panel</div>
<div class="mockup-body" style="padding:12px;font-family:monospace;font-size:12px">
<div style="display:flex;gap:8px;height:200px">
<div style="flex:1;border:1px solid #d8dadd;border-radius:6px;background:#fff;padding:8px">
<div style="font-weight:600;margin-bottom:6px">Bank lines</div>
<div style="background:#dbeafe;padding:6px;border-radius:4px;margin-bottom:4px;font-size:11px">Apr 12 RBC $1,847.50 ✓ selected</div>
<div style="padding:6px;font-size:11px;color:#666">Apr 12 RBC $245.00</div>
<div style="padding:6px;font-size:11px;color:#666">Apr 11 Visa $89.99</div>
<div style="padding:6px;font-size:11px;color:#666">Apr 11 RBC $3,200.00</div>
</div>
<div style="width:200px;border:1px solid #d8dadd;border-radius:6px;background:#f8fafc;padding:8px">
<div style="font-weight:600;font-size:11px;margin-bottom:6px">AI Suggestions</div>
<div style="padding:6px;background:#fff;border-radius:4px;margin-bottom:4px;font-size:10px">
<div style="color:#22c55e;font-weight:600">92% INV/2026/00123</div>
<div style="color:#666">Westin Plating $1,847.50</div>
</div>
<div style="padding:6px;background:#fff;border-radius:4px;font-size:10px">
<div style="color:#f59e0b;font-weight:600">68% INV/2026/00098</div>
<div style="color:#666">Westin Plating $1,800.00</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-body">
<h3>B — Dedicated Side Panel</h3>
<p>Bank lines on the left, AI suggestions panel on the right, updates as you select a line. Multiple ranked suggestions visible. More screen real estate for AI; line list stays clean.</p>
</div>
</div>
<div class="card" data-choice="hover_only" onclick="toggleSelect(this)">
<div class="card-image">
<div class="mockup">
<div class="mockup-header">Layout C — Hover Reveal</div>
<div class="mockup-body" style="padding:12px;font-family:monospace;font-size:13px;line-height:1.7">
<div style="border:1px solid #d8dadd;padding:10px;border-radius:6px;background:#fff;margin-bottom:6px">
<div style="display:flex;justify-content:space-between;align-items:center">
<div>
<div style="font-weight:600">Apr 12 — RBC ETF deposit</div>
<div style="color:#666;font-size:12px">Cheque ref 4827 · $1,847.50 CAD</div>
</div>
<div style="display:flex;align-items:center;gap:6px">
<div style="width:8px;height:8px;background:#22c55e;border-radius:50%"></div>
<div style="color:#666;font-size:11px;font-style:italic">hover for AI</div>
</div>
</div>
</div>
<div style="border:1px solid #22c55e;padding:10px;border-radius:6px;background:#f0fdf4;box-shadow:0 4px 12px rgba(0,0,0,0.08)">
<div style="display:flex;justify-content:space-between;align-items:center">
<div>
<div style="font-weight:600">Apr 12 — RBC e-transfer</div>
<div style="color:#166534;font-size:12px">💡 92% match: INV/2026/00123 — $1,847.50 · <a href="#" style="color:#22c55e">Accept</a></div>
</div>
<div style="background:#22c55e;color:#fff;padding:3px 8px;border-radius:12px;font-size:11px">92%</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-body">
<h3>C — Hover-to-Reveal</h3>
<p>Just a confidence dot on each line. AI details appear on hover/click. Cleanest visual, most Enterprise-like density. Slowest discovery for new users.</p>
</div>
</div>
</div>
<p class="subtitle">Click your preferred option(s). I'll read your selection on the next turn. You can also describe in the terminal what you'd like changed.</p>

View File

@@ -0,0 +1,29 @@
<h2>Phase 1 — Bank Reconciliation</h2>
<p class="subtitle">Brainstorming session for the next sub-module: <code>fusion_accounting_bank_rec</code></p>
<div class="section">
<h3>What we're designing</h3>
<p>A native bank-rec widget that replaces Odoo Enterprise's <code>account_accountant</code> bank reconciliation, using Odoo 19's frontend OWL architecture. It reads/writes the same <code>account.partial.reconcile</code> tables Community owns, so existing reconciliations are immune to Enterprise uninstall (verified empirically in Phase 0).</p>
</div>
<div class="section">
<h3>Reference material I've already scanned</h3>
<ul>
<li><strong>Roadmap design</strong> Section 4.3 — Phase 1 scope, exit criteria</li>
<li><strong>Enterprise V19 source</strong> at <code>RePackaged-Odoo/accounting/account_accountant/</code> — 17 OWL components in <code>static/src/components/bank_reconciliation/</code>, 1 service file (140 lines), 3 inherits on community models, 2 wizards</li>
<li><strong>Phase 0 BankRecAdapter</strong> — already present at <code>fusion_accounting_ai/services/data_adapters/bank_rec.py</code> with a stub <code>list_unreconciled_via_fusion()</code> waiting to be filled in</li>
</ul>
</div>
<div class="section">
<h3>How this session works</h3>
<ol>
<li>I ask clarifying questions one at a time (terminal for scope/concept, this browser for layout/visual)</li>
<li>I propose 2-3 architectural approaches with tradeoffs</li>
<li>We work through the design section by section</li>
<li>I write the spec doc and you approve it</li>
<li>Then we transition to writing the implementation plan</li>
</ol>
</div>
<p class="subtitle">Continuing in terminal for the first question...</p>

View File

@@ -0,0 +1,4 @@
<div style="display:flex;align-items:center;justify-content:center;min-height:60vh;flex-direction:column;gap:16px">
<p class="subtitle">UI layout approved ✓</p>
<p class="subtitle">Continuing in terminal — next sections are about file structure, reconcile engine algorithms, and migration. Browser will return for any further visual decisions.</p>
</div>

View File

@@ -0,0 +1,4 @@
<div style="display:flex;align-items:center;justify-content:center;min-height:60vh;flex-direction:column;gap:16px">
<p class="subtitle">Spec approved ✓ — committed as <code>2d64f7e</code></p>
<p class="subtitle">Now writing the Phase 1 implementation plan in terminal. Browser session can be closed; the visual companion isn't needed for plan-writing.</p>
</div>

View File

@@ -0,0 +1 @@
{"reason":"idle timeout","timestamp":1776605003749}

View File

@@ -0,0 +1,12 @@
{"type":"server-started","port":50540,"host":"127.0.0.1","url_host":"localhost","url":"http://localhost:50540","screen_dir":"/Users/gurpreet/Github/Odoo-Modules/.superpowers/brainstorm/84408-1776602183/content","state_dir":"/Users/gurpreet/Github/Odoo-Modules/.superpowers/brainstorm/84408-1776602183/state"}
{"type":"screen-added","file":"/Users/gurpreet/Github/Odoo-Modules/.superpowers/brainstorm/84408-1776602183/content/intro.html"}
{"type":"screen-added","file":"/Users/gurpreet/Github/Odoo-Modules/.superpowers/brainstorm/84408-1776602183/content/ai-badge-placement.html"}
{"type":"screen-added","file":"/Users/gurpreet/Github/Odoo-Modules/.superpowers/brainstorm/84408-1776602183/content/ai-badge-hybrid-v2.html"}
{"source":"user-event","type":"click","text":"✓\n \n Looks right — proceed with this hybrid\n I'll capture this as the default UI design in the spec. Specific colour choices and exact pixel spacing get refined during implementation.","choice":"approve","id":null,"timestamp":1776603091592}
{"source":"user-event","type":"click","text":"✓\n \n Looks right — proceed with this hybrid\n I'll capture this as the default UI design in the spec. Specific colour choices and exact pixel spacing get refined during implementation.","choice":"approve","id":null,"timestamp":1776603096458}
{"source":"user-event","type":"click","text":"✓\n \n Looks right — proceed with this hybrid\n I'll capture this as the default UI design in the spec. Specific colour choices and exact pixel spacing get refined during implementation.","choice":"approve","id":null,"timestamp":1776603097158}
{"source":"user-event","type":"click","text":"✓\n \n Looks right — proceed with this hybrid\n I'll capture this as the default UI design in the spec. Specific colour choices and exact pixel spacing get refined during implementation.","choice":"approve","id":null,"timestamp":1776603097583}
{"source":"user-event","type":"click","text":"✓\n \n Looks right — proceed with this hybrid\n I'll capture this as the default UI design in the spec. Specific colour choices and exact pixel spacing get refined during implementation.","choice":"approve","id":null,"timestamp":1776603097800}
{"source":"user-event","type":"click","text":"✓\n \n Looks right — proceed with this hybrid\n I'll capture this as the default UI design in the spec. Specific colour choices and exact pixel spacing get refined during implementation.","choice":"approve","id":null,"timestamp":1776603098691}
{"type":"screen-added","file":"/Users/gurpreet/Github/Odoo-Modules/.superpowers/brainstorm/84408-1776602183/content/waiting-1.html"}
{"type":"server-stopped","reason":"idle timeout"}

View File

@@ -0,0 +1 @@
84418

View File

@@ -0,0 +1,355 @@
# Graph Report - /Users/gurpreet/Github/Odoo-Modules/Entech Plating (2026-04-22)
## Corpus Check
- 13 files · ~19,911 words
- Verdict: corpus is large enough that graph structure adds value.
## Summary
- 312 nodes · 494 edges · 45 communities detected
- Extraction: 96% EXTRACTED · 4% INFERRED · 0% AMBIGUOUS · INFERRED: 20 edges (avg confidence: 0.8)
- Token cost: 0 input · 0 output
## Community Hubs (Navigation)
- [[_COMMUNITY_Community 0|Community 0]]
- [[_COMMUNITY_Community 1|Community 1]]
- [[_COMMUNITY_Community 2|Community 2]]
- [[_COMMUNITY_Community 3|Community 3]]
- [[_COMMUNITY_Community 4|Community 4]]
- [[_COMMUNITY_Community 5|Community 5]]
- [[_COMMUNITY_Community 6|Community 6]]
- [[_COMMUNITY_Community 7|Community 7]]
- [[_COMMUNITY_Community 8|Community 8]]
- [[_COMMUNITY_Community 9|Community 9]]
- [[_COMMUNITY_Community 10|Community 10]]
- [[_COMMUNITY_Community 11|Community 11]]
- [[_COMMUNITY_Community 12|Community 12]]
- [[_COMMUNITY_Community 13|Community 13]]
- [[_COMMUNITY_Community 14|Community 14]]
- [[_COMMUNITY_Community 15|Community 15]]
- [[_COMMUNITY_Community 16|Community 16]]
- [[_COMMUNITY_Community 17|Community 17]]
- [[_COMMUNITY_Community 18|Community 18]]
- [[_COMMUNITY_Community 19|Community 19]]
- [[_COMMUNITY_Community 20|Community 20]]
- [[_COMMUNITY_Community 21|Community 21]]
- [[_COMMUNITY_Community 22|Community 22]]
- [[_COMMUNITY_Community 23|Community 23]]
- [[_COMMUNITY_Community 24|Community 24]]
- [[_COMMUNITY_Community 25|Community 25]]
- [[_COMMUNITY_Community 26|Community 26]]
- [[_COMMUNITY_Community 27|Community 27]]
- [[_COMMUNITY_Community 28|Community 28]]
- [[_COMMUNITY_Community 29|Community 29]]
- [[_COMMUNITY_Community 30|Community 30]]
- [[_COMMUNITY_Community 31|Community 31]]
- [[_COMMUNITY_Community 32|Community 32]]
- [[_COMMUNITY_Community 33|Community 33]]
- [[_COMMUNITY_Community 34|Community 34]]
- [[_COMMUNITY_Community 35|Community 35]]
- [[_COMMUNITY_Community 36|Community 36]]
- [[_COMMUNITY_Community 37|Community 37]]
- [[_COMMUNITY_Community 38|Community 38]]
- [[_COMMUNITY_Community 39|Community 39]]
- [[_COMMUNITY_Community 40|Community 40]]
- [[_COMMUNITY_Community 41|Community 41]]
- [[_COMMUNITY_Community 42|Community 42]]
- [[_COMMUNITY_Community 43|Community 43]]
- [[_COMMUNITY_Community 44|Community 44]]
## God Nodes (most connected - your core abstractions)
1. `FusionTechnicianTask` - 65 edges
2. `FusionTaskMapController` - 38 edges
3. `FusionTaskSyncConfig` - 14 edges
4. `create()` - 10 edges
5. `_float_to_time_str()` - 10 edges
6. `FusionEmailBuilderMixin` - 9 edges
7. `create()` - 7 edges
8. `_check_no_overlap()` - 6 edges
9. `_get_tech_start_locations()` - 6 edges
10. `_cron_check_late_arrivals()` - 6 edges
## Surprising Connections (you probably didn't know these)
- `log_location()` --calls--> `create()` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/technician_location.py → /Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/res_partner.py
- `create()` --calls--> `_push_tasks()` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/technician_task.py → /Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/task_sync.py
- `get_map_data()` --calls--> `get_latest_locations()` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/technician_task.py → /Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/technician_location.py
- `register_subscription()` --calls--> `create()` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/push_subscription.py → /Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/res_partner.py
## Communities
### Community 0 - "Community 0"
Cohesion: 0.05
Nodes (28): FusionTechnicianTask, _onchange_is_in_store(), Populate address fields from a partner record., Create or update a linked calendar.event for external calendar sync. On, Hook: post task creation notice to linked order chatter. Override in fus, Hook: mark linked sale orders as ready for delivery. Override in fusion_, Mark task as Completed., Hook: check additional requirements before task completion. Override in (+20 more)
### Community 1 - "Community 1"
Cohesion: 0.07
Nodes (12): classifyDate(), classifyTask(), extractTechnicians(), floatToTime12(), FusionMapArchParser, FusionTaskMapController, groupTasks(), initialsOf() (+4 more)
### Community 2 - "Community 2"
Cohesion: 0.09
Nodes (22): FusionPushSubscription, register_subscription(), create(), ResPartner, _cron_pull_remote_tasks(), FusionTaskSyncConfig, _push_shadow_status(), _push_tasks() (+14 more)
### Community 3 - "Community 3"
Cohesion: 0.09
Nodes (18): _check_no_overlap(), _compute_datetimes(), _compute_prev_task_summary(), _compute_schedule_info(), _compute_time_displays(), default_get(), _float_to_time_str(), _onchange_compute_end_time() (+10 more)
### Community 4 - "Community 4"
Cohesion: 0.11
Nodes (16): _cron_calculate_travel_times(), _cron_send_push_notifications(), _get_clock_in_locations(), _get_tech_start_locations(), Get the start address for a technician. Priority: 1. Technici, Geocode an address string and return (lat, lng) or (0.0, 0.0)., Recalculate travel for a set of (tech_id, date) combinations. Start-poi, Get the technician's most recent GPS location. Priority: 1. L (+8 more)
### Community 5 - "Community 5"
Cohesion: 0.11
Nodes (12): _cron_check_late_arrivals(), Recalculate travel time for THIS task from the tech's current GPS. Call, Check that all earlier tasks for the same technician+date are completed., Write GPS coordinates from context onto the task record., Mark task as En Route., Mark task as In Progress., Cancel the task. Sends cancellation email and runs cancel hooks., Hook: additional side-effects after task cancellation. Override in fusio (+4 more)
### Community 6 - "Community 6"
Cohesion: 0.14
Nodes (9): FusionEmailBuilderMixin, Build a labeled details table section. Args: heading: Secti, Build a left-border accent note block., Build a centered CTA button., Build a dashed-border attachment callout. Args: description, Return an inline status badge/pill HTML snippet., Return company name, phone, email for email templates., Check if email notifications are enabled in settings. (+1 more)
### Community 7 - "Community 7"
Cohesion: 0.12
Nodes (10): FusionTechnicianLocation, get_latest_locations(), log_location(), create(), _fill_address_vals(), get_map_data(), Hook: fill address from linked records during create. Base implementati, Hook: post-create side-effects for linked records. Override in fusion_c (+2 more)
### Community 8 - "Community 8"
Cohesion: 1.0
Nodes (2): _fusion_tasks_post_init(), Post-install hook for fusion_tasks. 1. Sets default ICP values (upsert - sa
### Community 9 - "Community 9"
Cohesion: 1.0
Nodes (1): ResCompany
### Community 10 - "Community 10"
Cohesion: 1.0
Nodes (1): ResUsers
### Community 11 - "Community 11"
Cohesion: 1.0
Nodes (1): ResConfigSettings
### Community 12 - "Community 12"
Cohesion: 1.0
Nodes (0):
### Community 13 - "Community 13"
Cohesion: 1.0
Nodes (0):
### Community 14 - "Community 14"
Cohesion: 1.0
Nodes (1): Log the current user's location. Called from portal JS.
### Community 15 - "Community 15"
Cohesion: 1.0
Nodes (1): Get the most recent location for each technician (for map view). Includ
### Community 16 - "Community 16"
Cohesion: 1.0
Nodes (1): Remove location logs based on configurable retention setting. Setting (
### Community 17 - "Community 17"
Cohesion: 1.0
Nodes (1): Register or update a push subscription.
### Community 18 - "Community 18"
Cohesion: 1.0
Nodes (1): Generate 12-hour time slots every 15 minutes, store hours only (9 AM - 6 PM).
### Community 19 - "Community 19"
Cohesion: 1.0
Nodes (1): Sync the 12h selection fields from the raw float values.
### Community 20 - "Community 20"
Cohesion: 1.0
Nodes (1): Convert float hours to readable time strings.
### Community 21 - "Community 21"
Cohesion: 1.0
Nodes (1): Set default duration based on task type.
### Community 22 - "Community 22"
Cohesion: 1.0
Nodes (1): Auto-compute end time from start + duration. Also run overlap check.
### Community 23 - "Community 23"
Cohesion: 1.0
Nodes (1): Combine date + float time into proper Datetime fields for calendar. time
### Community 24 - "Community 24"
Cohesion: 1.0
Nodes (1): Show booked + available time slots for the technician on the selected date.
### Community 25 - "Community 25"
Cohesion: 1.0
Nodes (1): Show previous task info + travel time warning with color coding.
### Community 26 - "Community 26"
Cohesion: 1.0
Nodes (1): Auto-fill company address when task is marked as in-store.
### Community 27 - "Community 27"
Cohesion: 1.0
Nodes (1): Auto-fill address fields from the selected client's address.
### Community 28 - "Community 28"
Cohesion: 1.0
Nodes (1): Non-in-store tasks must have a geocoded address.
### Community 29 - "Community 29"
Cohesion: 1.0
Nodes (1): Prevent overlapping bookings for the same technician on the same date.
### Community 30 - "Community 30"
Cohesion: 1.0
Nodes (1): Auto-set start/end time to the first available slot when tech+date change.
### Community 31 - "Community 31"
Cohesion: 1.0
Nodes (1): Handle calendar time range selection: pre-fill date + times from context.
### Community 32 - "Community 32"
Cohesion: 1.0
Nodes (1): Helper to fill address vals dict from a partner record.
### Community 33 - "Community 33"
Cohesion: 1.0
Nodes (1): Return task data, technician locations, and Google Maps API key. Args:
### Community 34 - "Community 34"
Cohesion: 1.0
Nodes (1): Build a dict of technician start locations for route origins. Priority
### Community 35 - "Community 35"
Cohesion: 1.0
Nodes (1): Get today's clock-in lat/lng from fusion_clock if installed. Uses the t
### Community 36 - "Community 36"
Cohesion: 1.0
Nodes (1): Cron job: Calculate travel times for today and tomorrow. Runs every 15
### Community 37 - "Community 37"
Cohesion: 1.0
Nodes (1): Cron: detect tasks where the technician hasn't started and the scheduled
### Community 38 - "Community 38"
Cohesion: 1.0
Nodes (1): Cron: Send push notifications for upcoming tasks.
### Community 39 - "Community 39"
Cohesion: 1.0
Nodes (1): Convert float hours to time string like '9:30 AM'.
### Community 40 - "Community 40"
Cohesion: 1.0
Nodes (1): Push local task changes to all active remote instances. Called from tech
### Community 41 - "Community 41"
Cohesion: 1.0
Nodes (1): Push local status changes on shadow tasks back to their source instance.
### Community 42 - "Community 42"
Cohesion: 1.0
Nodes (1): Push a technician's location update to all remote instances. Called whe
### Community 43 - "Community 43"
Cohesion: 1.0
Nodes (1): Cron job: pull tasks and technician locations from all active remote instances.
### Community 44 - "Community 44"
Cohesion: 1.0
Nodes (1): Remove shadow tasks older than 30 days (completed/cancelled).
## Knowledge Gaps
- **119 isolated node(s):** `Post-install hook for fusion_tasks. 1. Sets default ICP values (upsert - sa`, `FusionTechnicianLocation`, `Log the current user's location. Called from portal JS.`, `Get the most recent location for each technician (for map view). Includ`, `Remove location logs based on configurable retention setting. Setting (` (+114 more)
These have ≤1 connection - possible missing edges or undocumented components.
- **Thin community `Community 9`** (2 nodes): `ResCompany`, `res_company.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 10`** (2 nodes): `ResUsers`, `res_users.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 11`** (2 nodes): `ResConfigSettings`, `res_config_settings.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 12`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 13`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 14`** (1 nodes): `Log the current user's location. Called from portal JS.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 15`** (1 nodes): `Get the most recent location for each technician (for map view). Includ`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 16`** (1 nodes): `Remove location logs based on configurable retention setting. Setting (`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 17`** (1 nodes): `Register or update a push subscription.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 18`** (1 nodes): `Generate 12-hour time slots every 15 minutes, store hours only (9 AM - 6 PM).`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 19`** (1 nodes): `Sync the 12h selection fields from the raw float values.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 20`** (1 nodes): `Convert float hours to readable time strings.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 21`** (1 nodes): `Set default duration based on task type.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 22`** (1 nodes): `Auto-compute end time from start + duration. Also run overlap check.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 23`** (1 nodes): `Combine date + float time into proper Datetime fields for calendar. time`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 24`** (1 nodes): `Show booked + available time slots for the technician on the selected date.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 25`** (1 nodes): `Show previous task info + travel time warning with color coding.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 26`** (1 nodes): `Auto-fill company address when task is marked as in-store.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 27`** (1 nodes): `Auto-fill address fields from the selected client's address.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 28`** (1 nodes): `Non-in-store tasks must have a geocoded address.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 29`** (1 nodes): `Prevent overlapping bookings for the same technician on the same date.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 30`** (1 nodes): `Auto-set start/end time to the first available slot when tech+date change.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 31`** (1 nodes): `Handle calendar time range selection: pre-fill date + times from context.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 32`** (1 nodes): `Helper to fill address vals dict from a partner record.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 33`** (1 nodes): `Return task data, technician locations, and Google Maps API key. Args:`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 34`** (1 nodes): `Build a dict of technician start locations for route origins. Priority`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 35`** (1 nodes): `Get today's clock-in lat/lng from fusion_clock if installed. Uses the t`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 36`** (1 nodes): `Cron job: Calculate travel times for today and tomorrow. Runs every 15`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 37`** (1 nodes): `Cron: detect tasks where the technician hasn't started and the scheduled`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 38`** (1 nodes): `Cron: Send push notifications for upcoming tasks.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 39`** (1 nodes): `Convert float hours to time string like '9:30 AM'.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 40`** (1 nodes): `Push local task changes to all active remote instances. Called from tech`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 41`** (1 nodes): `Push local status changes on shadow tasks back to their source instance.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 42`** (1 nodes): `Push a technician's location update to all remote instances. Called whe`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 43`** (1 nodes): `Cron job: pull tasks and technician locations from all active remote instances.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 44`** (1 nodes): `Remove shadow tasks older than 30 days (completed/cancelled).`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
## Suggested Questions
_Questions this graph is uniquely positioned to answer:_
- **Why does `FusionTechnicianTask` connect `Community 0` to `Community 3`, `Community 4`, `Community 5`, `Community 7`?**
_High betweenness centrality (0.331) - this node is a cross-community bridge._
- **Why does `_push_shadow_status()` connect `Community 2` to `Community 5`?**
_High betweenness centrality (0.031) - this node is a cross-community bridge._
- **Why does `_push_tasks()` connect `Community 2` to `Community 5`, `Community 7`?**
_High betweenness centrality (0.027) - this node is a cross-community bridge._
- **What connects `Post-install hook for fusion_tasks. 1. Sets default ICP values (upsert - sa`, `FusionTechnicianLocation`, `Log the current user's location. Called from portal JS.` to the rest of the system?**
_119 weakly-connected nodes found - possible documentation gaps or missing edges._
- **Should `Community 0` be split into smaller, more focused modules?**
_Cohesion score 0.05 - nodes in this community are weakly interconnected._
- **Should `Community 1` be split into smaller, more focused modules?**
_Cohesion score 0.07 - nodes in this community are weakly interconnected._
- **Should `Community 2` be split into smaller, more focused modules?**
_Cohesion score 0.09 - nodes in this community are weakly interconnected._

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_manifest_py", "label": "__manifest__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/__manifest__.py", "source_location": "L1"}], "edges": [], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "target": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/__init__.py", "source_location": "L5", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "target": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/__init__.py", "source_location": "L6", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "target": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/__init__.py", "source_location": "L7", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "target": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/__init__.py", "source_location": "L8", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "target": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/__init__.py", "source_location": "L9", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "target": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/__init__.py", "source_location": "L10", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "target": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/__init__.py", "source_location": "L11", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "target": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/__init__.py", "source_location": "L12", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "target": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/__init__.py", "source_location": "L13", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_res_company_py", "label": "res_company.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/res_company.py", "source_location": "L1"}, {"id": "res_company_rescompany", "label": "ResCompany", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/res_company.py", "source_location": "L8"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_res_company_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/res_company.py", "source_location": "L5", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_res_company_py", "target": "res_company_rescompany", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/res_company.py", "source_location": "L8", "weight": 1.0}], "raw_calls": []}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_res_config_settings_py", "label": "res_config_settings.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/res_config_settings.py", "source_location": "L1"}, {"id": "res_config_settings_resconfigsettings", "label": "ResConfigSettings", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/res_config_settings.py", "source_location": "L8"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_res_config_settings_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/res_config_settings.py", "source_location": "L5", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_res_config_settings_py", "target": "res_config_settings_resconfigsettings", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/res_config_settings.py", "source_location": "L8", "weight": 1.0}], "raw_calls": []}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_res_users_py", "label": "res_users.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/res_users.py", "source_location": "L1"}, {"id": "res_users_resusers", "label": "ResUsers", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/res_users.py", "source_location": "L8"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_res_users_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/res_users.py", "source_location": "L5", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_res_users_py", "target": "res_users_resusers", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/res_users.py", "source_location": "L8", "weight": 1.0}], "raw_calls": []}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/__init__.py", "source_location": "L1"}, {"id": "init_fusion_tasks_post_init", "label": "_fusion_tasks_post_init()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/__init__.py", "source_location": "L8"}, {"id": "init_rationale_9", "label": "Post-install hook for fusion_tasks. 1. Sets default ICP values (upsert - sa", "file_type": "rationale", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/__init__.py", "source_location": "L9"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_init_py", "target": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/__init__.py", "source_location": "L5", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_init_py", "target": "init_fusion_tasks_post_init", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/__init__.py", "source_location": "L8", "weight": 1.0}, {"source": "init_rationale_9", "target": "init_fusion_tasks_post_init", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/__init__.py", "source_location": "L9", "weight": 1.0}], "raw_calls": [{"caller_nid": "init_fusion_tasks_post_init", "callee": "sudo", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/__init__.py", "source_location": "L15"}, {"caller_nid": "init_fusion_tasks_post_init", "callee": "items", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/__init__.py", "source_location": "L25"}, {"caller_nid": "init_fusion_tasks_post_init", "callee": "get_param", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/__init__.py", "source_location": "L26"}, {"caller_nid": "init_fusion_tasks_post_init", "callee": "set_param", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/__init__.py", "source_location": "L27"}, {"caller_nid": "init_fusion_tasks_post_init", "callee": "ref", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/__init__.py", "source_location": "L30"}, {"caller_nid": "init_fusion_tasks_post_init", "callee": "search", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/__init__.py", "source_location": "L32"}, {"caller_nid": "init_fusion_tasks_post_init", "callee": "write", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/__init__.py", "source_location": "L36"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_push_subscription_py", "label": "push_subscription.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/push_subscription.py", "source_location": "L1"}, {"id": "push_subscription_fusionpushsubscription", "label": "FusionPushSubscription", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/push_subscription.py", "source_location": "L15"}, {"id": "push_subscription_register_subscription", "label": "register_subscription()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/push_subscription.py", "source_location": "L55"}, {"id": "push_subscription_rationale_56", "label": "Register or update a push subscription.", "file_type": "rationale", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/push_subscription.py", "source_location": "L56"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_push_subscription_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/push_subscription.py", "source_location": "L9", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_push_subscription_py", "target": "logging", "relation": "imports", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/push_subscription.py", "source_location": "L10", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_push_subscription_py", "target": "push_subscription_fusionpushsubscription", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/push_subscription.py", "source_location": "L15", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_entech_plating_fusion_tasks_models_push_subscription_py", "target": "push_subscription_register_subscription", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/push_subscription.py", "source_location": "L55", "weight": 1.0}, {"source": "push_subscription_rationale_56", "target": "push_subscription_fusionpushsubscription_register_subscription", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/push_subscription.py", "source_location": "L56", "weight": 1.0}], "raw_calls": [{"caller_nid": "push_subscription_register_subscription", "callee": "search", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/push_subscription.py", "source_location": "L57"}, {"caller_nid": "push_subscription_register_subscription", "callee": "sudo", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/push_subscription.py", "source_location": "L57"}, {"caller_nid": "push_subscription_register_subscription", "callee": "write", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/push_subscription.py", "source_location": "L59"}, {"caller_nid": "push_subscription_register_subscription", "callee": "create", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/push_subscription.py", "source_location": "L67"}, {"caller_nid": "push_subscription_register_subscription", "callee": "sudo", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Entech Plating/fusion_tasks/models/push_subscription.py", "source_location": "L67"}]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,829 @@
# Graph Report - /Users/gurpreet/Github/Odoo-Modules/Obsolete Files (2026-04-22)
## Corpus Check
- 173 files · ~1,651,049 words
- Verdict: corpus is large enough that graph structure adds value.
## Summary
- 682 nodes · 1218 edges · 121 communities detected
- Extraction: 93% EXTRACTED · 7% INFERRED · 0% AMBIGUOUS · INFERRED: 83 edges (avg confidence: 0.79)
- Token cost: 0 input · 0 output
## Community Hubs (Navigation)
- [[_COMMUNITY_Community 0|Community 0]]
- [[_COMMUNITY_Community 1|Community 1]]
- [[_COMMUNITY_Community 2|Community 2]]
- [[_COMMUNITY_Community 3|Community 3]]
- [[_COMMUNITY_Community 4|Community 4]]
- [[_COMMUNITY_Community 5|Community 5]]
- [[_COMMUNITY_Community 6|Community 6]]
- [[_COMMUNITY_Community 7|Community 7]]
- [[_COMMUNITY_Community 8|Community 8]]
- [[_COMMUNITY_Community 9|Community 9]]
- [[_COMMUNITY_Community 10|Community 10]]
- [[_COMMUNITY_Community 11|Community 11]]
- [[_COMMUNITY_Community 12|Community 12]]
- [[_COMMUNITY_Community 13|Community 13]]
- [[_COMMUNITY_Community 14|Community 14]]
- [[_COMMUNITY_Community 15|Community 15]]
- [[_COMMUNITY_Community 16|Community 16]]
- [[_COMMUNITY_Community 17|Community 17]]
- [[_COMMUNITY_Community 18|Community 18]]
- [[_COMMUNITY_Community 19|Community 19]]
- [[_COMMUNITY_Community 20|Community 20]]
- [[_COMMUNITY_Community 21|Community 21]]
- [[_COMMUNITY_Community 22|Community 22]]
- [[_COMMUNITY_Community 23|Community 23]]
- [[_COMMUNITY_Community 24|Community 24]]
- [[_COMMUNITY_Community 25|Community 25]]
- [[_COMMUNITY_Community 26|Community 26]]
- [[_COMMUNITY_Community 27|Community 27]]
- [[_COMMUNITY_Community 28|Community 28]]
- [[_COMMUNITY_Community 29|Community 29]]
- [[_COMMUNITY_Community 30|Community 30]]
- [[_COMMUNITY_Community 31|Community 31]]
- [[_COMMUNITY_Community 32|Community 32]]
- [[_COMMUNITY_Community 33|Community 33]]
- [[_COMMUNITY_Community 34|Community 34]]
- [[_COMMUNITY_Community 35|Community 35]]
- [[_COMMUNITY_Community 36|Community 36]]
- [[_COMMUNITY_Community 37|Community 37]]
- [[_COMMUNITY_Community 38|Community 38]]
- [[_COMMUNITY_Community 39|Community 39]]
- [[_COMMUNITY_Community 40|Community 40]]
- [[_COMMUNITY_Community 41|Community 41]]
- [[_COMMUNITY_Community 42|Community 42]]
- [[_COMMUNITY_Community 43|Community 43]]
- [[_COMMUNITY_Community 44|Community 44]]
- [[_COMMUNITY_Community 45|Community 45]]
- [[_COMMUNITY_Community 46|Community 46]]
- [[_COMMUNITY_Community 47|Community 47]]
- [[_COMMUNITY_Community 48|Community 48]]
- [[_COMMUNITY_Community 49|Community 49]]
- [[_COMMUNITY_Community 50|Community 50]]
- [[_COMMUNITY_Community 51|Community 51]]
- [[_COMMUNITY_Community 52|Community 52]]
- [[_COMMUNITY_Community 53|Community 53]]
- [[_COMMUNITY_Community 54|Community 54]]
- [[_COMMUNITY_Community 55|Community 55]]
- [[_COMMUNITY_Community 56|Community 56]]
- [[_COMMUNITY_Community 57|Community 57]]
- [[_COMMUNITY_Community 58|Community 58]]
- [[_COMMUNITY_Community 59|Community 59]]
- [[_COMMUNITY_Community 60|Community 60]]
- [[_COMMUNITY_Community 61|Community 61]]
- [[_COMMUNITY_Community 62|Community 62]]
- [[_COMMUNITY_Community 63|Community 63]]
- [[_COMMUNITY_Community 64|Community 64]]
- [[_COMMUNITY_Community 65|Community 65]]
- [[_COMMUNITY_Community 66|Community 66]]
- [[_COMMUNITY_Community 67|Community 67]]
- [[_COMMUNITY_Community 68|Community 68]]
- [[_COMMUNITY_Community 69|Community 69]]
- [[_COMMUNITY_Community 70|Community 70]]
- [[_COMMUNITY_Community 71|Community 71]]
- [[_COMMUNITY_Community 72|Community 72]]
- [[_COMMUNITY_Community 73|Community 73]]
- [[_COMMUNITY_Community 74|Community 74]]
- [[_COMMUNITY_Community 75|Community 75]]
- [[_COMMUNITY_Community 76|Community 76]]
- [[_COMMUNITY_Community 77|Community 77]]
- [[_COMMUNITY_Community 78|Community 78]]
- [[_COMMUNITY_Community 79|Community 79]]
- [[_COMMUNITY_Community 80|Community 80]]
- [[_COMMUNITY_Community 81|Community 81]]
- [[_COMMUNITY_Community 82|Community 82]]
- [[_COMMUNITY_Community 83|Community 83]]
- [[_COMMUNITY_Community 84|Community 84]]
- [[_COMMUNITY_Community 85|Community 85]]
- [[_COMMUNITY_Community 86|Community 86]]
- [[_COMMUNITY_Community 87|Community 87]]
- [[_COMMUNITY_Community 88|Community 88]]
- [[_COMMUNITY_Community 89|Community 89]]
- [[_COMMUNITY_Community 90|Community 90]]
- [[_COMMUNITY_Community 91|Community 91]]
- [[_COMMUNITY_Community 92|Community 92]]
- [[_COMMUNITY_Community 93|Community 93]]
- [[_COMMUNITY_Community 94|Community 94]]
- [[_COMMUNITY_Community 95|Community 95]]
- [[_COMMUNITY_Community 96|Community 96]]
- [[_COMMUNITY_Community 97|Community 97]]
- [[_COMMUNITY_Community 98|Community 98]]
- [[_COMMUNITY_Community 99|Community 99]]
- [[_COMMUNITY_Community 100|Community 100]]
- [[_COMMUNITY_Community 101|Community 101]]
- [[_COMMUNITY_Community 102|Community 102]]
- [[_COMMUNITY_Community 103|Community 103]]
- [[_COMMUNITY_Community 104|Community 104]]
- [[_COMMUNITY_Community 105|Community 105]]
- [[_COMMUNITY_Community 106|Community 106]]
- [[_COMMUNITY_Community 107|Community 107]]
- [[_COMMUNITY_Community 108|Community 108]]
- [[_COMMUNITY_Community 109|Community 109]]
- [[_COMMUNITY_Community 110|Community 110]]
- [[_COMMUNITY_Community 111|Community 111]]
- [[_COMMUNITY_Community 112|Community 112]]
- [[_COMMUNITY_Community 113|Community 113]]
- [[_COMMUNITY_Community 114|Community 114]]
- [[_COMMUNITY_Community 115|Community 115]]
- [[_COMMUNITY_Community 116|Community 116]]
- [[_COMMUNITY_Community 117|Community 117]]
- [[_COMMUNITY_Community 118|Community 118]]
- [[_COMMUNITY_Community 119|Community 119]]
- [[_COMMUNITY_Community 120|Community 120]]
## God Nodes (most connected - your core abstractions)
1. `_classCallCheck()` - 37 edges
2. `ResConfigSettings` - 27 edges
3. `get()` - 21 edges
4. `PrintProductLabel` - 20 edges
5. `PrintProductLabelSection` - 16 edges
6. `add()` - 14 edges
7. `getCharacterType()` - 12 edges
8. `get_quick_report_action()` - 10 edges
9. `ResUsers` - 10 edges
10. `PrintProductLabelTemplate` - 10 edges
## Surprising Connections (you probably didn't know these)
- `Test internal user's access rights` --uses--> `TestProductLabel` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/test_access_rights.py → /Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py
- `default_get()` --calls--> `_get_user_allowed_templates()` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/product_label_layout.py → /Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/models/print_product_label_template.py
- `_compute_garazd_allowed_template_ids()` --calls--> `_get_user_allowed_templates()` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/product_label_layout.py → /Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/models/print_product_label_template.py
- `_compute_allowed_template_ids()` --calls--> `set()` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/print_product_label.py → /Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/static/lib/pdfjs/web/viewer.js
- `_get_color_info_from_url()` --calls--> `compile()` [INFERRED]
/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_colors/models/color_assets_editor.py → /Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/static/src/views/form/form_compiler.js
## Communities
### Community 0 - "Community 0"
Cohesion: 0.04
Nodes (102): active(), apiPageModeToSidebarView(), appendTextToDiv(), approximateFraction(), asyncGeneratorStep(), AsyncIterator(), _asyncToGenerator(), backtrackBeforeAllVisibleElements() (+94 more)
### Community 1 - "Community 1"
Cohesion: 0.04
Nodes (34): Http, get_report_name(), print_label_pdf(), PrintPDF, PrintPreviewController, _complete_label_fields(), _compute_allowed_template_ids(), _compute_is_template_report() (+26 more)
### Community 2 - "Community 2"
Cohesion: 0.07
Nodes (9): ColorAssetsEditor, _get_color_info_from_url(), _get_colors_asset(), _get_colors_attachment(), _get_colors_from_url(), _get_custom_colors_url(), _save_color_asset(), _uninstall_cleanup() (+1 more)
### Community 3 - "Community 3"
Cohesion: 0.1
Nodes (26): binary_field_types(), _check_height(), _check_widget_image(), _compute_display_name(), _compute_field_ids(), _compute_nested_relation_model_id(), _compute_relation_model_id(), _compute_template_preview_html() (+18 more)
### Community 4 - "Community 4"
Cohesion: 0.1
Nodes (29): active(), add(), c(), cboxOnClick(), cleanup(), clear(), enable(), getStatIndex() (+21 more)
### Community 5 - "Community 5"
Cohesion: 0.07
Nodes (15): _setup_module(), MatchSaleOrderWizard, Link the selected Sale Order to the Purchase Order, Set a specific number of labels for all lines., Reset the skip empty places count value., If the Dymo label width or height were changed, we should change it to t, PurchaseOrder, Batch match multiple POs to Sale Orders based on x_marked_for field. Cal (+7 more)
### Community 6 - "Community 6"
Cohesion: 0.08
Nodes (29): AnnotationLayerBuilder(), AppOptions(), _classCallCheck(), Context(), DefaultAnnotationLayerFactory(), DefaultTextLayerFactory(), DownloadManager(), EventBus() (+21 more)
### Community 7 - "Community 7"
Cohesion: 0.14
Nodes (8): BaseUsersCommon, setUpClass(), TestProductLabel, Test internal user's access rights, TestAccessRights, TestPrintProductLabel, TestProductLabel, TransactionCase
### Community 8 - "Community 8"
Cohesion: 0.21
Nodes (3): ResUsers, SELF_READABLE_FIELDS(), SELF_WRITEABLE_FIELDS()
### Community 9 - "Community 9"
Cohesion: 0.16
Nodes (14): _assertThisInitialized(), BasePreferences(), GenericPreferences(), getDefaultPreferences(), _getPrototypeOf(), isValidExplicitDestination(), PDFSinglePageViewer(), PDFViewer() (+6 more)
### Community 10 - "Community 10"
Cohesion: 0.27
Nodes (7): default_get(), _onchange_batch_vendor_id(), _onchange_vendor_id(), PurchaseOrderWizard, PurchaseProductWiz, Returns the values to create the purchase order line., Generate purchase orders grouped by vendor
### Community 11 - "Community 11"
Cohesion: 0.18
Nodes (11): getCharacterType(), isAlphabeticalScript(), isAscii(), isAsciiAlpha(), isAsciiDigit(), isAsciiSpace(), isHalfwidthKatakana(), isHan() (+3 more)
### Community 12 - "Community 12"
Cohesion: 0.18
Nodes (6): CollapseAll, ExpandAll, scrollModeChanged(), spreadModeChanged(), webViewerInitialized(), webViewerNamedAction()
### Community 13 - "Community 13"
Cohesion: 0.27
Nodes (4): _compute_barcode(), _compute_company_id(), _compute_product_price(), PrintProductLabelLine
### Community 14 - "Community 14"
Cohesion: 0.27
Nodes (7): _compute_garazd_allowed_template_ids(), default_get(), ProductLabelLayout, set(), webViewerScrollModeChanged(), webViewerSidebarViewChanged(), webViewerSpreadModeChanged()
### Community 15 - "Community 15"
Cohesion: 0.36
Nodes (5): getAutoLoadStorageKey(), getAutoLoadStorageValue(), removeAutoLoadStorageValue(), setAutoLoadStorageValue(), toggleAutoLoad()
### Community 16 - "Community 16"
Cohesion: 0.22
Nodes (9): abort(), clear(), dispatchEvent(), fireL10nReadyEvent(), getL10nDictionary(), getL10nResourceLinks(), getViewerConfiguration(), loadLocale() (+1 more)
### Community 17 - "Community 17"
Cohesion: 0.5
Nodes (2): _check_page_layout(), PrintProductLabelTemplateAdd
### Community 18 - "Community 18"
Cohesion: 0.25
Nodes (8): close(), open(), parseResource(), PDFFindBar(), webViewerClick(), webViewerDocumentProperties(), webViewerKeyDown(), xhrLoadText()
### Community 19 - "Community 19"
Cohesion: 0.25
Nodes (8): getChildElementCount(), getL10nAttributes(), getL10nData(), getTranslatableChildren(), substArguments(), substIndexes(), translateElement(), translateFragment()
### Community 20 - "Community 20"
Cohesion: 0.29
Nodes (2): ProductProduct, If a user has direct print option and a label template, return the direct print
### Community 21 - "Community 21"
Cohesion: 0.29
Nodes (1): IrHttp
### Community 22 - "Community 22"
Cohesion: 0.4
Nodes (1): ResCompany
### Community 23 - "Community 23"
Cohesion: 0.4
Nodes (5): _arrayWithHoles(), getPageSizeInches(), _iterableToArrayLimit(), _nonIterableRest(), _slicedToArray()
### Community 24 - "Community 24"
Cohesion: 0.5
Nodes (5): doneResult(), makeInvokeMethod(), maybeInvokeDelegate(), tryCatch(), wrap()
### Community 25 - "Community 25"
Cohesion: 0.4
Nodes (5): ensureOverlay(), getLanguage(), PasswordPrompt(), PDFDocumentProperties(), register()
### Community 26 - "Community 26"
Cohesion: 0.5
Nodes (1): AppsMenu
### Community 27 - "Community 27"
Cohesion: 0.5
Nodes (0):
### Community 28 - "Community 28"
Cohesion: 0.5
Nodes (1): AppsBar
### Community 29 - "Community 29"
Cohesion: 0.5
Nodes (1): Http
### Community 30 - "Community 30"
Cohesion: 0.67
Nodes (1): PrintLabelTypePy
### Community 31 - "Community 31"
Cohesion: 0.67
Nodes (1): PrintProductLabelPreview
### Community 32 - "Community 32"
Cohesion: 0.67
Nodes (0):
### Community 33 - "Community 33"
Cohesion: 0.67
Nodes (0):
### Community 34 - "Community 34"
Cohesion: 0.67
Nodes (2): Category, Product
### Community 35 - "Community 35"
Cohesion: 0.67
Nodes (0):
### Community 36 - "Community 36"
Cohesion: 0.67
Nodes (3): setZoomDisabledTimeout(), webViewerVisibilityChange(), webViewerWheel()
### Community 37 - "Community 37"
Cohesion: 0.67
Nodes (3): isValidScrollMode(), isValidSpreadMode(), values()
### Community 38 - "Community 38"
Cohesion: 0.67
Nodes (1): reportPreviewConfigItem()
### Community 39 - "Community 39"
Cohesion: 1.0
Nodes (0):
### Community 40 - "Community 40"
Cohesion: 1.0
Nodes (1): Product
### Community 41 - "Community 41"
Cohesion: 1.0
Nodes (0):
### Community 42 - "Community 42"
Cohesion: 1.0
Nodes (0):
### Community 43 - "Community 43"
Cohesion: 1.0
Nodes (1): ResUsersSettings
### Community 44 - "Community 44"
Cohesion: 1.0
Nodes (0):
### Community 45 - "Community 45"
Cohesion: 1.0
Nodes (0):
### Community 46 - "Community 46"
Cohesion: 1.0
Nodes (0):
### Community 47 - "Community 47"
Cohesion: 1.0
Nodes (0):
### Community 48 - "Community 48"
Cohesion: 1.0
Nodes (0):
### Community 49 - "Community 49"
Cohesion: 1.0
Nodes (0):
### Community 50 - "Community 50"
Cohesion: 1.0
Nodes (0):
### Community 51 - "Community 51"
Cohesion: 1.0
Nodes (0):
### Community 52 - "Community 52"
Cohesion: 1.0
Nodes (0):
### Community 53 - "Community 53"
Cohesion: 1.0
Nodes (0):
### Community 54 - "Community 54"
Cohesion: 1.0
Nodes (0):
### Community 55 - "Community 55"
Cohesion: 1.0
Nodes (0):
### Community 56 - "Community 56"
Cohesion: 1.0
Nodes (0):
### Community 57 - "Community 57"
Cohesion: 1.0
Nodes (0):
### Community 58 - "Community 58"
Cohesion: 1.0
Nodes (0):
### Community 59 - "Community 59"
Cohesion: 1.0
Nodes (0):
### Community 60 - "Community 60"
Cohesion: 1.0
Nodes (0):
### Community 61 - "Community 61"
Cohesion: 1.0
Nodes (0):
### Community 62 - "Community 62"
Cohesion: 1.0
Nodes (0):
### Community 63 - "Community 63"
Cohesion: 1.0
Nodes (0):
### Community 64 - "Community 64"
Cohesion: 1.0
Nodes (0):
### Community 65 - "Community 65"
Cohesion: 1.0
Nodes (0):
### Community 66 - "Community 66"
Cohesion: 1.0
Nodes (0):
### Community 67 - "Community 67"
Cohesion: 1.0
Nodes (0):
### Community 68 - "Community 68"
Cohesion: 1.0
Nodes (0):
### Community 69 - "Community 69"
Cohesion: 1.0
Nodes (0):
### Community 70 - "Community 70"
Cohesion: 1.0
Nodes (0):
### Community 71 - "Community 71"
Cohesion: 1.0
Nodes (0):
### Community 72 - "Community 72"
Cohesion: 1.0
Nodes (0):
### Community 73 - "Community 73"
Cohesion: 1.0
Nodes (0):
### Community 74 - "Community 74"
Cohesion: 1.0
Nodes (0):
### Community 75 - "Community 75"
Cohesion: 1.0
Nodes (0):
### Community 76 - "Community 76"
Cohesion: 1.0
Nodes (0):
### Community 77 - "Community 77"
Cohesion: 1.0
Nodes (0):
### Community 78 - "Community 78"
Cohesion: 1.0
Nodes (0):
### Community 79 - "Community 79"
Cohesion: 1.0
Nodes (0):
### Community 80 - "Community 80"
Cohesion: 1.0
Nodes (0):
### Community 81 - "Community 81"
Cohesion: 1.0
Nodes (0):
### Community 82 - "Community 82"
Cohesion: 1.0
Nodes (0):
### Community 83 - "Community 83"
Cohesion: 1.0
Nodes (0):
### Community 84 - "Community 84"
Cohesion: 1.0
Nodes (0):
### Community 85 - "Community 85"
Cohesion: 1.0
Nodes (0):
### Community 86 - "Community 86"
Cohesion: 1.0
Nodes (0):
### Community 87 - "Community 87"
Cohesion: 1.0
Nodes (0):
### Community 88 - "Community 88"
Cohesion: 1.0
Nodes (0):
### Community 89 - "Community 89"
Cohesion: 1.0
Nodes (0):
### Community 90 - "Community 90"
Cohesion: 1.0
Nodes (0):
### Community 91 - "Community 91"
Cohesion: 1.0
Nodes (0):
### Community 92 - "Community 92"
Cohesion: 1.0
Nodes (0):
### Community 93 - "Community 93"
Cohesion: 1.0
Nodes (1): Set additional fields for product labels. Method to override.
### Community 94 - "Community 94"
Cohesion: 1.0
Nodes (1): Allow to get a report action for custom labels. Method to override.
### Community 95 - "Community 95"
Cohesion: 1.0
Nodes (0):
### Community 96 - "Community 96"
Cohesion: 1.0
Nodes (0):
### Community 97 - "Community 97"
Cohesion: 1.0
Nodes (1): Overwritten completely to use with custom label templates.
### Community 98 - "Community 98"
Cohesion: 1.0
Nodes (1): Post-processing of the price value before converting to the string. Meth
### Community 99 - "Community 99"
Cohesion: 1.0
Nodes (1): Collect all pricelist rules that affect the current product.
### Community 100 - "Community 100"
Cohesion: 1.0
Nodes (1): System administrators are not restricted anyway. Other users are restric
### Community 101 - "Community 101"
Cohesion: 1.0
Nodes (0):
### Community 102 - "Community 102"
Cohesion: 1.0
Nodes (0):
### Community 103 - "Community 103"
Cohesion: 1.0
Nodes (0):
### Community 104 - "Community 104"
Cohesion: 1.0
Nodes (0):
### Community 105 - "Community 105"
Cohesion: 1.0
Nodes (0):
### Community 106 - "Community 106"
Cohesion: 1.0
Nodes (0):
### Community 107 - "Community 107"
Cohesion: 1.0
Nodes (0):
### Community 108 - "Community 108"
Cohesion: 1.0
Nodes (0):
### Community 109 - "Community 109"
Cohesion: 1.0
Nodes (0):
### Community 110 - "Community 110"
Cohesion: 1.0
Nodes (0):
### Community 111 - "Community 111"
Cohesion: 1.0
Nodes (0):
### Community 112 - "Community 112"
Cohesion: 1.0
Nodes (0):
### Community 113 - "Community 113"
Cohesion: 1.0
Nodes (0):
### Community 114 - "Community 114"
Cohesion: 1.0
Nodes (1): When user selects a batch vendor, apply it to selected lines only
### Community 115 - "Community 115"
Cohesion: 1.0
Nodes (1): Load SO lines into wizard
### Community 116 - "Community 116"
Cohesion: 1.0
Nodes (1): Update price based on vendor's price list if available
### Community 117 - "Community 117"
Cohesion: 1.0
Nodes (0):
### Community 118 - "Community 118"
Cohesion: 1.0
Nodes (0):
### Community 119 - "Community 119"
Cohesion: 1.0
Nodes (0):
### Community 120 - "Community 120"
Cohesion: 1.0
Nodes (0):
## Knowledge Gaps
- **33 isolated node(s):** `Set additional fields for product labels. Method to override.`, `Return two params for a report action: record "ids" and "data".`, `Set a specific number of labels for all lines.`, `Restore the initial number of labels for all lines.`, `Allow to get a report action for custom labels. Method to override.` (+28 more)
These have ≤1 connection - possible missing edges or undocumented components.
- **Thin community `Community 39`** (2 nodes): `setup()`, `navbar.js`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 40`** (2 nodes): `Product`, `refresh.test.js`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 41`** (2 nodes): `onClickDialogSizeToggle()`, `select_create_dialog.js`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 42`** (2 nodes): `displayMessages()`, `thread.js`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 43`** (2 nodes): `ResUsersSettings`, `res_users_settings.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 44`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 45`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 46`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 47`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 48`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 49`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 50`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 51`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 52`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 53`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 54`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 55`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 56`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 57`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 58`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 59`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 60`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 61`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 62`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 63`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 64`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 65`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 66`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 67`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 68`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 69`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 70`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 71`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 72`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 73`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 74`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 75`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 76`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 77`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 78`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 79`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 80`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 81`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 82`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 83`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 84`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 85`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 86`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 87`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 88`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 89`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 90`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 91`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 92`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 93`** (1 nodes): `Set additional fields for product labels. Method to override.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 94`** (1 nodes): `Allow to get a report action for custom labels. Method to override.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 95`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 96`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 97`** (1 nodes): `Overwritten completely to use with custom label templates.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 98`** (1 nodes): `Post-processing of the price value before converting to the string. Meth`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 99`** (1 nodes): `Collect all pricelist rules that affect the current product.`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 100`** (1 nodes): `System administrators are not restricted anyway. Other users are restric`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 101`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 102`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 103`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 104`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 105`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 106`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 107`** (1 nodes): `webclient.js`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 108`** (1 nodes): `app_menu_service.js`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 109`** (1 nodes): `__init__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 110`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 111`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 112`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 113`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 114`** (1 nodes): `When user selects a batch vendor, apply it to selected lines only`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 115`** (1 nodes): `Load SO lines into wizard`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 116`** (1 nodes): `Update price based on vendor's price list if available`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 117`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 118`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 119`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 120`** (1 nodes): `__manifest__.py`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
## Suggested Questions
_Questions this graph is uniquely positioned to answer:_
- **Why does `get()` connect `Community 1` to `Community 0`, `Community 3`, `Community 4`, `Community 5`, `Community 9`, `Community 10`, `Community 12`?**
_High betweenness centrality (0.293) - this node is a cross-community bridge._
- **Why does `add()` connect `Community 4` to `Community 12`, `Community 6`?**
_High betweenness centrality (0.053) - this node is a cross-community bridge._
- **Why does `_save_color_asset()` connect `Community 2` to `Community 5`?**
_High betweenness centrality (0.045) - this node is a cross-community bridge._
- **Are the 13 inferred relationships involving `get()` (e.g. with `_get_product_label_ids()` and `default_get()`) actually correct?**
_`get()` has 13 INFERRED edges - model-reasoned connections that need verification._
- **What connects `Set additional fields for product labels. Method to override.`, `Return two params for a report action: record "ids" and "data".`, `Set a specific number of labels for all lines.` to the rest of the system?**
_33 weakly-connected nodes found - possible documentation gaps or missing edges._
- **Should `Community 0` be split into smaller, more focused modules?**
_Cohesion score 0.04 - nodes in this community are weakly interconnected._
- **Should `Community 1` be split into smaller, more focused modules?**
_Cohesion score 0.04 - nodes in this community are weakly interconnected._

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_res_company_py", "label": "res_company.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_company.py", "source_location": "L1"}, {"id": "res_company_rescompany", "label": "ResCompany", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_company.py", "source_location": "L4"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_res_company_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_company.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_res_company_py", "target": "res_company_rescompany", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_company.py", "source_location": "L4", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_refresh_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_refresh_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_refresh_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/__init__.py", "source_location": "L1", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_static_src_js_user_menu_js", "label": "user_menu.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L1"}, {"id": "user_menu_reportpreviewconfigitem", "label": "reportPreviewConfigItem()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L9"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_static_src_js_user_menu_js", "target": "registry", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_static_src_js_user_menu_js", "target": "translation", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L4", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_static_src_js_user_menu_js", "target": "rpc", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L5", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_static_src_js_user_menu_js", "target": "user", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L6", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_static_src_js_user_menu_js", "target": "user_menu_reportpreviewconfigitem", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L9", "weight": 1.0}], "raw_calls": [{"caller_nid": "user_menu_reportpreviewconfigitem", "callee": "_t", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L13"}, {"caller_nid": "user_menu_reportpreviewconfigitem", "callee": "rpc", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L15"}, {"caller_nid": "user_menu_reportpreviewconfigitem", "callee": "doAction", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L19"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_group_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/__init__.py", "source_location": "L1"}], "edges": [], "raw_calls": []}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_garazd_product_label_tests_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/tests/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_garazd_product_label_tests_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_garazd_product_label_tests_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/tests/__init__.py", "source_location": "L1", "weight": 1.0}], "raw_calls": []}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_wizard_match_sale_order_wiz_py", "label": "match_sale_order_wiz.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/wizard/match_sale_order_wiz.py", "source_location": "L1"}, {"id": "match_sale_order_wiz_matchsaleorderwizard", "label": "MatchSaleOrderWizard", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/wizard/match_sale_order_wiz.py", "source_location": "L7"}, {"id": "match_sale_order_wiz_matchsaleorderwizard_action_confirm", "label": ".action_confirm()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/wizard/match_sale_order_wiz.py", "source_location": "L29"}, {"id": "match_sale_order_wiz_rationale_30", "label": "Link the selected Sale Order to the Purchase Order", "file_type": "rationale", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/wizard/match_sale_order_wiz.py", "source_location": "L30"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_wizard_match_sale_order_wiz_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/wizard/match_sale_order_wiz.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_wizard_match_sale_order_wiz_py", "target": "odoo_exceptions", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/wizard/match_sale_order_wiz.py", "source_location": "L4", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_wizard_match_sale_order_wiz_py", "target": "match_sale_order_wiz_matchsaleorderwizard", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/wizard/match_sale_order_wiz.py", "source_location": "L7", "weight": 1.0}, {"source": "match_sale_order_wiz_matchsaleorderwizard", "target": "match_sale_order_wiz_matchsaleorderwizard_action_confirm", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/wizard/match_sale_order_wiz.py", "source_location": "L29", "weight": 1.0}, {"source": "match_sale_order_wiz_rationale_30", "target": "match_sale_order_wiz_matchsaleorderwizard_action_confirm", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/wizard/match_sale_order_wiz.py", "source_location": "L30", "weight": 1.0}], "raw_calls": [{"caller_nid": "match_sale_order_wiz_matchsaleorderwizard_action_confirm", "callee": "ensure_one", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/wizard/match_sale_order_wiz.py", "source_location": "L31"}, {"caller_nid": "match_sale_order_wiz_matchsaleorderwizard_action_confirm", "callee": "UserError", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/wizard/match_sale_order_wiz.py", "source_location": "L34"}, {"caller_nid": "match_sale_order_wiz_matchsaleorderwizard_action_confirm", "callee": "_", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/wizard/match_sale_order_wiz.py", "source_location": "L34"}, {"caller_nid": "match_sale_order_wiz_matchsaleorderwizard_action_confirm", "callee": "write", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/wizard/match_sale_order_wiz.py", "source_location": "L40"}, {"caller_nid": "match_sale_order_wiz_matchsaleorderwizard_action_confirm", "callee": "_", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/wizard/match_sale_order_wiz.py", "source_location": "L49"}, {"caller_nid": "match_sale_order_wiz_matchsaleorderwizard_action_confirm", "callee": "_", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/wizard/match_sale_order_wiz.py", "source_location": "L50"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_models_res_users_py", "label": "res_users.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/models/res_users.py", "source_location": "L1"}, {"id": "res_users_resusers", "label": "ResUsers", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/models/res_users.py", "source_location": "L4"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_models_res_users_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/models/res_users.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_models_res_users_py", "target": "res_users_resusers", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/models/res_users.py", "source_location": "L4", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_garazd_product_label_print_controllers_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/controllers/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_garazd_product_label_print_controllers_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_garazd_product_label_print_controllers_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/controllers/__init__.py", "source_location": "L1", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_res_users_py", "label": "res_users.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_users.py", "source_location": "L1"}, {"id": "res_users_resusers", "label": "ResUsers", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_users.py", "source_location": "L4"}, {"id": "res_users_self_readable_fields", "label": "SELF_READABLE_FIELDS()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_users.py", "source_location": "L13"}, {"id": "res_users_self_writeable_fields", "label": "SELF_WRITEABLE_FIELDS()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_users.py", "source_location": "L19"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_res_users_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_users.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_res_users_py", "target": "res_users_resusers", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_users.py", "source_location": "L4", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_res_users_py", "target": "res_users_self_readable_fields", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_users.py", "source_location": "L13", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_res_users_py", "target": "res_users_self_writeable_fields", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_users.py", "source_location": "L19", "weight": 1.0}], "raw_calls": [{"caller_nid": "res_users_self_readable_fields", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_users.py", "source_location": "L14"}, {"caller_nid": "res_users_self_writeable_fields", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_users.py", "source_location": "L20"}]}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_garazd_product_label_models_product_template_py", "label": "product_template.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_template.py", "source_location": "L1"}, {"id": "product_template_producttemplate", "label": "ProductTemplate", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_template.py", "source_location": "L4"}, {"id": "product_template_producttemplate_action_open_label_layout", "label": ".action_open_label_layout()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_template.py", "source_location": "L7"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_garazd_product_label_models_product_template_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_template.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_garazd_product_label_models_product_template_py", "target": "product_template_producttemplate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_template.py", "source_location": "L4", "weight": 1.0}, {"source": "product_template_producttemplate", "target": "product_template_producttemplate_action_open_label_layout", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_template.py", "source_location": "L7", "weight": 1.0}], "raw_calls": [{"caller_nid": "product_template_producttemplate_action_open_label_layout", "callee": "get_param", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_template.py", "source_location": "L9"}, {"caller_nid": "product_template_producttemplate_action_open_label_layout", "callee": "sudo", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_template.py", "source_location": "L9"}, {"caller_nid": "product_template_producttemplate_action_open_label_layout", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_template.py", "source_location": "L10"}, {"caller_nid": "product_template_producttemplate_action_open_label_layout", "callee": "_for_xml_id", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_template.py", "source_location": "L11"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_garazd_product_label_pro_models_res_users_py", "label": "res_users.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/res_users.py", "source_location": "L1"}, {"id": "res_users_resusers", "label": "ResUsers", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/res_users.py", "source_location": "L4"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_garazd_product_label_pro_models_res_users_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/res_users.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_garazd_product_label_pro_models_res_users_py", "target": "res_users_resusers", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/res_users.py", "source_location": "L4", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_sale_order_to_purchase_order_app_wizard_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/sale_order_to_purchase_order_app/wizard/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_sale_order_to_purchase_order_app_wizard_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_sale_order_to_purchase_order_app_wizard_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/sale_order_to_purchase_order_app/wizard/__init__.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_sale_order_to_purchase_order_app_wizard_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_sale_order_to_purchase_order_app_wizard_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/sale_order_to_purchase_order_app/wizard/__init__.py", "source_location": "L4", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_group_static_src_search_collapse_all_collapse_all_js", "label": "collapse_all.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/src/search/collapse_all/collapse_all.js", "source_location": "L1"}, {"id": "collapse_all_collapseall", "label": "CollapseAll", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/src/search/collapse_all/collapse_all.js", "source_location": "L7"}, {"id": "collapse_all_collapseall_oncollapsebuttonclicked", "label": ".onCollapseButtonClicked()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/src/search/collapse_all/collapse_all.js", "source_location": "L13"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_group_static_src_search_collapse_all_collapse_all_js", "target": "owl", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/src/search/collapse_all/collapse_all.js", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_group_static_src_search_collapse_all_collapse_all_js", "target": "registry", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/src/search/collapse_all/collapse_all.js", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_group_static_src_search_collapse_all_collapse_all_js", "target": "dropdown_item", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/src/search/collapse_all/collapse_all.js", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_group_static_src_search_collapse_all_collapse_all_js", "target": "collapse_all_collapseall", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/src/search/collapse_all/collapse_all.js", "source_location": "L7", "weight": 1.0}, {"source": "collapse_all_collapseall", "target": "collapse_all_collapseall_oncollapsebuttonclicked", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/src/search/collapse_all/collapse_all.js", "source_location": "L13", "weight": 1.0}], "raw_calls": [{"caller_nid": "collapse_all_collapseall_oncollapsebuttonclicked", "callee": "filter", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/src/search/collapse_all/collapse_all.js", "source_location": "L16"}, {"caller_nid": "collapse_all_collapseall_oncollapsebuttonclicked", "callee": "toggle", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/src/search/collapse_all/collapse_all.js", "source_location": "L21"}, {"caller_nid": "collapse_all_collapseall_oncollapsebuttonclicked", "callee": "map", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/src/search/collapse_all/collapse_all.js", "source_location": "L24"}, {"caller_nid": "collapse_all_collapseall_oncollapsebuttonclicked", "callee": "reduce", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/src/search/collapse_all/collapse_all.js", "source_location": "L27"}, {"caller_nid": "collapse_all_collapseall_oncollapsebuttonclicked", "callee": "load", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/src/search/collapse_all/collapse_all.js", "source_location": "L31"}, {"caller_nid": "collapse_all_collapseall_oncollapsebuttonclicked", "callee": "notify", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/src/search/collapse_all/collapse_all.js", "source_location": "L32"}]}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_theme_models_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_theme/models/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_theme_models_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_theme_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_theme/models/__init__.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_theme_models_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_theme_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_theme/models/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_theme_models_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_theme_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_theme/models/__init__.py", "source_location": "L3", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_models_res_company_py", "label": "res_company.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/models/res_company.py", "source_location": "L1"}, {"id": "res_company_rescompany", "label": "ResCompany", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/models/res_company.py", "source_location": "L4"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_models_res_company_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/models/res_company.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_models_res_company_py", "target": "res_company_rescompany", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/models/res_company.py", "source_location": "L4", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/__init__.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/__init__.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/__init__.py", "source_location": "L4", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/__init__.py", "source_location": "L5", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_models_res_users_py", "label": "res_users.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/res_users.py", "source_location": "L1"}, {"id": "res_users_resusers", "label": "ResUsers", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/res_users.py", "source_location": "L6"}, {"id": "res_users_resusers_preview_reload", "label": ".preview_reload()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/res_users.py", "source_location": "L18"}, {"id": "res_users_resusers_preview_print_save", "label": ".preview_print_save()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/res_users.py", "source_location": "L24"}, {"id": "res_users_self_readable_fields", "label": "SELF_READABLE_FIELDS()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/res_users.py", "source_location": "L31"}, {"id": "res_users_self_writeable_fields", "label": "SELF_WRITEABLE_FIELDS()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/res_users.py", "source_location": "L35"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_models_res_users_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/res_users.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_models_res_users_py", "target": "res_users_resusers", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/res_users.py", "source_location": "L6", "weight": 1.0}, {"source": "res_users_resusers", "target": "res_users_resusers_preview_reload", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/res_users.py", "source_location": "L18", "weight": 1.0}, {"source": "res_users_resusers", "target": "res_users_resusers_preview_print_save", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/res_users.py", "source_location": "L24", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_models_res_users_py", "target": "res_users_self_readable_fields", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/res_users.py", "source_location": "L31", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_models_res_users_py", "target": "res_users_self_writeable_fields", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/res_users.py", "source_location": "L35", "weight": 1.0}], "raw_calls": [{"caller_nid": "res_users_self_readable_fields", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/res_users.py", "source_location": "L32"}, {"caller_nid": "res_users_self_writeable_fields", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/res_users.py", "source_location": "L36"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_garazd_product_label_models_print_label_type_py", "label": "print_label_type.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/print_label_type.py", "source_location": "L1"}, {"id": "print_label_type_printlabeltypepy", "label": "PrintLabelTypePy", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/print_label_type.py", "source_location": "L4"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_garazd_product_label_models_print_label_type_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/print_label_type.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_garazd_product_label_models_print_label_type_py", "target": "print_label_type_printlabeltypepy", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/print_label_type.py", "source_location": "L4", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_sale_order_to_purchase_order_app_models_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/sale_order_to_purchase_order_app/models/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_sale_order_to_purchase_order_app_models_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_sale_order_to_purchase_order_app_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/sale_order_to_purchase_order_app/models/__init__.py", "source_location": "L3", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/__init__.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/__init__.py", "source_location": "L4", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/__init__.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/__init__.py", "source_location": "L4", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_voip_ringcentral_static_src_voip_service_patch_js", "label": "voip_service_patch.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/voip_ringcentral/static/src/voip_service_patch.js", "source_location": "L1"}, {"id": "voip_service_patch_arecredentialsset", "label": "areCredentialsSet()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/voip_ringcentral/static/src/voip_service_patch.js", "source_location": "L8"}, {"id": "voip_service_patch_authorizationusername", "label": "authorizationUsername()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/voip_ringcentral/static/src/voip_service_patch.js", "source_location": "L11"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_voip_ringcentral_static_src_voip_service_patch_js", "target": "voip_service", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/voip_ringcentral/static/src/voip_service_patch.js", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_voip_ringcentral_static_src_voip_service_patch_js", "target": "patch", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/voip_ringcentral/static/src/voip_service_patch.js", "source_location": "L5", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_voip_ringcentral_static_src_voip_service_patch_js", "target": "voip_service_patch_arecredentialsset", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/voip_ringcentral/static/src/voip_service_patch.js", "source_location": "L8", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_voip_ringcentral_static_src_voip_service_patch_js", "target": "voip_service_patch_authorizationusername", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/voip_ringcentral/static/src/voip_service_patch.js", "source_location": "L11", "weight": 1.0}], "raw_calls": [{"caller_nid": "voip_service_patch_arecredentialsset", "callee": "Boolean", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/voip_ringcentral/static/src/voip_service_patch.js", "source_location": "L9"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_dialog_models_res_users_py", "label": "res_users.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/models/res_users.py", "source_location": "L1"}, {"id": "res_users_resusers", "label": "ResUsers", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/models/res_users.py", "source_location": "L4"}, {"id": "res_users_self_readable_fields", "label": "SELF_READABLE_FIELDS()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/models/res_users.py", "source_location": "L13"}, {"id": "res_users_self_writeable_fields", "label": "SELF_WRITEABLE_FIELDS()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/models/res_users.py", "source_location": "L19"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_dialog_models_res_users_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/models/res_users.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_dialog_models_res_users_py", "target": "res_users_resusers", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/models/res_users.py", "source_location": "L4", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_dialog_models_res_users_py", "target": "res_users_self_readable_fields", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/models/res_users.py", "source_location": "L13", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_dialog_models_res_users_py", "target": "res_users_self_writeable_fields", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/models/res_users.py", "source_location": "L19", "weight": 1.0}], "raw_calls": [{"caller_nid": "res_users_self_readable_fields", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/models/res_users.py", "source_location": "L14"}, {"caller_nid": "res_users_self_writeable_fields", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/models/res_users.py", "source_location": "L20"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_garazd_product_label_pro_models_res_config_settings_py", "label": "res_config_settings.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/res_config_settings.py", "source_location": "L1"}, {"id": "res_config_settings_resconfigsettings", "label": "ResConfigSettings", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/res_config_settings.py", "source_location": "L4"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_garazd_product_label_pro_models_res_config_settings_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/res_config_settings.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_garazd_product_label_pro_models_res_config_settings_py", "target": "res_config_settings_resconfigsettings", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/res_config_settings.py", "source_location": "L4", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_dialog_static_src_views_view_dialogs_select_create_dialog_js", "label": "select_create_dialog.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/static/src/views/view_dialogs/select_create_dialog.js", "source_location": "L1"}, {"id": "select_create_dialog_onclickdialogsizetoggle", "label": "onClickDialogSizeToggle()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/static/src/views/view_dialogs/select_create_dialog.js", "source_location": "L6"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_dialog_static_src_views_view_dialogs_select_create_dialog_js", "target": "patch", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/static/src/views/view_dialogs/select_create_dialog.js", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_dialog_static_src_views_view_dialogs_select_create_dialog_js", "target": "select_create_dialog", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/static/src/views/view_dialogs/select_create_dialog.js", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_dialog_static_src_views_view_dialogs_select_create_dialog_js", "target": "select_create_dialog_onclickdialogsizetoggle", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/static/src/views/view_dialogs/select_create_dialog.js", "source_location": "L6", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/__init__.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/__init__.py", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/__init__.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/__init__.py", "source_location": "L4", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_chatter_models_ir_http_py", "label": "ir_http.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/models/ir_http.py", "source_location": "L1"}, {"id": "ir_http_irhttp", "label": "IrHttp", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/models/ir_http.py", "source_location": "L4"}, {"id": "ir_http_irhttp_session_info", "label": ".session_info()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/models/ir_http.py", "source_location": "L12"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_chatter_models_ir_http_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/models/ir_http.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_chatter_models_ir_http_py", "target": "ir_http_irhttp", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/models/ir_http.py", "source_location": "L4", "weight": 1.0}, {"source": "ir_http_irhttp", "target": "ir_http_irhttp_session_info", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/models/ir_http.py", "source_location": "L12", "weight": 1.0}], "raw_calls": [{"caller_nid": "ir_http_irhttp_session_info", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/models/ir_http.py", "source_location": "L13"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_refresh_models_ir_http_py", "label": "ir_http.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/models/ir_http.py", "source_location": "L1"}, {"id": "ir_http_irhttp", "label": "IrHttp", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/models/ir_http.py", "source_location": "L4"}, {"id": "ir_http_irhttp_session_info", "label": ".session_info()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/models/ir_http.py", "source_location": "L12"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_refresh_models_ir_http_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/models/ir_http.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_refresh_models_ir_http_py", "target": "ir_http_irhttp", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/models/ir_http.py", "source_location": "L4", "weight": 1.0}, {"source": "ir_http_irhttp", "target": "ir_http_irhttp_session_info", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/models/ir_http.py", "source_location": "L12", "weight": 1.0}], "raw_calls": [{"caller_nid": "ir_http_irhttp_session_info", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/models/ir_http.py", "source_location": "L13"}, {"caller_nid": "ir_http_irhttp_session_info", "callee": "int", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/models/ir_http.py", "source_location": "L14"}, {"caller_nid": "ir_http_irhttp_session_info", "callee": "get_param", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/models/ir_http.py", "source_location": "L15"}, {"caller_nid": "ir_http_irhttp_session_info", "callee": "sudo", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/models/ir_http.py", "source_location": "L15"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_dialog_models_ir_http_py", "label": "ir_http.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/models/ir_http.py", "source_location": "L1"}, {"id": "ir_http_irhttp", "label": "IrHttp", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/models/ir_http.py", "source_location": "L4"}, {"id": "ir_http_irhttp_session_info", "label": ".session_info()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/models/ir_http.py", "source_location": "L12"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_dialog_models_ir_http_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/models/ir_http.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_dialog_models_ir_http_py", "target": "ir_http_irhttp", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/models/ir_http.py", "source_location": "L4", "weight": 1.0}, {"source": "ir_http_irhttp", "target": "ir_http_irhttp_session_info", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/models/ir_http.py", "source_location": "L12", "weight": 1.0}], "raw_calls": [{"caller_nid": "ir_http_irhttp_session_info", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/models/ir_http.py", "source_location": "L13"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_print_product_label_line_py", "label": "print_product_label_line.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/print_product_label_line.py", "source_location": "L1"}, {"id": "print_product_label_line_printproductlabelline", "label": "PrintProductLabelLine", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/print_product_label_line.py", "source_location": "L9"}, {"id": "print_product_label_line_compute_product_price", "label": "_compute_product_price()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/print_product_label_line.py", "source_location": "L18"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_print_product_label_line_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/print_product_label_line.py", "source_location": "L6", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_print_product_label_line_py", "target": "print_product_label_line_printproductlabelline", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/print_product_label_line.py", "source_location": "L9", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_print_product_label_line_py", "target": "print_product_label_line_compute_product_price", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/print_product_label_line.py", "source_location": "L18", "weight": 1.0}], "raw_calls": [{"caller_nid": "print_product_label_line_compute_product_price", "callee": "filtered", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/print_product_label_line.py", "source_location": "L21"}, {"caller_nid": "print_product_label_line_compute_product_price", "callee": "_get_product_price", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/print_product_label_line.py", "source_location": "L25"}, {"caller_nid": "print_product_label_line_compute_product_price", "callee": "_get_product_price", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/print_product_label_line.py", "source_location": "L28"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_models_ir_http_py", "label": "ir_http.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/ir_http.py", "source_location": "L1"}, {"id": "ir_http_http", "label": "Http", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/ir_http.py", "source_location": "L5"}, {"id": "ir_http_http_session_info", "label": ".session_info()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/ir_http.py", "source_location": "L8"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_models_ir_http_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/ir_http.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_models_ir_http_py", "target": "ir_http_http", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/ir_http.py", "source_location": "L5", "weight": 1.0}, {"source": "ir_http_http", "target": "ir_http_http_session_info", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/ir_http.py", "source_location": "L8", "weight": 1.0}], "raw_calls": [{"caller_nid": "ir_http_http_session_info", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/ir_http.py", "source_location": "L9"}, {"caller_nid": "ir_http_http_session_info", "callee": "update", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/ir_http.py", "source_location": "L13"}, {"caller_nid": "ir_http_http_session_info", "callee": "bool", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/models/ir_http.py", "source_location": "L16"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_controllers_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/controllers/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_controllers_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_controllers_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/controllers/__init__.py", "source_location": "L1", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_voip_ringcentral_models_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/voip_ringcentral/models/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_voip_ringcentral_models_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_voip_ringcentral_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/voip_ringcentral/models/__init__.py", "source_location": "L5", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_voip_ringcentral_models_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_voip_ringcentral_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/voip_ringcentral/models/__init__.py", "source_location": "L6", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_voip_ringcentral_models_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_voip_ringcentral_models_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/voip_ringcentral/models/__init__.py", "source_location": "L7", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_report_product_label_report_py", "label": "product_label_report.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/report/product_label_report.py", "source_location": "L1"}, {"id": "product_label_report_reportgarazdproductlabelfromtemplate", "label": "ReportGarazdProductLabelFromTemplate", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/report/product_label_report.py", "source_location": "L4"}, {"id": "product_label_report_reportgarazdproductlabelfromtemplate_get_report_values", "label": "._get_report_values()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/report/product_label_report.py", "source_location": "L8"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_report_product_label_report_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/report/product_label_report.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_report_product_label_report_py", "target": "product_label_report_reportgarazdproductlabelfromtemplate", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/report/product_label_report.py", "source_location": "L4", "weight": 1.0}, {"source": "product_label_report_reportgarazdproductlabelfromtemplate", "target": "product_label_report_reportgarazdproductlabelfromtemplate_get_report_values", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/report/product_label_report.py", "source_location": "L8", "weight": 1.0}], "raw_calls": [{"caller_nid": "product_label_report_reportgarazdproductlabelfromtemplate_get_report_values", "callee": "browse", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/report/product_label_report.py", "source_location": "L9"}, {"caller_nid": "product_label_report_reportgarazdproductlabelfromtemplate_get_report_values", "callee": "get", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/report/product_label_report.py", "source_location": "L9"}, {"caller_nid": "product_label_report_reportgarazdproductlabelfromtemplate_get_report_values", "callee": "get", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/report/product_label_report.py", "source_location": "L14"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_garazd_product_label_pro_manifest_py", "label": "__manifest__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/__manifest__.py", "source_location": "L1"}], "edges": [], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_res_config_settings_py", "label": "res_config_settings.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_config_settings.py", "source_location": "L1"}, {"id": "res_config_settings_resconfigsettings", "label": "ResConfigSettings", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_config_settings.py", "source_location": "L4"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_res_config_settings_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_config_settings.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_models_res_config_settings_py", "target": "res_config_settings_resconfigsettings", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/models/res_config_settings.py", "source_location": "L4", "weight": 1.0}], "raw_calls": []}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_group_static_tests_group_test_js", "label": "group.test.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/tests/group.test.js", "source_location": "L1"}, {"id": "group_test_category", "label": "Category", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/tests/group.test.js", "source_location": "L11"}, {"id": "group_test_product", "label": "Product", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/tests/group.test.js", "source_location": "L19"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_group_static_tests_group_test_js", "target": "hoot", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/tests/group.test.js", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_group_static_tests_group_test_js", "target": "web_test_helpers", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/tests/group.test.js", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_group_static_tests_group_test_js", "target": "group_test_category", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/tests/group.test.js", "source_location": "L11", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_group_static_tests_group_test_js", "target": "group_test_product", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/static/tests/group.test.js", "source_location": "L19", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_appsbar_manifest_py", "label": "__manifest__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_appsbar/__manifest__.py", "source_location": "L1"}], "edges": [], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_garazd_product_label_models_res_config_settings_py", "label": "res_config_settings.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/res_config_settings.py", "source_location": "L1"}, {"id": "res_config_settings_resconfigsettings", "label": "ResConfigSettings", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/res_config_settings.py", "source_location": "L4"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_garazd_product_label_models_res_config_settings_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/res_config_settings.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_garazd_product_label_models_res_config_settings_py", "target": "res_config_settings_resconfigsettings", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/res_config_settings.py", "source_location": "L4", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_chatter_models_res_users_py", "label": "res_users.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/models/res_users.py", "source_location": "L1"}, {"id": "res_users_resusers", "label": "ResUsers", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/models/res_users.py", "source_location": "L4"}, {"id": "res_users_self_readable_fields", "label": "SELF_READABLE_FIELDS()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/models/res_users.py", "source_location": "L13"}, {"id": "res_users_self_writeable_fields", "label": "SELF_WRITEABLE_FIELDS()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/models/res_users.py", "source_location": "L19"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_chatter_models_res_users_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/models/res_users.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_chatter_models_res_users_py", "target": "res_users_resusers", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/models/res_users.py", "source_location": "L4", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_chatter_models_res_users_py", "target": "res_users_self_readable_fields", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/models/res_users.py", "source_location": "L13", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_chatter_models_res_users_py", "target": "res_users_self_writeable_fields", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/models/res_users.py", "source_location": "L19", "weight": 1.0}], "raw_calls": [{"caller_nid": "res_users_self_readable_fields", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/models/res_users.py", "source_location": "L14"}, {"caller_nid": "res_users_self_writeable_fields", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/models/res_users.py", "source_location": "L20"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_garazd_product_label_pro_models_product_product_py", "label": "product_product.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/product_product.py", "source_location": "L1"}, {"id": "product_product_productproduct", "label": "ProductProduct", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/product_product.py", "source_location": "L4"}, {"id": "product_product_productproduct_action_open_label_layout", "label": ".action_open_label_layout()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/product_product.py", "source_location": "L7"}, {"id": "product_product_rationale_8", "label": "If a user has direct print option and a label template, return the direct print", "file_type": "rationale", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/product_product.py", "source_location": "L8"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_garazd_product_label_pro_models_product_product_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/product_product.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_garazd_product_label_pro_models_product_product_py", "target": "product_product_productproduct", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/product_product.py", "source_location": "L4", "weight": 1.0}, {"source": "product_product_productproduct", "target": "product_product_productproduct_action_open_label_layout", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/product_product.py", "source_location": "L7", "weight": 1.0}, {"source": "product_product_rationale_8", "target": "product_product_productproduct_action_open_label_layout", "relation": "rationale_for", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/product_product.py", "source_location": "L8", "weight": 1.0}], "raw_calls": [{"caller_nid": "product_product_productproduct_action_open_label_layout", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/product_product.py", "source_location": "L12"}, {"caller_nid": "product_product_productproduct_action_open_label_layout", "callee": "get_param", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/product_product.py", "source_location": "L13"}, {"caller_nid": "product_product_productproduct_action_open_label_layout", "callee": "sudo", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/product_product.py", "source_location": "L13"}, {"caller_nid": "product_product_productproduct_action_open_label_layout", "callee": "get_quick_report_action", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/product_product.py", "source_location": "L15"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_pdf_print_preview_manifest_py", "label": "__manifest__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/pdf_print_preview/__manifest__.py", "source_location": "L1"}], "edges": [], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_garazd_product_label_print_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_garazd_product_label_print_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_garazd_product_label_print_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/__init__.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_garazd_product_label_print_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_garazd_product_label_print_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/__init__.py", "source_location": "L2", "weight": 1.0}], "raw_calls": []}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_dialog_manifest_py", "label": "__manifest__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_dialog/__manifest__.py", "source_location": "L1"}], "edges": [], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_garazd_product_label_print_manifest_py", "label": "__manifest__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/__manifest__.py", "source_location": "L1"}], "edges": [], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_garazd_product_label_pro_models_res_company_py", "label": "res_company.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/res_company.py", "source_location": "L1"}, {"id": "res_company_rescompany", "label": "ResCompany", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/res_company.py", "source_location": "L4"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_garazd_product_label_pro_models_res_company_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/res_company.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_garazd_product_label_pro_models_res_company_py", "target": "res_company_rescompany", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/garazd_product_label_pro/models/res_company.py", "source_location": "L4", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_static_src_js_user_menu_js", "label": "user_menu.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L1"}, {"id": "user_menu_reportpreviewconfigitem", "label": "reportPreviewConfigItem()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L9"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_static_src_js_user_menu_js", "target": "registry", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_static_src_js_user_menu_js", "target": "translation", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L4", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_static_src_js_user_menu_js", "target": "rpc", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L5", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_static_src_js_user_menu_js", "target": "user", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L6", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_pdf_print_preview_static_src_js_user_menu_js", "target": "user_menu_reportpreviewconfigitem", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L9", "weight": 1.0}], "raw_calls": [{"caller_nid": "user_menu_reportpreviewconfigitem", "callee": "_t", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L13"}, {"caller_nid": "user_menu_reportpreviewconfigitem", "callee": "rpc", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L15"}, {"caller_nid": "user_menu_reportpreviewconfigitem", "callee": "doAction", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/pdf_print_preview/static/src/js/user_menu.js", "source_location": "L19"}]}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_manifest_py", "label": "__manifest__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/__manifest__.py", "source_location": "L1"}], "edges": [], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_garazd_product_label_models_product_product_py", "label": "product_product.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_product.py", "source_location": "L1"}, {"id": "product_product_productproduct", "label": "ProductProduct", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_product.py", "source_location": "L4"}, {"id": "product_product_productproduct_action_open_label_layout", "label": ".action_open_label_layout()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_product.py", "source_location": "L7"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_garazd_product_label_models_product_product_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_product.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_garazd_product_label_models_product_product_py", "target": "product_product_productproduct", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_product.py", "source_location": "L4", "weight": 1.0}, {"source": "product_product_productproduct", "target": "product_product_productproduct_action_open_label_layout", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_product.py", "source_location": "L7", "weight": 1.0}], "raw_calls": [{"caller_nid": "product_product_productproduct_action_open_label_layout", "callee": "get_param", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_product.py", "source_location": "L9"}, {"caller_nid": "product_product_productproduct_action_open_label_layout", "callee": "sudo", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_product.py", "source_location": "L9"}, {"caller_nid": "product_product_productproduct_action_open_label_layout", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_product.py", "source_location": "L10"}, {"caller_nid": "product_product_productproduct_action_open_label_layout", "callee": "_for_xml_id", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label/garazd_product_label/models/product_product.py", "source_location": "L11"}]}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_theme_models_res_company_py", "label": "res_company.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_theme/models/res_company.py", "source_location": "L1"}, {"id": "res_company_rescompany", "label": "ResCompany", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_theme/models/res_company.py", "source_location": "L4"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_theme_models_res_company_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_theme/models/res_company.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_theme_models_res_company_py", "target": "res_company_rescompany", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_theme/models/res_company.py", "source_location": "L4", "weight": 1.0}], "raw_calls": []}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_garazd_product_label_print_controllers_main_py", "label": "main.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/controllers/main.py", "source_location": "L1"}, {"id": "main_printpdf", "label": "PrintPDF", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/controllers/main.py", "source_location": "L12"}, {"id": "main_print_label_pdf", "label": "print_label_pdf()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/controllers/main.py", "source_location": "L20"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_garazd_product_label_print_controllers_main_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/controllers/main.py", "source_location": "L6", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_garazd_product_label_print_controllers_main_py", "target": "odoo_http", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/controllers/main.py", "source_location": "L7", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_garazd_product_label_print_controllers_main_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_garazd_product_label_print_wizard_print_product_label_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/controllers/main.py", "source_location": "L9", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_garazd_product_label_print_controllers_main_py", "target": "main_printpdf", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/controllers/main.py", "source_location": "L12", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_garazd_product_label_print_controllers_main_py", "target": "main_print_label_pdf", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/controllers/main.py", "source_location": "L20", "weight": 1.0}], "raw_calls": [{"caller_nid": "main_print_label_pdf", "callee": "not_found", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/controllers/main.py", "source_location": "L22"}, {"caller_nid": "main_print_label_pdf", "callee": "int", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/controllers/main.py", "source_location": "L25"}, {"caller_nid": "main_print_label_pdf", "callee": "not_found", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/controllers/main.py", "source_location": "L27"}, {"caller_nid": "main_print_label_pdf", "callee": "search", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/controllers/main.py", "source_location": "L29"}, {"caller_nid": "main_print_label_pdf", "callee": "sudo", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/controllers/main.py", "source_location": "L29"}, {"caller_nid": "main_print_label_pdf", "callee": "not_found", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/controllers/main.py", "source_location": "L36"}, {"caller_nid": "main_print_label_pdf", "callee": "render", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/garazd_product_label_print/controllers/main.py", "source_location": "L39"}]}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_tests_common_py", "label": "common.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L1"}, {"id": "common_testproductlabel", "label": "TestProductLabel", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L11"}, {"id": "transactioncase", "label": "TransactionCase", "file_type": "code", "source_file": "", "source_location": ""}, {"id": "common_setupclass", "label": "setUpClass()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L14"}, {"id": "common_testproductlabel_setup", "label": ".setUp()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L39"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_tests_common_py", "target": "odoo_tests_common", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L6", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_tests_common_py", "target": "odoo_tests", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L7", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_tests_common_py", "target": "common_testproductlabel", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L11", "weight": 1.0}, {"source": "common_testproductlabel", "target": "transactioncase", "relation": "inherits", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L11", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_tests_common_py", "target": "common_setupclass", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L14", "weight": 1.0}, {"source": "common_testproductlabel", "target": "common_testproductlabel_setup", "relation": "method", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L39", "weight": 1.0}], "raw_calls": [{"caller_nid": "common_setupclass", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L15"}, {"caller_nid": "common_setupclass", "callee": "create", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L17"}, {"caller_nid": "common_setupclass", "callee": "ref", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L19"}, {"caller_nid": "common_setupclass", "callee": "create", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L26"}, {"caller_nid": "common_setupclass", "callee": "create", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L32"}, {"caller_nid": "common_testproductlabel_setup", "callee": "super", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L40"}, {"caller_nid": "common_testproductlabel_setup", "callee": "create", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L42"}, {"caller_nid": "common_testproductlabel_setup", "callee": "with_context", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/tests/common.py", "source_location": "L42"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_refresh_static_tests_refresh_test_js", "label": "refresh.test.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/static/tests/refresh.test.js", "source_location": "L1"}, {"id": "refresh_test_product", "label": "Product", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/static/tests/refresh.test.js", "source_location": "L11"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_refresh_static_tests_refresh_test_js", "target": "hoot", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/static/tests/refresh.test.js", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_refresh_static_tests_refresh_test_js", "target": "web_test_helpers", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/static/tests/refresh.test.js", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_refresh_static_tests_refresh_test_js", "target": "refresh_test_product", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/static/tests/refresh.test.js", "source_location": "L11", "weight": 1.0}], "raw_calls": []}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_chatter_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_chatter_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_chatter_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/__init__.py", "source_location": "L1", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_models_res_config_settings_py", "label": "res_config_settings.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/models/res_config_settings.py", "source_location": "L1"}, {"id": "res_config_settings_resconfigsettings", "label": "ResConfigSettings", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/models/res_config_settings.py", "source_location": "L4"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_models_res_config_settings_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/models/res_config_settings.py", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_models_res_config_settings_py", "target": "res_config_settings_resconfigsettings", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/models/res_config_settings.py", "source_location": "L4", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_sale_order_to_purchase_order_app_init_py", "label": "__init__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/sale_order_to_purchase_order_app/__init__.py", "source_location": "L1"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_sale_order_to_purchase_order_app_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_sale_order_to_purchase_order_app_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/sale_order_to_purchase_order_app/__init__.py", "source_location": "L3", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_sale_order_to_purchase_order_app_init_py", "target": "users_gurpreet_github_odoo_modules_obsolete_files_sale_order_to_purchase_order_app_sale_order_to_purchase_order_app_init_py", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/sale_order_to_purchase_order_app/sale_order_to_purchase_order_app/__init__.py", "source_location": "L4", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_refresh_manifest_py", "label": "__manifest__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_refresh/__manifest__.py", "source_location": "L1"}], "edges": [], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_print_product_label_preview_py", "label": "print_product_label_preview.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/print_product_label_preview.py", "source_location": "L1"}, {"id": "print_product_label_preview_printproductlabelpreview", "label": "PrintProductLabelPreview", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/print_product_label_preview.py", "source_location": "L9"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_print_product_label_preview_py", "target": "odoo", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/print_product_label_preview.py", "source_location": "L6", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_pro_wizard_print_product_label_preview_py", "target": "print_product_label_preview_printproductlabelpreview", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_pro/wizard/print_product_label_preview.py", "source_location": "L9", "weight": 1.0}], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_chatter_static_src_chatter_chatter_js", "label": "chatter.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/static/src/chatter/chatter.js", "source_location": "L1"}, {"id": "chatter_setup", "label": "setup()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/static/src/chatter/chatter.js", "source_location": "L7"}, {"id": "chatter_onclicknotificationstoggle", "label": "onClickNotificationsToggle()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/static/src/chatter/chatter.js", "source_location": "L17"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_chatter_static_src_chatter_chatter_js", "target": "patch", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/static/src/chatter/chatter.js", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_chatter_static_src_chatter_chatter_js", "target": "browser", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/static/src/chatter/chatter.js", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_chatter_static_src_chatter_chatter_js", "target": "chatter", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/static/src/chatter/chatter.js", "source_location": "L4", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_chatter_static_src_chatter_chatter_js", "target": "chatter_setup", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/static/src/chatter/chatter.js", "source_location": "L7", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_chatter_static_src_chatter_chatter_js", "target": "chatter_onclicknotificationstoggle", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/static/src/chatter/chatter.js", "source_location": "L17", "weight": 1.0}], "raw_calls": [{"caller_nid": "chatter_setup", "callee": "getItem", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/static/src/chatter/chatter.js", "source_location": "L9"}, {"caller_nid": "chatter_setup", "callee": "parse", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/static/src/chatter/chatter.js", "source_location": "L14"}, {"caller_nid": "chatter_onclicknotificationstoggle", "callee": "setItem", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_chatter/static/src/chatter/chatter.js", "source_location": "L19"}]}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_garazd_product_label_print_manifest_py", "label": "__manifest__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/garazd_product_label_print/__manifest__.py", "source_location": "L1"}], "edges": [], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_group_manifest_py", "label": "__manifest__.py", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_group/__manifest__.py", "source_location": "L1"}], "edges": [], "raw_calls": []}

View File

@@ -0,0 +1 @@
{"nodes": [{"id": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_theme_static_src_webclient_navbar_navbar_js", "label": "navbar.js", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_theme/static/src/webclient/navbar/navbar.js", "source_location": "L1"}, {"id": "navbar_setup", "label": "setup()", "file_type": "code", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_theme/static/src/webclient/navbar/navbar.js", "source_location": "L8"}], "edges": [{"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_theme_static_src_webclient_navbar_navbar_js", "target": "patch", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_theme/static/src/webclient/navbar/navbar.js", "source_location": "L1", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_theme_static_src_webclient_navbar_navbar_js", "target": "hooks", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_theme/static/src/webclient/navbar/navbar.js", "source_location": "L2", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_theme_static_src_webclient_navbar_navbar_js", "target": "navbar", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_theme/static/src/webclient/navbar/navbar.js", "source_location": "L4", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_theme_static_src_webclient_navbar_navbar_js", "target": "appsmenu", "relation": "imports_from", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_theme/static/src/webclient/navbar/navbar.js", "source_location": "L5", "weight": 1.0}, {"source": "users_gurpreet_github_odoo_modules_obsolete_files_muk_web_theme_19_0_1_4_1_muk_web_theme_static_src_webclient_navbar_navbar_js", "target": "navbar_setup", "relation": "contains", "confidence": "EXTRACTED", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_theme/static/src/webclient/navbar/navbar.js", "source_location": "L8", "weight": 1.0}], "raw_calls": [{"caller_nid": "navbar_setup", "callee": "useService", "source_file": "/Users/gurpreet/Github/Odoo-Modules/Obsolete Files/muk_web_theme-19.0.1.4.1/muk_web_theme/static/src/webclient/navbar/navbar.js", "source_location": "L10"}]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More