Today a daily batch re-prices MSD subscriptions for two weeks, resends each order to FIS, and someone watches it until go-live. With FIS replaced by Business Central, the proposal is to record the price change once, apply it once at go-live, and send Business Central one acknowledged message per subscription.
LIKE '%MSD%'), the date sits in a Custom Label, and nothing records what changed.cc.bsline.priceupdate, cc.bsschedule.priceupdate, cc.bsorder.priceupdate). The key makes a resend safe: Business Central updates the same record instead of creating a second one.Price Change is the record Finance approves. Price Change Line is one affected subscription line; it's the audit row, the work list for Apply and the outbox for Business Central in one. It's a master-detail child, so the header can count lines in each state with roll-ups.
| Line | Order | Amount | Apply status | Sync status |
|---|---|---|---|---|
| PCL-001201 | 00081234 | $54.90 to $59.90 | Applied | Acknowledged |
| PCL-001202 | 00081267 | $54.90 to $59.90 | Skipped: order cancelled | Not Sent |
| PCL-001203 | 00081302 | $49.41 to $53.91 (10% discount) | Applied | Failed: timeout, 3 attempts |
Sketch only; numbers, names and buttons are illustrative. The tiles are the header's roll-ups, which replace the three-week watch with one number to check.
Lines_Expected__c). Amber names are the header roll-ups that count each state. The Price Change is reconciled when expected = applied + skipped, applied = acknowledged, and nothing is in Error or Failed.| # | Field | Type | Purpose |
|---|---|---|---|
| What is changing | |||
| 1 | Description__c | Text(255) | For example "MSD price change July 2026" |
| 2 | Product__c | Lookup(Product2), required | The product being re-priced: one Price Change per product, chosen by id rather than by name |
| 3 | Effective_Date__c | Date, required | Go-live: the first billing date at the new price |
| 4 | Pricebook_Update_Date__c | Date | When the pricebook changed for new orders (about three weeks before) |
| 5 | Old_Price_Excl_GST__c | Currency(16,2) | Price before the change, excluding GST |
| 6 | Old_Price_Incl_GST__c | Currency(16,2) | Price before the change, including GST |
| 7 | New_Price_Excl_GST__c | Currency(16,2) | New price excluding GST, also written to the pricebook |
| 8 | New_Price_Incl_GST__c | Currency(16,2) | New price including GST, the billed amount |
| Approval and status | |||
| 9 | Status__c | Picklist | Draft, Approved, Pricebook Updated, Previewed, Applied, Synced, Closed, Cancelled |
| 10 | Approved_By__c | Lookup(User) | Finance approver |
| 11 | Approved_On__c | Date/Time | When it was approved |
| Counts and totals (roll-up summaries from the lines) | |||
| 12 | Lines_Expected__c | Roll-up count | All lines the preview found |
| 13 | Lines_Applied__c | Roll-up count | Apply Status = Applied |
| 14 | Lines_Skipped__c | Roll-up count | Apply Status = Skipped |
| 15 | Lines_Apply_Errors__c | Roll-up count | Apply Status = Error |
| 16 | Lines_Acknowledged__c | Roll-up count | Sync Status = Acknowledged |
| 17 | Lines_Sync_Failed__c | Roll-up count | Sync Status = Failed |
| 18 | Total_Old_Amount__c | Roll-up sum | Old amount per billing cycle across all lines, for the Finance preview |
| 19 | Total_New_Amount__c | Roll-up sum | New amount per billing cycle across all lines |
| 20 | Reconciled__c | Formula checkbox | True when expected = applied + skipped, applied = acknowledged, and errors and failures are both 0 |
| # | Field | Type | Purpose |
|---|---|---|---|
| Relationships | |||
| 1 | Price_Change__c | Master-detail(Price_Change__c) | The parent price change |
| 2 | Account__c | Lookup(Account) | Customer, for reports and support |
| 3 | Order__c | Lookup(Order) | Order whose totals are updated |
| 4 | Order_Product__c | Lookup(OrderItem) | Subscription line being re-priced |
| 5 | Old_Billing_Schedule__c | Lookup(Billing_Schedule__c) | Schedule ended the day before go-live |
| 6 | New_Billing_Schedule__c | Lookup(Billing_Schedule__c) | Schedule created from go-live at the new price |
| Amount and schedule (captured at preview) | |||
| 7 | Old_Amount__c | Currency(16,2) | Amount per cycle before, incl GST |
| 8 | New_Amount__c | Currency(16,2) | Amount per cycle after, incl GST |
| 9 | Discount_Amount__c | Currency(16,2) | Line discount carried across, as today |
| 10 | Billing_Frequency__c | Text(40) | Copied from the schedule |
| 11 | Next_Billing_Date__c | Date | Next billing date, for the Finance report |
| Apply result | |||
| 12 | Apply_Status__c | Picklist | Pending, Applied, Skipped, Error |
| 13 | Skip_Reason__c | Text(255) | Why a line was skipped: cancelled, downgraded, schedule ended |
| 14 | Applied_On__c | Date/Time | When Apply ran for this line |
| Business Central sync (the outbox) | |||
| 15 | Sync_Status__c | Picklist | Not Sent, Sent, Acknowledged, Failed |
| 16 | Sync_Attempts__c | Number(3,0) | Send attempts; automatic retry stops at a configured limit |
| 17 | Last_Sent_On__c | Date/Time | Last send to AIS |
| 18 | Acknowledged_On__c | Date/Time | When Business Central confirmed |
| 19 | BC_Reference__c | Text(80) | Business Central's id for the update |
| 20 | Last_Error__c | Long Text(32,768) | Last apply or sync error |
| 21 | Idempotency_Key__c | Text(80), unique, external ID | Price Change id + OrderItem id: a line can't be created twice, a resend is safe, and AIS can return acknowledgements by upsert on this key |
Also needed: a Finance permission set (create, approve, view) and an integration permission for AIS to update sync fields. Eight roll-ups are well under the per-object limit (25 by default).
Salesforce re-prices schedules and transactions. Business Central receives line, schedule and order price updates with an effective date and invoices from Salesforce's billing transactions. Least change, and it reuses the AIS topics being built.
Salesforce sends one price-list change (product, new price, effective date) and Business Central re-prices its own contracts. Fewest messages, but it needs Business Central subscription billing in scope.
TelecareMSDPriceChangeUpdateBatch and the MSDPriceDateChange label after the first run on the new design. If FIS needs one more cycle first: bulkify its inserts and updates, select by product id, and update order totals.OrderPatchHourlyBatch, OrderLinePatchHourlyBatch, BillingScheduleHourlyBatch) pick records changed in the last hour, so a failed or skipped run can miss changes silently. For price changes they send from the lines instead; the same outbox pattern would make the general sync safer.UNABLE_TO_LOCK_ROW. Apply runs as one batch, and AIS returns acknowledgements in groups (an upsert of up to 200 lines per call on Idempotency_Key__c), not one call per line.