MSP Commercial Service review migration
commercial_services.msp_review configures existing candidate Commercial
Services from their linked Managed Services Plans. It adds five optional fields
to Commercial Services: Current_Agreement_Deal, Current_Agreement_Start,
Current_Agreement_Accepted, Current_Agreement_Renewal and
Commercial_Summary. These fields use category-neutral meanings. Only selected
MSP records are populated by this command.
The current agreement values come from the captured Plan; its Deal must belong to the same customer. A separately prepared summary describes the operational configuration, accepted agreement evidence and review scope. The original Deal, service identity, Plan link, lifecycle, service start/end and legacy source evidence remain unchanged. A renewal commencement does not replace the start of a continuing service.
The command also fills existing Service_Invoice_Lines coverage fields from
the linked native invoice's MSP_Billing_Period_Start and
MSP_Billing_Period_End, only for explicit invoice_header decisions. An
unresolved decision retains blank coverage and explains the conflict. Invoice
date alone is never used. All candidate services and lines remain Needs Review.
Private inputs and preview
Capture full records into a new private directory as source.json. Include
only the selected Commercial_Services, their Managed_Services_Plans, current
agreement Deals, relevant configured MSP_Invoice_Lines, captured
Service_Invoice_Lines and their native Invoices. Preserve field/layout
metadata with the capture. Use the repository's read-only CRM client and
owner-only file writer. Customer prices, raw records and decisions are private
working evidence and are not committed.
decisions.json contains services and lines, keyed by captured record ID.
Every captured service requires a nonempty summary and review_reason.
Every line requires coverage (invoice_header or unresolved) and a
nonempty reason. These are explicit reviewed mappings, not an automatic
description parser. Compare line descriptions with configured charge validity
and invoice coverage before selecting an inheritance rule.
python -m commercial_services.msp_review --directory .local/msp-service-review
preview.json records the source hash, decisions, optional field definitions,
exact target IDs/values and batch hash. It creates no CRM records and changes
no remote data. Review the populated summary text as well as the field payloads.
Apply and read back
python -m commercial_services.msp_review \
--directory .local/msp-service-review \
--apply --expected-batch <reviewed-batch-hash>
The writer regenerates the preview from the captured source and decisions. It checks all captured business records before any schema or record write, validates customer/Plan/invoice/document relationships and source-line uniqueness, then checks field compatibility and Standard-layout visibility. Only the five named optional service fields can be created.
Updates use trigger: [] and If-Unmodified-Since. Each target is checked again
immediately before writing and read back afterward. The writer preserves all
other captured business fields, including Products, source-line identities,
quantities, prices, discounts, taxes and totals. It rejects changes to any
operational Plan, configured charge, native invoice, Deal or other record.
The private journal retains request intent, complete before-images, responses
and verified records. applied.json lists changed and already-matching IDs.
Repeating a matching batch makes no additional field or record changes.
Conflicting human edits, changed sources, metadata conflicts or failed readback
stop the command. After interruption, inspect the journal and resume the same
batch; there is no destructive rollback.
CRM review surface and limits
Review the candidate Commercial Service's Actual Invoice Lines, or follow its native CRM Invoice to Actual Service Lines. The invoice list shows Commercial Service, Product, Configured MSP Invoice Line, quantity, unit/net amounts, service-period start/end and document status. These are native CRM display settings, separate from business-record writes. Commercial summaries and agreement context are optional; they are not prerequisites for line capture or configured-charge mapping.
This is an operator-run candidate migration, not ongoing synchronisation. Plan agreement fields are source context; the command does not maintain a second editable billing configuration or synchronise commercial edits back to the Plan. Native invoice refresh and Xero sync remain unchanged. The captured line representation retains its financial source identity and values; Product corrections and disputed periods require separate evidence. No Service Month record or Service Terms record is required for this slice.
Verification: tests/commercial_services/test_msp_review.py covers customer
and invoice ownership, date inheritance, unresolved periods, business-source
drift, financial preservation, schema conflicts, transport restrictions and
idempotence. The process rules are in
MSP Invoicing.
Configured charge links
commercial_services.invoice_charge_links adds the optional
Service_Invoice_Lines.Configured_MSP_Invoice_Line lookup to
MSP_Invoice_Lines and populates explicitly selected actual lines. Its reverse
related list is Actual Invoice Lines on a configured charge. The existing
CRM_Invoice lookup supplies the Invoice → actual lines relationship.
Capture complete selected records into private source.json, with a records
object containing these five module arrays: Service_Invoice_Lines,
MSP_Invoice_Lines, Invoices, Commercial_Services, and
Managed_Services_Plans. Include the target lines and all records needed to
verify their invoice, service, Plan and configured-charge relationships.
decisions.json maps each selected actual-line ID to charge_id and a nonempty
reason. Unselected lines remain untouched. Select matches from evidence;
this command does not infer a match from the Product alone.
python -m commercial_services.invoice_charge_links --directory .local/invoice-charge-links
python -m commercial_services.invoice_charge_links \
--directory .local/invoice-charge-links \
--apply --expected-batch <preview-batch-hash>
The preview validates that the selected charge and invoice share the service's Plan/customer, the line and charge share a Product, and source document and currency identifiers agree. Missing or duplicate source-line identifiers and different existing charge links stop the preview. Historical quantity and price differences are allowed; those values are preserved. Product identity differences require a separate attribution decision before using this command.
Apply checks captured records for drift before any write, creates only the
named optional lookup when missing, and verifies its target and Standard-layout
visibility. Each update changes only that lookup, uses trigger: [] and
If-Unmodified-Since, and is read back against all captured business values.
The private journal retains before-images and responses. A matching rerun skips
record writes. Invoice generation, source status/payment synchronisation and
changes to operational charge configuration are outside the command.
Verification: tests/commercial_services/test_invoice_charge_links.py covers
historical financial preservation, ownership and Product mismatches, source
drift, duplicate lines, conflicting links, schema conflicts, idempotence and the
write boundary. Success Works' eight INV-0319 mappings are applied with private
evidence in .local/commercial-services/invoice-charge-links-20260908/.