Skip to content

Commit cc107f8

Browse files
authored
Merge main into docs/al-docs/shopify
2 parents c203b30 + cb500b9 commit cc107f8

16 files changed

Lines changed: 501 additions & 12 deletions

File tree

.github/AL-Go-Settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"runs-on": "windows-latest",
77
"cacheImageName": "",
88
"UsePsSession": false,
9-
"artifact": "bcinsider/Sandbox/29.0.47702.0//latest",
9+
"artifact": "bcinsider/Sandbox/29.0.47831.0//latest",
1010
"country": "base",
1111
"useProjectDependencies": true,
1212
"incrementalBuilds": {
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# API Reports - Finance
2+
3+
Read-only API layer that exposes raw financial data (GL entries, customer/vendor
4+
ledger entries, budgets, dimensions) through OData/REST endpoints. Unlike the
5+
standard BC API v2.0 financial endpoints (trialBalance, balanceSheet, etc.) which
6+
return pre-aggregated report data, this app exposes granular transactional records
7+
that consumers aggregate themselves -- a "data warehouse" approach for building
8+
custom financial reports.
9+
10+
## Quick reference
11+
12+
- **ID range**: 30300--30399
13+
- **Namespace**: Microsoft.API.FinancialManagement
14+
- **API route**: `api/microsoft/reportsFinance/beta/`
15+
- **API version**: beta (not GA -- endpoints may change)
16+
17+
## How it works
18+
19+
The app defines 9 API Pages and 6 API Queries, all read-only. Pages expose
20+
master/reference data (chart of accounts, customers, vendors, dimensions,
21+
budgets, accounting periods, business units, global settings). Queries expose
22+
transactional data (GL entries, GL budget entries, customer ledger entries,
23+
detailed customer ledger entries, vendor ledger entries, detailed vendor ledger
24+
entries).
25+
26+
Every object follows the same template: `PageType = API` or `QueryType = API`,
27+
`DataAccessIntent = ReadOnly`, all insert/modify/delete disabled, `ODataKeyFields
28+
= SystemId`. The app defines no tables of its own -- it reads directly from base
29+
app tables (G/L Entry, Cust. Ledger Entry, etc.).
30+
31+
The only procedural logic lives in two page triggers:
32+
33+
- **Accounting Periods** (`APIFinanceAccPeriods.Page.al`): computes
34+
`FiscalYearStartDate`, `FiscalYearEndDate`, and `EndingDate` on each record
35+
fetch. The ending date is derived by peeking at the next period's start date
36+
and subtracting one day.
37+
38+
- **GL Accounts** (`APIFinanceGLAccount.Page.al`): reconstructs the chart of
39+
accounts parent-child hierarchy at runtime using a `Dictionary<Integer,
40+
Code[20]>` keyed by indentation level. This is order-dependent -- it relies on
41+
records arriving sorted by account number with ascending indentation.
42+
43+
## Things to know
44+
45+
- All 15 data endpoints are completely read-only. There is zero write logic, zero
46+
events, zero extensibility hooks, and zero codeunits.
47+
- The GL Account parent tracking via dictionary is fragile. It works because API
48+
pages iterate records in sort order, but the pattern wouldn't survive
49+
re-sorting or filtering that breaks indentation sequencing.
50+
- `globalSettings` is a virtual page -- it reads from both the Company record and
51+
General Ledger Setup in `OnOpenPage`, exposing just company name, LCY code, and
52+
additional reporting currency.
53+
- The app has several caption typos in the query objects: `entryType` is captioned
54+
as `'Entry Number'` in both detailed ledger entry queries, and
55+
`initialEntryGlobalDim2` is captioned as `'...Dimension 1'` instead of
56+
`'...Dimension 2'`.
57+
- The `reveresd` column name in `APIFinanceGLEntry.Query.al` is a typo for
58+
`reversed`.
59+
- GL Budget Entry query has a duplicate column: both `accountNo` and
60+
`generalLedgerAccountNumber` map to the same `G/L Account No.` field.
61+
- Permissions follow the standard stacking pattern: one base permission set
62+
(`API Reports Finance - Objects`) extended into 6 D365 roles.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Troubleshoot FA Ledger Entries
2+
3+
This app detects and corrects rounding issues in Fixed Asset ledger entries. Some FA entries end up with amounts that have more decimal places than the currency's rounding precision allows (e.g., 1234.567 when precision is 0.01), which can cause downstream posting and reporting problems. The app scans for these entries, shows them to the user on the Fixed Asset Card via a notification, and lets them accept a rounded correction that writes directly back to the FA Ledger Entry table.
4+
5+
## Quick reference
6+
7+
| Item | Value |
8+
|------|-------|
9+
| ID range | 6090-6099 |
10+
| Namespace | `Microsoft.FixedAssets.Repair` |
11+
| Dependencies | None (base app + platform only) |
12+
| App ID | `7961e9dc-a8e5-49b1-839b-3a78803a4cb8` |
13+
| Object count | 1 table, 1 tableextension, 2 codeunits, 1 page, 10 permission objects |
14+
15+
## How it works
16+
17+
The app uses a **shadow table** pattern. Rather than flagging issues on the real FA Ledger Entry table, it copies problematic entries into its own staging table (`FA Ledg. Entry w. Issue`, table 6090). This avoids modifying production data during the detection phase and gives users a safe review step before any corrections happen.
18+
19+
**Detection** is handled by codeunit 6090 `FA Ledger Entries Scan`. It iterates FA Ledger Entries starting from a high-water mark stored on FA Setup (`LastEntryNo`), compares each entry's Amount to `Round(Amount, Currency."Amount Rounding Precision")`, and copies mismatched entries into the issues table. The scan is incremental -- it only looks at entries newer than the last scan, so repeated runs are cheap. The high-water mark advances to one past the last entry checked.
20+
21+
**Triggering** the scan is lazy and background-based. When a user opens a Fixed Asset Card, codeunit 6091 `FA Card Notifications` subscribes to `OnAfterGetCurrRecordEvent`. It checks a cooldown (7 days, stored as `Last time scanned` on FA Setup) and if enough time has passed, schedules the scan as a background task via `TaskScheduler.CreateTask` with a 1-second delay. This keeps the UI responsive -- the scan never blocks the page load. The notification only appears if the issues table already has uncorrected entries for that specific FA.
22+
23+
**Correction** happens on page 6090 `FA Ledger Entries Issues`. The user selects entries and clicks "Accept Selected". The page action directly modifies the real `FA Ledger Entry` record: it rounds the Amount, recalculates Debit/Credit amounts respecting the Correction flag, and marks the shadow entry as corrected. This is a permanent write to posted ledger entries -- there is no reversal mechanism.
24+
25+
## Structure
26+
27+
- **`src/tables/`** -- The shadow table for flagged entries and a tableextension on FA Setup for scan state (high-water mark, last scan timestamp).
28+
- **`src/codeunits/`** -- Scanner that detects rounding issues, and notification handler that wires into the Fixed Asset Card page.
29+
- **`src/pages/`** -- Review and correction page where users inspect flagged entries and accept fixes.
30+
- **`Permissions/`** -- Standard permission scaffolding. Extends D365 AUTOMATION, BASIC ISV, BUS FULL ACCESS, BUS PREMIUM, FA EDIT, and FULL ACCESS sets. The layered sets (Objects/Read/Edit) follow the BC permission set pattern.
31+
32+
## Things to know
33+
34+
- **The app modifies posted ledger entries directly.** The "Accept Selected" action writes to `FA Ledger Entry` without creating correcting entries or journal lines. This is unusual in BC where posted entries are typically immutable. The design is intentional -- these are sub-penny rounding fixes, not business corrections.
35+
36+
- **The scan is incremental, not full-table.** `FASetup.LastEntryNo` acts as a checkpoint. If you need to re-scan previously checked entries (e.g., after changing currency rounding precision), you would need to reset this field manually.
37+
38+
- **The 7-day cooldown is hardcoded.** `GetCacheRefreshInterval()` returns a fixed 1-week duration. There is no setup field to configure this. The cooldown prevents the scan from being scheduled on every Fixed Asset Card open.
39+
40+
- **Scan runs as a background task, not inline.** `TaskScheduler.CreateTask` means the scan executes in a separate session. The notification on the FA Card shows results from the *previous* scan, not a live check. A user opening the card for the first time after install will not see a notification until after the background task completes and they revisit the card.
41+
42+
- **The Amount field on the issues table stores the already-rounded value, not the original.** `TransferFields` copies from FA Ledger Entry, then the page's `OnAfterGetRecord` recalculates the original amount display and rounding difference on the fly. The `OriginalAmount` and `Rounding` columns on the page are computed, not stored.
43+
44+
- **Debit/Credit recalculation respects the Correction flag.** When rounding the amount, the code checks both the sign of the amount and the `Correction` boolean to determine which side (Debit vs Credit) gets the value. This mirrors standard BC posting logic where correction entries flip the normal debit/credit assignment.
45+
46+
- **No events are published.** The app subscribes to the FA Card page event but does not expose any integration or business events of its own. There are no extension points for customizing the scan logic or correction behavior.
47+
48+
- **Permission set extensions grant RIMD on the shadow table to all major D365 entitlements.** This means any user with standard BC licensing can see and interact with the correction page. The page itself also declares inline `Permissions` for both the shadow table and the real FA Ledger Entry table (RIMD on both).
49+
50+
- **The `Commit()` calls in both codeunits are deliberate lock-release patterns.** The scan codeunit locks FA Setup to update the timestamp, then commits to release the lock before the potentially long-running scan loop. The notification codeunit does the same before scheduling the background task.

src/Apps/W1/Subscription Billing/App/Customer Contracts/Pages/ClosedCustContLineSubp.Page.al

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
namespace Microsoft.SubscriptionBilling;
22

3+
using Microsoft.Finance.Dimension;
34
using Microsoft.Inventory.Item;
45

56
page 8080 "Closed Cust. Cont. Line Subp."
@@ -298,6 +299,24 @@ page 8080 "Closed Cust. Cont. Line Subp."
298299
Visible = false;
299300
Editable = false;
300301
}
302+
field("Shortcut Dimension 1 Code"; ServiceCommitment."Shortcut Dimension 1 Code")
303+
{
304+
ApplicationArea = Dimensions;
305+
Caption = 'Shortcut Dimension 1 Code';
306+
CaptionClass = '1,2,1';
307+
ToolTip = 'Specifies the code for Shortcut Dimension 1, which is one of two global dimension codes that you set up in the General Ledger Setup window.';
308+
Visible = false;
309+
Editable = false;
310+
}
311+
field("Shortcut Dimension 2 Code"; ServiceCommitment."Shortcut Dimension 2 Code")
312+
{
313+
ApplicationArea = Dimensions;
314+
Caption = 'Shortcut Dimension 2 Code';
315+
CaptionClass = '1,2,2';
316+
ToolTip = 'Specifies the code for Shortcut Dimension 2, which is one of two global dimension codes that you set up in the General Ledger Setup window.';
317+
Visible = false;
318+
Editable = false;
319+
}
301320
}
302321
}
303322
}
@@ -309,6 +328,21 @@ page 8080 "Closed Cust. Cont. Line Subp."
309328
{
310329
Caption = 'Contract Line';
311330
Image = "Item";
331+
action(Dimensions)
332+
{
333+
AccessByPermission = tabledata Dimension = R;
334+
ApplicationArea = Dimensions;
335+
Caption = 'Dimensions';
336+
Image = Dimensions;
337+
Scope = Repeater;
338+
ShortcutKey = 'Shift+Ctrl+D';
339+
ToolTip = 'View or edit dimensions, such as area, project, or department, that you can assign to sales and purchase documents to distribute costs and analyze transaction history.';
340+
341+
trigger OnAction()
342+
begin
343+
ServiceCommitment.EditDimensionSet();
344+
end;
345+
}
312346
action(ShowArchivedBillingLines)
313347
{
314348
Caption = 'Archived Billing Lines';

src/Apps/W1/Subscription Billing/App/Customer Contracts/Pages/CustomerContractLineSubp.Page.al

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,50 @@ page 8068 "Customer Contract Line Subp."
493493
UpdateServiceCommitmentOnPage(ServiceCommitment.FieldNo("Currency Factor Date"));
494494
end;
495495
}
496+
field("Shortcut Dimension 1 Code"; ServiceCommitment."Shortcut Dimension 1 Code")
497+
{
498+
ApplicationArea = Dimensions;
499+
Caption = 'Shortcut Dimension 1 Code';
500+
CaptionClass = '1,2,1';
501+
ToolTip = 'Specifies the code for Shortcut Dimension 1, which is one of two global dimension codes that you set up in the General Ledger Setup window.';
502+
Visible = false;
503+
Editable = not IsCommentLineEditable;
504+
Enabled = not IsCommentLineEditable;
505+
506+
trigger OnLookup(var Text: Text): Boolean
507+
begin
508+
DimMgt.LookupDimValueCode(1, ServiceCommitment."Shortcut Dimension 1 Code");
509+
Text := ServiceCommitment."Shortcut Dimension 1 Code";
510+
exit(true);
511+
end;
512+
513+
trigger OnValidate()
514+
begin
515+
UpdateServiceCommitmentOnPage(ServiceCommitment.FieldNo("Shortcut Dimension 1 Code"));
516+
end;
517+
}
518+
field("Shortcut Dimension 2 Code"; ServiceCommitment."Shortcut Dimension 2 Code")
519+
{
520+
ApplicationArea = Dimensions;
521+
Caption = 'Shortcut Dimension 2 Code';
522+
CaptionClass = '1,2,2';
523+
ToolTip = 'Specifies the code for Shortcut Dimension 2, which is one of two global dimension codes that you set up in the General Ledger Setup window.';
524+
Visible = false;
525+
Editable = not IsCommentLineEditable;
526+
Enabled = not IsCommentLineEditable;
527+
528+
trigger OnLookup(var Text: Text): Boolean
529+
begin
530+
DimMgt.LookupDimValueCode(2, ServiceCommitment."Shortcut Dimension 2 Code");
531+
Text := ServiceCommitment."Shortcut Dimension 2 Code";
532+
exit(true);
533+
end;
534+
535+
trigger OnValidate()
536+
begin
537+
UpdateServiceCommitmentOnPage(ServiceCommitment.FieldNo("Shortcut Dimension 2 Code"));
538+
end;
539+
}
496540
}
497541
}
498542
}
@@ -616,6 +660,7 @@ page 8068 "Customer Contract Line Subp."
616660

