Category Archives: D365 Business Central
Dealing with ISV Extension Updates in Business Central: A Practical Guide
As of August 2025, the number of third-party apps available for Dynamics 365 Business Central on Microsoft AppSource is estimated to be between 4,000 and 6,500. Microsoft regularly publishes marketplace updates, with 200–300 new offers added monthly across all product lines, a significant portion of which are Business Central extensions. It’s clear that the Business Central ecosystem is rapidly growing, making extension update management increasingly critical. The majority of clients we’ve worked with use third-party modules to enhance their business processes, making the management of extension updates a critical part of our environment health checklist. References Apps added to MS App Source MSLearn | Automatically update appsource apps with business central updates Configuration If you don’t have access to the Business Central Admin Center, your only option is to uninstall the extension and then reinstall it from AppSource. However, if you do have access to the Admin Center and prefer to manage app updates manually. Navigate to your environment and click on Apps. Here, you can – For those looking to automate this process, Microsoft offers the “Appa Update Cadence” setting, which controls how and when apps are updated alongside Business Central. There are three available settings: To conclude, managing third-party extension updates in D365 Business Central is essential to maintaining a stable and reliable environment. Whether updates are handled manually through the Admin Center or automated using the App Update Cadence feature, having a clear process helps minimize disruptions. With the growing number of extensions in AppSource, proactively testing updates, monitoring changes, and coordinating with ISV partners ensures your Business Central environment stays healthy and future ready. If you need further assistance or have specific questions about your ERP setup, 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@cloudfronts.com.
Share Story :
Mastering String Functions in Business Central: Practical Examples with AL
When working with Microsoft Dynamics 365 Business Central, string manipulation is an essential part of everyday development. From reversing names to formatting messages, AL provides multiple ways to handle text. In this blog, we’ll explore different approaches to string handling through practical examples, including custom logic and built-in AL string functions. Why String Handling Matters in Business Central Strings are everywhere—customer names, item descriptions, invoice messages, and more. Being able to manipulate these strings efficiently allows developers to: Let’s dive into some real-world AL examples where we extend the Customer List page with new actions for string manipulation. Part 1: Custom String Handling Approaches 🔹 a) Method 1: Using List of Text We can reverse a string by adding each character into a List of [Text] and then calling .Reverse(). action(CFS_ReverseSelectedCustomerName) { Caption = ‘Reverse Customer Name’; ApplicationArea = All; trigger OnAction() var StringList: List of [Text]; StringLetter: Text; ReversedString: Text; begin ReversedString := ”; foreach StringLetter in Rec.Name do StringList.Add(StringLetter); StringList.Reverse(); foreach StringLetter in StringList do ReversedString += StringLetter; Message(ReversedString); end; } This approach is useful when you want more control over the collection of characters. Output: Method 2: Using Index Manipulation Here, we iterate through the string from end to start and build the reversed string. action(CFS_NewIndex) { Caption = ‘New Index’; ApplicationArea = All; trigger OnAction() var ReversedString: Text; i: Integer; begin for i := StrLen(Rec.Name) downto 1 do ReversedString += CopyStr(Rec.Name, i, 1); Message(ReversedString); end; } A more direct approach, simple and efficient for reversing text. Method 3: Using CopyStr The CopyStr function is perfect for extracting characters one by one. action(CFS_NewText) { Caption = ‘New Text’; ApplicationArea = All; trigger OnAction() var ReversedString: Text; i: Integer; begin for i := StrLen(Rec.Name) downto 1 do ReversedString += CopyStr(Rec.Name, i, 1); Message(ReversedString); end; } Part 2: Built-in AL String Functions Beyond custom logic, AL offers powerful built-in functions for working with text. Let’s explore a few. Evaluate Examples The Evaluate function converts text into other datatypes (integer, date, boolean, duration, etc.). action(CFS_EvaluateExamples) { Caption = ‘Evaluate Examples’; ApplicationArea = All; trigger OnAction() var MyInt: Integer; MyDate: Date; MyBool: Boolean; MyDuration: Duration; Value: Text; OkInt: Boolean; OkDate: Boolean; OkBool: Boolean; OkDur: Boolean; begin Value := ‘150’; OkInt := Evaluate(MyInt, Value); Value := ‘2025-09-01’; OkDate := Evaluate(MyDate, Value); Value := ‘TRUE’; OkBool := Evaluate(MyBool, Value); Value := ‘3d 5h 45m’; OkDur := Evaluate(MyDuration, Value); Message( ‘Integer = %1 (Ok: %2)\Date = %3 (Ok: %4)\Boolean = %5 (Ok: %6)\Duration = %7 (Ok: %8)’, MyInt, OkInt, MyDate, OkDate, MyBool, OkBool, MyDuration, OkDur); end; } Super handy when parsing user input or imported text data. String Functions Examples Now let’s use some of the most common string functions in AL. action(CFS_StringFunctions) { Caption = ‘String Functions’; ApplicationArea = All; trigger OnAction() var SourceTxt: Text[100]; CopyTxt: Text[50]; DelTxt: Text[50]; Len: Integer; SubstTxt: Text[100]; UpperTxt: Text[50]; LowerTxt: Text[50]; begin SourceTxt := ‘Dynamics 365 Business Central’; CopyTxt := CopyStr(SourceTxt, 1, 8); // “Dynamics” DelTxt := DelStr(SourceTxt, 1, 9); // “365 Business Central” Len := StrLen(SourceTxt); // 29 SubstTxt := StrSubstNo(‘Hello %1, welcome to %2!’, ‘User’, ‘Business Central’); UpperTxt := UpperCase(SourceTxt); // “DYNAMICS 365 BUSINESS CENTRAL” LowerTxt := LowerCase(SourceTxt); // “dynamics 365 business central” Message( ‘Original: %1\CopyStr: %2\DelStr: %3\Length: %4\Substitute: %5\Upper: %6\Lower: %7’, SourceTxt, CopyTxt, DelTxt, Len, SubstTxt, UpperTxt, LowerTxt); end; } These built-in functions save time and make string handling straightforward. To conclude, whether you’re reversing a customer’s name, converting text into other data types, or formatting user-friendly messages, AL’s string manipulation capabilities are both flexible and powerful. By combining custom logic with built-in functions, you can handle almost any text-related scenario in Business Central. Try experimenting with these functions in your own extensions—you’ll be surprised how often they come in handy! We hope you found this blog useful, and if you would like to discuss anything, you can reach out to us at transform@cloudfronts.com.
Share Story :
Monitoring Job Queues: Setting Up Failure Notifications within Business Central
A job queue lets users set up and manage background tasks that run automatically. These tasks can be scheduled to run on a recurring schedule. For a long time, users had a common problem in Business Central—when a job queue failed, there was no alert or warning. You’d only notice something was wrong when a regular task didn’t run for a few days. Some people tried to fix this by setting up another job queue to watch and restart failed ones.But that didn’t always work, especially if an update happened at the same time. Now, Microsoft has finally added a built-in way to get alerts when a job queue fails. You can get notified either inside Business Central or by using Business Events. In this blog, we’ll look at how to set up notifications directly within Business Central. Configuration Search for “Assisted Setup” in Business Central’s global search. Scroll down till “Set up Job Queue notifications”. Click on Next. Add the additional users who need to be notified when the job queue fails along with the job creator (if required). Choose whether you want the notification to be in-product or using Business Events (and Power Automate). For now, I’m choosing in-product. Choose the frequency of the notification, you can have it either when a single job fails or you can have it after 3-5 jobs have failed (as per settings) Click on Finish. Now for testing I’ve run a job queue and on the home page, I get the following notification. Clicking on “Show more details” give me a list of all the failed job queues. To conclude, this new notification feature is a much-needed improvement and a good step forward. It helps users catch job queue failures quickly, without having to manually check every day. However, the setup and experience still feel a bit buggy and lacklustre. With some refinements, it could be a lot smoother and more user-friendly. If you need further assistance or have specific questions about your ERP setup, feel free to reach out for personalized guidance. I hope you found this blog useful, and if you would like to discuss anything, you can reach out to us at transform@cloudfronts.com.
Share Story :
Boost Job Automation in Business Central with Maximum Number of Attempts
Automation in Microsoft Dynamics 365 Business Central can drastically improve efficiency, especially when scheduled jobs run without manual intervention. But occasionally jobs fail due to temporary issues like network glitches or locked records. Setting the Maximum number of attempts ensures the system retries automatically, reducing failures and improving reliability. Steps to Optimize Job Automation 1. Navigate to Job Queue Entries Go to Search (Tell Me) → type Job Queue Entries → open the page. 2. Select or Create Your Job Either choose an existing job queue entry or create a new one for your automated task. 3. Set Maximum No. of Attempts In the Maximum No. of Attempts field, enter the number of retries you want (e.g., 3–5 attempts). This tells BC to retry automatically if the job fails. 4. Schedule the Job Define the Earliest Start Date/Time and Recurring Frequency if applicable. 5.Enable the Job Queue Make sure the Job Queue is On and your job is set to Ready. 6.Monitor and Adjust Review Job Queue Log Entries regularly. Pro Tips -Keep your jobs small and modular for faster retries. -Avoid setting attempts too high it may overload the system. -Combine retries with proper error handling in the code or process. To conclude, by leveraging the Maximum No. of Attempts feature in Business Central, you can make your job automation more resilient, reduce downtime, and ensure business processes run smoothly without constant supervision. I hope you found this blog useful, and if you would like to discuss anything, you can reach out to us at transform@cloudfronts.com.
Share Story :
Simplifying Access Management in Dynamics 365 Business Central Through Security Groups
A Security Group is a way to group users together so that you can give access to all of them at once.For example, if everyone in the Finance team needs access to certain files or apps, you can add them to a group and give the group permission instead of doing it for each person. In Office 365, Security Groups are managed through Azure Active Directory, which handles sign-ins and user identities in Microsoft 365. They help IT teams save time, stay organized, and keep company data safe. The same Security Groups you create in Azure Active Directory (AAD) can also be used in Dynamics 365 Business Central to manage user permissions. Instead of giving access to each user one by one in Business Central, you can connect a Security Group to a set of permissions. Then, anyone added to that group in Azure AD will automatically get the same permissions in Business Central. They’re also helpful when you want to control environment-level access, especially if your company uses different environments for testing and production. For example, only specific groups of users can be allowed into the production system. Security Groups aren’t just useful in Business Central; they can be used across many Microsoft 365 services. You can use them in tools like Power BI, Power Automate, and other Office 365 apps to manage who has access to certain reports, flows, or data. In Microsoft Entra (formerly Azure AD), these groups can be used in Conditional Access policies. This means you can set rules like “only users in this group can log in from trusted devices” or “users in this group must use multi-factor authentication.” References Compare types of groups in Microsoft 365 – Microsoft 365 admin | Microsoft Learn What is Conditional Access in Microsoft Entra ID? – Microsoft Entra ID | Microsoft Learn Simplify Conditional Access policy deployment with templates – Microsoft Entra ID | Microsoft Learn Usage Go to Home – Microsoft 365 admin center. Go to “Teams & Groups” > “Active Teams & Groups” > “Security Groups” Click on “Add a security group” to create a new group. Add a name and description for the group and click on Next and finish the process. Once the group is created, you can re-open it and click on “Members” tab to add Members. Click on “View all and manage members” > “Add Members” Select all the relevant Users and click on Add. Now, back in Business Central, search for Security Groups. Open it and click on New. Click on the drill down. You’ll see all the available security groups here, select the relevant one and click on OK. Mail groups are not considered in this list. You can change the Code it uses in Business Central if required.Once done, click on “Create” Select the new Security Group and click on Permissions. Assign the relevant permissions. Now, any User that will be added to this Security Group in Office 365 will have the D365 Banking Permission Set assigned to them. Further, these groups will also be visible in the Admin Center, from where you can define whether a particular group has access to a particular environment. To conclude, security Groups are a powerful way to manage user access across Microsoft 365 and Dynamics 365 Business Central. They save time, reduce manual effort, and help ensure that the right people have access to the right data and tools. By using Security Groups, IT teams can stay organized, manage permissions more consistently, and improve overall security. Whether you’re working with Business Central, Power BI, or setting up Conditional Access in Microsoft Entra, Security Groups provide a flexible and scalable solution for modern access management. If you need further assistance or have specific questions about your ERP setup, feel free to reach out for personalized guidance. I hope you found this blog useful, and if you would like to discuss anything, you can reach out to us at transform@cloudfronts.com.
Share Story :
Getting Started with the Event Recorder in Business Central
When developing customizations or extensions in Microsoft Dynamics 365 Business Central, working with events is a best practice. Events help ensure your code is upgrade-safe and cleanly decoupled from the standard application code. However, one common challenge developers face is figuring out which events are triggered during certain actions in the system. That’s where the Event Recorder comes in. What Is the Event Recorder? The Event Recorder is a built-in tool in Business Central that allows developers to monitor and log all published and subscribed events during a user session. Think of it as a “black box” recorder for event-driven development. It helps you identify: This tool is extremely helpful when you’re customizing functionality using event subscriptions (as per AL best practices) but aren’t sure which event to subscribe to. Why Use the Event Recorder? Traditionally, developers had to dig through AL code or documentation to find the right event to subscribe to. With the Event Recorder, this becomes faster and more efficient. Key benefits include: How to Use the Event Recorder Here’s a step-by-step guide: Step 1: Open Event Recorder Step 2: Start a New Recording Step 3: Stop Recording Step 4: Review the Results Best Practices Sample Use Case Suppose you’re trying to add custom logic every time a Sales Invoice is posted. You’re not sure which event gets triggered at that point. Using the Event Recorder: Now, you can write a subscriber in your AL code like this: [EventSubscriber(ObjectType::Page, Page::”Customer List”, ‘OnAfterGetRecordEvent’, ”, true, true)] local procedure MyProcedure() begin // Your custom logic here end; Limitations While powerful, the Event Recorder does have some limitations: To conclude, Event Recorder is an indispensable tool for any AL developer working in Business Central. It simplifies the discovery of relevant events, helps maintain clean and upgrade-safe extensions, and boosts overall development efficiency. Whether you’re new to AL or a seasoned developer, incorporating the Event Recorder into your workflow will save you time. 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.
Share Story :
How to Send Emails with CC and BCC in Business Central Using AL Language
Sending emails programmatically in Microsoft Dynamics 365 Business Central (BC) is a common requirement for customization be it sending invoices, reminders, or notifications. With the release of enhanced email capabilities in recent versions, AL developers can now include CC (Carbon Copy) and BCC (Blind Carbon Copy) recipients when sending emails. In this blog, we’ll walk through how to send an email in Business Central using AL and how to include CC and BCC fields effectively. Steps to Achieve goal: Code for example. procedure SendInvoiceEmail(var PurchaseInvHeader: Record “Purch. Inv. Header”): BooleanvarEmailAccount: Codeunit “Email Account”;EmailMessage: Codeunit “Email Message”;Email: Codeunit Email;PurchaseInvLine: Record “Purch. Inv. Line”;Vendor: Record Vendor;Item: Record Item;Currency: Record Currency;CurrencySymbol: Text;ItemDescription: Text[2048];ItemNumber: Code[30];TotalAmount: Decimal;Link: Text[2048];EmailType: Enum “Email Recipient Type”;begin// Get vendor informationVendor.SetRange(“No.”, PurchaseInvHeader.”Buy-from Vendor No.”);if Vendor.FindFirst() then; // Process purchase invoice linesPurchaseInvLine.SetRange(“Document No.”, PurchaseInvHeader.”No.”);PurchaseInvLine.SetFilter(Quantity, ‘<>%1’, 0);if PurchaseInvLine.FindSet() then repeat Item.Reset(); Item.SetRange(“No.”, PurchaseInvLine.”No.”); Item.SetRange(“Second Hand Goods”, true); // Example filter if Item.FindFirst() then begin ItemDescription := PurchaseInvLine.Description; ItemNumber := PurchaseInvLine.”No.”; TotalAmount += PurchaseInvLine.”Amount Including VAT”; Currency.SetRange(Code, PurchaseInvHeader.”Currency Code”); if Currency.FindFirst() then CurrencySymbol := Currency.Symbol else CurrencySymbol := ‘€’; // Default symbol end; until PurchaseInvLine.Next() = 0; // Generate a form link with dynamic query parameters (example only)Link := ‘https://your-form-url.com?vendor=’ + Vendor.”No.” + ‘&invoice=’ + PurchaseInvHeader.”No.”; // Create and configure the emailEmailMessage.Create( Vendor.”E-Mail”, ‘Subject: Review Your Invoice’, ‘Hello ‘ + Vendor.Name + ‘,<br><br>’ + ‘Please review the invoice details for item: ‘ + ItemDescription + ‘<br>’ + ‘Total: ‘ + Format(TotalAmount) + ‘ ‘ + CurrencySymbol + ‘<br>’ + ‘Form Link: <a href=”‘ + Link + ‘”>Click here</a><br><br>’ + ‘Best regards,<br>Your Company Name’, true // IsBodyHtml); // Add BCC (could also use AddCc)EmailMessage.AddRecipient(EmailType::BCC, ‘example@yourdomain.com’); // Update invoice status or flags (optional business logic)PurchaseInvHeader.”Custom Status Field” := PurchaseInvHeader.”Custom Status Field”::Started;PurchaseInvHeader.Modify(); // Send the emailexit(Email.Send(EmailMessage)); end; To conclude, sending emails directly from AL in Business Central is a powerful way to streamline communication with vendors, customers, and internal users. By leveraging the Email Message and Email codeunits, developers can easily customize the subject, body, and recipients, including support for CC and BCC fields. This flexibility makes it easy to automate notifications, document sharing, or approval requests directly from your business logic. Whether you’re integrating forms, sending invoices, or just keeping stakeholders in the loop, this approach ensures your extensions are both professional and user-friendly. With just a few lines of code, you can improve efficiency and enhance communication across your organization. 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
Share Story :
Transforming Financial Operations: The Strategic Impact of Customer Payment Registration in Dynamics 365 Business Central
When customers make electronic payments to your bank account, you should take the following steps: Use the Register Customer Payments page to reconcile internal accounts using actual cash figures, ensuring all payments are collected accurately. This functionality allows you to quickly verify and post individual or lump-sum payments, handle discounted payments, and identify unpaid documents. For different customers with varying payment dates, payments must be posted individually. However, payments from the same customer with the same payment date can be posted as a lump sum. This is particularly useful when a single payment covers multiple sales invoices. Pre-requisites Business Central onCloud Steps: Search for “Register Customer Payments” Since different payment types can be posted to different balancing accounts, it is necessary to select a balancing account on the Payment Registration Setup page before processing customer payments. If you consistently use the same balancing account, you can set it as the default to streamline the process and skip this step each time you open the Register Customer Payments page. Check the Payment Made box on the line corresponding to the posted document for which the payment has been made. Use Post payment option to post regular payment (Non Non-Lump). You can use the preview action to verify entries before payment post. Lump payment: Payment information is posted for documents on lines where the Payment Made checkbox is checked. The payment entries are recorded in the general ledger, bank, and customer accounts, with each payment applied to its corresponding posted sales document. To conclude, effectively managing customer payments is crucial for maintaining accurate financial records and ensuring smooth business operations. Microsoft Dynamics 365 Business Central offers a robust and flexible platform to streamline the payment registration process, empowering businesses to efficiently reconcile accounts, post payments, and handle diverse payment scenarios. By leveraging features like the Register Customer Payments page, businesses can save time, reduce errors, and maintain a clear view of their financial health. Whether it’s managing individual payments, lump-sum transactions, or discounted invoices, Dynamics 365 provides the tools needed to adapt to your organization’s unique requirements. With proper setup and utilization of its payment registration features, businesses can enhance their financial workflows, foster better customer relationships, and drive long-term growth. 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.
Share Story :
Generate Enhanced QR Codes in Business Central Using AL and QuickChart API
QR codes have become a standard tool for sharing data quickly and efficiently—whether it’s for product labeling, document tracking, or digital payments. Now, you can generate customized QR codes and barcodes directly within Microsoft Dynamics 365 Business Central using a simple action. This feature allows users to choose the barcode type and size, embed the image into a record, and optionally download it—all with just a few clicks. It’s an easy way to enhance records with scannable information, without leaving Business Central or needing external tools. In this article, we’ll walk through how this feature works and how it can be used in real business scenarios. What This Feature Does? The “Generate Enhanced QR Code” action gives users the ability to quickly create and manage barcodes within Business Central. Here’s what it can do: Business Scenarios Where This Shines AL Code Behind the Feature Output: Choose an image size (Small, Medium, Large). Select a barcode type (QR, Swiss QR, Aztec, Data Matrix, Telepen). Store the generated image in the Picture field of the item record. To conclude, this customization shows how a simple AL code extension can greatly boost efficiency in Microsoft Dynamics 365 Business Central. By enabling quick generation and embedding of QR codes and barcodes, you eliminate manual steps and streamline processes across departments—from inventory to sales and beyond. With support for multiple barcode types, customizable sizes, and built-in download and validation prompts, this feature brings powerful functionality right into the user’s workflow—no external tools needed. Whether you’re in warehousing, retail, manufacturing, or pharma, this tool helps standardize product labeling and enhances traceability with just a few clicks. Looking ahead? You can extend this further by including additional record fields, customizing encoding logic, or supporting more document types like purchase orders or invoices. 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.
Share Story :
Choosing the Right WIP (Work in Progress) Method for Your Business Central Projects
Managing projects in Microsoft Dynamics 365 Business Central isn’t just about tracking tasks—it’s about timing your revenue and cost recognition. That’s where WIP (Work in Progress) methods come into play. Whether you’re in construction, services, or implementation—your project accounting can get messy fast. WIP helps clean that up. Let’s explore the five WIP methods through simple scenarios to help you choose the right one. 5 WIP Methods in Business Central—With Scenarios! 1. Cost Value “I spend a lot upfront, billing comes later.” This method calculates WIP based on actual project costs. It defers those costs to the balance sheet until you’re ready to recognize them. Scenario: You’re building a factory. You spend ₹25 lakh on materials and labor in the first 3 months but won’t invoice the customer until completion. You don’t want those ₹25 lakh to hit your P&L yet. What happens: Costs get moved to a WIP account, so your P&L stays clean. WIP = Costs Incurred 2. Sales Value “I raise invoices early—before completing work.” This method calculates WIP based on billable sales value, regardless of actual cost incurred. Scenario: You sign a ₹20 lakh IT project. In Month 1, you invoice ₹5 lakh for kickoff and initial planning—even though you’ve barely incurred costs. What happens: That ₹5 lakh revenue sits in the WIP account until you’ve actually done that much work. WIP = Revenue Billed (or Billable) – Work Performed 3. Cost of Sales “I bill monthly and want a straightforward approach.” Here, there is no WIP. Costs and revenues hit your P&L as soon as they’re posted. Scenario: You run a monthly maintenance contract. Every month, you invoice ₹1 lakh and spend ₹70,000 on service staff. What happens: Both ₹1 lakh and ₹70,000 show up in your P&L that month—no balance sheet entries, no deferrals. Simple: Revenue – Cost = Monthly Profit 4. Percentage of Completion (POC) “I want my financials to reflect actual progress.” This method tracks job progress and calculates revenue based on how much of the job is completed. Scenario: You’re doing a ₹60 lakh construction job. You’ve completed 40% of the work and spent ₹20 lakh so far. Your system calculates revenue as 40% of ₹60 lakh = ₹24 lakh. What happens: Business Central adjusts both revenue and cost based on progress—not just what’s billed or spent. % Completion = Actual Cost ÷ Estimated Cost Recognized Revenue = % Completion × Contract Value 5. Completed Contract “I only recognize anything after the job is fully done.” This method holds everything—revenue and cost—until the project is completed. Scenario: You’ve been hired to deliver a complex machine. The contract clearly states: “No billing or revenue recognition until handover.” What happens: You might spend ₹10 lakh and do months of work—but nothing shows up in your P&L until the machine is delivered and accepted. Recognize all revenue and cost only at job completion Quick Table Comparison WIP Method Recognizes Costs Recognizes Revenue Scenario Style Cost Value Deferred Deferred Spend-heavy, bill-later projects Sales Value Deferred Based on billing Invoice-early, delivery-later Cost of Sales Immediate Immediate Simple monthly billing Percentage of Completion Gradual Gradual Long-term projects with clear phases Completed Contract At Completion At Completion Strict final delivery-based billing Over to you! Which WIP method do you think suits your projects? Have you used Percentage of Completion before? Or do you prefer a simpler Cost of Sales approach? 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.