30-day undo for accidental deletes on Perfex CRM. Snapshot, restore, purge.
Perfex hard-deletes everything. One wrong click = mysqldump in the best case, lost data in the worst. This module fixes that.
On every Perfex before_*_deleted hook for the entities below, the row (and its critical children) is snapshotted to JSON in a dedicated tbltrash table before Perfex actually deletes it. You get a Trash page with one-click Restore and a configurable retention window (default 30 days, max 365).
Coverage:
| Entity | Primary row | Children snapshotted |
|---|---|---|
| Invoice | tblinvoices |
itemable, item_tax, customfieldsvalues, taggables |
| Estimate | tblestimates |
same as invoice |
| Proposal | tblproposals |
same as invoice |
| Credit note | tblcreditnotes |
same as invoice |
| Project | tblprojects |
project_members, project_settings |
| Task | tbltasks |
task_assigned, task_followers, task_comments, task_checklist_items |
| Client | tblclients |
contacts |
| Contract | tblcontracts |
— |
| Expense | tblexpenses |
— |
| Lead | tblleads |
— |
| Ticket | tbltickets |
ticket_replies |
- Copy
trash_bin/into<perfex-root>/modules/. - Setup → Modules → activate Trash Bin.
- Done. Anything you delete from now on lands in Setup → Trash.
Already-deleted records are not recoverable — only deletions occurring after activation are protected. (You'd be surprised how often someone activates Trash Bin in a panic after a deletion. Yeah. Sorry.)
- If the original ID is still free in the target table, the record is restored with the same ID (foreign keys to it work again).
- If the ID is already taken (someone created a new record between deletion and restore), the record is restored with a new auto-incremented ID. FKs from child rows are re-pointed automatically.
- Child rows are always inserted with a new auto-ID and re-pointed to the (possibly new) parent ID.
The restore runs inside a DB transaction — partial restores can't happen.
- Hooks into Perfex's
app_cron(runs whenever Perfex's existing cron triggers). - Deletes trash rows older than the configured retention.
- Configurable from the Trash page: 1 to 365 days.
MIT — © 2026 MogaCode.