Skip to Content
Odoo Menu
  • Sign in
  • Try it free
  • Apps
    Finance
    • Accounting
    • Invoicing
    • Expenses
    • Spreadsheet (BI)
    • Documents
    • Sign
    Sales
    • CRM
    • Sales
    • POS Shop
    • POS Restaurant
    • Subscriptions
    • Rental
    Websites
    • Website Builder
    • eCommerce
    • Blog
    • Forum
    • Live Chat
    • eLearning
    Supply Chain
    • Inventory
    • Manufacturing
    • PLM
    • Purchase
    • Maintenance
    • Quality
    Human Resources
    • Employees
    • Recruitment
    • Time Off
    • Appraisals
    • Referrals
    • Fleet
    Marketing
    • Social Marketing
    • Email Marketing
    • SMS Marketing
    • Events
    • Marketing Automation
    • Surveys
    Services
    • Project
    • Timesheets
    • Field Service
    • Helpdesk
    • Planning
    • Appointments
    Productivity
    • Discuss
    • Approvals
    • IoT
    • VoIP
    • Knowledge
    • WhatsApp
    Third party apps Odoo Studio Odoo Cloud Platform
  • Industries
    Retail
    • Book Store
    • Clothing Store
    • Furniture Store
    • Grocery Store
    • Hardware Store
    • Toy Store
    Food & Hospitality
    • Bar and Pub
    • Restaurant
    • Fast Food
    • Guest House
    • Beverage Distributor
    • Hotel
    Real Estate
    • Real Estate Agency
    • Architecture Firm
    • Construction
    • Property Management
    • Gardening
    • Property Owner Association
    Consulting
    • Accounting Firm
    • Odoo Partner
    • Marketing Agency
    • Law firm
    • Talent Acquisition
    • Audit & Certification
    Manufacturing
    • Textile
    • Metal
    • Furnitures
    • Food
    • Brewery
    • Corporate Gifts
    Health & Fitness
    • Sports Club
    • Eyewear Store
    • Fitness Center
    • Wellness Practitioners
    • Pharmacy
    • Hair Salon
    Trades
    • Handyman
    • IT Hardware & Support
    • Solar Energy Systems
    • Shoe Maker
    • Cleaning Services
    • HVAC Services
    Others
    • Nonprofit Organization
    • Environmental Agency
    • Billboard Rental
    • Photography
    • Bike Leasing
    • Software Reseller
    Browse all Industries
  • Community
    Learn
    • Tutorials
    • Documentation
    • Certifications
    • Training
    • Blog
    • Podcast
    Empower Education
    • Education Program
    • Scale Up! Business Game
    • Visit Odoo
    Get the Software
    • Download
    • Compare Editions
    • Releases
    Collaborate
    • Github
    • Forum
    • Events
    • Translations
    • Become a Partner
    • Services for Partners
    • Register your Accounting Firm
    Get Services
    • Find a Partner
    • Find an Accountant
      • Get a Tailored Demo
    • Implementation Services
    • Customer References
    • Support
    • Upgrades
    Github Youtube Twitter Linkedin Instagram Facebook Spotify
    +32 2 290 34 90
    • Get a Tailored Demo
  • Pricing
  • Help
  1. APPS
  2. Customs
  3. Soft Delete Manager v 16.0
  4. Sales Conditions FAQ

Soft Delete Manager

by DC Software https://github.com
Odoo

$ 199.99

v 16.0 Third Party 1
Apps purchases are linked to your Odoo account, please sign in or sign up first.
Availability
Odoo Online
Odoo.sh
On Premise
Odoo Apps Dependencies Discuss (mail)
Lines of code 7434
Technical Name soft_delete_recovery
LicenseLGPL-3
Websitehttps://github.com
Versions 16.0
You bought this module and need support? Click here!
Availability
Odoo Online
Odoo.sh
On Premise
Odoo Apps Dependencies Discuss (mail)
Lines of code 7434
Technical Name soft_delete_recovery
LicenseLGPL-3
Websitehttps://github.com
Versions 16.0
♻
v16.0.10.7.22

