- Created migration scripts for AnyDesk sessions and hardware assets. - Implemented apply_migration_115.py to execute migration for AnyDesk sessions. - Added set_customer_wiki_slugs.py script to update customer wiki slugs based on a predefined folder list. - Developed run_migration.py to apply AnyDesk migration schema. - Added tests for Service Contract Wizard to ensure functionality and dry-run mode.
7.4 KiB
7.4 KiB
Service Contract Migration Wizard - Implementation Summary
✅ What Was Built
A step-by-step wizard that migrates Vtiger service contracts to Hub systems:
- Cases → Archived to
tticket_archived_tickets - Timelogs → Transferred as klippekort top-ups (prepaid card hours)
Features:
- ✅ Dry-run toggle (preview mode without database writes)
- ✅ Step-by-step review of each case/timelog
- ✅ Manual klippekort selection per timelog
- ✅ Progress tracking and summary report
- ✅ Read-only from Vtiger (no writes back to Vtiger)
🎯 Files Created/Modified
New Files:
-
app/timetracking/backend/service_contract_wizard.py (275 lines)
- Core wizard service with all business logic
- Methods:
load_contract_detailed_data(),archive_case(),transfer_timelog_to_klippekort(),get_wizard_summary() - Dry-run support built into each method
-
app/timetracking/frontend/service_contract_wizard.html (650 lines)
- Complete wizard UI with Nordic design
- Contract dropdown selector
- Progress bar with live counters
- Current item display with conditional klippekort dropdown
- Summary report on completion
Modified Files:
-
app/services/vtiger_service.py (+65 lines)
- Added
get_service_contracts(account_id=None)- Fetch active service contracts - Added
get_service_contract_cases(contract_id)- Fetch cases linked to contract - Added
get_service_contract_timelogs(contract_id)- Fetch timelogs linked to contract
- Added
-
app/timetracking/backend/models.py (+70 lines)
ServiceContractBase- Base contract modelServiceContractItem- Single case/timelog itemServiceContractWizardData- Complete contract data for wizardServiceContractWizardAction- Action result (archive/transfer)ServiceContractWizardSummary- Final summaryTimologTransferRequest- Request model for timelog transferTimologTransferResult- Transfer result
-
app/timetracking/backend/router.py (+180 lines)
GET /api/v1/timetracking/service-contracts- List contracts dropdownPOST /api/v1/timetracking/service-contracts/wizard/load- Load contract dataPOST /api/v1/timetracking/service-contracts/wizard/archive-case- Archive casePOST /api/v1/timetracking/service-contracts/wizard/transfer-timelog- Transfer timelogGET /api/v1/timetracking/service-contracts/wizard/customer-cards/{customer_id}- Get klippekort
-
app/timetracking/frontend/views.py (+5 lines)
- Added frontend route:
/timetracking/service-contract-wizard
- Added frontend route:
🚀 How to Test
1. Start the API
docker-compose up -d api
docker-compose logs -f api
2. Access the Wizard
http://localhost:8000/timetracking/service-contract-wizard
3. Dry-Run Mode (Recommended First)
- Check the "Preview Mode" checkbox at top (enabled by default)
- Select a service contract from dropdown
- Review each case/timelog and click "Gem & Næste"
- No data is written to database in dry-run mode
- Review summary report to see what WOULD be changed
4. Live Mode
- Uncheck "Preview Mode" checkbox
- Select same or different contract
- Process items - changes ARE committed to database
- Cases are exported to
tticket_archived_tickets - Timelogs are added to klippekort via top-up transaction
🔍 Database Changes
Dryrun Mode:
- All operations are logged but NOT committed
- Queries are constructed but rolled back
- UI shows what WOULD happen
Live Mode:
-
Cases are inserted into
tticket_archived_ticketswith:source_system = 'vtiger_service_contract'external_id = vtiger case ID- Full case data in
raw_dataJSONB field
-
Timelogs create transactions in
tticket_prepaid_transactionswith:transaction_type = 'top_up'- Hours added to klippekort
purchased_hours - Description references vTiger timelog
📊 Data Flow
Vtiger Service Contract
↓
SelectContract (dropdown)
↓
LoadContractData
├─ Cases → Archive to tticket_archived_tickets
└─ Timelogs → Transfer to klippekort (top-up)
↓
WizardProgress (step-by-step review)
├─ [DRY RUN] Preview mode (no DB writes)
└─ [LIVE] Commit to database
↓
Summary Report
├─ Cases archived: N
├─ Hours transferred: N
└─ Failed items: N
🔐 Safety Features
- Dry-run mode enabled by default - Users see what WOULD happen first
- Customer linking - Looks up Hub customer ID from vTiger account
- Klippekort validation - Verifies card belongs to customer before transfer
- Read-only from Vtiger - No writes back to Vtiger (only reads)
- Transaction handling - Each operation is atomic
- Audit logging - All actions logged with DRY RUN/COMMITTED markers
🛠️ Technical Details
Wizard Service (ServiceContractWizardService)
- Stateless service class
- All methods are static
- Database operations via
execute_query()helpers - Klippekort transfers via
KlippekortService.top_up_card()
Frontend UI
- Vanilla JavaScript (no frameworks)
- Nordic Top design system (matches existing Hub UI)
- Responsive Bootstrap 5 grid
- Real-time progress updates
- Conditional klippekort dropdown (only for timelogs)
API Endpoints
- RESTful architecture
- All endpoints support
dry_runquery parameter - Request/response models use Pydantic validation
- Comprehensive error handling with HTTPException
📝 Logging Output
Dry-Run Mode:
🔍 DRY RUN: Would archive case 1x123: 'Case Title'
🔍 DRY RUN: Would transfer 5h to card 42 from timelog 2x456
Live Mode:
✅ Archived case 1x123 to tticket_archived_tickets (ID: 1234)
✅ Transferred 5h from timelog 2x456 to card 42
🐛 Troubleshooting
Contracts dropdown is empty:
- Verify Vtiger integration is configured (VTIGER_URL, VTIGER_USERNAME, VTIGER_API_KEY in .env)
- Check vTiger has active ServiceContracts
- Check API user has access to ServiceContracts module
Klippekort dropdown empty for customer:
- Customer may not have any active prepaid cards
- Or customer is not linked between Vtiger account and Hub customer
- Create a prepaid card for the customer first
Dry-run mode not working:
- Ensure checkbox is checked
- Check browser console for JavaScript errors
- Verify
dry_runparameter is passed to API endpoints
📋 Next Steps
- Test with sample data - Create test service contract in Vtiger
- Verify database changes - Query
tticket_archived_ticketspost-migration - Monitor klippekort - Check
tticket_prepaid_transactionsfor top-up entries - Adjust as needed - Tweak timelog filtering or case mapping based on results
🔗 Related Components
- Klippekort System: app/ticket/backend/klippekort_service.py
- Archive System: Database table
tticket_archived_tickets - Timetracking Module: app/timetracking/
- Vtiger Integration: app/services/vtiger_service.py
Status: ✅ Ready for testing and deployment Estimated Time to Test: 15-20 minutes Database Dependency: PostgreSQL (no migrations needed - uses existing tables)