617661
var
618662
ContractsGeneralMgt: Codeunit "Sub. Contracts General Mgt.";
663+
DimMgt: Codeunit DimensionManagement;
619664
NextBillingDateStyleExpr: Text;
620665
ContractLineQty: Decimal;
621666
VariantCode: Code[10];

src/Apps/W1/Subscription Billing/App/Customer Contracts/Pages/ServCommWOCustContract.Page.al

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,18 @@ page 8069 "Serv. Comm. WO Cust. Contract"
116116
ContactManagement.OpenContactCard(ServiceObject."End-User Contact No.");
117117
end;
118118
}
119+
field("Shortcut Dimension 1 Code"; Rec."Shortcut Dimension 1 Code")
120+
{
121+
ApplicationArea = Dimensions;
122+
Visible = false;
123+
Editable = false;
124+
}
125+
field("Shortcut Dimension 2 Code"; Rec."Shortcut Dimension 2 Code")
126+
{
127+
ApplicationArea = Dimensions;
128+
Visible = false;
129+
Editable = false;
130+
}
119131
}
120132
}
121133
}

src/Apps/W1/Subscription Billing/App/Service Commitments/Pages/ServiceCommitments.Page.al

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,16 @@ page 8064 "Service Commitments"
266266
ApplicationArea = All;
267267
ToolTip = 'Specifies the sequence number of the related reference.';
268268
}
269+
field("Shortcut Dimension 1 Code"; Rec."Shortcut Dimension 1 Code")
270+
{
271+
ApplicationArea = Dimensions;
272+
Visible = false;
273+
}
274+
field("Shortcut Dimension 2 Code"; Rec."Shortcut Dimension 2 Code")
275+
{
276+
ApplicationArea = Dimensions;
277+
Visible = false;
278+
}
269279

270280
}
271281
}

src/Apps/W1/Subscription Billing/App/Service Commitments/Pages/ServiceCommitmentsList.Page.al

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,12 @@ page 8014 "Service Commitments List"
148148
}
149149
field("Shortcut Dimension 1 Code"; Rec."Shortcut Dimension 1 Code")
150150
{
151-
ToolTip = 'Specifies the code for Shortcut Dimension 1, which is one of two global dimension codes that you set up in the General Ledger Setup window.';
151+
ApplicationArea = Dimensions;
152152
Visible = false;
153153
}
154154
field("Shortcut Dimension 2 Code"; Rec."Shortcut Dimension 2 Code")
155155
{
156-
ToolTip = 'Specifies the code for Shortcut Dimension 2, which is one of two global dimension codes that you set up in the General Ledger Setup window.';
156+
ApplicationArea = Dimensions;
157157
Visible = false;
158158
}
159159
field("Price (LCY)"; Rec."Price (LCY)")

0 commit comments

Comments
 (0)