Soft Delete Manager

Reversible deletes for any Odoo model — with cascade, snapshot backup, full audit trail, and analytics.

Nothing is ever truly lost. Restore even after permanent delete.

Odoo 16 CE + EE Python 3.8+ LGPL-3
5 Default Model Cap 6 Audit Action Types 3 Severity Levels 2 Daily Cron Jobs

Overview

Soft Delete Manager turns Odoo's destructive delete into a reversible Recycle Bin for any model you choose. When a user deletes a protected record, the row is hidden — not removed — and every action is written to an immutable audit log with severity, batch ID, and a JSON snapshot of the data. Children of a deleted parent follow it through a cascade, and even after a permanent delete the record can be recreated from its snapshot, with all its inbound relations reapplied.

A per-user, per-model permission matrix controls who can soft-delete, restore, or hard-delete each protected model. An analytics dashboard surfaces deletion-rate trends, severity breakdowns, time-of-day heatmaps, user activity scores, and model risk rankings. Two daily cron jobs keep the database tidy: one purges expired soft-deletes, the other rotates old audit logs.

Odoo 16 Community Odoo 16 Enterprise Data Safety Audit & Compliance

Video Demo

Watch Soft Delete Manager in action — full walkthrough of cascade soft delete, snapshot recovery, audit trail, and dashboard analytics.

Your browser does not support inline video. ▶ Watch on YouTube instead.
▶  Watch the full playlist on YouTube

Why Choose Soft Delete Manager?

♻
Reversible Deletes Records are hidden, not destroyed. Undo a delete in one click.
🔒
Per-User Permissions Three independent toggles for every (user, model) pair. Deny by default.
📊
Analytics Dashboard KPI deltas, severity donut, sparklines, time heatmap, user activity scores.
📂
JSON Snapshot Backup Every permanent delete saves a full record snapshot — recreate later from the audit log.
🔗
Cascade Aware Children follow parent on delete and on restore. Linked by batch UUID.
⏱
Auto-Cleanup Cron Configurable TTL for soft-deletes and audit logs — the table never bloats.

Key Features

Soft Delete Mixin Protected models get an x_is_deleted flag; unlink() sets it instead of removing the row. Recover Deleted Button One-click access to the Recycle Bin from list and kanban view headers.
Reason Wizard Capture why a record was deleted before it leaves the active dataset. Cascade Soft Delete Inbound foreign-key children are soft-deleted with the parent, linked by batch UUID.
Cascade Restore Restoring a parent automatically restores its tree of cascaded children. JSON Snapshot Backup Every permanent delete writes a full record snapshot to the audit log first.
Restore from Snapshot Recreate a permanently deleted record — with its M2M and inbound relations — from the audit row. 6-Type Audit Trail soft_delete, cascade_soft_delete, restore, cascade_restore, permanent_delete, auto_cleanup — with severity Info / Warning / Critical.
Analytics Dashboard KPI deltas, deletion-rate trend, severity donut, top deleters, time heatmap, model risk. Per-User Permission Matrix Three toggles per (user, model): Soft Delete, Restore, Permanent Delete. Deny by default.
Auto-Cleanup & Retention Two daily cron jobs: TTL on soft-deleted records and TTL on audit log entries. Email Alerts & XLSX Export Severity-coloured email on every permanent or bulk delete. Filtered audit logs export to Excel.

How It Works

