UNPKG

bc-code-intelligence-mcp

Version:

BC Code Intelligence MCP Server - Complete Specialist Bundle with AI-driven expert consultation, seamless handoffs, and context-preserving workflows

433 lines (393 loc) 13.2 kB
# SystemId Integration in API Pages - AL Code Sample ## Basic SystemId Usage as Primary Key ```al page 50200 "Customer SystemId API" { PageType = API; APIPublisher = 'contoso'; APIGroup = 'customers'; APIVersion = 'v1.0'; EntityName = 'customer'; EntitySetName = 'customers'; SourceTable = Customer; DelayedInsert = true; ODataKeyFields = SystemId; // Use SystemId as primary OData key layout { area(Content) { repeater(GroupName) { // SystemId exposed as 'id' for REST conventions field(id; Rec.SystemId) { Caption = 'Id'; Editable = false; // SystemId is system-generated } field(number; Rec."No.") { Caption = 'Number'; // Business key still available for reference } field(displayName; Rec.Name) { Caption = 'Display Name'; } field(lastModifiedDateTime; Rec.SystemModifiedAt) { Caption = 'Last Modified Date Time'; Editable = false; } } } } // SystemId automatically handled by BC platform // No custom triggers needed for SystemId generation } ``` ## SystemId with Related Records Navigation ```al page 50201 "Sales Order SystemId API" { PageType = API; APIPublisher = 'contoso'; APIGroup = 'sales'; APIVersion = 'v1.0'; EntityName = 'salesOrder'; EntitySetName = 'salesOrders'; SourceTable = "Sales Header"; DelayedInsert = true; ODataKeyFields = SystemId; layout { area(Content) { repeater(GroupName) { field(id; Rec.SystemId) { Caption = 'Id'; Editable = false; } field(number; Rec."No.") { Caption = 'Number'; } field(customerId; CustomerSystemId) { Caption = 'Customer Id'; // Link to customer using SystemId instead of business key } field(customerNumber; Rec."Sell-to Customer No.") { Caption = 'Customer Number'; // Keep business key for backward compatibility } field(orderDate; Rec."Order Date") { Caption = 'Order Date'; } field(totalAmount; TotalAmount) { Caption = 'Total Amount'; } } } } var CustomerSystemId: Guid; TotalAmount: Decimal; trigger OnAfterGetRecord() var Customer: Record Customer; begin // Resolve customer SystemId from business key if Customer.Get(Rec."Sell-to Customer No.") then CustomerSystemId := Customer.SystemId else Clear(CustomerSystemId); // Calculate total amount Rec.CalcFields("Amount Including VAT"); TotalAmount := Rec."Amount Including VAT"; end; trigger OnModifyRecord(): Boolean var Customer: Record Customer; begin // Handle customer assignment via SystemId if not IsNullGuid(CustomerSystemId) then begin Customer.SetRange(SystemId, CustomerSystemId); if Customer.FindFirst() then Rec.Validate("Sell-to Customer No.", Customer."No."); end; exit(true); end; } ``` ## SystemId Cross-Reference Implementation ```al // Helper codeunit for SystemId operations codeunit 50200 "SystemId Helper" { // Find record by SystemId across different tables procedure FindRecordBySystemId(TableID: Integer; SystemIdValue: Guid; var RecRef: RecordRef): Boolean var SystemIdFieldRef: FieldRef; begin RecRef.Open(TableID); SystemIdFieldRef := RecRef.Field(RecRef.SystemIdNo); SystemIdFieldRef.SetRange(SystemIdValue); exit(RecRef.FindFirst()); end; // Get SystemId from business key procedure GetSystemIdFromBusinessKey(TableID: Integer; KeyFieldNo: Integer; KeyValue: Variant): Guid var RecRef: RecordRef; KeyFieldRef: FieldRef; SystemIdFieldRef: FieldRef; begin RecRef.Open(TableID); KeyFieldRef := RecRef.Field(KeyFieldNo); KeyFieldRef.SetRange(KeyValue); if RecRef.FindFirst() then begin SystemIdFieldRef := RecRef.Field(RecRef.SystemIdNo); exit(SystemIdFieldRef.Value); end; exit(CreateGuid()); // Return empty GUID if not found end; // Validate SystemId exists in target table procedure ValidateSystemIdExists(TableID: Integer; SystemIdValue: Guid): Boolean var RecRef: RecordRef; begin exit(FindRecordBySystemId(TableID, SystemIdValue, RecRef)); end; } // API page demonstrating SystemId cross-references page 50202 "Purchase Order Line API" { PageType = API; APIPublisher = 'contoso'; APIGroup = 'purchasing'; APIVersion = 'v1.0'; EntityName = 'purchaseOrderLine'; EntitySetName = 'purchaseOrderLines'; SourceTable = "Purchase Line"; DelayedInsert = true; ODataKeyFields = SystemId; layout { area(Content) { repeater(GroupName) { field(id; Rec.SystemId) { Caption = 'Id'; Editable = false; } field(documentId; DocumentSystemId) { Caption = 'Document Id'; // Reference to purchase header via SystemId } field(itemId; ItemSystemId) { Caption = 'Item Id'; // Reference to item via SystemId } field(lineNumber; Rec."Line No.") { Caption = 'Line Number'; } field(quantity; Rec.Quantity) { Caption = 'Quantity'; } field(unitCost; Rec."Unit Cost") { Caption = 'Unit Cost'; } } } } var DocumentSystemId: Guid; ItemSystemId: Guid; SystemIdHelper: Codeunit "SystemId Helper"; trigger OnAfterGetRecord() var PurchaseHeader: Record "Purchase Header"; Item: Record Item; begin // Get document SystemId if PurchaseHeader.Get(Rec."Document Type", Rec."Document No.") then DocumentSystemId := PurchaseHeader.SystemId; // Get item SystemId if Item.Get(Rec."No.") then ItemSystemId := Item.SystemId; end; trigger OnModifyRecord(): Boolean var PurchaseHeader: Record "Purchase Header"; Item: Record Item; begin // Validate and set document reference if not IsNullGuid(DocumentSystemId) then begin PurchaseHeader.SetRange(SystemId, DocumentSystemId); if PurchaseHeader.FindFirst() then begin Rec.Validate("Document Type", PurchaseHeader."Document Type"); Rec.Validate("Document No.", PurchaseHeader."No."); end else Error('Purchase document with SystemId %1 not found', DocumentSystemId); end; // Validate and set item reference if not IsNullGuid(ItemSystemId) then begin Item.SetRange(SystemId, ItemSystemId); if Item.FindFirst() then Rec.Validate("No.", Item."No.") else Error('Item with SystemId %1 not found', ItemSystemId); end; exit(true); end; } ``` ## SystemId URL Navigation Patterns ```al // API page with SystemId-based navigation URLs page 50203 "Enhanced Customer API" { PageType = API; APIPublisher = 'contoso'; APIGroup = 'customers'; APIVersion = 'v1.0'; EntityName = 'customer'; EntitySetName = 'customers'; SourceTable = Customer; DelayedInsert = true; ODataKeyFields = SystemId; layout { area(Content) { repeater(GroupName) { field(id; Rec.SystemId) { Caption = 'Id'; Editable = false; } field(number; Rec."No.") { Caption = 'Number'; } field(displayName; Rec.Name) { Caption = 'Display Name'; } field(salesOrdersUrl; SalesOrdersNavigationUrl) { Caption = 'Sales Orders URL'; Editable = false; // Navigation URL using SystemId } field(paymentsUrl; PaymentsNavigationUrl) { Caption = 'Payments URL'; Editable = false; } } } } var SalesOrdersNavigationUrl: Text; PaymentsNavigationUrl: Text; trigger OnAfterGetRecord() begin // Build navigation URLs using SystemId SalesOrdersNavigationUrl := BuildNavigationUrl('salesOrders', Rec.SystemId); PaymentsNavigationUrl := BuildNavigationUrl('customerPayments', Rec.SystemId); end; local procedure BuildNavigationUrl(EntitySet: Text; RelatedSystemId: Guid): Text var BaseUrl: Text; CompanyName: Text; begin // Get base API URL from current request context BaseUrl := GetUrl(ClientType::ODataV4, CompanyName(), ObjectType::Page, 0); // Build related entity URL with SystemId filter exit(StrSubstNo('%1/%2?$filter=customerId eq %3', BaseUrl, EntitySet, RelatedSystemId)); end; } // Related sales orders API filtered by customer SystemId page 50204 "Customer Sales Orders API" { PageType = API; APIPublisher = 'contoso'; APIGroup = 'sales'; APIVersion = 'v1.0'; EntityName = 'customerSalesOrder'; EntitySetName = 'customerSalesOrders'; SourceTable = "Sales Header"; DelayedInsert = true; ODataKeyFields = SystemId; SourceTableView = WHERE("Document Type" = CONST(Order)); layout { area(Content) { repeater(GroupName) { field(id; Rec.SystemId) { Caption = 'Id'; Editable = false; } field(customerId; CustomerSystemId) { Caption = 'Customer Id'; Editable = false; } field(orderNumber; Rec."No.") { Caption = 'Order Number'; } field(orderDate; Rec."Order Date") { Caption = 'Order Date'; } } } } var CustomerSystemId: Guid; trigger OnAfterGetRecord() var Customer: Record Customer; begin // Resolve customer SystemId if Customer.Get(Rec."Sell-to Customer No.") then CustomerSystemId := Customer.SystemId; end; } ``` ## Implementation Notes **SystemId Integration Best Practices:** 1. **Primary Key Strategy:** - Always use SystemId as ODataKeyFields for API pages - Expose SystemId as 'id' field following REST conventions - Keep business keys available for backward compatibility 2. **Cross-Reference Management:** - Use SystemId for all entity relationships in APIs - Implement validation for SystemId references before updates - Provide helper functions for SystemId to business key conversion 3. **Navigation Patterns:** - Build related entity URLs using SystemId parameters - Implement consistent URL structures across API endpoints - Use SystemId filtering for efficient related data queries 4. **Performance Considerations:** - SystemId fields are automatically indexed by BC platform - Use SystemId for faster record lookups in large tables - Cache SystemId mappings for frequently accessed relationships