Skip to content

MSP Record Maintenance

This reference is for process owners and technical operators maintaining agreements, historical invoice attribution and reporting configuration. These reviewed maintenance operations do not replace the staff invoicing procedure. For recurring billing behavior, use the billing rules.

Current Agreement

The Plan can identify the accepted agreement currently governing the service while retaining its original Deal and operational billing dates:

Field Operator meaning
Current_Agreement_Deal Deal containing the reviewed current agreement reference
Current_Agreement_Start That agreement's commencement date
Current_Agreement_Accepted Its actual acceptance/signature date; this can follow commencement
Current_Agreement_Renewal Its next contractual renewal date; this does not end billing

These fields are optional and do not affect the invoice generator. The existing Deal retains the original source relationship, and Billing_Start / Billing_End retain their billing meaning. A renewal date is not copied into Billing_End. The current-agreement fields do not create a new Plan or a new monthly record.

An operator can prepare a migration for explicitly selected Plans using reviewed agreement evidence. The migration creates missing agreement fields and fills only those four fields on Plans with complete decisions. Plans without reviewed dates remain unfilled. Before writing, it checks that the agreement Deal belongs to the same Company, existing Plan values still match the capture, and field metadata is compatible. It disables optional record triggers, rejects concurrent record edits and verifies the saved values. A repeated matching batch makes no further updates.

The writer does not change billing dates, status, Plan type, purchase-order user counts, Seats, charges, invoices, support budgets or delivery scopes. Setting the current agreement does not resolve discrepancies in those other records.

Keep dated agreement evidence and the migration journal when changing the current reference; the four current fields alone are not a full amendment history. Technical preparation and apply instructions: MSP Plan agreement migration.

Commercial Service Review

Commercial Service is the shared commercial record for MSP, Tech Projects and Hardware. For an MSP with a Plan, the existing Plan and its linked operational records provide the initial configuration basis. Configured Service Lines remain under the Client Service; seats belong to its Account. See the Account seat migration for the ownership mapping and preserved billing checks.

For the six migrated Success Works and Sharps invoices, review native Invoiced Items directly on the Invoice, or the service's Native Invoiced Items. The earlier Actual Invoice Lines / Actual Service Lines lists refer to custom captures used by the preceding review steps below. Commercial summaries and agreement context are optional supporting information.

Optional agreement context

An operator can apply a selected candidate context review to the existing Commercial Service. The current agreement Deal, commencement, acceptance and renewal are copied from the reviewed Plan context. Commercial Summary describes that configuration and the accepted agreement evidence. Review Reason identifies differences that need a business decision. The service retains its original Deal and Plan link; a renewed agreement does not reset its original service dates.

The candidate's captured Actual Invoice Lines retain their native invoice, Product and source financial values. Explicitly selected ordinary monthly lines receive the native invoice's MSP billing-period dates. Lines with conflicting or insufficient coverage evidence remain undated, with the reason recorded. A licence renewal date is distinct from monthly coverage. Service month is a grouping of these lines; there is no separate monthly parent record.

This context migration sets its selected service and lines to Needs Review. Populating coverage does not certify that the Product, rate, quantity or agreement is correct. Operational settings, issued amounts and Product identities are not corrected by this migration. Customer entitlement, configured quantity and billed monthly quantity retain their separate meanings.

Before applying, the workflow checks the captured records, customer ownership and invoice relationships. It rejects intervening changes, restricts writes to the selected service context and captured-line coverage/review fields, and verifies every saved value. A matching rerun makes no further changes. This is a candidate migration with a private journal, not an automatic synchronisation or billing cutover. Use the native Actual Invoice Lines related list to review the captured billing records.

Implementation and tests: commercial_services/msp_review.py, tests/commercial_services/test_msp_review.py. Technical instructions: MSP Commercial Service review.

Invoice charge reconciliation

An operator can link selected actual invoice lines to their corresponding configured MSP Invoice Lines. The Configured MSP Invoice Line lookup makes the relationship navigable from the invoice's line list. A configured charge's Actual Invoice Lines list shows its matched historical lines.

Each selected match must identify the configured charge and its evidence. The workflow checks that the invoice and charge belong to the Commercial Service's Plan and customer, the Products match, and the actual line identifies the same source invoice and currency. Ambiguous lines can remain unselected. Different existing charge links and Product mismatches require separate review.

Only the configured-charge lookup is populated. Historical quantities, prices, coverage and source statuses retain their captured values even when today's charge configuration differs. Before writing, the workflow checks for changes since capture; updates suppress optional triggers and reject concurrent edits. Every saved line is verified, and matching reruns make no record changes.

Success Works' eight September INV-0319 lines have verified configured-charge links. This operation does not generate invoices or synchronise invoice statuses/payments. The native Invoice's creation/sync markers must not be interpreted as current Xero payment status.

Implementation and tests: commercial_services/invoice_charge_links.py, tests/commercial_services/test_invoice_charge_links.py. Technical instructions: Configured charge links.

Native invoice history

An operator applies an explicitly reviewed batch to existing native Invoice items. Each traced line receives Commercial Service, configured MSP charge, coverage dates and its Xero Line Item ID. Product and native item identities are preserved. Attribution alone cannot change billed values; a separately reviewed reconciliation mode corrects CRM snapshots to issued Xero quantities, prices and descriptions. Original snapshots remain in a private archive.