1
Configure Protected Models Pick the Odoo models you want to protect (up to 5 by default, raise the cap up to 100). The mixin is injected and an x_is_deleted flag is added.
2
Delete Triggers Soft Delete When a user deletes a protected record, the override sets x_is_deleted=True and the row vanishes from list, form, kanban, and graph views via an automatic domain filter.
3
Children Cascade with the Parent Inbound FK children are soft-deleted alongside the parent, all linked by a single batch UUID and a parent-log pointer for traceable trees.
4
Every Action is Audited User, company, model, record, IP, user-agent, reason, batch ID, severity — written to an immutable, read-only audit log.
5
Recover from the Recycle Bin Open the Recycle Bin tree filtered to x_is_deleted=True. Click Restore to bring back, or Permanently Delete — both gated by per-user permissions.
6
Recreate from Snapshot, Even After a Permanent Delete Permanent deletes save a JSON snapshot first. Open the audit row and click Recreate Record from Backup — the record and its cascade tree return with relations reapplied.

How Every Feature Works

A function-by-function breakdown so you know exactly what the module does before you install it.

1. Soft Delete Engine — the foundation

A single abstract model, soft.delete.mixin, gives every protected model the same reversible-delete behaviour without touching the model's own code.

  • The flag: a Boolean x_is_deleted field is added to each protected model.
  • The override: calling unlink() sets the flag to True; the row stays in the database.
  • The escape hatch: passing _force_unlink=True in the call context performs a real DB delete — used by Permanent Delete and the auto-cleanup cron.
  • The filter: every list, form, kanban, and graph action is rewritten with [('x_is_deleted','=',False)], so soft-deleted rows disappear automatically.
  • The Recycle Bin: a parallel tree filtered to x_is_deleted=True exposes the hidden rows for review and recovery.

2. Cascade Soft Delete & Restore

A parent never leaves its children behind. Cascading is unconditional and symmetric — the same tree comes back when the parent is restored.

  • On delete: every row that holds an inbound foreign key to the parent is soft-deleted with action type cascade_soft_delete.
  • Batch ID: all entries from one operation share a UUID stored on each audit row, so the whole tree is queryable in one filter.
  • Parent pointer: each child log carries parent_log_id → the parent's audit row, exposed under the Related Entries tab.
  • On restore: the same children are restored with action type cascade_restore, preserving the batch ID and parent link.

3. Permanent Delete with JSON Snapshot

Even permanent isn't permanent. Before any row leaves the database, the module writes everything needed to recreate it.

  • Step 1 — serialize: every stored field of the record is dumped into record_data_snapshot (a JSON Text field on the audit row).
  • Step 2 — relation walk: every inbound Many2one and Many2many referrer is recorded in a relations snapshot for later replay.
  • Step 3 — hard unlink: the row is removed with _force_unlink=True; the audit row is the only thing left.
  • Severity Critical: the audit entry is auto-flagged Critical so it stands out in dashboards and emails.

4. Restore from Snapshot — recovery after permanent delete

Open any audit row whose snapshot is present and click Recreate Record from Backup.

  • Recreate the parent: action_restore_from_snapshot rebuilds the original record from its JSON.
  • Recreate the tree: the cascade is followed via parent_log_id to recreate every child.
  • ID remapping: the new IDs assigned by Odoo are remapped across the tree so foreign keys point to the right rows.
  • Reapply relations: _sd_reapply_relations rebuilds Many2many links and inbound M2O / M2M references that pointed to the old record.

5. Audit Trail (soft.delete.audit.log)

Every lifecycle event is recorded with full context. The log is read-only from the UI; only SUPERUSER can intervene.

Action Severity When it fires
soft_delete Info A user soft-deletes a protected record.
cascade_soft_delete Warning Children follow a parent soft delete.
restore Info A user restores a soft-deleted record.
cascade_restore Info Children follow a parent restore.
permanent_delete Critical A user hard-deletes from the Recycle Bin.
auto_cleanup Critical The cron permanently deletes an expired soft-deleted row.
  • What's captured: user, company, model + record name, IP, user-agent, deletion reason, batch ID, parent log link, severity, timestamp, full record snapshot.
  • Tree view: colour-coded per severity (red / yellow / green / blue) and read-only — no edits or deletes from the UI.
  • Search: filter by user, model, action, batch, severity, or date range.
  • Export: one-click Export to XLSX with severity-coloured rows (export_audit_logs_xlsx).
  • Manual alert: Send Email Alert button on the audit form to notify after the fact.

