Skip to main content

Change Document — Service Order Lockout v1.1.0.1

v1.1.0.0 → v1.1.0.1 Bestway BC Development | March 16, 2026 Branch: fix/service-order-lockout-defects


1. Background

Two API pages and a Python-based functional test suite were added to the Service Order Lockout extension to support automated pre-deployment verification. The API pages expose the extension's lock state fields and setup configuration over OData v4, giving the test framework a reliable, UI-independent channel to set up preconditions and assert post-conditions without depending on browser automation for every scenario.

A pre-commit review identified two compliance gaps in the initial API page implementations: both pages were missing explicit InsertAllowed = false and DeleteAllowed = false guards. Without these guards, a user with SUPER permissions could insert a new Service Header or delete an existing one directly through the API endpoint — bypassing the standard BC UI workflow entirely. Both gaps were corrected in this version.


2. Summary of Changes

#CategoryDescription
1AddedAPI page 52403 ServiceOrderLockoutAPI — OData v4 endpoint exposing lock state fields on Service Header for test automation
2AddedAPI page 52404 ServiceOrderLockoutSetupAPI — OData v4 endpoint exposing the lockout setup singleton for test automation
3FixedInsertAllowed = false; DeleteAllowed = false added to both API pages — prevents unintended record creation or deletion through the OData endpoint
4AddedPython functional test suite (Service Order Lockout/test/) — 12 test areas, ~40 test cases covering all extension behaviors
5AddedBcPage helper methods for Service Order navigation, action inspection, and lockout message detection (tools/bc_test_helpers/bc_playwright_helpers.py)

3. Detailed Changes

3.1 API Pages

Page 52403 — ServiceOrderLockoutAPI

File: Page/ServiceOrderLockoutAPI.Page.al

Read/write OData v4 API page over Service Header. Exposes only the fields used by the locking mechanism: systemId, documentType, no, checkStatus, openByUserID, lockedAt, and status. The checkStatus, openByUserID, and lockedAt fields are writable to allow the test framework to simulate lock state via API PATCH without navigating through the BC UI.

InsertAllowed = false and DeleteAllowed = false are set explicitly. The intent is to allow reads and targeted field updates (PATCH) only — creating or deleting Service Headers through this endpoint is not a supported operation.

OData endpoint pattern: Lockout/Bestway/v1.0/serviceOrderLocks

Page 52404 — ServiceOrderLockoutSetupAPI

File: Page/ServiceOrderLockoutSetupAPI.Page.al

Read/write OData v4 API page over the Service Order Lockout Setup singleton table. Exposes systemId, lockoutEnabled, and staleLockTimeoutHours. Allows the test framework to verify and toggle lockout configuration without navigating through the BC UI.

InsertAllowed = false and DeleteAllowed = false are set explicitly. The setup table is a singleton — creating a second record would break the GetSetup() logic. The OnOpenPage trigger calls Rec.GetSetup() to ensure the singleton record is auto-created on first API access if it does not yet exist.

OData endpoint pattern: Lockout/Bestway/v1.0/lockoutSetups

Note on production presence: These API pages are part of the published extension and are accessible in production over OData. Access is gated by Business Central's standard authentication (OAuth2 / S2S). The pages do not introduce any capabilities beyond what the table data permissions already allow for authenticated callers.

3.2 Python Test Suite

Directory: Service Order Lockout/test/

A Playwright + pytest functional test suite covering all 12 test areas from the UAT test plan. Tests are organized by tier:

  • Tier 1 — API-only tests. No browser required. Fast, run first to verify extension connectivity.
  • Tier 2 — Single-user browser tests. Require a published extension and authenticated browser session.
  • Tier 3 — Multi-user browser tests (Phase 6). Require two separate Entra logins. Marked @pytest.mark.skip until Phase 6 infrastructure is available.

Test setup is handled by fixtures in test/conftest.py. Shared infrastructure (API client, Playwright helpers, test data management) lives in tools/bc_test_helpers/ and is reusable across all BC extensions.

3.3 BcPage Helper Additions

