Business Central Archives - Page 3 of 12 - - Page 3

Tag Archives: Business Central

Business Central Translations: Language Setup and Customization – Part 1

In today’s globalised world, firms frequently operate in numerous areas and languages. To efficiently manage worldwide operations, software with multilingual capabilities is required. Microsoft Dynamics 365 Business Central (BC) includes a powerful translation system that enables enterprises to customise language choices, thereby increasing user experience and operational efficiencies. This article looks at how translations function in Business Central and how they may be used to support global business operations. Why Are Translations Important in Business Central? Businesses that expand into new areas face a variety of languages, currencies, and regulatory regimes. Ensuring that employees can interact with Business Central in their native language improves the software’s usability and productivity. Business Central allows users to configure numerous languages across various modules, allowing workers to work smoothly in their favourite language. It also allows translations for custom fields, reports, and data entry, assuring consistency and correctness in both internal and external interactions. How Translation Works in Business Central Business Central supports several languages, including English, French, German, and Spanish. Here’s an outline on how to activate and use translations successfully. 1. Configuring Language Settings The first step in enabling multilingual support is to configure the Language Settings in Business Central. Users can choose their favourite language or use the organization’s default language settings. This guarantees that when a user logs in, the interface, menus, and forms appear in their preferred language. To configure a language in Business Central: 2. Standard Text Translations Business Central provides built-in translations for standard interface elements and commonly used terms such as “Sales Orders,” “Invoices,” and “Purchase Orders.” These translations are included in the base application by Microsoft. For example, changing the language from English to French automatically updates the captions. However, some standard texts may not be translated by default. To install additional language support: Once installed, the system updates with the new language settings, ensuring a localized user experience. 3. Translating Custom Fields Many businesses customize Business Central by adding custom fields, tables, and industry-specific terminology. While these enhancements improve operational efficiency, they may not be automatically translated in the base system. To resolve this, Business Central provides the CaptionML property, which allows developers to define multilingual captions for custom elements. Example: English: Displays field names and labels in English. French: The same fields are shown with French translations. By implementing the CaptionML property, businesses ensure a seamless multilingual experience even for customized elements. To conclude, Microsoft Dynamics 365 Business Central makes it simple for multinational companies to handle multilingual customers. Companies can improve usability and efficiency across regions by changing language settings, adding extra translations, and ensuring that custom fields are translated using CaptionML. Embracing Business Central’s translation skills enables firms to operate efficiently in a global market while providing a consistent and localized experience to all users. We hope you found this blog useful, and if you would like to discuss anything, you can reach out to us at transform@cloudfonts.com.

A Comprehensive Guide to Backups and Restores in Dynamics 365 Business Central

Managing your organization’s data effectively is a critical task for ensuring business continuity. Dynamics 365 Business Central simplifies this process by offering built-in backup and restore features via the Business Central Admin Center. In this blog, we’ll explore how you can utilize these features to safeguard your environment and handle potential mishaps. Overview of Backups in Dynamics 365 Business Central Business Central automatically manages backups for your production and sandbox environments. These backups are stored securely for a limited period, allowing administrators to restore environments when needed. The retention period and capabilities for restoring backups are influenced by the environment type (production or sandbox). Key Features of the Backup System Restoring an Environment Restoring an environment is a straightforward process, ensuring minimal downtime. Follow these steps to restore an environment using the Admin Center: Step 1: Access the Admin Center Log in to the Business Central Admin Center using your administrator account. Step 2: Select the Environment Navigate to the Environments page and select the environment you wish to restore. Step 3: Initiate the Restore Process Click on the Restore button and choose a backup point from the available restore options. Step 4: Configure Restore Options Step 5: Confirm the Action Review the details and confirm the restore. The system will notify you once the process is complete. To encapsulate, the backup and restore functionalities in Dynamics 365 Business Central offer a reliable safety net for your organization’s data. By leveraging the Admin Center, administrators can easily safeguard business continuity and minimize risks associated with data loss or corruption. We hope you found this blog useful, and if you would like to discuss anything, you can reach out to us at transform@cloudfonts.com.

Visualizing Data: How to Add Power BI Reports to Business Central

Power BI is a great tool for turning data into clear, interactive reports and the best part?  It works smoothly with Business Central, right out of the box.  You just need to set it up, and you can start viewing powerful reports right inside within Business Central dashboard.  Microsoft provides several ready-made reports, grouped into different apps, so you can pick and install only what you need.  Once set up, these reports help you track key business insights without switching between systems.  In this blog, we’ll walk you through how to set up and use Power BI reports in Business Central to make smarter decisions. References Introduction to Business Central and Power BI Install Power BI apps for Business Central Configuration Open your Business Central and search for “Assisted Setup”. Click on “Connect to Power BI” Once the set up page opens, click on Next. Fiscal: A 12-month calendar that begins in any month and ends 12 months after. Standard: A 12-month calendar that begins on January 1 and ends on December 31. Weekly: A calendar that supports 445, 454, or 544 week groupings.The first and last day of the year might not correspond to a first and last day of a month, respectively. Specify the time zone. Specify the working days. Here, it asks for configuring individual apps for Power BI. You can skip this for now as we’ll be back at this later. In the next screen, specify the environment name and the company name. Now, we’ll install the “D365 Business Central – Sales” app in Power BI. Go to your Power BI dashboard and click on Apps.  Search for Business Central Open the relevant one and click on “Get it now” Then click on “Install” Wait for a few seconds till the installation is complete. Now, when you open the report for the first time, it’ll show the report with sample data. To view it with your own data, we need to connect the data to Business Central. Enter the company and environment name. Specify the authentication method to OAuth 2.0 and click on “Sign in and connect” After a few minutes, the refresh will be completed and you’ll see your data. Once this is done, search for “Power BI Connector Setup” In the relevant tab, Sales Report for this example, click on “Power BI Sales” field’s drill down. Select the app that you installed. Now go back to your Business Central dashboard and scroll down to the “Power BI” section. Click on the “Get Started with Power BI” and keep clicking on Next till the end of the setup. If there are any selected reports, you will see the relevant report. If not, you’ll see the following-  In either case, click on the drop-down next to Power BI or click on the “Select reports” Scroll down to find the appropriate report and click on “Enable” and then click on Ok. You will see your Power BI report on the dashboard. You can enable multiple reports and cycle through them by clicking on the “Next” and “Previous” buttons. You can also expand the report to see it as a full page within Business Central by clicking on the “Expand” page. You can further view it in Fullscreen as well. If you want to see multiple reports on the same page, we can create a custom role center and add multiple reports to them. For example, I’ve created a “Power BI dashboard” role center. In this way, we can have n number of reports on our dashboard. Source Code – BCApps-PowerBIDashboard Setting up Power BI in Business Central is a simple way to bring your data to life.  With just a few steps, you can connect your reports, see real-time insights, and make better business decisions all without leaving Business Central.  Whether you need sales trends, financial reports, or custom dashboards, Power BI makes it easy to track what matters most. If you need further assistance or have specific questions about your Business Central and Power BI Integration, feel free to reach out for personalized guidance. We hope you found this blog useful, and if you would like to discuss anything, you can reach out to us at transform@cloudfonts.com.