6. Analytics Dashboard (soft.delete.dashboard)

A standalone dashboard built on aggregate audit data. Toggle off with enable_dashboard=False if you don't need it.

  • KPI cards with deltas: totals for the current window vs. the previous equal-length window, with % change.
  • Deletion-rate trend: daily counts across all configured models with a 7-day moving average (window length configurable).
  • Top deleters leaderboard: users ranked by deletion count.
  • Severity breakdown donut: Info / Warning / Critical share of audit volume.
  • Per-model sparklines: 14-day micro-trends per protected model.
  • Fastest-growing model: alert highlighting the model with the largest positive delta.
  • Time pattern heatmap: hour-of-day × day-of-week deletion density.
  • User activity scores: risk score per user, weighted by severity (Info×1, Warning×2, Critical×5; weights configurable).
  • Model risk analysis: models ranked on total_deletes + permanent_deletes×3.
  • Recent deletions stream: latest soft-deletes across every model in one feed.

7. Per-User Permission Matrix (soft.delete.user.permission)

Three independent toggles per (user, model) pair. Permissions are explicit — no row, no access.

  • Can Soft Delete — send a record to the Recycle Bin.
  • Can Restore — bring a record back from the Recycle Bin.
  • Can Permanently Delete — hard-delete a record from the Recycle Bin (high-risk; off by default).
  • Deny by default: a user with no permission row for a model gets nothing. Even System Administrators are gated; only the SUPERUSER (uid 1) bypasses.
  • Bulk helpers on the user form: Add All Protected Models populates rows with safe defaults (soft=on, restore=off, permanent=off); Clear All wipes them.
  • Two-layer enforcement:
    • Server-side gate _sd_can(action, model_name) — final authority, raises AccessError on deny.
    • Front-end RPC sd_get_button_perms(model_name) — pre-hides buttons in list, kanban, and form views; cached for 10 seconds.
  • Row decorations: green when all three are checked, yellow when soft+restore only, red when none.

8. Email Notifications

Severity-coloured HTML alerts driven by the soft_delete_audit_notification_template.

  • Header bar coloured by severity: red (Critical), yellow (Warning), green (Info).
  • Body fields: action, user, model, record + display name, record count, date, IP, deletion reason, details, batch ID, snapshot availability.
  • Per-event trigger: every permanent delete (toggle notify_on_permanent_delete).
  • Threshold trigger: when a single batch exceeds bulk_delete_threshold (default 10).
  • Recipient list: configurable per soft.delete.manage record via notification_user_ids.

9. Schedulers (Cron Jobs)

Two daily, unlimited-recurrence cron jobs in data/soft_delete_cron.xml:

  • Soft Delete: Auto-Cleanup Expired Records — _cron_auto_cleanup. Permanently deletes rows whose x_is_deleted=True is older than auto_cleanup_days. Default is 0 (disabled). Each row removed gets an auto_cleanup audit entry with a snapshot first.
  • Soft Delete: Cleanup Old Audit Logs — cleanup_old_logs. Removes audit rows older than audit_log_retention_days (default 90) so the log table never bloats.

10. Reason Wizard (soft.delete.reason.wizard)

A transient pop-up that captures the why before a record leaves the active dataset. Triggered from the form view's Delete with Reason action-menu item.

  • Three fields: reason (required Text), res_model (target model), res_ids (JSON list of IDs — supports batch).
  • Confirm path: action_confirm parses the JSON IDs, calls unlink() with the reason planted in self.env.context['soft_delete_reason'], then closes itself.
  • Audit pick-up: the mixin reads the reason from the context and stores it on the audit row's deletion_reason field, surfacing it in the email template and dashboard.
  • Permission gated: the menu item only appears if the user has can_soft_delete for that model.

