Solution design draft for discussion, 20 October 2026

Telecare price change, synced to Business Central without the three-week watch

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.

Today vs proposed

Today Pricebook changed by hand Daily batch finds MSD by product name runs every day for about two weeks Clone schedule and BT cancel old, update order line Resend whole order Order V2, one at a time FIS billing no acknowledgement Success is checked by watching the sync for about three weeks. Proposed Price Change one approved record Preview, once one line per schedule sign-off Apply once at go-live new schedule at new price Outbox, one per line AIS price-update topics Business Central acknowledgement and BC reference Next day: reconcile expected = applied = acknowledged, then close.
The daily loop and the whole-order resend go away. Affected subscriptions are found once from their billing schedules, the price is applied once, and every line waits for Business Central to confirm it.
Why today needs watching
  • Each schedule holds only one Upcoming billing transaction, and those appear as invoice dates roll on, so affected orders surface a few at a time and the batch has to run daily.
  • The FIS sync resends the whole order, one at a time, and nothing confirms it arrived.
  • The product is found by name (LIKE '%MSD%'), the date sits in a Custom Label, and nothing records what changed.
What the proposal changes
  • A price change is a business record for any product and price, with an approval.
  • Every affected subscription is listed two weeks ahead, so Finance signs off on a number.
  • New schedules carry the new price, so later transactions are right without reruns.
  • Business Central gets small, repeat-safe messages with an effective date, and confirms each one.

Timeline

19/0621/0623/06 25/0627/0629/06 01/0703/0705/07 07/0709/07 Price change Go-live Today Pricebook changed by hand Daily batch: re-price, resend to FIS Watch that FIS got every order Business and Finance checks Proposed Approve, update pricebook Preview and Finance sign-off Apply once, send to BC Reconcile and close expected = applied = acknowledged
Dates follow the MSD example (price change 19/06, go-live 03/07). In the proposal the system acts on three days. The preview window is the only part that needs people, and it ends in a sign-off rather than a watch.
Today: job or manual step Today: monitoring Proposed: system step

End-to-end flow