File: tools/bc_test_helpers/bc_playwright_helpers.py

Added methods required by tests 9–12:

MethodPurpose
open_service_order(order_no)Navigate to the Service Orders list and open a specific order by No.
click_next_record()Navigate to the next record (alias for navigate_next_record)
click_previous_record()Navigate to the previous record (alias for navigate_previous_record)
close_card()Close the current card page (alias for close_page)
get_action(caption)Find an action button and return a BcAction proxy for visibility/enabled/click inspection
confirm_dialog()Confirm a BC Confirm() dialog by clicking Yes
dismiss_dialog()Dismiss a BC Confirm() dialog by clicking No
has_lockout_message()Check whether the Service Order lockout notification dialog is visible

Also added BcAction — a lightweight proxy class wrapping a Playwright element, providing is_visible(), is_enabled(), and click(). Tests use get_action()BcAction to inspect and interact with action buttons in a single call rather than three separate is_action_visible / is_action_enabled / click_action calls.


4. Object Inventory (v1.1.0.1)

All objects use the extension's declared ID range (52400–52499).

Object TypeIDNameStatus
Table Extension52400ServiceHeader (extends Service Header)Unchanged
Table52401Service Order Lockout SetupUnchanged
Page Extension52400ServiceOrders (extends Service Orders)Unchanged
Page Extension52401ServiceOrder (extends Service Order)Unchanged
Page52402Service Order Lockout SetupUnchanged
Page52403ServiceOrderLockoutAPINew
Page52404ServiceOrderLockoutSetupAPINew
Permission Set52401BW-CS-SERVICEUnchanged
Codeunit52402Service Order Lockout UpgradeUnchanged

5. Final File Structure

Service Order Lockout/
├── app.json
├── Codeunit/
│ └── ServiceOrderLockoutUpgrade.Codeunit.al
├── Page/
│ ├── ServiceOrderLockoutAPI.Page.al (new)
│ ├── ServiceOrderLockoutSetup.Page.al
│ └── ServiceOrderLockoutSetupAPI.Page.al (new)
├── PageExt/
│ ├── ServiceOrder.PageExt.al
│ └── ServiceOrders.PageExt.al
├── PermissionSet/
│ └── BWCSService.PermissionSet.al
├── Table/
│ └── ServiceOrderLockoutSetup.Table.al
├── TableExt/
│ └── ServiceHeader.TableExt.al
├── test/
│ ├── conftest.py
│ ├── pytest.ini
│ ├── requirements.txt
│ └── tests/
│ ├── test_01_live_status.py through test_12_super_user.py
└── docs/
├── CHANGELOG.md
├── CHANGE-v1.1.0.0.md
├── CHANGE-v1.1.0.1.md
└── UAT Test Plan - Service Order Lockout v1.1.0.0.docx

6. Known Limitations

No new known limitations. Existing limitations from v1.1.0.0 apply (sub-second race on concurrent lock acquisition; locking enforced at page layer only — see CHANGE-v1.1.0.0.md §6).

Tier 3 tests deferred: Multi-user browser tests (Phase 6) require two authenticated Entra sessions running concurrently. These tests are marked @pytest.mark.skip(reason="Requires multi-user browser auth — Phase 6") and are not expected to run until that infrastructure is available.


7. Deployment Notes

No pre/post-deployment steps beyond standard extension upgrade. The new API pages are included in the compiled .app and are published automatically.

Post-deployment verification:

  • Confirm GET .../Lockout/Bestway/v1.0/serviceOrderLocks returns Service Header records
  • Confirm GET .../Lockout/Bestway/v1.0/lockoutSetups returns the setup singleton
  • Run the Tier 1 test suite (pytest -m tier1) to validate API connectivity before browser tests

8. Testing

Tier 1 (API-only) tests in test/tests/test_10_setup_page.py directly validate the new API pages. Tier 2 browser tests (tests 09, 11) use the open_service_order, get_action, and navigation helper methods added in this version. All Tier 3 tests remain skipped pending Phase 6.