Skip to content

Commit 15e72f7

Browse files
author
John75SunCity
committed
feat: Add bin migration wizard to consolidate bin models
- Created bin_migration_wizard to migrate records from: - barcode.storage.box (Bin Barcode Inventory - 838 records) - shred.bin (Customer Shred Bins) to shredding.service.bin (primary model for work order scanning) - Wizard features: - Preview source and target record counts - Skip duplicate barcodes option - Archive source records after migration - Default bin size selection - Migration log with results - Added menu item under Configuration > Migrate Bins to Service Bins
1 parent 451620b commit 15e72f7

File tree

5 files changed

+253
-0
lines changed

5 files changed

+253
-0
lines changed

records_management/__manifest__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,7 @@
599599
"views/unified_work_order_views.xml",
600600
"views/rm_sale_order_views.xml", # Sale order extension for work order integration
601601
"wizards/work_order_wizard_views.xml", # Multi-step work order creation wizard
602+
"wizards/bin_migration_wizard_views.xml", # Migrate bins from redundant models
602603
"views/visitor_views.xml",
603604
"views/wizard_template_views.xml",
604605
"views/work_order_creation_wizard_views.xml",

records_management/security/ir.model.access.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,3 +1009,4 @@ access_shredding_bin_scan_wizard_user,shredding.bin.scan.wizard.user,model_shred
10091009
access_shredding_bin_scan_wizard_manager,shredding.bin.scan.wizard.manager,model_shredding_bin_scan_wizard,records_management.group_records_manager,1,1,1,1
10101010
access_rm_work_order_wizard_user,rm.work.order.wizard.user,model_rm_work_order_wizard,records_management.group_records_user,1,1,1,0
10111011
access_rm_work_order_wizard_manager,rm.work.order.wizard.manager,model_rm_work_order_wizard,records_management.group_records_manager,1,1,1,1
1012+
access_bin_migration_wizard_manager,bin.migration.wizard.manager,model_bin_migration_wizard,records_management.group_records_manager,1,1,1,1