Finance Salesforce (CC) AIS Business Central 1 Create and approve Price Change 2 Update pricebook (new orders) 3 Preview: create the lines 4 Preview report for sign-off 5 Sign off Go-live day 6 Apply once (schedules, prices, totals) Loop: each applied line 7 Price update, effective date, key 8 Upsert subscription price 9 Acknowledge with BC reference 10 Line marked Acknowledged no ack: retry, then Failed 11 Reconciliation report
Option A (recommended now): Salesforce stays the billing engine. Business Central receives line, schedule and order price updates with an effective date, reusing the AIS topics already being built (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.

What happens to one subscription at go-live

Billing schedule Old schedule, $54.90 a month, ends 2 Jul New schedule, $59.90 a month, from 3 Jul Go-live 3 Jul Billing transactions 3 May, paid 3 Jun, paid 3 Jul, re-priced once 3 Aug, new price 3 Sep, new price
Apply ends the old schedule the day before go-live and starts a new one at the new price. The transaction already due on go-live is re-priced once; later ones are generated from the new schedule, so nothing needs to rerun. The same step updates the order line and order totals and carries any line discount across. Amounts are illustrative.

The two new objects

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.

Price_Change__c Name PC-{0000} + 20 custom fields Description__cText(255) Product__cLookup(Product2) Effective_Date__cDate Pricebook_Update_Date__cDate Old_Price_Excl_GST__cCurrency Old_Price_Incl_GST__cCurrency New_Price_Excl_GST__cCurrency New_Price_Incl_GST__cCurrency Status__cPicklist Approved_By__cLookup(User) Approved_On__cDate/Time Lines_Expected__cRoll-up count Lines_Applied__cRoll-up count Lines_Skipped__cRoll-up count Lines_Apply_Errors__cRoll-up count Lines_Acknowledged__cRoll-up count Lines_Sync_Failed__cRoll-up count Total_Old_Amount__cRoll-up sum Total_New_Amount__cRoll-up sum Reconciled__cFormula(Checkbox) master-detail one to many Price_Change_Line__c Name PCL-{000000} + 21 custom fields Price_Change__cMaster-detail Account__cLookup(Account) Order__cLookup(Order) Order_Product__cLookup(OrderItem) Old_Billing_Schedule__cLookup New_Billing_Schedule__cLookup Old_Amount__cCurrency New_Amount__cCurrency Discount_Amount__cCurrency Billing_Frequency__cText(40) Next_Billing_Date__cDate Apply_Status__cPicklist Skip_Reason__cText(255) Applied_On__cDate/Time Sync_Status__cPicklist Sync_Attempts__cNumber Last_Sent_On__cDate/Time Acknowledged_On__cDate/Time BC_Reference__cText(80) Last_Error__cLong text Idempotency_Key__cText, unique, ext ID AccountAccount__c OrderOrder__c OrderItemOrder_Product__c Billing Scheduleold and new Billing_Schedule__c Product2Product__c UserApproved_By__c Groups, top to bottom: relationships, amounts and schedule, apply result, Business Central sync. Amber = roll-up summary on the header (8 of them).
Two new objects, 41 custom fields in all (20 on Price Change, 21 on Price Change Line), each with an auto-number Name. Billing Schedule (amber) is the existing object whose records Apply ends and creates. No new fields are needed on existing objects.

How a Price Change record looks to Finance

Price Change
PC-0007, MSD price change July 2026
Update PricebookRun PreviewApplyResend Failed
  1. Draft
  2. Approved
  3. Pricebook Updated
  4. Previewed
  5. Applied
  6. Synced
  7. Closed
Product
MSD monthly monitoring
Effective date
3 Jul 2026
Old price incl GST
$54.90
New price incl GST
$59.90
Approved by
Finance approver, 18 Jun 2026
Reconciled
No: 5 lines to resend
1,240Lines expected
1,236Applied
4Skipped
0Apply errors
1,231Acknowledged by BC
5Sync failed
LineOrderAmountApply statusSync status
PCL-00120100081234$54.90 to $59.90AppliedAcknowledged
PCL-00120200081267$54.90 to $59.90Skipped: order cancelledNot Sent
PCL-00120300081302$49.41 to $53.91 (10% discount)AppliedFailed: 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.

Line status lifecycle

Apply_Status__c Sync_Status__c Skipped Lines_Skipped__c Pending Error Lines_Apply_Errors__c Applied Lines_Applied__c Sent Acknowledged Lines_Acknowledged__c Failed Lines_Sync_Failed__c order changed fails fixed, retry apply OK send BC confirms no ack after retries resend
The preview creates every line as Pending (that's 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 lists

Price_Change__c, Price Change

Name (auto-number PC-{0000}) + 20 custom fields: 11 entered or set by the process, 8 roll-ups, 1 formula
#FieldTypePurpose
What is changing
1Description__cText(255)For example "MSD price change July 2026"
2Product__cLookup(Product2), requiredThe product being re-priced: one Price Change per product, chosen by id rather than by name
3Effective_Date__cDate, requiredGo-live: the first billing date at the new price
4Pricebook_Update_Date__cDateWhen the pricebook changed for new orders (about three weeks before)
5Old_Price_Excl_GST__cCurrency(16,2)Price before the change, excluding GST
6Old_Price_Incl_GST__cCurrency(16,2)Price before the change, including GST
7New_Price_Excl_GST__cCurrency(16,2)New price excluding GST, also written to the pricebook
8New_Price_Incl_GST__cCurrency(16,2)New price including GST, the billed amount
Approval and status
9Status__cPicklistDraft, Approved, Pricebook Updated, Previewed, Applied, Synced, Closed, Cancelled
10Approved_By__cLookup(User)Finance approver
11Approved_On__cDate/TimeWhen it was approved
Counts and totals (roll-up summaries from the lines)
12Lines_Expected__cRoll-up countAll lines the preview found
13Lines_Applied__cRoll-up countApply Status = Applied
14Lines_Skipped__cRoll-up countApply Status = Skipped
15Lines_Apply_Errors__cRoll-up countApply Status = Error
16Lines_Acknowledged__cRoll-up countSync Status = Acknowledged
17Lines_Sync_Failed__cRoll-up countSync Status = Failed
18Total_Old_Amount__cRoll-up sumOld amount per billing cycle across all lines, for the Finance preview
19Total_New_Amount__cRoll-up sumNew amount per billing cycle across all lines
20Reconciled__cFormula checkboxTrue when expected = applied + skipped, applied = acknowledged, and errors and failures are both 0

Price_Change_Line__c, Price Change Line

Name (auto-number PCL-{000000}) + 21 custom fields: 6 relationships, 5 amount and schedule, 3 apply, 7 sync
#FieldTypePurpose
Relationships
1Price_Change__cMaster-detail(Price_Change__c)The parent price change
2Account__cLookup(Account)Customer, for reports and support
3Order__cLookup(Order)Order whose totals are updated
4Order_Product__cLookup(OrderItem)Subscription line being re-priced
5Old_Billing_Schedule__cLookup(Billing_Schedule__c)Schedule ended the day before go-live
6New_Billing_Schedule__cLookup(Billing_Schedule__c)Schedule created from go-live at the new price
Amount and schedule (captured at preview)
7Old_Amount__cCurrency(16,2)Amount per cycle before, incl GST
8New_Amount__cCurrency(16,2)Amount per cycle after, incl GST
9Discount_Amount__cCurrency(16,2)Line discount carried across, as today
10Billing_Frequency__cText(40)Copied from the schedule
11Next_Billing_Date__cDateNext billing date, for the Finance report
Apply result
12Apply_Status__cPicklistPending, Applied, Skipped, Error
13Skip_Reason__cText(255)Why a line was skipped: cancelled, downgraded, schedule ended
14Applied_On__cDate/TimeWhen Apply ran for this line
Business Central sync (the outbox)
15Sync_Status__cPicklistNot Sent, Sent, Acknowledged, Failed
16Sync_Attempts__cNumber(3,0)Send attempts; automatic retry stops at a configured limit
17Last_Sent_On__cDate/TimeLast send to AIS
18Acknowledged_On__cDate/TimeWhen Business Central confirmed
19BC_Reference__cText(80)Business Central's id for the update
20Last_Error__cLong Text(32,768)Last apply or sync error
21Idempotency_Key__cText(80), unique, external IDPrice 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).

Options for the Business Central side

Recommended now

A. Salesforce stays the billing engine

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.

Later option

B. Business Central owns subscription billing

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.

Changes to what exists

  • Retire 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.
  • AIS patch batches (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.
  • No whole-order resend (Order V2) for price changes.

Risks and how the design handles them

  • Parent record locking. Each line update recalculates the header's roll-ups, so many updates at once can fail with 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.
  • Orders that change between preview and go-live (cancel, downgrade, swap): Apply re-checks each line and marks it Skipped with a reason.
  • Discounts and line overrides are carried across as today, and the preview lists them as exceptions before go-live.
  • GST: prices including and excluding GST come from the pricebook entry, as today, and order totals are recalculated.
  • First use: a full rehearsal in UAT against the Business Central test environment, with a reconciliation sign-off, before the first production price change.

Questions for the Business Central and AIS team

  1. Who generates recurring invoices in the Business Central design: Salesforce billing transactions (A) or Business Central subscription billing (B)?
  2. Can AIS or Business Central return an acknowledgement per message, with Business Central's reference, in groups?
  3. Do the price-update messages carry an effective date, and can Business Central hold a future-dated price?
  4. Will Business Central upsert on Salesforce ids (OrderItem, billing schedule), so a resend is safe?
  5. Expected volume per price change, and the AIS limit per hour.