Add print badges, pagination, route splitting, JWT auth fixes, and list page alignment
- Fix equipment badge barcode not rendering (loading race condition) - Fix printer QR code not rendering on initial load (same race condition) - Add model image to equipment badge via imageurl from Model table - Fix white-on-white machine number text on badge, tighten barcode spacing - Add PaginationBar component used across all list pages - Split monolithic router into per-plugin route modules - Fix 25 GET API endpoints returning 401 (jwt_required -> optional=True) - Align list page columns across Equipment, PCs, and Network pages - Add print views: EquipmentBadge, PrinterQRSingle, PrinterQRBatch, USBLabelBatch - Add PC Relationships report, migration docs, and CLAUDE.md project guide - Various plugin model, API, and frontend refinements Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
321
migrations/DATA_MIGRATION_GUIDE.md
Normal file
321
migrations/DATA_MIGRATION_GUIDE.md
Normal file
@@ -0,0 +1,321 @@
|
||||
# ShopDB Flask Data Migration Guide
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes how to migrate data from the legacy `shopdb` database to the new `shopdb_flask` database schema.
|
||||
|
||||
## Database Configuration
|
||||
|
||||
**Development:**
|
||||
- Legacy database: `shopdb` (Classic ASP/VBScript schema)
|
||||
- New database: `shopdb_flask` (Flask/SQLAlchemy schema)
|
||||
- Connection: `mysql+pymysql://root:rootpassword@127.0.0.1:3306/shopdb_flask`
|
||||
|
||||
**Production:**
|
||||
- Follow the same migration steps on production MySQL server
|
||||
- Update connection string in `.env` accordingly
|
||||
|
||||
## Schema Differences
|
||||
|
||||
### Legacy Schema (shopdb)
|
||||
- `machines` table holds ALL assets (equipment, PCs, network devices)
|
||||
- `printers` table is separate
|
||||
- No unified asset abstraction
|
||||
|
||||
### New Schema (shopdb_flask)
|
||||
- `assets` table: Core asset data (shared fields)
|
||||
- `assettypes` table: Asset category registry
|
||||
- Plugin extension tables:
|
||||
- `equipment` - Manufacturing equipment details
|
||||
- `computers` - PC-specific fields
|
||||
- `networkdevices` - Network device details
|
||||
- `printers` - Printer-specific fields
|
||||
- Each extension links to `assets` via `assetid`
|
||||
|
||||
## Migration Steps
|
||||
|
||||
### Step 1: Seed Reference Data
|
||||
|
||||
```bash
|
||||
cd /home/camp/projects/shopdb-flask
|
||||
source venv/bin/activate
|
||||
flask seed reference-data
|
||||
```
|
||||
|
||||
This creates:
|
||||
- Asset types (equipment, computer, network_device, printer)
|
||||
- Asset statuses (In Use, Spare, Retired, etc.)
|
||||
- Machine types, operating systems, relationship types
|
||||
|
||||
### Step 2: Migrate Asset Types
|
||||
|
||||
```sql
|
||||
-- Insert asset types if not exists
|
||||
INSERT INTO assettypes (assettype, pluginname, tablename, description) VALUES
|
||||
('equipment', 'equipment', 'equipment', 'Manufacturing equipment'),
|
||||
('computer', 'computers', 'computers', 'PCs and workstations'),
|
||||
('network_device', 'network', 'networkdevices', 'Network infrastructure'),
|
||||
('printer', 'printers', 'printers', 'Printers and MFPs')
|
||||
ON DUPLICATE KEY UPDATE assettype=assettype;
|
||||
```
|
||||
|
||||
### Step 3: Migrate Equipment
|
||||
|
||||
```sql
|
||||
-- Migrate equipment from legacy machines table
|
||||
INSERT INTO assets (assetid, assetnumber, name, serialnumber, assettypeid, statusid,
|
||||
locationid, businessunitid, mapleft, maptop, notes,
|
||||
createddate, modifieddate, isactive)
|
||||
SELECT
|
||||
m.machineid,
|
||||
m.machinenumber,
|
||||
m.alias,
|
||||
m.serialnumber,
|
||||
(SELECT assettypeid FROM assettypes WHERE assettype = 'equipment'),
|
||||
m.statusid,
|
||||
m.locationid,
|
||||
m.businessunitid,
|
||||
m.mapleft,
|
||||
m.maptop,
|
||||
m.notes,
|
||||
m.createddate,
|
||||
m.modifieddate,
|
||||
m.isactive
|
||||
FROM shopdb.machines m
|
||||
JOIN shopdb.machinetypes mt ON m.machinetypeid = mt.machinetypeid
|
||||
WHERE mt.category = 'Equipment'
|
||||
AND m.pctypeid IS NULL;
|
||||
|
||||
-- Insert equipment extension data
|
||||
INSERT INTO equipment (assetid, equipmenttypeid, vendorid, modelnumberid,
|
||||
controllertypeid, controllervendorid, controllermodelid)
|
||||
SELECT
|
||||
m.machineid,
|
||||
m.machinetypeid,
|
||||
m.vendorid,
|
||||
m.modelnumberid,
|
||||
m.controllertypeid,
|
||||
m.controllervendorid,
|
||||
m.controllermodelid
|
||||
FROM shopdb.machines m
|
||||
JOIN shopdb.machinetypes mt ON m.machinetypeid = mt.machinetypeid
|
||||
WHERE mt.category = 'Equipment'
|
||||
AND m.pctypeid IS NULL;
|
||||
```
|
||||
|
||||
### Step 4: Migrate PCs/Computers
|
||||
|
||||
```sql
|
||||
-- Migrate PCs to assets table
|
||||
INSERT INTO assets (assetid, assetnumber, name, serialnumber, assettypeid, statusid,
|
||||
locationid, businessunitid, mapleft, maptop, notes,
|
||||
createddate, modifieddate, isactive)
|
||||
SELECT
|
||||
m.machineid,
|
||||
m.machinenumber,
|
||||
m.alias,
|
||||
m.serialnumber,
|
||||
(SELECT assettypeid FROM assettypes WHERE assettype = 'computer'),
|
||||
m.statusid,
|
||||
m.locationid,
|
||||
m.businessunitid,
|
||||
m.mapleft,
|
||||
m.maptop,
|
||||
m.notes,
|
||||
m.createddate,
|
||||
m.modifieddate,
|
||||
m.isactive
|
||||
FROM shopdb.machines m
|
||||
WHERE m.pctypeid IS NOT NULL;
|
||||
|
||||
-- Insert computer extension data
|
||||
INSERT INTO computers (assetid, computertypeid, hostname, osid,
|
||||
loggedinuser, lastreporteddate, lastboottime,
|
||||
isvnc, iswinrm, isshopfloor)
|
||||
SELECT
|
||||
m.machineid,
|
||||
m.pctypeid,
|
||||
m.hostname,
|
||||
m.osid,
|
||||
m.loggedinuser,
|
||||
m.lastreporteddate,
|
||||
m.lastboottime,
|
||||
m.isvnc,
|
||||
m.iswinrm,
|
||||
m.isshopfloor
|
||||
FROM shopdb.machines m
|
||||
WHERE m.pctypeid IS NOT NULL;
|
||||
```
|
||||
|
||||
### Step 5: Migrate Network Devices
|
||||
|
||||
```sql
|
||||
-- Migrate network devices to assets
|
||||
INSERT INTO assets (assetid, assetnumber, name, serialnumber, assettypeid, statusid,
|
||||
locationid, businessunitid, mapleft, maptop, notes,
|
||||
createddate, modifieddate, isactive)
|
||||
SELECT
|
||||
m.machineid,
|
||||
m.machinenumber,
|
||||
m.alias,
|
||||
m.serialnumber,
|
||||
(SELECT assettypeid FROM assettypes WHERE assettype = 'network_device'),
|
||||
m.statusid,
|
||||
m.locationid,
|
||||
m.businessunitid,
|
||||
m.mapleft,
|
||||
m.maptop,
|
||||
m.notes,
|
||||
m.createddate,
|
||||
m.modifieddate,
|
||||
m.isactive
|
||||
FROM shopdb.machines m
|
||||
JOIN shopdb.machinetypes mt ON m.machinetypeid = mt.machinetypeid
|
||||
WHERE mt.category = 'Network';
|
||||
|
||||
-- Insert network device extension data
|
||||
INSERT INTO networkdevices (assetid, networkdevicetypeid, hostname, vendorid, modelnumberid)
|
||||
SELECT
|
||||
m.machineid,
|
||||
m.machinetypeid,
|
||||
m.hostname,
|
||||
m.vendorid,
|
||||
m.modelnumberid
|
||||
FROM shopdb.machines m
|
||||
JOIN shopdb.machinetypes mt ON m.machinetypeid = mt.machinetypeid
|
||||
WHERE mt.category = 'Network';
|
||||
```
|
||||
|
||||
### Step 6: Migrate Printers
|
||||
|
||||
```sql
|
||||
-- Migrate printers to assets (printers are in separate table in legacy)
|
||||
INSERT INTO assets (assetnumber, name, serialnumber, assettypeid, statusid,
|
||||
locationid, businessunitid, notes, createddate, modifieddate, isactive)
|
||||
SELECT
|
||||
p.hostname,
|
||||
p.windowsname,
|
||||
NULL,
|
||||
(SELECT assettypeid FROM assettypes WHERE assettype = 'printer'),
|
||||
1, -- Default status
|
||||
p.locationid,
|
||||
p.businessunitid,
|
||||
NULL,
|
||||
p.createddate,
|
||||
p.modifieddate,
|
||||
p.isactive
|
||||
FROM shopdb.printers p;
|
||||
|
||||
-- Insert printer extension data (need to get the new assetid)
|
||||
INSERT INTO printers (assetid, printertypeid, vendorid, modelnumberid, hostname,
|
||||
windowsname, sharename, iscsf, installpath, pin,
|
||||
iscolor, isduplex, isnetwork)
|
||||
SELECT
|
||||
a.assetid,
|
||||
p.printertypeid,
|
||||
p.vendorid,
|
||||
p.modelnumberid,
|
||||
p.hostname,
|
||||
p.windowsname,
|
||||
p.sharename,
|
||||
p.iscsf,
|
||||
p.installpath,
|
||||
p.pin,
|
||||
p.iscolor,
|
||||
p.isduplex,
|
||||
p.isnetwork
|
||||
FROM shopdb.printers p
|
||||
JOIN assets a ON a.assetnumber = p.hostname
|
||||
WHERE a.assettypeid = (SELECT assettypeid FROM assettypes WHERE assettype = 'printer');
|
||||
```
|
||||
|
||||
### Step 7: Migrate Communications (IP Addresses)
|
||||
|
||||
```sql
|
||||
-- Migrate communications/IP addresses
|
||||
INSERT INTO communications (machineid, assetid, comtypeid, address,
|
||||
subnetid, isprimary, createddate, modifieddate, isactive)
|
||||
SELECT
|
||||
c.machineid,
|
||||
c.machineid, -- assetid = machineid for migrated assets
|
||||
c.comtypeid,
|
||||
c.address,
|
||||
c.subnetid,
|
||||
c.isprimary,
|
||||
c.createddate,
|
||||
c.modifieddate,
|
||||
c.isactive
|
||||
FROM shopdb.communications c;
|
||||
```
|
||||
|
||||
### Step 8: Migrate Notifications
|
||||
|
||||
```sql
|
||||
INSERT INTO notifications (notificationid, notificationtypeid, businessunitid, appid,
|
||||
notification, starttime, endtime, ticketnumber, link,
|
||||
isactive, isshopfloor, employeesso, employeename)
|
||||
SELECT * FROM shopdb.notifications;
|
||||
```
|
||||
|
||||
### Step 9: Migrate Supporting Tables
|
||||
|
||||
```sql
|
||||
-- Vendors
|
||||
INSERT INTO vendors SELECT * FROM shopdb.vendors
|
||||
ON DUPLICATE KEY UPDATE vendor=VALUES(vendor);
|
||||
|
||||
-- Models
|
||||
INSERT INTO models SELECT * FROM shopdb.models
|
||||
ON DUPLICATE KEY UPDATE modelnumber=VALUES(modelnumber);
|
||||
|
||||
-- Locations
|
||||
INSERT INTO locations SELECT * FROM shopdb.locations
|
||||
ON DUPLICATE KEY UPDATE locationname=VALUES(locationname);
|
||||
|
||||
-- Business Units
|
||||
INSERT INTO businessunits SELECT * FROM shopdb.businessunits
|
||||
ON DUPLICATE KEY UPDATE businessunit=VALUES(businessunit);
|
||||
|
||||
-- Subnets
|
||||
INSERT INTO subnets SELECT * FROM shopdb.subnets
|
||||
ON DUPLICATE KEY UPDATE subnet=VALUES(subnet);
|
||||
```
|
||||
|
||||
## Verification Queries
|
||||
|
||||
```sql
|
||||
-- Check migration counts
|
||||
SELECT 'Legacy machines' as source, COUNT(*) as cnt FROM shopdb.machines
|
||||
UNION ALL SELECT 'New assets', COUNT(*) FROM shopdb_flask.assets
|
||||
UNION ALL SELECT 'Equipment', COUNT(*) FROM shopdb_flask.equipment
|
||||
UNION ALL SELECT 'Computers', COUNT(*) FROM shopdb_flask.computers
|
||||
UNION ALL SELECT 'Network devices', COUNT(*) FROM shopdb_flask.networkdevices
|
||||
UNION ALL SELECT 'Printers', COUNT(*) FROM shopdb_flask.printers;
|
||||
|
||||
-- Verify asset type distribution
|
||||
SELECT at.assettype, COUNT(a.assetid) as count
|
||||
FROM shopdb_flask.assets a
|
||||
JOIN shopdb_flask.assettypes at ON a.assettypeid = at.assettypeid
|
||||
GROUP BY at.assettype;
|
||||
```
|
||||
|
||||
## Production Deployment Notes
|
||||
|
||||
1. **Backup production database first**
|
||||
2. Create `shopdb_flask` database on production
|
||||
3. Run `flask db-utils create-all` to create schema
|
||||
4. Execute migration SQL scripts in order
|
||||
5. Verify data counts match
|
||||
6. Update Flask `.env` to point to production database
|
||||
7. Restart Flask services
|
||||
|
||||
## Rollback
|
||||
|
||||
If migration fails:
|
||||
1. Drop all tables in `shopdb_flask`: `flask db-utils drop-all`
|
||||
2. Recreate schema: `flask db-utils create-all`
|
||||
3. Investigate and fix migration scripts
|
||||
4. Re-run migration
|
||||
|
||||
---
|
||||
Last updated: 2026-01-28
|
||||
89
migrations/FIX_LOCATIONONLY_EQUIPMENT_TYPES.md
Normal file
89
migrations/FIX_LOCATIONONLY_EQUIPMENT_TYPES.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Fix LocationOnly Equipment Types Migration
|
||||
|
||||
## Issue
|
||||
During the original migration from the VBScript ShopDB site, 110 machines were imported with `LocationOnly` type even though they have models assigned that specify the correct equipment type.
|
||||
|
||||
## Root Cause
|
||||
The migration copied the `machinetypeid` directly from the `machines` table, but many machines had `machinetypeid=1` (LocationOnly) even when they had a model with a proper type.
|
||||
|
||||
## Affected Records
|
||||
- **110 machines** in the `machines` table
|
||||
- **110 equipment** records in the `equipment` table
|
||||
|
||||
## Example
|
||||
| Machine | Current Type | Should Be | Model |
|
||||
|---------|-------------|-----------|-------|
|
||||
| 7502 | LocationOnly | Horizontal Machining Center | a81nx |
|
||||
| 3108 | LocationOnly | Vertical Lathe | VTM-100 |
|
||||
| 4001 | LocationOnly | 5-axis Mill | VP9000 |
|
||||
|
||||
## Fix SQL
|
||||
|
||||
### Step 1: Preview affected records
|
||||
```sql
|
||||
-- Preview what will be changed
|
||||
SELECT
|
||||
m.machineid,
|
||||
m.machinenumber,
|
||||
mt_current.machinetype as current_type,
|
||||
mt_model.machinetype as correct_type,
|
||||
mo.modelnumber
|
||||
FROM machines m
|
||||
JOIN models mo ON mo.modelnumberid = m.modelnumberid
|
||||
JOIN machinetypes mt_current ON mt_current.machinetypeid = m.machinetypeid
|
||||
JOIN machinetypes mt_model ON mt_model.machinetypeid = mo.machinetypeid
|
||||
WHERE m.machinetypeid = 1 -- Currently LocationOnly
|
||||
AND mo.machinetypeid != 1; -- Model has a real type
|
||||
```
|
||||
|
||||
### Step 2: Fix the machines table
|
||||
```sql
|
||||
-- Update machines table to use the model's machine type
|
||||
UPDATE machines m
|
||||
JOIN models mo ON mo.modelnumberid = m.modelnumberid
|
||||
SET m.machinetypeid = mo.machinetypeid
|
||||
WHERE m.machinetypeid = 1 -- Currently LocationOnly
|
||||
AND mo.machinetypeid != 1; -- Model has a real type
|
||||
```
|
||||
|
||||
### Step 3: Fix the equipment table
|
||||
```sql
|
||||
-- Update equipment table to match
|
||||
-- Note: equipmenttypeid values match machinetypeid values
|
||||
UPDATE equipment e
|
||||
JOIN assets a ON a.assetid = e.assetid
|
||||
JOIN machines m ON m.machinenumber = SUBSTRING_INDEX(a.assetnumber, '-', 1)
|
||||
SET e.equipmenttypeid = m.machinetypeid
|
||||
WHERE e.equipmenttypeid = 1 -- Currently LocationOnly
|
||||
AND m.machinetypeid != 1; -- Machine now has correct type
|
||||
```
|
||||
|
||||
### Alternative Step 3 (if asset numbers don't match)
|
||||
```sql
|
||||
-- Update equipment based on their own model reference
|
||||
UPDATE equipment e
|
||||
JOIN models mo ON mo.modelnumberid = e.modelnumberid
|
||||
SET e.equipmenttypeid = mo.machinetypeid
|
||||
WHERE e.equipmenttypeid = 1 -- Currently LocationOnly
|
||||
AND mo.machinetypeid != 1 -- Model has a real type
|
||||
AND e.modelnumberid IS NOT NULL;
|
||||
```
|
||||
|
||||
## Verification
|
||||
```sql
|
||||
-- Count remaining LocationOnly records that should have been fixed
|
||||
SELECT COUNT(*) as remaining_fixable
|
||||
FROM machines m
|
||||
JOIN models mo ON mo.modelnumberid = m.modelnumberid
|
||||
WHERE m.machinetypeid = 1
|
||||
AND mo.machinetypeid != 1;
|
||||
-- Should return 0 after fix
|
||||
```
|
||||
|
||||
## Notes for Future Migrations
|
||||
1. When importing equipment, always check if the model has a type and use that as the default
|
||||
2. Only use "LocationOnly" for genuine location markers (rooms, offices) without models
|
||||
3. Validate after import: any equipment with a model should NOT be LocationOnly
|
||||
|
||||
## Date Created
|
||||
2026-01-27
|
||||
92
migrations/MIGRATE_USB_DEVICES_FROM_EQUIPMENT.md
Normal file
92
migrations/MIGRATE_USB_DEVICES_FROM_EQUIPMENT.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# Migrate USB Devices from Equipment Table
|
||||
|
||||
## Issue
|
||||
6 USB devices were incorrectly stored in the `equipment` table instead of the proper `usbdevices` table.
|
||||
|
||||
## Status
|
||||
- [x] `pin` field added to `usbdevices` table for encrypted devices
|
||||
- [x] `pin` field added to USBDevice model
|
||||
- [x] USB Device equipment type deactivated (equipmenttypeid=44)
|
||||
- [ ] Migrate 6 USB devices to usbdevices table
|
||||
|
||||
## Affected Records
|
||||
| Asset Number | Name | Serial Number |
|
||||
|--------------|------|---------------|
|
||||
| 82841957-5891 | Green Kingston 64GB | 82841957 |
|
||||
| 48854302-5892 | Blue Kingston 64GB | 48854302 |
|
||||
| 75953637-5893 | Blue Kingston 64GB USB 3.0 | 75953637 |
|
||||
| 41299370-5904 | Lenovo Portable DVD | 41299370 |
|
||||
| 15492331-5905 | TEAC Portable Floppy Drive | 15492331 |
|
||||
| 25777358-5906 | Netgear WiFi Adapter | 25777358 |
|
||||
|
||||
## Migration SQL
|
||||
|
||||
### Step 1: Insert into usbdevices
|
||||
```sql
|
||||
INSERT INTO usbdevices (
|
||||
serialnumber,
|
||||
label,
|
||||
assetnumber,
|
||||
usbdevicetypeid,
|
||||
storagelocation,
|
||||
notes,
|
||||
createddate,
|
||||
modifieddate,
|
||||
isactive
|
||||
)
|
||||
SELECT
|
||||
a.serialnumber,
|
||||
a.name,
|
||||
a.assetnumber,
|
||||
NULL, -- Assign proper type later
|
||||
NULL, -- Storage location TBD
|
||||
a.notes,
|
||||
a.createddate,
|
||||
a.modifieddate,
|
||||
a.isactive
|
||||
FROM assets a
|
||||
JOIN equipment e ON e.assetid = a.assetid
|
||||
WHERE e.equipmenttypeid = 44; -- USB Device type
|
||||
```
|
||||
|
||||
### Step 2: Delete from equipment table
|
||||
```sql
|
||||
DELETE e FROM equipment e
|
||||
JOIN assets a ON a.assetid = e.assetid
|
||||
WHERE e.equipmenttypeid = 44;
|
||||
```
|
||||
|
||||
### Step 3: Delete from assets table
|
||||
```sql
|
||||
DELETE a FROM assets a
|
||||
JOIN equipment e ON e.assetid = a.assetid
|
||||
WHERE e.equipmenttypeid = 44;
|
||||
|
||||
-- Note: Run step 2 first since it references assets
|
||||
```
|
||||
|
||||
### Alternative: Manual Migration
|
||||
Since there are only 6 devices, you may prefer to:
|
||||
1. Manually create them in the USB Devices section
|
||||
2. Delete the equipment/asset records
|
||||
|
||||
## USB Device Types to Create
|
||||
```sql
|
||||
-- Check if types exist, create if needed
|
||||
INSERT IGNORE INTO usbdevicetypes (typename, description, icon) VALUES
|
||||
('Flash Drive', 'USB flash drive / thumb drive', 'usb'),
|
||||
('External HDD', 'External hard disk drive', 'harddisk'),
|
||||
('External SSD', 'External solid state drive', 'harddisk'),
|
||||
('Card Reader', 'SD/CF card reader', 'sdcard'),
|
||||
('Optical Drive', 'External CD/DVD/Blu-ray drive', 'disc'),
|
||||
('WiFi Adapter', 'USB wireless network adapter', 'wifi'),
|
||||
('Other', 'Other USB device', 'usb');
|
||||
```
|
||||
|
||||
## Notes
|
||||
- USB Device equipment type has been deactivated (isactive=0)
|
||||
- New USB devices should be created in the USB Devices section
|
||||
- USB devices do NOT need map positions (no mapleft/maptop)
|
||||
|
||||
## Date Created
|
||||
2026-01-27
|
||||
165
migrations/PRODUCTION_MIGRATION_GUIDE.md
Normal file
165
migrations/PRODUCTION_MIGRATION_GUIDE.md
Normal file
@@ -0,0 +1,165 @@
|
||||
# Production Migration Guide
|
||||
|
||||
## Overview
|
||||
This guide documents the process for migrating data from the legacy VBScript ShopDB site to the new Flask-based ShopDB.
|
||||
|
||||
## Database Architecture
|
||||
|
||||
### Legacy System (VBScript)
|
||||
- Single `machines` table containing all equipment, PCs, printers
|
||||
- `machinetypes` table for classification
|
||||
- `models` table with `machinetypeid` reference
|
||||
|
||||
### New System (Flask)
|
||||
- Core `assets` table (unified asset registry)
|
||||
- Plugin-specific extension tables:
|
||||
- `equipment` (equipmenttypeid → equipmenttypes)
|
||||
- `computers` (computertypeid → computertypes)
|
||||
- `printers` (printertypeid → printertypes)
|
||||
- `network_device` (networkdevicetypeid → networkdevicetypes)
|
||||
|
||||
## Key Mappings
|
||||
|
||||
### Asset Type Mapping
|
||||
| Legacy Category | New Asset Type | Extension Table |
|
||||
|-----------------|---------------|-----------------|
|
||||
| Equipment machines | Equipment | equipment |
|
||||
| PC/Computer | Computer | computers |
|
||||
| Printer | Printer | printers |
|
||||
| Network (IDF, Switch, AP) | Network Device | network_device |
|
||||
|
||||
### Type ID Alignment
|
||||
The `equipmenttypes` table IDs match `machinetypes` IDs for easy migration:
|
||||
- equipmenttypeid = machinetypeid (where applicable)
|
||||
|
||||
## Migration Steps
|
||||
|
||||
### Step 1: Export from Legacy Database
|
||||
```sql
|
||||
-- Export machines with all related data
|
||||
SELECT
|
||||
m.*,
|
||||
mt.machinetype,
|
||||
mo.modelnumber,
|
||||
mo.machinetypeid as model_typeid,
|
||||
v.vendor,
|
||||
bu.businessunit,
|
||||
s.status
|
||||
FROM machines m
|
||||
LEFT JOIN machinetypes mt ON mt.machinetypeid = m.machinetypeid
|
||||
LEFT JOIN models mo ON mo.modelnumberid = m.modelnumberid
|
||||
LEFT JOIN vendors v ON v.vendorid = m.vendorid
|
||||
LEFT JOIN businessunits bu ON bu.businessunitid = m.businessunitid
|
||||
LEFT JOIN statuses s ON s.statusid = m.statusid;
|
||||
```
|
||||
|
||||
### Step 2: Create Assets
|
||||
For each machine, create an asset record:
|
||||
```sql
|
||||
INSERT INTO assets (assetnumber, name, assettypeid, statusid, locationid, businessunitid, mapleft, maptop)
|
||||
SELECT
|
||||
CONCAT(machinenumber, '-', machineid), -- Unique asset number
|
||||
alias,
|
||||
CASE
|
||||
WHEN category = 'PC' THEN 2 -- Computer
|
||||
WHEN category = 'Printer' THEN 4 -- Printer
|
||||
ELSE 1 -- Equipment
|
||||
END,
|
||||
statusid,
|
||||
locationid,
|
||||
businessunitid,
|
||||
mapleft,
|
||||
maptop
|
||||
FROM machines;
|
||||
```
|
||||
|
||||
### Step 3: Create Extension Records
|
||||
```sql
|
||||
-- For Equipment
|
||||
INSERT INTO equipment (assetid, equipmenttypeid, vendorid, modelnumberid)
|
||||
SELECT
|
||||
a.assetid,
|
||||
COALESCE(mo.machinetypeid, m.machinetypeid), -- Use model's type if available!
|
||||
m.vendorid,
|
||||
m.modelnumberid
|
||||
FROM machines m
|
||||
JOIN assets a ON a.assetnumber = CONCAT(m.machinenumber, '-', m.machineid)
|
||||
LEFT JOIN models mo ON mo.modelnumberid = m.modelnumberid
|
||||
WHERE m.category = 'Equipment' OR m.category IS NULL;
|
||||
```
|
||||
|
||||
### Step 4: Post-Migration Fixes
|
||||
|
||||
#### Fix LocationOnly Equipment Types
|
||||
Equipment imported with LocationOnly type should inherit type from their model:
|
||||
```sql
|
||||
-- Fix equipment that has a model with a proper type
|
||||
UPDATE equipment e
|
||||
JOIN assets a ON a.assetid = e.assetid
|
||||
JOIN machines m ON m.machinenumber = SUBSTRING_INDEX(a.assetnumber, '-', 1)
|
||||
JOIN models mo ON mo.modelnumberid = m.modelnumberid
|
||||
SET e.equipmenttypeid = mo.machinetypeid
|
||||
WHERE e.equipmenttypeid = 1 -- LocationOnly
|
||||
AND mo.machinetypeid != 1; -- Model has real type
|
||||
```
|
||||
|
||||
## Validation Queries
|
||||
|
||||
### Check for Orphaned Assets
|
||||
```sql
|
||||
SELECT a.* FROM assets a
|
||||
LEFT JOIN equipment e ON e.assetid = a.assetid
|
||||
LEFT JOIN computers c ON c.assetid = a.assetid
|
||||
LEFT JOIN printers p ON p.assetid = a.assetid
|
||||
WHERE a.assettypeid = 1 -- Equipment type
|
||||
AND e.assetid IS NULL;
|
||||
```
|
||||
|
||||
### Check LocationOnly with Models
|
||||
```sql
|
||||
-- Should return 0 after migration fix
|
||||
SELECT COUNT(*)
|
||||
FROM equipment e
|
||||
JOIN assets a ON a.assetid = e.assetid
|
||||
JOIN machines m ON m.machinenumber = SUBSTRING_INDEX(a.assetnumber, '-', 1)
|
||||
JOIN models mo ON mo.modelnumberid = m.modelnumberid
|
||||
WHERE e.equipmenttypeid = 1
|
||||
AND mo.machinetypeid != 1;
|
||||
```
|
||||
|
||||
### Verify Type Distribution
|
||||
```sql
|
||||
SELECT et.equipmenttype, COUNT(*) as count
|
||||
FROM equipment e
|
||||
JOIN equipmenttypes et ON et.equipmenttypeid = e.equipmenttypeid
|
||||
GROUP BY et.equipmenttype
|
||||
ORDER BY count DESC;
|
||||
```
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Issue: Equipment marked as LocationOnly but has model
|
||||
**Cause**: Migration copied machinetypeid from machines table instead of using model's type
|
||||
**Fix**: See FIX_LOCATIONONLY_EQUIPMENT_TYPES.md
|
||||
|
||||
### Issue: Missing model relationship
|
||||
**Cause**: Equipment table modelnumberid not populated during migration
|
||||
**Fix**: Link through machines table using asset number pattern
|
||||
|
||||
### Issue: Duplicate asset numbers
|
||||
**Cause**: Asset number generation didn't account for existing duplicates
|
||||
**Fix**: Use unique suffix or check before insert
|
||||
|
||||
## Scripts Location
|
||||
- `/migrations/FIX_LOCATIONONLY_EQUIPMENT_TYPES.md` - Fix for LocationOnly type issue
|
||||
- `/scripts/import_from_mysql.py` - Original import script (may need updates)
|
||||
- `/scripts/migration/` - Migration utilities
|
||||
|
||||
## Notes
|
||||
- Always backup before running migration fixes
|
||||
- Test on staging/dev before production
|
||||
- Verify counts before and after each fix
|
||||
- Keep legacy `machines` table for reference during transition
|
||||
|
||||
## Date Created
|
||||
2026-01-27
|
||||
23
migrations/rename_underscore_columns.sql
Normal file
23
migrations/rename_underscore_columns.sql
Normal file
@@ -0,0 +1,23 @@
|
||||
-- Rename database columns to remove underscores per naming convention
|
||||
-- Date: 2026-02-03
|
||||
-- Affects: assettypes, assetrelationships, equipment, usbcheckouts
|
||||
|
||||
-- 1. assettypes table
|
||||
ALTER TABLE assettypes CHANGE COLUMN plugin_name pluginname VARCHAR(100) NULL COMMENT 'Plugin that owns this type';
|
||||
ALTER TABLE assettypes CHANGE COLUMN table_name tablename VARCHAR(100) NULL COMMENT 'Extension table name for this type';
|
||||
|
||||
-- 2. assetrelationships table
|
||||
ALTER TABLE assetrelationships CHANGE COLUMN source_assetid sourceassetid INT NOT NULL;
|
||||
ALTER TABLE assetrelationships CHANGE COLUMN target_assetid targetassetid INT NOT NULL;
|
||||
|
||||
-- 3. equipment table
|
||||
ALTER TABLE equipment CHANGE COLUMN controller_vendorid controllervendorid INT NULL COMMENT 'Controller vendor (e.g., FANUC)';
|
||||
ALTER TABLE equipment CHANGE COLUMN controller_modelid controllermodelid INT NULL COMMENT 'Controller model (e.g., 31B)';
|
||||
|
||||
-- 4. usbcheckouts table
|
||||
ALTER TABLE usbcheckouts CHANGE COLUMN checkout_name checkoutname VARCHAR(100) NULL COMMENT 'Name of user';
|
||||
ALTER TABLE usbcheckouts CHANGE COLUMN checkout_time checkouttime DATETIME NOT NULL;
|
||||
ALTER TABLE usbcheckouts CHANGE COLUMN checkin_time checkintime DATETIME NULL;
|
||||
ALTER TABLE usbcheckouts CHANGE COLUMN checkout_reason checkoutreason TEXT NULL COMMENT 'Reason for checkout';
|
||||
ALTER TABLE usbcheckouts CHANGE COLUMN checkin_notes checkinnotes TEXT NULL;
|
||||
ALTER TABLE usbcheckouts CHANGE COLUMN was_wiped waswiped TINYINT(1) NULL COMMENT 'Was device wiped after return';
|
||||
Reference in New Issue
Block a user