11. Recycle Bin & "All Modules" Live View

Two complementary ways to find soft-deleted rows — one per model, one across every protected model in a single grid.

  • Per-model: the Recover Deleted button on any list or kanban view opens a transient wizard listing the deleted rows for that model. The wizard is created dynamically when the model is first protected, so every protected model gets its own tailor-made Recycle Bin.
  • Cross-model: the All Modules menu (soft.delete.manager.all.modules) renders a SQL view enumerating every dynamically-created wizard model with a live deleted-record count. The view is dropped and recreated on every search so the numbers are always fresh, never cached.
  • Reverse name mapping: wizard names like x_partner_custom_wizard are mapped back to source model names like partner.custom via _get_source_model_name — clicking a row in All Modules opens the matching Recycle Bin tree.
  • Empty-safe SQL: when no wizard tables exist yet (fresh install), the underlying UNION ALL falls back to a no-op WHERE FALSE stub instead of erroring.

12. Custom Tracking Fields (the x_* set)

When a model is added to soft.delete.manage.model_ids, eight fields are auto-injected via _ensure_soft_delete_fields. All are stored, readonly to users, marked state='manual', and have copied=False so they never leak into duplicates.

Field Type What it stores
x_is_deleted Boolean The soft-delete flag (the rest of the system reads this).
x_deleted_by Many2one → res.users The user who triggered the soft delete.
x_deleted_date Datetime When the soft delete fired.
x_deletion_reason Text Reason captured by the Reason Wizard, if any.
x_cascade_deleted_from Char Breadcrumb "parent_model,parent_id" for rows that were soft-deleted by cascade.
x_restored_by Many2one → res.users The user who restored the row (if it was restored).
x_restored_date Datetime When the restore happened.
x_relations_snapshot Text (JSON) Inbound M2O / M2M references cleared on cascade delete — replayed by _sd_reapply_relations on restore.

13. Multi-Company Support

Audit data is correctly attributed to the right company in multi-company databases — even when SUPERUSER is the actor.

  • Auto-resolved company: log_action fills company_id from the acting user's company; for SUPERUSER it uses self.env.company.id; failures default to False rather than raising.
  • Search filters: the audit-log search view exposes Company as a field, filter, and group-by — all conditional on base.group_multi_company.
  • Record-rule friendly: standard Odoo record rules on res.company apply automatically; users only see audit rows for companies they're allowed to read.
  • Email recipients: the notification_user_ids recipient list is per soft.delete.manage record, so each company can configure its own alert routing.

Settings & Configuration

Every tunable lives in Settings → Soft Delete (global) or on the Soft Delete Settings form (per-config). Defaults are sensible — touch them only when you need to.

Limits & Caps

Key Default Purpose
max_models 5 (max 100) Maximum protected models per config record.
top_users_limit 10 Top deleters slice on the dashboard.
top_models_limit 10 Model inventory rows on the dashboard.
recent_entries_limit 20 Recent deletions stream length.
trend_window_days 30 Days covered by the deletion-rate trend chart.
moving_avg_days 7 Smoothing window for the moving average overlay.
user_scores_limit 15 Rows in the user activity scores table.

Severity Score Weights

Key Default Purpose
score_info 1 Weight applied to Info-severity actions in user risk scores.
score_warning 2 Weight for Warning-severity actions.
score_critical 5 Weight for Critical-severity actions.

Privacy & Performance Toggles