The Power of Real-Time Data: How Business Central Enhances Pharma Decision-Making

Consider the scenario of a pharmaceutical manufacturer facing an unexpected shortage of essential raw materials. This situation inevitably leads to production delays, potentially causing missed deadlines and expensive product recalls. In today’s dynamic pharmaceutical sector, where adherence to regulations and a responsive supply chain are crucial, outdated information poses a significant risk. What if these disruptions could be predicted and mitigated before they materialize? What if you had immediate, comprehensive visibility into your entire operational landscape? This is the advantage offered by real-time data, and solutions like Microsoft Business Central are spearheading the evolution of pharmaceutical decision-making. The Shortcomings of Traditional Pharmaceutical Data: Historically, the pharmaceutical industry has operated with data that is often delayed. Reports generated several days or weeks after events occur provide a historical perspective, lacking the current operational awareness needed for effective management. This results in: Real-Time Data: A Game-Changer for Pharma: Our Business Central Pharma module provides a unified platform that delivers real-time visibility across your entire pharmaceutical operation. This empowers you to: Practical Implementation and Tangible Benefits: Implementing Business Central can seem daunting, but the benefits are undeniable. By having the end-to-end process in one system can be very beneficiary. The Future of Data-Driven Pharma: The future of pharma lies in leveraging the power of data. Imagine being able to anticipate potential supply chain disruptions or quality issues before they occur. This is the promise of data-driven Pharma Module. To encapsulate, in the pharmaceutical industry, where precision and speed are critical, real-time data is no longer a luxury—it’s a necessity. Our Business Central pharma module helps companies to embrace the data revolution, enabling faster, more informed decisions that drive efficiency, compliance, and growth. Ready to unlock the power of real-time data for your pharmaceutical operations? Contact us today at transform@cloudfonts.com to learn how our Business Central pharma module can transform your business.

Enhancing the Recurring General Journal with Automated Approval Workflows in Dynamics 365 Business Central