The September 2026 batch covers Success Works July–September and Sharps June–August: six invoices and 43 issued lines. Success Works' August coverage uses August despite stale July descriptions, by explicit review. Its additional zero-value CRM-only row is retained without an invented source line. Historical Product associations remain explicit rather than replacing Products to match current configuration.

Invoice and due dates follow Xero independently of coverage. Xero Document Status, paid/due/credited amounts, source tax and reconciliation time record the source state. Operational creation/sync markers retain their existing meaning. Zoho calculates nominal tax; a bounded rounding adjustment preserves the exact issued total where Xero's per-line rounding differs. Source tax is available separately as Xero Tax Amount.

Apply stops if supporting records or source invoices have changed, writes only the reviewed fields with optional triggers suppressed, and verifies all saved values. A matching rerun makes no invoice changes. This workflow does not regenerate invoices or change Xero, billing configuration, Seats or agreements. It does not run automatically for later invoices or source payment changes.

The saved MSP Native Invoice History report joins Invoices and Invoiced Items for the reviewed scope. Line net amounts can be grouped by service, Product, coverage, currency and source status. Count header totals and payments once per invoice. Negative lines retain their signs; multi-month coverage does not imply a proportional allocation. The invoice-only validation blocks credit allocations against selected invoices until a native credit representation is reviewed. Credits outside the selected scope remain explicit exclusions.

After the native report and existing margin reader are verified, an operator can retire only the exact redundant custom captures. Retirement preserves full before-images, checks native replacements, source freshness, workflows and related records, and moves captures to the recycle bin with workflows disabled. Changed or unverifiable dependencies stop deletion. Native invoices, items, configuration, unrelated captures and the custom module remain intact. The existing margin report reads migrated native items, and old capture writers reject duplicates for the configured migrated documents.

Implementation: commercial_services/native_invoice_migration.py, native_invoice_history.py, native_invoice_retirement.py and app/commercial_margin/native_items.py. Technical instructions and recovery: Native MSP invoice history.

Margin and Timesheet Foundation

The Managed Services Plan also carries a small set of planning fields so margin reporting can cover months before structured MSP Invoice Lines existed. The Commercial Margin report can already reconcile labour from the Plan, and a later timesheet report can reuse the same scope without retaining recurring Delivery Models:

  • Fallback_Monthly_Revenue is the temporary monthly revenue estimate. MSP Invoice Lines remain the preferred revenue source whenever they cover the reporting month.
  • Expected_Support_Hours_per_Month is the recurring monthly support budget. It is a quantity of hours, not a cost. Reporting applies the user labour-rate assumption separately.
  • Timesheet_Scope_Type identifies whether the scope is a Zoho Projects Project, Tasklist, Task, or Phase.
  • Timesheet_Scope_ID stores the ID for that selected scope type. The pair is enough to construct the relevant Zoho Projects link and match timelogs; do not copy four separate scope ID fields onto the plan.
  • Margin_Budget_Source records where the planning values came from. Initial migration values use Migrated Delivery Model; maintained values can use Manual or MSP Invoice Lines.

These fields are exposed by the current MSP Plan and MSP Plan history reporting feeds and are used by the Commercial Margin Power BI model. Applicable MSP Invoice Lines remain authoritative for expected revenue. An uncovered Plan month uses Fallback_Monthly_Revenue; expected labour comes directly from the Plan; and actual timelogs are assigned through the Plan scope pair. Recurring Delivery Models no longer contribute to Commercial Margin.

Migrate Existing Recurring Delivery Models

Run the migration from the repository root without --apply first:

python -m msp_imports.migrate_delivery_models_to_msp_plans

The dry run writes a CSV audit and makes no CRM changes. It matches a recurring Delivery Model to a plan by the Delivery Model's MSP_Plan lookup first, then by their shared Deal. Retired recurring models are included because retirement is part of moving the budget authority to the plan. Labour in days is converted at 7.6 hours per day. Scope_Type selects the one matching project_id, tasklist_id, task_id, or phase_id to place in Timesheet_Scope_ID.

The migration flags missing values, unsupported units/scopes, conflicting Delivery Models, and existing different plan values for review. It selects the most recent Valid_From only when multiple candidates produce the same target values. It also compares Delivery Model fallback revenue with applicable MSP Invoice Line revenue for the current month and reports the variance as a warning. The comparison does not prevent a safe migration.

After reviewing the CSV, apply only the safe update_plan rows with:

python -m msp_imports.migrate_delivery_models_to_msp_plans --apply

Existing different plan values are preserved unless an operator deliberately adds --overwrite. The migration never deletes or edits Delivery Models and does not alter timesheets, invoices, or invoice lines.

The initial migration was applied on 2026-09-04. It updated 21 Plans and left five review exceptions unchanged: Batteries&Mobility had no task ID for its Task scope, while Bromleys, Cameragal, Pathmaker, and Scale Meets Flow had no recurring Delivery Model to migrate. These Plans remain visible as Incomplete until their Plan planning/scope fields are maintained manually.

Shared service lines

The existing MSP Invoice Lines records also belong to Commercial Services through an optional lookup. Their Plan links and billing values are retained. Plan is optional on the layout so Tech Project, Home and Hardware lines can belong directly to a Commercial Service; Product remains required. The MSP generator selects only lines linked to its Plan, so these other lines do not enter MSP billing. The module display name and API name are unchanged.

Native Invoices have an optional Commercial Service header relationship. Use it only for a document belonging to one service; retain native item attribution for mixed-service documents. See the shared-record cleanup.