records_management/wizards/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,4 @@
4444
from . import scanbot_barcode_scanner_wizard
4545
from . import barcode_sheet_wizard
4646
from . import work_order_wizard # Multi-step work order creation wizard
47+
from . import bin_migration_wizard # Migrate bins from redundant models
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Bin Migration Wizard
4+
5+
Migrates bins from barcode.storage.box to shredding.service.bin
6+
to consolidate duplicate bin inventory systems.
7+
"""
8+
9+
from odoo import models, fields, api, _
10+
from odoo.exceptions import UserError
11+
12+
13+
class BinMigrationWizard(models.TransientModel):
14+
"""Wizard to migrate bins from barcode.storage.box to shredding.service.bin."""
15+
16+
_name = 'bin.migration.wizard'
17+
_description = 'Migrate Bins to Shredding Service Bins'
18+
19+
# Source selection
20+
source_model = fields.Selection([
21+
('barcode.storage.box', 'Barcode Storage Box (Bin Barcode Inventory)'),
22+
('shred.bin', 'Shred Bin (Customer Shred Bins)'),
23+
], string="Migrate From", required=True, default='barcode.storage.box')
24+
25+
# Preview counts
26+
source_count = fields.Integer(string="Source Records", compute='_compute_counts')
27+
existing_count = fields.Integer(string="Existing Service Bins", compute='_compute_counts')
28+
29+
# Options
30+
skip_duplicates = fields.Boolean(
31+
string="Skip Duplicates",
32+
default=True,
33+
help="Skip records where barcode already exists in shredding.service.bin"
34+
)
35+
36+
archive_source = fields.Boolean(
37+
string="Archive Source Records After Migration",
38+
default=True,
39+
help="Set source records to inactive after successful migration"
40+
)
41+
42+
default_bin_size = fields.Selection([
43+
('23', '23 Gallon Shredinator'),
44+
('32g', '32 Gallon Bin'),
45+
('32c', '32 Gallon Console'),
46+
('64', '64 Gallon Bin'),
47+
('96', '96 Gallon Bin'),
48+
], string="Default Bin Size", default='32g',
49+
help="Bin size to use when source record doesn't specify")
50+
51+
# Results
52+
migrated_count = fields.Integer(string="Migrated", readonly=True)
53+
skipped_count = fields.Integer(string="Skipped (Duplicates)", readonly=True)
54+
error_count = fields.Integer(string="Errors", readonly=True)
55+
migration_log = fields.Text(string="Migration Log", readonly=True)
56+
57+
@api.depends('source_model')
58+
def _compute_counts(self):
59+
"""Compute record counts for preview."""
60+
for wizard in self:
61+
if wizard.source_model:
62+
wizard.source_count = self.env[wizard.source_model].search_count([])
63+
else:
64+
wizard.source_count = 0
65+
wizard.existing_count = self.env['shredding.service.bin'].search_count([])
66+
67+
def _map_bin_size(self, source_record):
68+
"""Map source bin size to shredding.service.bin bin_size selection."""
69+
# Try to get bin_size from source
70+
if hasattr(source_record, 'bin_size') and source_record.bin_size:
71+
return source_record.bin_size
72+
73+
# Try container_type mapping (from barcode.storage.box)
74+
if hasattr(source_record, 'container_type') and source_record.container_type:
75+
mapping = {
76+
'type_01': '23', # Small boxes map to 23 gallon
77+
'type_02': '32g', # Standard to 32 gallon
78+
'type_03': '32c', # Console type
79+
'type_04': '64', # Large to 64 gallon
80+
'type_06': '96', # XL to 96 gallon
81+
}
82+
return mapping.get(source_record.container_type, self.default_bin_size)
83+
84+
return self.default_bin_size
85+
86+
def action_preview(self):
87+
"""Refresh counts and show preview."""
88+
self._compute_counts()
89+
return {
90+
'type': 'ir.actions.act_window',
91+
'res_model': self._name,
92+
'res_id': self.id,
93+
'view_mode': 'form',
94+
'target': 'new',
95+
}
96+
97+
def action_migrate(self):
98+
"""Execute the migration."""
99+
self.ensure_one()
100+
101+
if not self.source_model:
102+
raise UserError(_("Please select a source model to migrate from."))
103+
104+
SourceModel = self.env[self.source_model]
105+
TargetModel = self.env['shredding.service.bin']
106+
107+
source_records = SourceModel.search([('active', 'in', [True, False])])
108+
109+
migrated = 0
110+
skipped = 0
111+
errors = 0
112+
log_lines = []
113+
114+
for record in source_records:
115+
try:
116+
barcode = record.barcode if hasattr(record, 'barcode') else None
117+
118+
if not barcode:
119+
log_lines.append(_("SKIP: Record %s has no barcode") % record.id)
120+
skipped += 1
121+
continue
122+
123+
# Check for duplicates
124+
if self.skip_duplicates:
125+
existing = TargetModel.search([('barcode', '=', barcode)], limit=1)
126+
if existing:
127+
log_lines.append(_("SKIP: Barcode %s already exists") % barcode)
128+
skipped += 1
129+
continue
130+
131+
# Prepare values for new record
132+
vals = {
133+
'barcode': barcode,
134+
'bin_size': self._map_bin_size(record),
135+
'status': 'available',
136+
'manual_size_override': True, # Since we're setting size manually
137+
}
138+
139+
# Map optional fields
140+
if hasattr(record, 'name') and record.name:
141+
vals['name'] = record.name
142+
143+
if hasattr(record, 'partner_id') and record.partner_id:
144+
vals['current_customer_id'] = record.partner_id.id
145+
146+
if hasattr(record, 'location_id') and record.location_id:
147+
vals['location_id'] = record.location_id.id
148+
149+
# Create the service bin
150+
TargetModel.create(vals)
151+
migrated += 1
152+
log_lines.append(_("OK: Migrated barcode %s") % barcode)
153+
154+
# Archive source if requested
155+
if self.archive_source and hasattr(record, 'active'):
156+
record.active = False
157+
158+
except Exception as e:
159+
errors += 1
160+
log_lines.append(_("ERROR: Record %s - %s") % (record.id, str(e)))
161+
162+
# Update wizard with results
163+
self.write({
164+
'migrated_count': migrated,
165+
'skipped_count': skipped,
166+
'error_count': errors,
167+
'migration_log': '\n'.join(log_lines[-100:]), # Last 100 lines
168+
})
169+
170+
# Return updated wizard
171+
return {
172+
'type': 'ir.actions.act_window',
173+
'res_model': self._name,
174+
'res_id': self.id,
175+
'view_mode': 'form',
176+
'target': 'new',
177+
'context': {'migration_complete': True},
178+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<odoo>
3+
<data>
4+
<!-- Bin Migration Wizard Form View -->
5+
<record id="bin_migration_wizard_view_form" model="ir.ui.view">
6+
<field name="name">bin.migration.wizard.form</field>
7+
<field name="model">bin.migration.wizard</field>
8+
<field name="arch" type="xml">
9+
<form string="Migrate Bins to Shredding Service Bins">
10+
<sheet>
11+
<div class="alert alert-info" role="alert">
12+
<h4><i class="fa fa-info-circle"/> Bin Migration Wizard</h4>
13+
<p>This wizard migrates bin records from redundant models to the primary
14+
<strong>Shredding Service Bins</strong> model, which integrates with
15+
work order scanning and billing.</p>
16+
</div>
17+
18+
<group>
19+
<group string="Source Selection">
20+
<field name="source_model" widget="radio"/>
21+
<field name="source_count" readonly="1"/>
22+
</group>
23+
<group string="Current Service Bins">
24+
<field name="existing_count" readonly="1"/>
25+
</group>
26+
</group>
27+
28+
<group string="Migration Options">
29+
<field name="default_bin_size"/>
30+
<field name="skip_duplicates"/>
31+
<field name="archive_source"/>
32+
</group>
33+
34+
<group string="Results" invisible="migrated_count == 0 and skipped_count == 0 and error_count == 0">
35+
<group>
36+
<field name="migrated_count"/>
37+
<field name="skipped_count"/>
38+
<field name="error_count"/>
39+
</group>
40+
</group>
41+
42+
<group string="Migration Log" invisible="not migration_log">
43+
<field name="migration_log" nolabel="1" readonly="1"/>
44+
</group>
45+
</sheet>
46+
47+
<footer>
48+
<button name="action_migrate" string="Migrate Bins" type="object"
49+
class="btn-primary" icon="fa-exchange"
50+
confirm="This will migrate bins to Shredding Service Bins. Continue?"/>
51+
<button string="Cancel" class="btn-secondary" special="cancel"/>
52+
</footer>
53+
</form>
54+
</field>
55+
</record>
56+
57+
<!-- Wizard Action -->
58+
<record id="bin_migration_wizard_action" model="ir.actions.act_window">
59+
<field name="name">Migrate Bins</field>
60+
<field name="res_model">bin.migration.wizard</field>
61+
<field name="view_mode">form</field>
62+
<field name="target">new</field>
63+
</record>
64+
65+
<!-- Menu Item in Configuration -->
66+
<menuitem id="menu_bin_migration_wizard"
67+
name="Migrate Bins to Service Bins"
68+
parent="records_management.menu_records_configuration"
69+
action="bin_migration_wizard_action"
70+
sequence="99"/>
71+
</data>
72+
</odoo>

0 commit comments

Comments
 (0)