In any accounting or financial system, ensuring that the proper approvals are in place is critical for maintaining audit trails and accountability. Microsoft Dynamics 365 Business Central (BC) offers powerful approval workflows that can automate this process, ensuring compliance and accuracy in your financial entries. This blog will guide you through creating an extension for the Recurring General Journal page, enabling automated approval requests for journal batches and journal lines. Understanding the Recurring General Journal The Recurring General Journal in Business Central allows users to post transactions that occur periodically, such as monthly expenses. However, posting journal entries often requires an approval process to guarantee compliance and accuracy. Our extension will empower users to request approvals, cancel requests, and manage the approval status directly from the Recurring General Journal. Solution Outline This extension will: Code Here’s the complete PageExtension code that extends the Recurring General Journal page: pageextension 50103 RecurringGenJnl extends “Recurring General Journal” {     layout     {         addafter(CurrentJnlBatchName)         {             field(StatusLine; Rec.StatusBatch)             {                 ApplicationArea = All;                 Caption = ‘Approval Status’;                 Editable = false;                 Visible = true;             }         }     }     actions     {         addafter(“F&unctions”)         {             group(“Request Approval”)             {                 Caption = ‘Request Approval’;                 group(SendApprovalRequest)                 {                     Caption = ‘Send Approval Request’;                     Image = SendApprovalRequest;                     action(SendApprovalRequestJournalLine)                     {                         ApplicationArea = Basic, Suite;                         Caption = ‘Journal Batch’;                         Image = SendApprovalRequest;                         Enabled = true;                         ToolTip = ‘Send all journal lines for approval, also those that you may not see because of filters.’;                         trigger OnAction()                         var                             GenJournalLine: Record “Gen. Journal Line”;                             GenJournalBatch: Record “Gen. Journal Batch”;                             ApprovalsMgmt: Codeunit “Approvals Mgmt.”;                             IsLineValid: Boolean;                         begin                             GenJournalBatch.Get(Rec.”Journal Template Name”, Rec.”Journal Batch Name”);                             if GenJournalLine.SetCurrentKey(“Journal Template Name”, “Journal Batch Name”) then begin                                 GenJournalLine.SetRange(“Journal Template Name”, GenJournalBatch.”Journal Template Name”);                                 GenJournalLine.SetRange(“Journal Batch Name”, GenJournalBatch.”Name”);                                 if GenJournalLine.FindSet() then                                     ApprovalsMgmt.TrySendJournalBatchApprovalRequest(GenJournalLine);                                 SetControlAppearanceFromBatch();                                 SetControlAppearance();                             end;                         end;                     }                 }                 group(CancelApprovalRequest)                 {                     Caption = ‘Cancel Approval Request’;                     Image = Cancel;                     Enabled = true;                     action(CancelApprovalRequestJournalBatch)                     {                         ApplicationArea = Basic, Suite;                         Caption = ‘Journal Batch’;                         Image = CancelApprovalRequest;                         ToolTip = ‘Cancel sending all journal lines for approval, also those that you may not see because of filters.’;                         trigger OnAction()                         var                             ApprovalsMgmt: Codeunit “Approvals Mgmt.”;                             GenJournalBatch: Record “Gen. Journal Batch”;                             GenJournalLine: Record “Gen. Journal Line”;                             IsLineValid: Boolean;                         begin                             GenJournalBatch.Get(Rec.”Journal Template Name”, Rec.”Journal Batch Name”);                             //ApprovalsMgmt.TryCancelJournalBatchApprovalRequest(GenJournalLine);                             if GenJournalLine.SetCurrentKey(“Journal Template Name”, “Journal Batch Name”) then begin                                 GenJournalLine.SetRange(“Journal Template Name”, GenJournalBatch.”Journal Template Name”);                                 GenJournalLine.SetRange(“Journal Batch Name”, GenJournalBatch.”Name”);                                 if GenJournalLine.FindSet() then                                     IsLineValid := true;                                 if (GenJournalLine.Status.ToUpper() = ‘OPEN’) or                                    (GenJournalLine.Status.ToUpper() = ‘APPROVED’) then begin                                     IsLineValid := false;                                 end;                                 if IsLineValid then                                     ApprovalsMgmt.TryCancelJournalBatchApprovalRequest(GenJournalLine);                                 //ApprovalsMgmt.TryCancelJournalLineApprovalRequests(GenJournalLine);                             end else begin                                 Message(‘Gen. Journal Batch not found for the provided template and batch names.’);                             end;                             SetControlAppearanceFromBatch();                             SetControlAppearance();                         end;                     }                 }                 group(Approval)                 {                     Caption = ‘Approval’;                     action(Approve)                     {                         ApplicationArea = All;                         Caption = ‘Approve’;                         Image = Approve;                         ToolTip = ‘Approve the requested changes.’;                         Visible = true;                         trigger OnAction()                         var                             ApprovalsMgmt: Codeunit “Approvals Mgmt.”;                         begin                             ApprovalsMgmt.ApproveGenJournalLineRequest(Rec);                         end;                     }                     action(Reject)                     {                         ApplicationArea = All;                         Caption = ‘Reject’;                         Image = Reject;                         ToolTip = ‘Reject the approval request.’;                         Visible = true;                         trigger OnAction()                         var                             ApprovalsMgmt: Codeunit “Approvals Mgmt.”;                         begin                             ApprovalsMgmt.RejectGenJournalLineRequest(Rec);                         end;                     }                     action(Delegate)                     {                         ApplicationArea = All;                         Caption = ‘Delegate’;                         Image = Delegate;                         ToolTip = ‘Delegate the approval to a substitute approver.’;                         Visible = OpenApprovalEntriesExistForCurrUser;                         trigger OnAction()                         var                             ApprovalsMgmt: Codeunit “Approvals Mgmt.”;                         begin                             ApprovalsMgmt.DelegateGenJournalLineRequest(Rec);                         end;                     }                 }             }         }     }     trigger OnOpenPage()     begin         SetControlAppearanceFromBatch();     end;     trigger OnAfterGetCurrRecord()     var         GenJournalBatch: Record “Gen. Journal Batch”;     begin         EnableApplyEntriesAction();         SetControlAppearance();         if GenJournalBatch.Get(GetJournalTemplateNameFromFilter(), CurrentJnlBatchName) then             SetApprovalStateForBatch(GenJournalBatch, Rec, OpenApprovalEntriesExistForCurrUser, OpenApprovalEntriesOnJnlBatchExist, OpenApprovalEntriesOnBatchOrAnyJnlLineExist, CanCancelApprovalForJnlBatch, CanRequestFlowApprovalForBatch, CanCancelFlowApprovalForBatch, CanRequestFlowApprovalForBatchAndAllLines, ApprovalEntriesExistSentByCurrentUser, EnabledGenJnlBatchWorkflowsExist, EnabledGenJnlLineWorkflowsExist);         ApprovalMgmt.GetGenJnlBatchApprovalStatus(Rec, Rec.StatusBatch, EnabledGenJnlBatchWorkflowsExist);     end;     trigger OnAfterGetRecord()     var         GenJournalLine: Record “Gen. Journal Line”;         GenJournalBatch: Record “Gen. Journal Batch”;         ApprovalsMgmt: Codeunit “Approvals Mgmt.”;     begin         GenJnlManagement.GetAccounts(Rec, AccName, BalAccName);         Rec.ShowShortcutDimCode(ShortcutDimCode);         SetUserInteractions();         GenJournalBatch.Get(Rec.”Journal Template Name”, Rec.”Journal Batch Name”);         if GenJournalLine.SetCurrentKey(“Journal Template Name”, “Journal Batch Name”) then begin             GenJournalLine.SetRange(“Journal Template Name”, GenJournalBatch.”Journal Template Name”);             GenJournalLine.SetRange(“Journal Batch Name”, GenJournalBatch.”Name”);             if GenJournalLine.FindSet() then                 repeat                     ApprovalMgmt.GetGenJnlLineApprovalStatus(Rec, Rec.StatusBatch, EnabledGenJnlLineWorkflowsExist);                 until GenJournalLine.Next() = 0;         end;     end;     trigger OnModifyRecord(): Boolean     var         GenJournalBatch: Record “Gen. Journal Batch”;         GenJournalLine: Record “Gen. Journal Line”;         ApprovalsMgmt: Codeunit “Approvals Mgmt.”;         IsLineValid: Boolean;     begin         SetUserInteractions();         ApprovalMgmt.CleanGenJournalApprovalStatus(Rec, Rec.StatusBatch, Rec.Status);         if Rec.StatusBatch = ‘Pending Approval’ then             Error(‘Modification not allowed. The journal batch “%1” has entries with a status of “Pending Approval”. Please approve, reject, or cancel these entries before making changes.’, GenJournalBatch.”Name”);     end;     var         GenJnlManagement: Codeunit GenJnlManagement;         JournalErrorsMgt: Codeunit “Journal Errors Mgt.”;         BackgroundErrorHandlingMgt: Codeunit “Background Error Handling Mgt.”;         ApprovalMgmt: Codeunit “Approvals Mgmt.”;         ChangeExchangeRate: Page “Change Exchange Rate”;         GLReconcile: Page Reconciliation;         GenJnlBatchApprovalStatus: Text[20];         GenJnlLineApprovalStatus: Text[20];         Balance: Decimal;         TotalBalance: Decimal;         NumberOfRecords: Integer;         ShowBalance: Boolean;         ShowTotalBalance: Boolean;         HasIncomingDocument: Boolean;         BalanceVisible: Boolean;         TotalBalanceVisible: Boolean;         StyleTxt: Text;         ApprovalEntriesExistSentByCurrentUser: Boolean;         OpenApprovalEntriesExistForCurrUser: Boolean;         OpenApprovalEntriesOnJnlBatchExist: Boolean;         OpenApprovalEntriesOnJnlLineExist: Boolean;         OpenApprovalEntriesOnBatchOrCurrJnlLineExist: Boolean;         OpenApprovalEntriesOnBatchOrAnyJnlLineExist: Boolean;         EnabledGenJnlLineWorkflowsExist: Boolean;         EnabledGenJnlBatchWorkflowsExist: Boolean;         ShowWorkflowStatusOnBatch: Boolean;         ShowWorkflowStatusOnLine: Boolean;         CanCancelApprovalForJnlBatch: Boolean;         CanCancelApprovalForJnlLine: Boolean;         ImportPayrollTransactionsAvailable: Boolean;         CanRequestFlowApprovalForBatch: Boolean;         CanRequestFlowApprovalForBatchAndAllLines: Boolean;         CanRequestFlowApprovalForBatchAndCurrentLine: Boolean;         CanCancelFlowApprovalForBatch: Boolean;         CanCancelFlowApprovalForLine: Boolean;         BackgroundErrorCheck: Boolean;         ShowAllLinesEnabled: Boolean;         CurrentPostingDate: Date;     protected var         ApplyEntriesActionEnabled: Boolean;         IsSimplePage: Boolean;     local procedure EnableApplyEntriesAction()     begin         ApplyEntriesActionEnabled :=           (Rec.”Account Type” in [Rec.”Account Type”::Customer, Rec.”Account Type”::Vendor, Rec.”Account Type”::Employee]) or           (Rec.”Bal. Account Type” in [Rec.”Bal. Account Type”::Customer, Rec.”Bal. Account Type”::Vendor, Rec.”Bal. Account Type”::Employee]);         OnAfterEnableApplyEntriesAction(Rec, ApplyEntriesActionEnabled);     end;     local procedure CurrentJnlBatchNameOnAfterVali()     begin         CurrPage.SaveRecord();         GenJnlManagement.SetName(CurrentJnlBatchName, Rec);         SetControlAppearanceFromBatch();         CurrPage.Update(false);     end;     procedure SetUserInteractions()     begin         StyleTxt := Rec.GetStyle();     end;     local procedure GetCurrentlySelectedLines(var GenJournalLine: Record “Gen. Journal Line”): Boolean     begin         CurrPage.SetSelectionFilter(GenJournalLine);         exit(GenJournalLine.FindSet());     end;     local procedure GetPostingDate(): Date     begin         if IsSimplePage then             exit(CurrentPostingDate);         exit(Workdate());     end;     internal procedure SetApprovalState(RecordId: RecordId; OpenApprovalEntriesOnJournalBatchExist: Boolean; LocalCanRequestFlowApprovalForBatch: Boolean; var LocalCanCancelFlowApprovalForLine: Boolean; var OpenApprovalEntriesExistForCurrentUser: Boolean; var OpenApprovalEntriesOnJournalLineExist: Boolean; var OpenApprovalEntriesOnBatchOrCurrentJournalLineExist: Boolean; var CanCancelApprovalForJournalLine: Boolean; var LocalCanRequestFlowApprovalForBatchAndCurrentLine: Boolean)     var         ApprovalsMgmt: Codeunit “Approvals Mgmt.”;         WorkflowWebhookManagement: Codeunit “Workflow Webhook Management”;         CanRequestFlowApprovalForLine: Boolean;     begin         OpenApprovalEntriesExistForCurrentUser := OpenApprovalEntriesExistForCurrentUser or ApprovalsMgmt.HasOpenApprovalEntriesForCurrentUser(RecordId);         OpenApprovalEntriesOnJournalLineExist := ApprovalsMgmt.HasOpenApprovalEntries(RecordId);         OpenApprovalEntriesOnBatchOrCurrentJournalLineExist := OpenApprovalEntriesOnJournalBatchExist or OpenApprovalEntriesOnJournalLineExist;         CanCancelApprovalForJournalLine := ApprovalsMgmt.CanCancelApprovalForRecord(RecordId);         WorkflowWebhookManagement.GetCanRequestAndCanCancel(RecordId, CanRequestFlowApprovalForLine, LocalCanCancelFlowApprovalForLine);         LocalCanRequestFlowApprovalForBatchAndCurrentLine := LocalCanRequestFlowApprovalForBatch and CanRequestFlowApprovalForLine;     end;     internal procedure SetApprovalStateForBatch(GenJournalBatch: Record “Gen. Journal Batch”; GenJournalLine: Record “Gen. Journal Line”; var OpenApprovalEntriesExistForCurrentUser: Boolean; var OpenApprovalEntriesOnJournalBatchExist: Boolean; var OpenApprovalEntriesOnBatchOrAnyJournalLineExist: Boolean; var CanCancelApprovalForJournalBatch: Boolean; var LocalCanRequestFlowApprovalForBatch: Boolean; var LocalCanCancelFlowApprovalForBatch: Boolean; var LocalCanRequestFlowApprovalForBatchAndAllLines: Boolean; var LocalApprovalEntriesExistSentByCurrentUser: Boolean; var EnabledGeneralJournalBatchWorkflowsExist: Boolean; var EnabledGeneralJournalLineWorkflowsExist: Boolean)     var         ApprovalsMgmt: Codeunit “Approvals Mgmt.”;         WorkflowWebhookManagement: Codeunit “Workflow Webhook Management”;         WorkflowEventHandling: Codeunit “Workflow Event Handling”;         WorkflowManagement: Codeunit “Workflow Management”;         CanRequestFlowApprovalForAllLines: Boolean;     begin         OpenApprovalEntriesExistForCurrentUser := OpenApprovalEntriesExistForCurrentUser or ApprovalsMgmt.HasOpenApprovalEntriesForCurrentUser(GenJournalBatch.RecordId);         OpenApprovalEntriesOnJournalBatchExist := ApprovalsMgmt.HasOpenApprovalEntries(GenJournalBatch.RecordId);         OpenApprovalEntriesOnBatchOrAnyJournalLineExist := OpenApprovalEntriesOnJournalBatchExist or ApprovalsMgmt.HasAnyOpenJournalLineApprovalEntries(GenJournalLine.”Journal Template Name”, GenJournalLine.”Journal Batch Name”);         CanCancelApprovalForJournalBatch := … Continue reading Enhancing the Recurring General Journal with Automated Approval Workflows in Dynamics 365 Business Central

Managing Profile Pictures on Custom Pages in Microsoft Dynamics 365 Business Central

When creating custom pages in Business Central, sometimes you need to allow users to handle profile pictures. Whether you’re working with a custom Employee Profile page or another entity, it’s crucial to provide intuitive ways for users to manage their pictures. In this blog, we’ll walk through the process of implementing four key actions for handling profile pictures in custom pages: These features can be achieved using AL (the programming language for Business Central). Setting Up the Custom UserProfile Page Let’s first define the User Profile page where the user can manage their profile picture. This page will provide the fields for Profile ID, Profile Name, and a FactBox to display the profile picture. Code: page 50213 “UserProfileCard” {     PageType = Card;     SourceTable = “UserProfile”;     ApplicationArea = All;     Caption = ‘User Profile’;     layout     {         area(content)         {             group(Group)             {                 field(“Profile ID”; Rec.”Profile ID”)                 {                     ApplicationArea = All;                 }                 field(“Profile Name”; Rec.”Profile Name”)                 {                     ApplicationArea = All;                 }             }         }         // FactBox area to display profile picture         area(factboxes)         {             part(“Profile Picture FactBox”; “ProfilePictureFactBoxPart”)             {                 ApplicationArea = All;             }         }     }     actions     {         area(Processing)         {             action(“Take Picture”)             {                 ApplicationArea = All;                 trigger OnAction()                 var                     Camera: Codeunit “Camera”;                     InS: InStream;                     PicName: Text;                 begin                     // Validate the selected profile                     if not IsProfileSelected(Rec.”Profile ID”) then                         exit;                     // Check if the camera is available                     if Camera.IsAvailable() then begin                         // Get and import the picture                         if Camera.GetPicture(InS, PicName) then begin                             // Import the picture into the profile record                             Rec.”Profile Picture”.ImportStream(InS, PicName);                             Rec.Modify(); // Save the modified record                             Message(‘Profile picture updated successfully.’);                         end                         else                             Message(‘Failed to capture the picture. Try again.’);                     end                     else                         Message(‘No camera detected. Please connect a camera.’);                 end;             }             fileuploadaction(“Import Picture”)             {                 ApplicationArea = All;                 Caption = ‘Import’;                 Image = Import;                 ToolTip = ‘Import a picture file.’;                 trigger OnAction(Files: List of [FileUpload])                 var                     FileName: Text;                     InStream: InStream;                     FileUpload: FileUpload;                 begin                     Rec.TestField(“Profile ID”);                     if Rec.”Profile Name” = ” then                         Error(MustSpecifyNameErr);                     if Rec.”Profile Picture”.HasValue() then                         if not Confirm(OverrideImageQst) then                             exit;                     // Ensure the file is valid                     if Files.Count = 0 then                         Error(‘No file selected.’);                     // Iterate through the Files list (typically just one file)                     foreach FileUpload in Files do begin                         // Create the InStream from the current file                         FileUpload.CreateInStream(InStream);                         Rec.”Profile Picture”.ImportStream(InStream, FileName);                     end;                     Rec.Modify(true);                     Message(‘Picture imported successfully: %1’, FileName);                 end;             }             action(“Export Picture”)             {                 ApplicationArea = All;                 Caption = ‘Export’;                 Image = Export;                 ToolTip = ‘Export the picture to a file.’;                 trigger OnAction()                 var                     FileName: Text;                     OutStream: OutStream;                     InStream: InStream;                     TempBlob: Codeunit “Temp Blob”; // Helps with the stream conversion                 begin                     Rec.TestField(“Profile ID”);                     Rec.TestField(“Profile Name”);                     // Ensure there’s a profile picture to export                     if not Rec.”Profile Picture”.HasValue() then begin                         Message(‘No profile picture found to export.’);                         exit;                     end;                     // Generate a file name for the exported picture                     FileName := Rec.”Profile Name” + ‘_ProfilePicture.jpg’;                     // Export the image to an OutStream via TempBlob                     TempBlob.CreateOutStream(OutStream); // Prepare the OutStream                     Rec.”Profile Picture”.ExportStream(OutStream); // Export the Media field content into the OutStream                     TempBlob.CreateInStream(InStream); // Create InStream from TempBlob to use for download                     // Trigger the file download                     DownloadFromStream(InStream, FileName, ”, ”, FileName);                     // Show success message                     Message(‘Profile picture exported successfully as %1’, FileName);                 end;             }             action(“Delete Picture”)             {                 ApplicationArea = All;                 Caption = ‘Delete’;                 Image = Delete;                 ToolTip = ‘Delete the picture.’;                 trigger OnAction()                 begin                     Rec.TestField(“Profile ID”);                     if not Confirm(DeleteImageQst) then                         exit;                     Clear(Rec.”Profile Picture”);                     Rec.Modify(true);                 end;             }         }     }     trigger OnAfterGetCurrRecord()     begin         SetEditableOnPictureActions();     end;     trigger OnOpenPage()     begin         CameraAvailable := Camera.IsAvailable();     end;     var         Camera: Codeunit Camera;         CameraAvailable: Boolean;         OverrideImageQst: Label ‘The existing picture will be replaced. Do you want to continue?’;         DeleteImageQst: Label ‘Are you sure you want to delete the picture?’;         SelectPictureTxt: Label ‘Select a picture to upload’;         FileManagement: Codeunit “File Management”;         MustSpecifyNameErr: Label ‘You must specify a profile name before you can import a picture.’;     local procedure SetEditableOnPictureActions()     begin         // Enabling or disabling the delete/export actions based on whether a picture is present.     end;     // Function to check if a profile is selected     procedure IsProfileSelected(ProfileID: Code[20]): Boolean     begin         if ProfileID = ” then begin             Message(‘Please select a profile first!’);             exit(False);         end;         exit(True);     end; } Understanding the Key Actions Let’s break down the actions implemented in this custom UserProfile page: 1. Take Picture This action utilizes the Camera Codeunit to capture a picture. If the camera is connected, it will fetch an image and store it in the “Profile Picture” field. 2. Import (Upload) Picture The Import Picture action allows users to upload a picture from their local system into the “Profile Picture” field. It uses the FileUpload control and confirms if the existing image should be replaced. 3. Export Picture The Export Picture action downloads the profile picture to the user’s system. The image is exported to an OutStream, then triggered for download using DownloadFromStream. 4. Delete Picture The Delete Picture action clears the profile picture field. It prompts for confirmation before removing the image. Benefits To encapsulate, in standard Business Central, the functionality for managing user profiles and pictures is built in. However, when working with custom pages, you often need to implement these features manually. By using the actions … Continue reading Managing Profile Pictures on Custom Pages in Microsoft Dynamics 365 Business Central

Understanding and Analyzing Customer Ledger Data with Business Charts in Dynamics 365

In today’s business world, understanding your financial data is crucial for making informed decisions. One of the key areas of focus for businesses is tracking customer payments and outstanding invoices. With Dynamics 365, you can leverage customer ledger entries to provide visual insights into customer behaviors, payment patterns, and outstanding amounts. These insights help businesses optimize collections, improve cash flow, and make data-driven decisions. In this blog, we’ll explore how to analyze Customer Ledger Entries through Business Charts in Dynamics 365, focusing on Outstanding Invoices, Payments Applied, and Aging of Outstanding Amounts. What Are Customer Ledger Entries? Customer Ledger Entries in Dynamics 365 track all transactions related to a customer, including invoices, payments, credit memos, and adjustments. Each entry contains details such as: By analyzing this data, businesses can gain valuable insights into a customer’s payment habits, outstanding debts, and the status of their invoices. Why Use Business Charts? Business Charts in Dynamics 365 provide a visual representation of your data, making it easier to spot trends and gain actionable insights. Instead of manually sorting through customer ledger entries, you can use charts to instantly assess: This allows teams to make timely decisions about follow-ups with customers and plan for collections. Creating Charts to Analyze Customer Ledger Data Let’s dive into some key charting logic you can apply to Customer Ledger Entries in Dynamics 365 to get more detailed insights into your data. 1. Outstanding Invoices (Remaining Amount per Invoice) The first and most essential data point to track is the Remaining Amount of each invoice. By grouping this data by invoice number, you can quickly identify which invoices are outstanding and need to be followed up. Logic: Buffer.AddMeasure(‘Remaining Amount’, 2, Buffer.”Data Type”::Decimal, ChartType.AsInteger()); Buffer.SetXAxis(‘Document No.’, Buffer.”Data Type”::String); // Group by invoice number The chart will help visualize which invoices are outstanding and need to be prioritized for payment. Code page 50215 “Business Charts” {     ApplicationArea = All;     Caption = ‘Business Charts’;     PageType = CardPart;     UsageCategory = Administration;     layout     {         area(Content)         {             usercontrol(chart; BusinessChart)             {                 ApplicationArea = All;                 trigger AddInReady()                 var                     Buffer: Record “Business Chart Buffer” temporary;                     CustLedgerEntry: Record “Cust. Ledger Entry”;                     Customer: Record Customer;                     ChartType: Enum “Business Chart Type”;                     AppliedAmount: Decimal;                     RemainingAmount: Decimal;                     s: Integer;                 begin                     // Initialize the chart buffer and variables                     Buffer.Initialize();                     ChartType := “Business Chart Type”::Pie; // Use a bar chart for better visual representation                     // Add measure for ‘Remaining Amount’                     Buffer.AddMeasure(‘Remaining Amount’, 2, Buffer.”Data Type”::Decimal, ChartType.AsInteger());                     // Set X-axis to ‘Invoice No.’ for grouping data by invoice                     Buffer.SetXAxis(‘Document No.’, Buffer.”Data Type”::String);                     // Loop through all customers                     if Customer.FindSet() then begin                         repeat                             // Loop through Customer Ledger Entries to accumulate remaining amounts                             if CustLedgerEntry.FindSet() then begin                                 repeat                                     CustLedgerEntry.CalcFields(“Remaining Amount”);                                     // Only accumulate amounts for the current customer based on Customer No.                                     if CustLedgerEntry.”Customer No.” = Customer.”No.” then begin                                         // If it is an Invoice, accumulate Remaining Amount                                         if CustLedgerEntry.”Document Type” = “Gen. Journal Document Type”::Invoice then begin                                             Buffer.AddColumn(CustLedgerEntry.”Document No.”);  // Label by Invoice No.                                             Buffer.SetValueByIndex(0, s, CustLedgerEntry.”Remaining Amount”);  // Set RemainingAmount for the invoice                                             s += 1;                                         end;                                     end;                                 until CustLedgerEntry.Next() = 0;                             end;                         until Customer.Next() = 0;                     end;                     // Update the chart with the accumulated data                     if s > 0 then                         Buffer.UpdateChart(CurrPage.Chart)                     else                         Message(‘No outstanding invoices to display in the chart.’);                 end;             }         }     } } 2. Payments Applied (Amount Applied to Invoices) Another important metric is the Amount Applied to customer invoices. Tracking payments allows you to understand customer payment behavior and outstanding balances. By focusing on Payments, you can track how much a customer has paid against their total balance. Logic: Buffer.AddMeasure(‘Amount Applied’, 2, Buffer.”Data Type”::Decimal, ChartType.AsInteger()); Buffer.SetXAxis(‘Customer No.’, Buffer.”Data Type”::String); // Group by customer This chart will help businesses track customer payments and identify any customers with overdue payments. 3. Aging of Outstanding Amounts (Bucketed by Days Overdue) Aging reports are an essential tool for understanding the timeliness of payments. By grouping outstanding amounts into aging buckets (e.g., 0-30 days, 31-60 days, etc.), businesses can better assess which invoices are overdue and prioritize collection efforts. Logic: // Calculate aging based on Due Date if (Today – CustLedgerEntry.”Due Date”) <= 30 then     AgingBucket := ‘0-30 Days’ elseif (Today – CustLedgerEntry.”Due Date”) <= 60 then     AgingBucket := ’31-60 Days’ Buffer.SetXAxis(‘Aging Bucket’, Buffer.”Data Type”::String); // Group by aging bucket This chart will provide a clear picture of which invoices are overdue and for how long, helping businesses prioritize collections. Benefits of Using Business Charts for Customer Ledger Analysis By leveraging Customer Ledger Entries and Business Charts in Dynamics 365, businesses can transform raw data into valuable insights. Visualizing outstanding invoices, payments applied, and aging amounts helps businesses prioritize collections, forecast cash flow, and ultimately improve their financial health. These charts make it easier for accounting and finance teams to manage customer payments and reduce the risk of overdue balances. The ability to track customer behavior and quickly identify payment issues gives businesses a competitive edge, helping them maintain a healthy cash flow and strong customer relationships. We hope you found this blog useful, and if you would like to discuss anything, you can reach out to us at transform@cloudfonts.com.

Mastering Date Manipulation with CALCDATE in Microsoft Dynamics 365 Business Central

Microsoft Dynamics 365 Business Central provides a comprehensive suite of tools designed to streamline business processes, and one of the most powerful tools for managing dates and times is the CALCDATE function. This versatile function enables users to perform complex date calculations with ease, making it indispensable for developers, consultants, and power users. In this blog post, we’ll dive deep into the CALCDATE function, explain its syntax, and explore how you can leverage it in your Business Central environment. Understanding CALCDATE The CALCDATE function is used to calculate a new date based on a specific date expression and an optional reference date. It is particularly helpful in scenarios where you need to determine dates relative to a given point in time. This could include calculating due dates, forecasting future events, setting up recurring transactions, or determining any other date relative to the system’s current or a user-defined date. For example, if you need to find the first day of next month or calculate a due date based on the current date, CALCDATE can handle these tasks efficiently. Syntax of CALCDATE The syntax of the CALCDATE function is simple, but the power lies in how you use the date expressions to represent relative time periods. NewDate := System.CalcDate(DateExpression: Text [, Date: Date]) Parameters DateExpression (Type: Text): This is the key input to the function, where you specify the date you want to calculate. The date expression can represent a variety of time periods, ranging from days to weeks, months, quarters, and years. The expression is evaluated from left to right, and each subexpression is processed one at a time. The valid syntax for the date expression follows a set of rules: Subexpression: A date expression consists of one or more subexpressions, each of which may be prefixed with a + or – sign. The subexpression can specify a time unit (day, week, month, etc.) along with a number. Here’s the structure of a typical date expression: <Subexpression> = [<Sign>] <Term> <Sign> = + | – <Term> = <Number><Unit> | <Unit><Number> | <Prefix><Unit> Examples of valid date expressions: The calendar in Business Central starts on Monday and ends on Sunday, where Monday is considered weekday 1 and Sunday is weekday 7. An invalid date expression, such as specifying an incorrect syntax, will result in a runtime error. 2. [Optional] Date (Type: Date):This optional parameter is used to define the reference date. If you omit it, the system defaults to the current date. You can specify any date here, and CALCDATE will perform the calculation based on that reference date instead of the current system date. Return Value Example: pageextension 50103 CustomerPageExt1 extends “Customer Card” {     trigger OnOpenPage()     var         StartDate: Date;         EndDate: Date;         FirstDateofPreviousMonth: Date;         LastDateofPreviousMonth: Date;         FirstDateofNextMonth: Date;         LastDateofNextMonth: Date;         TodayDate: Date;         FirstDateofYear: Date;         LastDateofYear: Date;         FirstDayOfNextQuarter: Date;         LastDayOfCurrentQuarter: Date;         FirstDayOfNextWeek: Date;         FirstDayOfNextWeek10D: Date;     begin         // Current Month Start and End Dates         StartDate := System.CalcDate(‘<-CM>’, Today);         EndDate := System.CalcDate(‘<CM>’, Today);         // Previous Month Start and End Dates         TodayDate := TODAY;         FirstDateOfPreviousMonth := CALCDATE(‘<-1M>’, CALCDATE(‘<-CM>’, TodayDate));         LastDateOfPreviousMonth := CALCDATE(‘<-1M>’, CALCDATE(‘<CM>+1D’, TodayDate) – 1);         // Next Month Start and End Dates         FirstDateOfNextMonth := CALCDATE(‘<+1M>’, CALCDATE(‘<-CM>’, TodayDate));         LastDateOfNextMonth := CALCDATE(‘<+1M>’, CALCDATE(‘<CM>+1D’, TodayDate) – 1);         // First and Last Date of the Current Year         FirstDateofYear := CALCDATE(‘<-CY>’, TodayDate);         LastDateOfYear := CALCDATE(‘<CY>’, TODAY);         // First Day of the Next Quarter         FirstDayOfNextQuarter := CALCDATE(‘<+1Q>’, CALCDATE(‘<-CQ>’, TodayDate));         // Last Day of the Current Quarter         LastDayOfCurrentQuarter := CALCDATE(‘<CQ>’, TODAY);         // First Day of the Next Week         FirstDayOfNextWeek := CALCDATE(‘<+1W>’, CALCDATE(‘<-CW>’, TodayDate));         // First Day of the Next Week + 10D         FirstDayOfNextWeek10D := CALCDATE(‘<+1W>+10D’, CALCDATE(‘<-CW>’, TodayDate));         Message(             ‘Current Month: ‘ + ‘\’ +             ‘Start Date: %1, End Date: %2’ + ‘\’ +             ‘\’ +             ‘Previous Month: ‘ + ‘\’ +             ‘Start Date: %3, End Date: %4’ + ‘\’ +             ‘\’ +             ‘Next Month: ‘ + ‘\’ +             ‘Start Date: %5, End Date: %6’ + ‘\’ +             ‘\’ +             ‘Current Year: ‘ + ‘\’ +             ‘Start Date: %7, End Date: %8’ + ‘\’ +             ‘\’ +             ‘Next Quarter: ‘ + ‘\’ +             ‘Start Date: %9’ + ‘\’ +             ‘\’ +             ‘Current Quarter: ‘ + ‘\’ +             ‘End Date: %10’ + ‘\’ +             ‘\’ +             ‘Next Week: ‘ + ‘\’ +             ‘Start Date: %11’ + ‘\’ +             ‘\’ +             ‘Next Week + 10D: ‘ + ‘\’ +             ‘Start Date: %12’,             StartDate, EndDate, FirstDateOfPreviousMonth, LastDateOfPreviousMonth,             FirstDateOfNextMonth, LastDateOfNextMonth, FirstDateofYear, LastDateOfYear,             FirstDayOfNextQuarter, LastDayOfCurrentQuarter, FirstDayOfNextWeek, FirstDayOfNextWeek10D         );     end; } Why Use CALCDATE in Business Central? The CALCDATE function is incredibly useful for automating and simplifying date-based calculations in Microsoft Dynamics 365 Business Central. Whether you are calculating due dates, generating reports based on time periods, or working with recurring events, CALCDATE saves time and reduces the chances of errors by automating these calculations. Here are some scenarios where CALCDATE can be particularly useful: To conclude, the CALCDATE function is a vital tool for anyone working in Microsoft Dynamics 365 Business Central. It simplifies the process of calculating dates based on specific time intervals, allowing users to manage and manipulate time-based data with ease. By understanding its syntax and functionality, you can unlock the full potential of CALCDATE and streamline your business processes. If you’re a developer or power user, mastering the CALCDATE function will not only enhance your efficiency but also give you greater control over your business data and operations. We hope you found this blog useful, and if you would like to discuss anything, you can reach out to us at transform@cloudfonts.com.

Maximizing Sales Productivity with Dynamics 365 CE: The Power of Process Automation

In the fast-evolving business landscape, sales leaders and business owners—whether new startups or established enterprises—face an unprecedented challenge: how to scale efficiently while maintaining a competitive edge. The digital revolution has created a vast ecosystem of tools, but many businesses are still unsure of how to leverage them effectively. For existing businesses, the challenge lies in moving away from manual data entry, disjointed workflows, and delayed decision-making that hinder productivity. Many companies still rely on outdated methods like Excel sheets, paperwork, and disconnected systems, leading to inefficiencies and lost revenue. For new or growing businesses, the challenge is different—they need to build a scalable foundation from day one, ensuring that the right digital tools are in place to support growth, automation, and decision-making. This is where Microsoft’s cloud ecosystem, particularly Dynamics 365 CE, Power Platform, and Power BI, plays a critical role in setting up businesses for long-term success. Automation is no longer just an operational advantage; it is a strategic imperative. Leveraging these tools, organizations can create a seamless, data-driven ecosystem that empowers sales teams to work smarter, not harder. But automation must be approached thoughtfully. It’s not about replacing human intuition; it’s about enhancing it. The Business Challenge: Automation is for Everyone, Not Just Tech Giants A common misconception is that automation is reserved for large enterprises with vast IT budgets. However, small and mid-sized businesses, as well as new startups, can also harness automation to streamline operations and scale efficiently. The key lies in understanding where automation can add value and how leaders can architect a strategy that integrates human judgment with system intelligence. Consider a mid-sized manufacturing firm that still manages leads and customer follow-ups manually. The sales team spends hours logging interactions, tracking deals, and following up via emails, leading to lost opportunities. By implementing Power Automate with Dynamics 365 CE, the company can: For a new business venturing into the cloud ecosystem, automation is a game-changer from day one. Instead of relying on traditional methods, they can: The result? More deals closed in less time, with greater accuracy and a human-first approach to relationship-building. The “ACTION” Framework for Sales Automation (Automate, Connect, Track, Improve, Optimize, Nurture) Sales Process Automation: From Lead to Close with Structured Chaos The “SMART” Approach to Sales Automation (Simplify, Monitor, Automate, Refine, Transform) Example 1: Automating Lead Qualification Imagine a sales rep manually filtering through hundreds of incoming leads to identify high-potential prospects. This process is not only time-consuming but also prone to bias. With AI-powered lead scoring in Dynamics 365 CE, the system automatically: Example 2: Automated Follow-Ups to Prevent Lost Deals A major challenge in sales is following up consistently. Research suggests that 80% of sales require five follow-ups, yet many reps give up after one or two. With Power Automate, businesses can: These micro-automations ensure no lead falls through the cracks, keeping the pipeline healthy and sales reps focused on closing deals. Power Virtual Agents (Copilot Agents): Revolutionizing Customer Engagement With the rise of AI, Power Virtual Agents, now called Copilot Agents, have transformed how businesses handle customer engagement and service. These AI-driven chatbots can: CRM Integration: The Power of a Unified System Many organizations use third-party tools for sales, marketing, and customer service. However, seamless CRM integration with Dynamics 365 CE provides unmatched insights and operational efficiency. By integrating with external platforms: Stakeholders & Business Owners: Making Data-Driven Decisions For business owners and key decision-makers, automation isn’t just about efficiency—it’s about strategic growth and profitability. By leveraging AI and automation tools, they can: Challenges in Sales Automation and How to Overcome Them 1. User Resistance to Automation 2. Integration Difficulties 3. Lack of Proper Communication 4. Data Quality Issues Conclusion: The Future of Business is Automated, But Still Human Automation is not a replacement for human expertise—it’s a force multiplier. Businesses that embrace automation with a strategic, human-first approach will thrive in the modern market. By leveraging Dynamics 365 CE, Power Platform, and Power BI, businesses can build a scalable, insight-driven ecosystem that not only improves sales productivity but future-proofs the organization for long-term success. I hope you found this blog useful, and if you would like to discuss anything, you can reach out to us at transform@cloudfonts.com.

SEARCH :

FOLLOW CLOUDFRONTS BLOG :

FOLLOW CLOUDFRONTS BLOG :


Secured By miniOrange