bmc_hub/SERVICE_CONTRACT_WIZARD_README.md
Christian 3d7fb1aa48 feat(migrations): add AnyDesk session management and customer wiki slug updates
- 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.
2026-02-10 14:40:38 +01:00

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:

  1. 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
  2. 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:

  1. 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
  2. app/timetracking/backend/models.py (+70 lines)

    • ServiceContractBase - Base contract model
    • ServiceContractItem - Single case/timelog item
    • ServiceContractWizardData - Complete contract data for wizard
    • ServiceContractWizardAction - Action result (archive/transfer)
    • ServiceContractWizardSummary - Final summary
    • TimologTransferRequest - Request model for timelog transfer
    • TimologTransferResult - Transfer result
  3. app/timetracking/backend/router.py (+180 lines)

    • GET /api/v1/timetracking/service-contracts - List contracts dropdown
    • POST /api/v1/timetracking/service-contracts/wizard/load - Load contract data
    • POST /api/v1/timetracking/service-contracts/wizard/archive-case - Archive case
    • POST /api/v1/timetracking/service-contracts/wizard/transfer-timelog - Transfer timelog
    • GET /api/v1/timetracking/service-contracts/wizard/customer-cards/{customer_id} - Get klippekort
  4. app/timetracking/frontend/views.py (+5 lines)

    • Added frontend route: /timetracking/service-contract-wizard

🚀 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
  1. Check the "Preview Mode" checkbox at top (enabled by default)
  2. Select a service contract from dropdown
  3. Review each case/timelog and click "Gem & Næste"
  4. No data is written to database in dry-run mode
  5. Review summary report to see what WOULD be changed

4. Live Mode

  1. Uncheck "Preview Mode" checkbox
  2. Select same or different contract
  3. Process items - changes ARE committed to database
  4. Cases are exported to tticket_archived_tickets
  5. 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_tickets with:

    • source_system = 'vtiger_service_contract'
    • external_id = vtiger case ID
    • Full case data in raw_data JSONB field
  • Timelogs create transactions in tticket_prepaid_transactions with:

    • 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

  1. Dry-run mode enabled by default - Users see what WOULD happen first
  2. Customer linking - Looks up Hub customer ID from vTiger account
  3. Klippekort validation - Verifies card belongs to customer before transfer
  4. Read-only from Vtiger - No writes back to Vtiger (only reads)
  5. Transaction handling - Each operation is atomic
  6. 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_run query 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_run parameter is passed to API endpoints

📋 Next Steps

  1. Test with sample data - Create test service contract in Vtiger
  2. Verify database changes - Query tticket_archived_tickets post-migration
  3. Monitor klippekort - Check tticket_prepaid_transactions for top-up entries
  4. Adjust as needed - Tweak timelog filtering or case mapping based on results

Status: Ready for testing and deployment Estimated Time to Test: 15-20 minutes Database Dependency: PostgreSQL (no migrations needed - uses existing tables)