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. The proposal: record the price change once, apply it once at go-live to every weekly, fortnightly and monthly subscription, and send Business Central one acknowledged message per subscription.
Today vs proposed
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 bill, 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, the order totals aren't updated, and nothing records what changed.
What the proposal changes
A price change is a business record: scope (MSD), go-live date and an approval. Prices stay in the pricebook.
Every affected subscription is listed two weeks ahead, so Finance signs off on a number.
Each subscription switches at the start of its own billing period, whatever its frequency.
Business Central gets small, repeat-safe messages and confirms each one.
Timeline
Dates follow the MSD example (price change 19/06, go-live 03/07). The system acts on three days. After that, automatic checks run when each frequency's first new-price bill is due (about one, two and four weeks later). Nobody has to watch.
Today: job or manual stepToday: monitoringProposed: system step
How it works, step by step
Seven steps, each shown as the screen Finance or the system would see. Product names and today's prices are real; counts, new prices and order numbers are samples.
1
Update the pricebook
About three weeks before go-live. Product admin or Finance, as today.
You
Change the price on each MSD product's Standard Price Book entry, by hand or with Data Loader, as you do today.
The system
Sells new orders at the new price from now on. Existing customers don't change until go-live.
You check
Nothing yet. Step 4 checks every price before anything else happens. Running the preview straight away catches mistakes early.
Standard Price Book: MSD productsEdited 12 Jun by product admin
Product
Price before (incl GST)
Price now
Medical Alarm - MSD Funded - Weekly
$17.27
$17.96
Medical Alarm - MSD Funded - Fortnightly
$34.54
$35.29
Medical Alarm - MSD Funded InAdvance - Monthly
$74.84
$77.83
… 23 more products
The fortnightly price has a typo. Nothing flags it here; step 4 does.
2
Create the price change
Same day, or any time before the preview. Finance.
You
Create a Price Change: description, funder, go-live date and price rule. No products or prices are typed in.
The system
Saves it as Draft. The funder decides which products are in scope, and the pricebook holds the prices, so there's nothing to keep in step.
New Price ChangeDraft
Draft
Previewed
Approved
Applied
Synced
Closed
Products: every product with Funder = MSD. Prices: the pricebook.Save
3
Preview who changes
Any time before go-live; about two weeks ahead at the latest. Can be rerun until approved.
You
Click Run Preview.
The system
Finds every product with Funder = MSD, inactive ones included, then every live subscription to them. It creates one Price Change Line each, with the old price from the billing schedule and the new price from the pricebook. Separately it counts the live billing schedules per product. The two counts must match in every cell.
You check
The grid is all ticks, and every exception has an answer.
Preview, PC-0007Run 19 Jun, 10:02
26Products
4,315Live subscriptions
4,315Lines created
0Missing products
Product group
Weekly
Fortnightly
Monthly
Medical Alarm
172 ✓
2,751 ✓
7 ✓
Medical Alarm Two Pendant
4 ✓
111 ✓
none
MSD Anywhere (incl. old product codes)
103 ✓
945 ✓
none
Securely Home
19 ✓
186 ✓
1 ✓
Add-ons (mobile, extra pendant)
1 ✓
15 ✓
none
Total
299
4,008
8
!3 subscriptions are on a custom amount, not the list price. Finance confirms each one.
✓12 are already at the new price (orders placed since the pricebook changed). Their lines are marked Skipped.
✓2 customers on a billing holiday are included; they pay the new price when billing resumes.
✓1 subscription has an end date after go-live; it's re-priced until it ends.
4
Check the prices and approve
After the preview. Finance manager.
The system
Shows each product's price today, its pricebook price and that price as a weekly amount. It flags any weekly, fortnightly and monthly prices that don't agree.
You
Fix any flagged price in the pricebook and rerun the preview. Approve is available only when every row is ticked.
Prices, PC-0007From the preview of 19 Jun
Draft
Previewed
Approved
Applied
Synced
Closed
Product
Bills
Paying now
Pricebook
Per week
Check
Medical Alarm - MSD Funded - Weekly
Weekly
$17.27
$17.96
$17.96
✓
Medical Alarm - MSD Funded - Fortnightly
Fortnightly
$34.54
$35.29
$17.65
✗ 2 × weekly is $35.92
Medical Alarm - MSD Funded InAdvance - Monthly
Monthly
$74.84
$77.83
$17.96
✓
MSD Anywhere - Fortnightly inactive, still billing
Fortnightly
$51.14
$53.18
$26.59
✓
Securely - MSD Home - Monthly
Monthly
$74.84
$77.83
$17.96
✓
… 21 more products
1 price to fix in the pricebook, then rerun the preview.
Rerun PreviewApprove
5
Apply at go-live
Go-live day, automatically (or one click).
The system
For each line, re-checks the subscription (a cancelled order is skipped with a reason) and finds the start of its next billing period. It ends the old billing schedule the day before and starts a new one at the new price on that day. It also updates the order line and order totals and makes the first bill at the new price. The section below shows each record change.
You check
Errors = 0. Every subscription keeps its own billing day.
Apply, PC-0007Go-live Fri 3 Jul 2026
4,300Applied
15Skipped, with reason
0Errors
Sample subscription
Old schedule ends
New schedule starts
First bill at new price
Weekly, in arrears, cycle starts Tuesday
Mon 6 Jul
Tue 7 Jul
Mon 13 Jul, $17.96
Fortnightly, in arrears, cycle started Wed 1 Jul
Tue 14 Jul
Wed 15 Jul
Tue 28 Jul, $35.92
Monthly, in advance, on the 20th
Sun 19 Jul
Mon 20 Jul
Mon 20 Jul, $77.83
Skipped: 12 already at the new price, 2 orders cancelled since the preview, 1 moved to a non-MSD product.
6
Send each change to Business Central
Straight after Apply, automatically.
The system
Sends each applied line to Business Central through AIS: which subscription, the new price and the date it starts. Business Central replies with its reference and the line ticks to Confirmed. No reply means 3 automatic retries, then Failed.
Think of it as
Tracked parcels: Salesforce posts one, AIS delivers it, Business Central signs for it. A line isn't done until it's signed for.
You check
Failed = 0, or click Resend Failed.
Business Central sync, PC-0007Updated 3 Jul, 06:40
4,300Sent
4,295Confirmed by BC
0Waiting
5Failed
Line
Message
Result
PCL-001201
Weekly, $17.96 from 7 Jul
Confirmed, BC ref SUB-48213
PCL-001202
Fortnightly, $35.92 from 15 Jul
Confirmed, BC ref SUB-48214
PCL-001203
Monthly, $77.83 from 20 Jul
No reply after 3 tries
Failed lines keep their error until resent.Resend Failed
7
Reconcile and close
The day after go-live, then automatically when each frequency's first new bill is due.
The system
Runs the checks and shows them as ticks. It also looks for anything still at the old price; that number must be 0.
You
Act only on what isn't ticked. Close the price change when everything is.
Reconciliation, PC-0007Status: Synced
✓Every live subscription has a line (4,315 of 4,315)
✓Every line applied, or skipped with a reason (4,300 + 15)
✓Business Central confirmed every applied line (4,300 of 4,300, after resend)
✓Nothing left at an old price (0 schedules, 0 upcoming bills)
✓First weekly bills at the new price (checked Tue 14 Jul)
✓First monthly bills at the new price (checked Tue 21 Jul)
…First fortnightly bills: check runs Wed 29 Jul
Close becomes available when every check is ticked.Close price change
Technical view: the same flow as a system sequence
Step 7 reuses the AIS topics already being built (cc.bsline.priceupdate, cc.bsschedule.priceupdate, cc.bsorder.priceupdate). The key (Price Change + OrderItem) makes a resend safe, because Business Central updates the same record instead of creating a second one.
How the records are created
Price Change (step 2)
When: once the pricebook has the new prices, and before the preview. Finance creates it from the Price Changes tab with New.
What's on it: description, funder (MSD), go-live date and the price rule. Status starts at Draft.
What isn't: products or prices. The funder attribute decides the products and the pricebook holds the prices, so the two can't disagree.
Approval comes after the preview (step 4), so Finance approves the real prices and the real number of subscriptions.
Price Change Lines (step 3, Preview)
A batch first finds the products: every product with Funder = MSD, active or not. It uses ProductController.getProductsByDefinitionAttributes, the lookup the June draft in QA already uses. As a safety net, any product with live schedules whose name contains MSD but whose funder isn't MSD is counted as a missing product. Then it reads the billing schedules, not the bills, so every subscription is found at once, whatever its frequency and wherever it is in its cycle. One line per schedule:
SELECT Id, Order_Product__c, Order_Product__r.OrderId, Order_Product__r.Product2Id, Account__c,
Amount_to_be_billed__c, Billing_Start_Date__c, Billing_Frequency__c, Billing_Type__c,
Quantity__c, Next_Billing_Date_Calculated__c, Order_Product__r.LineDiscountAmount__c
FROM Billing_Schedule__c
WHERE Order_Product__r.Product2Id IN :productsWithFunderMSD
AND Order_Product__r.Order.Status = 'Activated'
AND Charge_Type__c = 'Recurring'
AND Billing_Start_Date__c != null
AND (Billing_End_Date__c = null OR Billing_End_Date__c >= :goLiveDate)
Filled on each line: Product, Order, OrderItem, Account and old schedule.
Old_Amount__c is the schedule's Amount_to_be_billed__c.
New_Amount__c is the product's active Standard Price Book price incl GST.
Also: discount, frequency, in advance or in arrears, next billing date and the forecast cutover date.
Apply Status = Pending, Sync Status = Not Sent.
Already at the new price (old = new, for orders placed since the pricebook changed): the line is marked Skipped, so the counts still add up.
Rerun-safe: lines are upserted on Idempotency_Key__c (Price Change + OrderItem), so a second preview updates lines instead of duplicating them.
Counted twice: live schedules are also counted straight from Billing_Schedule__c, into Live_Schedules__c on the header and per product on the preview screen.
Billing holidays: a holiday is its own schedule record (Charge Type = Billing Holiday). The customer's recurring schedule stays live, so it's included.
At Apply: the same query runs again, and any subscription activated since the preview gets a late line. The pricebook is read again too. If a product's price no longer matches its lines' New_Amount__c, those lines stop with an error ("pricebook changed since approval"): rerun the preview and approve again.
What Apply does to the records
Example: a fortnightly, in-arrears subscription whose cycle started Wednesday 1 July. Go-live is Friday 3 July, the price goes from $34.54 to $35.92, and the rule is "billing periods starting on or after go-live". Its cutover is therefore Wednesday 15 July.
Record
Action
Fields (example values)
Old Billing Schedule
Updated
Billing_End_Date__c: blank to 14 Jul (cutover − 1). Nothing else changes, so its history stays intact.
New Billing Schedule
Created
A copy of the old one (account, bank and payment details, quantity, frequency, in arrears or in advance), with: Billing_Start_Date__c = 15 Jul (cutover, so the customer keeps their Wednesday fortnight) First_Payment_Date__c = 28 Jul (in arrears: end of the first period; in advance: the cutover date) Amount_to_be_billed__c = $35.92; Billing_End_Date__c = blank, or the old end date if one was set
Upcoming bill on the old schedule
Left or Cancelled
Period starts before cutover (1 to 14 Jul): left at the old price. Period starts on or after cutover (possible for weekly customers): Status__c = Cancelled.
First bill on the new schedule
Created
Billing_Period_Start_Date__c / End = 15 to 28 Jul; Status__c = Upcoming Rate__c and Total_Amount_Value__c = $35.92; GST_Amount_Value__c = $4.69; List_Price_Value__c = $31.23 Discount_Amount_Value__c = the line discount; quantity, payment method, and payment date (in arrears: period end)
OrderItem
Updated
UnitPrice $30.03 to $31.23; LineGSTAmount__c $4.51 to $4.69; LineTotalAmount__c $34.54 to $35.92. LineDiscountAmount__c unchanged.
Order
Updated
OrderSubTotalAmount__c, OrderTotalGSTAmount__c, OrderTotalAmount__c and OrderDiscountAmount__c recalculated from all the order's lines (base plus add-ons). These are plain number fields that today's batch leaves stale. The standard TotalAmount follows UnitPrice automatically.
Price Change Line
Updated
New_Billing_Schedule__c, Cutover_Date__c = 15 Jul, Apply_Status__c = Applied, Applied_On__c. Then it joins the Business Central outbox.
All or nothing per line. Each line's changes are made together. If any one fails, that line's changes roll back, the line shows Error with the message, and the rest carry on.
Later bills need no new code. When a bill is submitted, the existing flow Create recurring Billing Transactions (BillingTransactionController) makes the next Upcoming bill on the same schedule. It prices it from the schedule's Amount_to_be_billed__c and the OrderItem, both of which are now at the new price.
Watch old bills in reports.Total_Amount__c, GST_Amount__c and Unit_Price__c on bills are formulas that read the OrderItem. After Apply, even paid bills show the new price in those fields. Reports and the AIS bill payload must use the stored …_Value__c fields.
Weekly, fortnightly and monthly: making sure every subscription is covered
MSD products come in weekly, fortnightly and monthly versions. Each version is its own product with its own price, for example Medical Alarm at $17.27 a week, $34.54 a fortnight and $74.84 a month. So the design works by product, never by name or frequency. Each subscription bills on a cycle counted from its own start date: the same weekday for weekly and fortnightly, the same date for monthly. The switch has to land on that cycle.
Each subscription's new schedule starts on its own next cycle boundary, never on the go-live date itself. The billing-date formula counts cycles from Billing_Start_Date__c, so starting a weekly customer's new schedule on Friday 3 July would move their billing day. Today's batch gets this right by starting the new schedule at the upcoming bill's period start. The new Apply keeps that rule.
The one decision Finance needs to make
Most MSD subscriptions are billed in arrears, at the end of each period. That leaves one question: what price does the period that straddles go-live pay?
Recommended
Billing periods starting on or after go-live
Customers pay the new price only for service after go-live. It's the same rule for every frequency, in advance or in arrears. The first new-price bill comes up to one cycle after go-live (above: 7, 15 and 20 July).
What today's batch does
Bills dated on or after go-live
For in-arrears customers, the period that straddles go-live is billed in full at the new price. A fortnightly customer would pay the new price for up to 13 days of service before go-live (above: the whole 1 to 14 July period).
Five checks that prove nothing is missed
Check
When
Passes when
Every product with live MSD subscriptions is in scope: found by funder, inactive (grandfathered) products included
Every live subscription has a line, counted per product and frequency straight from the billing schedules
Preview, and again at Apply
Live schedules = lines, in every cell
Each line switches at the start of its own billing period, within one cycle of go-live (7, 14 or about 31 days)
Apply
0 exceptions
Nothing left at an old price: no live schedule or upcoming bill on these products at an amount other than the pricebook price (confirmed custom amounts aside)
Day after go-live, then when each frequency's first new bill is due (about 1, 2 and 4 weeks)
0 found
The two new objects
Price Change is the record Finance approves: scope, go-live date and price rule. Price Change Line is one affected subscription: the audit row, the work list for Apply and the outbox for Business Central in one. Products and prices aren't stored separately: the funder attribute decides the products and the pricebook holds the prices.
Two new objects, 44 custom fields in all (20 + 24), each with an auto-number Name. Arrows point from a record to the record it looks up. Amber types are roll-up summaries. Billing Schedule (amber box) is the existing object Apply ends and creates. No new fields on existing objects; the full field lists are below.
Line status lifecycle
The preview creates every line as Pending (counted by Lines_Expected__c). Amber names are the header roll-ups that count each state.
Field lists
Price_Change__c, Price Change
Name (auto-number PC-{0000}) + 20 custom fields: 13 entered or set by the process, 6 roll-ups, 1 formula
#
Field
Type
Purpose
What and when
1
Description__c
Text(255)
For example "MSD price change July 2026"
2
Funder__c
Picklist, required
Scope: every product with this funder attribute (MSD), active or not
3
Effective_Date__c
Date, required
Go-live date
4
Price_Rule__c
Picklist
"Billing periods starting on or after go-live" (default) or "Bills dated on or after go-live"
Finance approver; approval follows the preview and the price checks
7
Approved_On__c
Date/Time
Counts (roll-up summaries from the lines)
8
Lines_Expected__c
Roll-up count
All lines
9
Lines_Applied__c
Roll-up count
Apply Status = Applied
10
Lines_Skipped__c
Roll-up count
Apply Status = Skipped
11
Lines_Apply_Errors__c
Roll-up count
Apply Status = Error
12
Lines_Acknowledged__c
Roll-up count
Sync Status = Acknowledged
13
Lines_Sync_Failed__c
Roll-up count
Sync Status = Failed
Checks (set by the preview and check jobs)
14
Products_In_Scope__c
Number
Products found by funder
15
Live_Schedules__c
Number
Live schedules counted straight from Billing_Schedule__c, to compare with Lines_Expected__c
16
Missing_Products__c
Number
Products with live MSD-named subscriptions whose funder isn't MSD
17
Price_Check_Issues__c
Number
Products whose pricebook prices don't agree across weekly, fortnightly and monthly
18
Left_At_Old_Price__c
Number
Live schedules or upcoming bills on these products not at the pricebook price (confirmed custom amounts aside)
19
First_Bill_Checks__c
Text(255)
For example "Weekly OK 14 Jul; Monthly OK 21 Jul; Fortnightly due 29 Jul"
20
Reconciled__c
Formula checkbox
No missing products or price issues, live schedules = lines = applied + skipped, applied = acknowledged, no errors or failures, nothing left at the old price
Price_Change_Line__c, Price Change Line
Name (auto-number PCL-{000000}) + 24 custom fields: 7 relationships, 7 amount and schedule, 3 apply, 7 sync
#
Field
Type
Purpose
Relationships
1
Price_Change__c
Master-detail(Price_Change__c)
The parent price change
2
Product__c
Lookup(Product2)
For the per-product counts and price checks
3
Account__c
Lookup(Account)
Customer, for reports and support
4
Order__c
Lookup(Order)
Order whose totals are recalculated
5
Order_Product__c
Lookup(OrderItem)
Subscription line being re-priced
6
Old_Billing_Schedule__c
Lookup(Billing_Schedule__c)
Ended the day before cutover
7
New_Billing_Schedule__c
Lookup(Billing_Schedule__c)
Created from cutover at the new price
Amount and schedule
8
Old_Amount__c
Currency(16,2)
From the schedule's Amount_to_be_billed__c, per period incl GST
9
New_Amount__c
Currency(16,2)
From the pricebook at preview, per period incl GST
10
Discount_Amount__c
Currency(16,2)
Line discount carried across
11
Billing_Frequency__c
Text(3)
1W, 2W or 1M
12
Billing_Type__c
Text(2)
AR (in arrears) or AD (in advance)
13
Next_Billing_Date__c
Date
At preview, for the Finance report
14
Cutover_Date__c
Date
First day at the new price: the start of this subscription's first billing period under the price rule
Apply result
15
Apply_Status__c
Picklist
Pending, Applied, Skipped, Error
16
Skip_Reason__c
Text(255)
Already at the new price, cancelled, product changed, schedule ended
17
Applied_On__c
Date/Time
Business Central sync (the outbox)
18
Sync_Status__c
Picklist
Not Sent, Sent, Acknowledged, Failed
19
Sync_Attempts__c
Number(3,0)
Automatic retry up to a set limit
20
Last_Sent_On__c
Date/Time
21
Acknowledged_On__c
Date/Time
22
BC_Reference__c
Text(80)
Business Central's id for the update
23
Last_Error__c
Long Text(32,768)
Last apply or sync error
24
Idempotency_Key__c
Text(80), unique, external ID
Price Change id + OrderItem id: no duplicate lines, a resend is safe, and AIS can return acknowledgements by upsert
Also needed: a Finance permission set (create, approve, view) and an integration permission for AIS to update the sync fields. Six roll-ups is 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 bills as above. Business Central receives each subscription's new price with its cutover date, and invoices from Salesforce's bills. Least change, and it reuses the AIS topics being built.
Later option
B. Business Central owns subscription billing
Salesforce sends one price-list change per product (new price, go-live, price rule) and Business Central re-prices its own contracts. Fewest messages, but it needs Business Central subscription billing in scope.
Changes to what exists
RetireTelecareMSDPriceChangeUpdateBatch, its schedule class and the MSDPriceDateChange label after the first run on the new design. Keep its one good rule: the new schedule starts at a period start.
June draft in QA (TelecarePriceChangeBatch, PriceChangeService; not in UAT or Prod): reuse its product lookup by funder attribute, then retire it. As written, it sets every schedule on an order to the whole order total, and adds bills with no dates or status.
AIS patch batches (OrderPatchHourlyBatch, OrderLinePatchHourlyBatch, BillingScheduleHourlyBatch) pick records changed in the last hour, so a failed run can miss changes. 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
New orders get the new price before approval. The pricebook changes first, by hand, as today, and a wrong price is caught only at the step 4 check. Run the preview the same day the pricebook changes; Apply still waits for go-live.
Pricebook edited after approval: Apply compares the pricebook with each line's New_Amount__c and stops that product's lines. Rerun the preview and approve again.
Billing day moves if a new schedule starts on go-live day. Apply starts it on the subscription's own cycle boundary, and check 4 proves it.
Volume: a price change touches every live MSD subscription, tens of thousands of lines. Apply and the sync run in batches. AIS returns acknowledgements in groups (an upsert of up to 200 lines per call on Idempotency_Key__c), so header roll-ups don't hit UNABLE_TO_LOCK_ROW.
Old bills show new prices in three formula fields. Reports and the AIS payload use the stored …_Value__c fields.
Orders that change between preview and go-live (cancel, downgrade, swap): Apply re-checks each line and skips with a reason; new subscriptions get late lines.
Custom amounts and discounts: the preview lists subscriptions not on the list price for Finance to confirm. Line discounts carry across as today.
GST: incl and excl GST prices come from the pricebook entry, as today.
First use: a full rehearsal in UAT against the Business Central test environment, with the five checks signed off, before the first production price change.
Questions
For Finance
Price rule: billing periods starting on or after go-live (recommended), or bills dated on or after go-live (today's behaviour)?
Who approves a price change?
Is it OK that new orders get the new price when the pricebook changes, before the price change is approved? This is today's process.
For the Business Central and AIS team
Who generates recurring invoices in the Business Central design: Salesforce bills (A) or Business Central subscription billing (B)?
Can AIS or Business Central return an acknowledgement per message, with Business Central's reference, in groups?
Can Business Central hold a future-dated price per subscription? Each subscription has its own cutover date.
Will Business Central upsert on Salesforce ids (OrderItem, billing schedule), so a resend is safe?
A price change covers every live MSD subscription. What is the AIS limit per hour?