Key Default Purpose
enable_ip_tracking true Capture client IP in audit logs.
enable_user_agent_tracking true Capture browser user-agent in audit logs.
enable_undo_toast true Show an undo toast immediately after a soft delete.
enable_xlsx_export true Allow audit log export to Excel.
enable_dashboard true Master kill-switch for the analytics dashboard (turn off if you don't need it).

Defaults for New soft.delete.manage Records

Key Default Purpose
default_bulk_delete_threshold 10 Default bulk-delete email-alert threshold.
default_audit_log_retention_days 90 Default TTL for audit log rows.
default_auto_cleanup_days 0 (disabled) Default TTL for soft-deleted records (0 disables auto-cleanup).

Per-Config Toggles (Soft Delete Settings form)

  • Email alerts: notify_on_permanent_delete, notify_on_bulk_delete, bulk_delete_threshold, notification_user_ids.
  • Retention: auto_cleanup_days, audit_log_retention_days (override the global defaults per config).
  • Uninstall preferences: per-model Recover vs Delete choice; bulk Recover All / Permanently Delete All helpers; live summary of expected outcome on uninstall.

Frontend Layer

The browser-side patches that put the soft-delete UI into Odoo's list, kanban, and form controllers — plus the Archive Vault dashboard component and its themes.

Utility Layer (soft_delete_utils.js)

Shared helpers that every view controller calls before deciding which buttons to render.

  • checkSoftDeleteEnabled(orm, modelName) — calls res.users.sd_is_model_protected() over RPC and remembers the answer for the rest of the session. Fail-closed: if the call errors, the buttons are hidden so we don't advertise a broken feature.
  • getSoftDeletePerms(orm, modelName) — calls res.users.sd_get_button_perms() and caches the three booleans for 10 seconds. Fail-open: if the call errors, the buttons are shown but the server-side gate _sd_can still blocks the action, so nothing slips through.
  • clearSoftDeleteCache(modelName) and clearSoftDeletePermsCache(modelName) — manual invalidation hooks; pass no argument to wipe the entire cache.
  • No leading underscores: Odoo's JSON-RPC layer rejects calls to private methods, so every cache helper is deliberately exposed with a public name.

List & Kanban View Buttons

Two patches inject the same UI into both list and kanban controllers (soft_delete_tree_view_header_button.js and soft_delete_kanban_view_header_button.js).

  • Recover Deleted button in the view header — only rendered if the model is protected and the current user has can_restore=True. Click opens the Recycle Bin tree pre-populated for that model.
  • Delete with Reason entry in the bulk-action dropdown — triggers the Reason Wizard with the selected IDs.
  • Undo toast after every soft delete (controlled by enable_undo_toast). The toast carries an Undo action that calls soft.delete.manage.restore_records and reloads the list. Auto-dismisses on navigation.
  • Display name fetch: on click, the button does a small ir.model.search_read call so the wizard window title shows "Recycle Bin: Sales Order" instead of "Recycle Bin: sale.order".

Form View Action Menu (soft_delete_form_view_header_button.js)

Patches FormController to add two action-menu items on protected models.

  • Delete with Reason — opens the Reason Wizard for the current record. Visible only when can_soft_delete=True.
  • Open Recycle Bin — jumps to the per-model Recycle Bin tree. Visible only when can_restore=True.
  • Post-delete redirect: after a successful soft delete, the form redirects to the model's list view since the current record is no longer visible there.

Archive Vault Dashboard Component (soft_delete_dashboard.js / .xml)

An OWL component (SoftDeleteDashboard) that renders every chart and table you see on the Archive Vault page.

  • Filter bar: period chips (7 d, 30 d, 90 d, custom), date pickers, model dropdown, user dropdown.
  • Auto-refresh: a checkbox in the header toggles a 60-second polling loop. The loop is cleared automatically on component unmount so it never leaks.
  • Drill-down: clicking any KPI, severity slice, model bar, user score, or timeline row routes to the audit log tree view with a pre-built domain — one click takes you from "who made the most permanent deletes last week" to the actual rows.
  • Export: a Download button calls export_dashboard_xlsx with the active filters and streams an Excel file back.
  • Initial period: derived from the session-info payload (see below) so the chart range matches the global setting on load.
  • Disabled state: when enable_dashboard=false, the server returns {enabled:false} and the component renders a friendly placeholder instead of empty charts.

Session-Info Injection (ir.http override)

A small session_info() override pushes four configuration values into every page-load payload so the JS layer never has to do a synchronous bootstrap call.

  • enable_undo_toast — read by the list controller before showing the post-delete notification.
  • enable_dashboard — read by the dashboard component to short-circuit data loading when off.
  • enable_xlsx_export — read to hide the Excel-export buttons when off.
  • trend_window_days — sets the dashboard's initial period chip without a round trip.
  • Fail-safe: the override is wrapped in try/except and falls back to safe defaults so a misconfiguration can never break the session bootstrap.

Themes (SCSS)

Two SCSS files style the dashboard and an opt-in dark "hacker" overlay for individual list/form views.

  • soft_delete_dashboard.scss — slate + rust-orange professional theme with dual-layer KPI cards, chip-style filters, and a body-class scrollbar fix scoped via .sdr-dashboard-mounted so the override never leaks out of the dashboard.
  • soft_delete_hacker.scss — opt-in phosphor-green-on-near-black overlay activated by adding class="o_sdr_hacker" to a tree or form arch root. The v10.7.22 selector chain uses bare .o_sdr_hacker, the :has() traversal, and explicit .o_form_renderer.o_sdr_hacker together so the styles attach no matter where Odoo 16 puts the class. A subtle text-shadow glow is applied via the hk-glow mixin.

Module Lifecycle

What happens on every server start and at uninstall — with safety nets at every step.

Server Start — _register_hook (relation tables)

Runs every time the registry is built. Idempotent — never re-creates what already exists.

  • Two M2M relation tables created if missing: res_config_settings_model_ids_rel and res_config_settings_specific_models_recover_rel.
  • Existence check first: information_schema.tables is queried before any DDL; no destructive operations run unconditionally.
  • UNIQUE INDEX on (config_id, model_id) for data integrity.
  • Silent on duplicates: table-already-exists and index-already-exists errors are swallowed so a fresh install and an upgrade behave identically.

Uninstall Wizard (base.module.uninstall override)

When a user clicks Uninstall on the Soft Delete Manager module, the standard Odoo uninstall wizard gets an extra tab where each protected model is listed with a per-model Recover vs Delete choice.

  • Pre-populated: the wizard's default_get reads the saved decisions from soft.delete.manage.uninstall_line_ids, so administrators can configure their preferences months ahead.
  • Live summary: a computed sentence at the top — "Will recover 42 records across 3 models; permanently delete 10 records across 2 models" — updates as the choices change.
  • Bulk helpers: one-click Recover All and Permanently Delete All buttons.
  • Phantom-row hardening: the transient model's create/write overrides silently drop empty (0, 0, {}) commands the web client emits when reconciling the One2many field, so opening the wizard twice never breaks state.
  • Persistence to ir.config_parameter: action_uninstall serialises the decisions as JSON into the soft_delete_recovery.uninstall_preferences parameter before the parent uninstall runs, because the persistent tables are gone by the time the post-uninstall hook fires.

Uninstall — uninstall_hook

Runs after the records and views have been removed but before the registry forgets the module. Reads the JSON preferences and acts on them.

  • Resolve preferences: reads soft_delete_recovery.uninstall_preferences; falls back to legacy comma-separated id-list parameters if the JSON variant is missing.
  • SAVEPOINT-isolated per-model action: for every (model, action) pair the hook opens a SAVEPOINT, runs the action (recover → x_is_deleted=False; delete → unlink_original), and either RELEASEs or ROLLBACKs that savepoint. One model failing does not poison the rest.
  • Audit-log the cleanup: each row touched gets a restore or auto_cleanup entry so the log preserves the trail even after the module is gone.
  • Final cleanup: the action_cleanup_soft_delete method strips custom views, server actions, and dynamically-created fields; then every soft_delete_recovery.* parameter is wiped so a future reinstall starts clean.

Models Reference

Every Python model the module ships, organised by layer.

Core layer

Model Kind Role
soft.delete.mixin AbstractModel Adds x_is_deleted and overrides unlink() on every protected model.
soft.delete.manage Model Central config: protected models, retention, alerts, uninstall preferences. Owns _ensure_soft_delete_fields and action_cleanup_soft_delete.
soft.delete.audit.log Model Immutable lifecycle log + every analytics method consumed by the dashboard + restore-from-snapshot.
soft.delete.dashboard AbstractModel Aggregates audit data into the get_dashboard_data payload (KPI deltas, sparklines, severity donut, fastest-growing model).
soft.delete.user.permission Model Per-user, per-model 3-flag matrix. Unique on (user_id, model_id).
soft.delete.reason.wizard TransientModel Captures the deletion reason and forwards it to the mixin via context.
soft.delete.manager.all.modules Model (SQL view, _auto=False) Live UNION ALL across every wizard table for the cross-model Recycle Bin grid.

Extensions to standard Odoo models

Inherits What's added
res.users Permissions tab on the user form, bulk helpers, the _sd_can server gate, and the public RPCs sd_get_button_perms / sd_is_model_protected.
res.config.settings Every global tunable surfaced earlier in Settings & Configuration.
ir.http session_info() override pushing four feature flags into the page-load payload.
base.module.uninstall Per-model recover/delete decision tab + savepoint-isolated execution path for soft-delete-aware uninstalls.

Helper / lifecycle

Model Role
soft.delete.manage.uninstall.line Persistent per-model recover/delete decision; unique on (manage_id, model_id).
soft.delete.uninstall.line.wizard Transient mirror of the line model with phantom-row filtering for the wizard form.
execute.soft.delete.rel.tables AbstractModel; _register_hook creates the two M2M relation tables idempotently at every server start.
soft.delete.manager.config (legacy) Older configuration model retained for backward compatibility — not the active flow.

Compatibility

Odoo 16 Community Odoo 16 Enterprise Python 3.8+
PostgreSQL 12+ OWL 2.0 Any Odoo Model

Quick Start

1
Drop the module into your Odoo addons directory and refresh the Apps list.
2
Search for "Soft Delete Manager" and install.
3
Open Soft Delete Manager → Soft Delete Settings and pick the models to protect.
4
Grant access on the user form's Soft Delete Permissions tab — remember deny by default.
5
Tune limits, weights, and toggles in Settings → Soft Delete. Use "Recover Deleted" on any list/kanban to find the Recycle Bin.

Ready to Get Started?

Reversible deletes, cascade-aware recovery, snapshot backup, and an audit trail you can trust.

Install Now — $199.99
Support
Author: DC Software
dcsoftware.support@gmail.com
License
LGPL-3
Version 16.0.10.7.22 | Odoo 16

Please log in to comment on this module

  • The author can leave a single reply to each comment.
  • This section is meant to ask simple questions or leave a rating. Every report of a problem experienced while using the module should be addressed to the author directly (refer to the following point).
  • If you want to start a discussion with the author or have a question related to your purchase, please use the support page.
Community
  • Tutorials
  • Documentation
  • Forum
Open Source
  • Download
  • Github
  • Runbot
  • Translations
Services
  • Odoo.sh Hosting
  • Support
  • Upgrade
  • Custom Developments
  • Education
  • Find an Accountant
  • Find a Partner
  • Become a Partner
About us
  • Our company
  • Brand Assets
  • Contact us
  • Jobs
  • Events
  • Podcast
  • Blog
  • Customers
  • Legal • Privacy
  • Security

Odoo is a suite of open source business apps that cover all your company needs: CRM, eCommerce, accounting, inventory, point of sale, project management, etc.

Odoo's unique value proposition is to be at the same time very easy to use and fully integrated.

Website made with