Category: Sage300c

Intercepting Events and Adding Custom Logic in Sage 300c Customizations

Sage details this well in their Order Entry Customization Tutorial (Section 4.3) in the SDK.

There are 2 ways:

  1. Unbind the existing handler from the event, and bind the event to your own custom handler. You can then call the original handler from your own custom handler.
  2. Interception Ajax calls using the ajaxSuccess and ajaxComplete functions.

Which one you decide to use, depends on your scenario and desired behaviour. For example, intercepting ajax calls may not be the way to go, if you need to do some custom processing before letting the existing event continue. Due to javascript’s asynchronous nature, you’d need to use the unbinding/binding method.

Sage has great examples of this in their SDK. We’ll show you another rudimentary example here:

In this example, we are working with OE Order Entry. We want to do some custom logic before letting a user post an order. Before allowing a post, we want to ask the server (our own custom controller) if it is ok to post the order. It will return a value isApproved, which will indicate if we should post the order or not.

Upon the page being loaded, we first save the original Post button’s handler, so we can use it later. Then, we unbind the Post button’s event, and replace it with our own:

var customPostHandler = null;
    // Post button event intercept
    if ($('#btnPost')[0] == undefined) return;
    var postHandlers = $('#btnPost').data('events').click;
    if (postHandlers && postHandlers.length > 0) {
        customPostHandler = postHandlers[0].handler;

Next, we unbind the Post button’s click handler, and replace it with our own:

// unbind the original
// bind the modified one
$('#btnPost').click(function () {
        //check with controller to see if this user is allowed
        var url = sg.utls.url.buildUrl("CU", "HutilityCustomization", "CheckCustomerApproverPost");
        var approverUserId = $('#txtApproverUserId').val();
        var approverPw = $('#txtApproverPw').val();
        var customerNumber = orderEntryUI.finderData.CustomerNumber;
        if (approverUserId && approverPw) {
                function () {
                    sg.utls.ajaxPost(url, { user: approverUserId, pw: approverPw, customerNumber: customerNumber}, HutilityOrderEntryCustomizationUICallback.jbtest);
                null, "Approve order with user [" + approverUserId + "].", "Demo");
        else {
            sg.utls.showValidationMessage("Please enter the credit approver credentials");

Next, we’ll initialize a callback function (HutilityOrderEntryCustomizationUICallback.jbtest) which will handle the data returned from our custom controller. If the response has isApproved as true, we allow the posting to continue by calling customPostHandler():

var HutilityOrderEntryCustomizationUICallback = {

    jbtest: function (data) {
        if (data.Data != undefined) {
            if (data.Data.isApproved == false) {
                sg.utls.showValidationMessage("Could not post order: " + data.Data.message);
            else {
        else {
            console.log("returned data is undefined");


Making Ajax POST Request in Sage 300c Customizations

Here’s how to make a POST request, using Sage’s supplied ajaxPost function:

sg.utls.ajaxPost(url, { user: approverUserId, pw: approverPw, customerNumber: customerNumber}, HutilityOrderEntryCustomizationUICallback.jbtest);

Here we’re supplying it with a url, our post data, and a callback function to handle the response.

Originally we tried to make POST requests using JQuery, but ran into issues. After inspecting the requests in Chrome Dev Tools, we found that the Sage ajaxPost includes tokens in the request that must be acting as CSRF tokens.

Sage 300c Customization: Modals, Dialog Boxes and Prompts

Plain old javascript dialogs and prompts cannot be readily used in customizations, as the web screens run inside of frames.

For example, running the below code:

 var r = confirm("Are you sure you want to post for customer [" + data.model.CustomerNumber + "] from group [" + data.model.CustomerGroupCode + "]?");

Will be ignored by the browser, and the following will be logged in the console:

Ignored call to 'confirm()'. The document is sandboxed, and the 'allow-modals' keyword is not set.

To avoid this, we must use one of the numerous dialog box options available to us in Sage’s global.js.

There are A LOT of functions, so we’ll add them here as we learn how to use them.

Here are a few to start:


Using this, simply shows an error validation message.

It can used like this:

sg.utls.showValidationMessage("This is an error validation message!");

And results in this:

Example of sg.utls.showValidationMessage


Using this shows a yes/no prompt.

It can be used like this:

    var approverUserId = $('#txtApproverUserId').val();
    var approverPw = $('#txtApproverPw').val();
    var customerNumber = orderEntryUI.finderData.CustomerNumber;
    if(approverUserId && approverPw)
        sg.utls.showKendoConfirmationDialog(function () {
                sg.utls.ajaxPost(url, { user: approverUserId, pw: approverPw, customerNumber: customerNumber }, HutilityOrderEntryCustomizationUICallback.jbtest);
            null, "Approve order with user [" + approverUserId + "].", "Demo");
    else {
        sg.utls.showValidationMessage("Please enter the credit approver credentials");

The above example shows a confirmation dialog if two textboxes have been filled in, otherwise it shows a validation error message. The confirmation dialog takes in 3 arguments: the function to run upon a “Yes”, the function to run upon a “No”, and the prompt message.

In this example, we’re sending an AJAX POST request to a custom controller if “Yes” is clicked.

The confirmation dialog shows like this:

Example of sg.utls.showKendoConfirmationDialog


More to come!

Initializing Finders in Sage 300c Web Customizations

This example shows a trimmed down portion of a javascript customization file, that only includes finder initialization.

In this example, the finder is for AR Customers, where the finder will only show the Customer ID field, and return that same field as the value.

HutilityOrderEntryCustomizationUI = {
    initCustomFinders: function () {
        sg.viewFinderHelper.setViewFinder("btnFinderCustomerTest", "txtFinderCustomerTest",
                viewID: "AR0024",
                viewOrder: 0,
                displayFieldNames: ["IDCUST"],
                returnFieldNames: ["IDCUST"],
                filter: null,
                initKeyValues: [],
                parentValAsInitKey: true
// Initial Entry
$(function () {

In the above code, btnFinderCustomerTest would be the id of the button that triggers the finder, and txtFinderCustomerTest would be id of the textbox where the finder result value is placed.

The button and textbox DOM elements can be defined using the Sage UI Customization wizard or defined via javascript as we’ve described here.

Sage 300c Customization Tip: Adding UI Elements Using Javascript

Here’s a way to add UI elements to your customization using javascript, bypassing the UI wizard.

One reason you might not want to use the wizard, is that it may be missing certain HTML elements. One example is adding a password input textbox. As of August 2019, the wizard doesn’t provide this option.

In the below example, we’re adding a textbox and button combo to initialize later on as a finder. We’re also adding a textbox for a user id, and a corresponding password. We’ll be adding these right before the row where the Post button is, on the OE Order Entry screen.

Sage300c customization - programatically adding UI elements

The code above can be done more elegantly, please excuse it for the sake of illustration purposes!

This is nothing specific to Sage 300c web development, just showing it as an option that can be done.


Debugging Sage 300c C# Controller Code

In Visual Studio, attach to the process w3wp.exe

You may need to run Visual Studio as administrator.

Once attached to the process, navigate to your customized screen on the Sage 300c web UI.

In Visual Studio, open ensure the symbols are loaded for the controller dll.

VS2017 - Debug Modules

VS2017 - Symbols Loaded

Use your custom screen, and any breakpoints you’ve set should be hit.


Make sure the pdb and the dll are matching versions, or VS will refuse to load symbols.

VS - symbols not loaded

Packaging and Installing a Sage 300c Web Screen Customization

So you have your customization files and a custom controller project. How do you get this installed?

It’s actually fairly easy, and Sage has a nice way to install them into individual companies for the web screens.


Find the dll compiled by your controller project. In our case, it’s named Hutility.CU.Web.dll.

Also, find the bootstrapper XML file in your project. In our case, it’s named HutilityCUBootstrapper.xml.

Package those 2 files, and along with the UI’s manifest, js and XML files into a zip.

Packaging Sage 300 customization


Navigate to your Sage 300c Admin dashboard. If you’re running locally that would be at http://localhost/Sage300/Admin¬†

From that screen, import your zip file.

Sage 300c Import Customization

Once imported, click on your customization, and assign it to be available to a company.

Sage 300c Assign customization

Log out of the admin dashboard, and navigate back to the main Sage300c application at:


Getting Started with Sage300c Customization Wizards

To kick things off, we’ll quickly go over the two main wizards you’ll use to create a web screen customization. Sample projects that use these are in the SDK on Github, but we’ll illustrate them here for a quick reference. You’ll find an example of an OE Order Entry screen customization, in the SDK, at: /docs/customization/Sage300SDK_WebScreenOrderEntryCustomizationTutorial.docx

The first wizard you’ll run, is for the client side web UI. You can find this wizard in the SDK, at: /bin/wizards/Sage.CA.SBS.ERP.Sage300.CustomizationWizard.exe

Sage 300c Web Customization Wizard

The screenshot above, is the 1st screen of this wizard. Sage has a more thorough walkthrough of how to use this wizard in their Order Entry tutorial referenced above.

Through this wizard, you add screens (OE Order Entry, AR Invoice Entry, etc.) and controls (textboxes, buttons, finders, etc.) to your customization. It will then produce the javascript, XML and manifest files that the web screens require to lay out the UI elements of your customization. The javascript file is the base from which you will be adding your custom UI logic.

Some HTML elements such as password boxes (i.e. an input field of type ‘password’) are currently not available as options via the wizard. A way to get them into your customization would be through javascript. That is, you would dynamically add the HTML elements to the DOM via javascript after the page has loaded.

The code and files generated from this wizard are for the client/UI side. This is enough for doing custom logic on the presentation layer, but what if you need to fetch data from the server? This is where the 2nd wizard comes in.

Before you can use the 2nd wizard, you’ll need to install Sage300UICustomizationSolution.vsix into Visual Studio (as of August 2019, that is for VS2017). This can be found in the SDK, at bin/wizards/Sage300UICustomizationSolution.vsix

Once installed, you’ll create a project in Visual Studio of type ‘Sage 300 UI Customization Wizard’.

Sage 300 UI Customization WIzard

From here, select the manifest file produced from the 1st wizard. Finish the wizard, and it will generate a project for a custom controller. If you encounter any issues at this step, verify that you have the latest version of Visual Studio, and ensure you are using the correct Sage 300 Web SDK version.

In future posts, we’ll go over how to package and install a customization, how to use the Sage javascript libraries, intercepting user actions and doing custom logic on the server side using a custom controller.

Sage300c Web Screen Customizations

We’ll be starting a new series of posts on Sage300c web screen customizations.

The purpose is to have a resource that has code snippets, gotchas and tips to help our internal developers and possibly anyone else looking to get started. Sage has provided their Sage 300 Web SDK as open source on Github, but we’re hoping to add some more code examples from a different perspective.

It’s a big move for 3rd party developers to go from VB6 screen customizations to the new web screens, so hopefully we can help some developers save some time on the way!