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
$('#btnPost').unbind('click');
// 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) {
            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");
        }
    });
}

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) {
        console.log(data);
        if (data.Data != undefined) {
            if (data.Data.isApproved == false) {
                sg.utls.showValidationMessage("Could not post order: " + data.Data.message);
            }
            else {
                customPostHandler();
            }
        }
        else {
            console.log("returned data is undefined");
        }
    },

};

Advertisements

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:

sg.utls.showValidationMessage

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

sg.utls.showKendoConfirmationDialog

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 () {
    HutilityOrderEntryCustomizationUI.init();
    HutilityOrderEntryCustomizationUI.initCustomFinders();
});

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.

Troubleshooting:

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.

Packaging

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

Installing

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:

http://localhost/Sage300