Sage 300 2018.2 Web SDK

Introduction

The Sage 300 Web SDK (SDK) is a collection of wizards, utilities, samples and documentation for developing Web Screens for the Sage 300 Application.

This week we released the Sage 300 2018.2 Web SDK to coincide with the release of the Sage 300 2018.2 Application.

It’s Available!

The SDK is available at https://github.com/SageNADev/Sage300-SDK.

Branches

As described in a previous blog and in the README file in the root of the repository, the branches contain the different versions of the SDK.

master

Contains the current version of the SDK (2018.2).

develop

Contains the in-progress version of the SDK (2019).

release-…

Contains the previous versions of the SDK (release-2017, release-2017.1, release-2017.2, release-2018, and release-2018.1)

What’s New

Documentation

Updated documentation is available.

In the docs\upgrades folder is a document for the upgrade procedures for moving partner source from Sage 300 2018.1 to Sage 300 2018.2. This folder also contains documents for explaining the upgrade steps specific to the Bundle Registration class and the Behaviour JavaScript file.

In the docs\development and docs\wizards folders you will find documents pertaining the wizards and tutorials which have been updated to reflect changes regarding to a …Behaviour JavaScript change.

The docs\presentations folder has been updated and includes a PowerPoint presentation for what’s new in the SDK for 2018.2.

In the docs\utilities folder you will find a document for the new Sage300Utilities utility which is used by the Sage 300 UI Wizard during compilation and an updated document for the MergeISVProject utility which has been refactored and enhanced for JavaScript Minification and Partner Deployment folders.

The samples\customization folder has a new folder called Sample4_AR_Invoice_Entry_Customization containing a new sample and document.

Visual Studio 2017

All wizard manifests have been revised to include Visual Studio 2017 as a target IDE.

This means that when registering the wizards, the registration process will prompt you to select the Visual Studio version for the wizard being registered.

Visual Studio 2013 and Visual Studio 2015 are still supported targets and all three versions can be used for Sage 300 Web Screen development.

Blog122

Samples

The previous samples have been updated with new global references and now reference the common AccpacDotNetVersion.props file in the settings folder.

A new sample has been added to the Web SDK. The AR Invoice Entry Customization Sample illustrates the following:

  • Adding a tab control
  • Enhancing the display via CSS
  • Populating a dropdown list
  • Populating a grid with a method in the Finder!
  • Save, Delete, Update, Grid Refresh

Blog123

Solution Wizard

Minor changes to the wizard to support the updated components and references in the Sage 300 web screens.

Customization Wizards

Minor changes to the wizard to support the updated components and references in the Sage 300 web screens.

Code Generation Wizard

Minor changes to the wizard to support the updated components and references in the Sage 300 web screens.

See the Defects Corrected section for information on the resolved defects

Sage 300 Utilities Executable

This is a new utility for 2018.2 which facilitates the building of template files used by the wizards. This is only relevant if the Sage 300 UI Wizard package is compiled in Visual Studio.

MergeISVProject Executable

This utility is a post-build utility used by various wizards and the generated partner solution to pre-compile Razor Views and deploy assets to a local Sage 300 installation for developer testing.

It has been refactored and enhanced in 2018.2:

  • Minify JavaScript files
    • Now your JavaScript files can be minified when delivered to a customer
    • As of 2018.1, Sage 300 JavaScript files are minified
  • Create deployment folders
    • Helpful for when the partner needs to create an installation for a customer
  • New informative messages in the Visual Studio Output Window
    • Easily see what has been created in what deployment folder

New settings folder in the Web SDK

The new settings folder in the Web SDK now contains a common AccpacDotNetVersion.props file that is used by the wizard and sample source instead of every solution having its own version.

A generated solution will still have its own version as it should no longer reference the Web SDK’s version.

Defects Corrected

  • An error will be encountered in the Code Generation Wizard if a column in a partner model is named “EntityName” as this is the name of a public constant in the Model class. A warning message will prevent the code generation until the column name is changed.
  • Finder code generated by the Code Generation Wizard regarding data type and expressions has been simplified and corrected. Additionally, the …Behaviour.js file, on successful return from a finder selection, was not performing a Get to get the record from the repository and instead used the object returned from the finder. The record returned from the finder is out-of-process and needs to be fetched by the screen. Changes to partner code are only required if a partner’s business view has logic regarding a new record which was incorrectly being invoked by an existing record that “looked like” a new record. This has been corrected. The following shows the previous routine from the Source Code Sample and the new routine:

Previous Logic

setFinderData: function () {

var data = sourceCodeUI.finderData;

sg.utls.clearValidations(“frmSourceCode”);

         ko.mapping.fromJS(data, {}, model Data);

sourceCodeUI.finderData = null;

         modelData.UIMode(sg.utls.OperationMode.SAVE);

         sourceCodeUI.sourceCodeModel.isModelDirty.reset();

         sourceCodeUISuccess.setkey();

},

New Logic

setFinderData: function () {

var data = sourceCodeUI.finderData;

sg.utls.clearValidations(“frmSourceCode”);

sourceCodeUI.finderData = null;

sourceCodeRepository.get(data.SourceLedger, sourceCodeUISuccess.get);

},

The Upgrade Wizard includes a step that indicates that this change is optional and MUST be done manually in existing partner Behaviour JavaScript files. Because manual changes may have been made to this routine since it was generated by the Code Generation Wizard, we are unable to automatically make this change via the Upgrade Wizard.

  • A business view property name of “Type” was previously generated by the Code Generation Wizard as {EntityName}Type.cs. This creates an error in our Optional Fields JavaScript implementation. This has been resolved by generating the model property as “Type” but prefixing the property with the namespace to avoid ambiguous references with the System.Type.
  • Corrected issue where the Next step validated credentials for Code Types that do not use credentials

Images for Partner Menus

Sage 300 2018.1 introduced vertical menus for navigation. However, the hardcoded images for partner menus were based upon the position of the partner menu (12 hardcoded images for 12 partner menus). It was not ideal, but all the time we had in 2018.1!

Sage 300 2018.2 has removed the hardcoded images and replaced them with default images that maybe overridden by the partner who wishes to supply their own images.

The {module}MenuDetails.xml has been enhanced with two new elements that are supplied via the Sage 300 UI Wizard. The elements are: IconName and MenuBackGroundImage:

<IconName>ValuedPartner/menuIcon.png</IconName>   <MenuBackGoundImage>ValuedPartner/menuBackGroundImage.jpg</MenuBackGoundImage>

Where ValuedPartner is the name the partner supplied in the UI Wizard

  • The IconName element defaults to the “puzzle piece” image
  • The element value is added as $companynamespace$/menuIcon.png
  • The MenuBackGroundImage defaults to the “discussion” image
  • The element value is added as $companynamespace$/menuBackGroundImage.jpg

Blog124

The MergeISVProject utility is the post-build event utility that deploys your solution to the developer’s local installation of Sage 300 when your solution is in Release Mode. It copies these files (menuIcon.png and MenuBackGroundImage.jpg) from your web project’s Content\Images\Nav folder to the External\Content\Images\Nav\$companynamespace$ folder of your local Sage 300 installation.

Therefore, in your web project’s Content\Images\Nav folder is where your will place your partner images (named menuIcon.png and menuBackGroudImage.jpg) and overwrite the existing files.

Summary

The Sage 300 2018.2 SDK is released and ready to be downloaded!

Documentation updates, the ability to run the wizards in Visual Studio 2017, a new AR Invoice Entry Customization sample, minification of JavaScript files, enhanced deployment folders, and the ability to specify partner images for the vertical menus are all in the Web SDK.

We continue to look forward to addressing the needs and expectations of the Sage partner community and ecosystem.

As a standard disclaimer, any topic in this article is subject to review and doesn’t represent a commitment as to when it will be available.

 

Advertisements

24 thoughts on “Sage 300 2018.2 Web SDK

  1. None of the sources and samples include any test projects. I’m curious as to what do you guys use for testing?
    I see that your repo class takes a Context object; what are the minimum fields to init on this context object in order to get the business repos working in test projects?
    Thanks in advance.

    Like

    1. Currently Running Sage 300 Web API v1.0 | 6.4.0.20

      I’m currently working on a integration project where I will be will utilizing the Sage 300 Web API. This integration will be focusing on Order Entry where we can insert a new order (POST) and eventually we will need to be able to update an existing order (PUT / PATCH). With the current version of the Sage Web API the only supported verbs are GET and POST for OEOrders. Sage 300 2019 is development I was wondering if you could provide information on the improvements being made to the Sage 300 Web API. Are new verbs being introduced to any of the modules or more specifically are the verbs PUT and/or PATCH being introduced to the OEOrders module?

      Thanks!

      Liked by 1 person

  2. Hey Serge,

    We have a story to include some tests for our samples and another story to create a basic test that is created when we generate source (web screen) in the Web SDK, but these stories are still outstanding.

    We use the Moq framework for our unit tests. The minimum setting for the Context object using the Moq framework is ‘var context = new Context{Container = new SageUnityContainer()};’ So, if we are testing a repository class, we can use Moq and fake data to test. As in one of our AR tests:

    #region TestSetup

    private Context Context { get; set; }
    private IUnityContainer Container { get; set; }
    private Mock MockEntity { get; set; }
    private Mock MockSession { get; set; }
    private CustomerRepository TestSubject { get; set; }
    private Mock MockCustomerBalanceEntity { get; set; }
    private Mock MockAgeDocumentEntity { get; set; }
    private Mock<CustomerBalanceMapper> MockCustomerBalanceMapper { get; set; }
    private Mock<AgeDocumentMapper> MockAgeDocumentMapper { get; set; }

    private readonly Expression<Action> _setValueExpression =
    x => x.SetValue(It.IsAny(), It.IsAny(), It.IsAny());

    [TestInitialize]
    public void SetupTest()
    {
    Container = new SageUnityContainer();
    Context = new Context {Container = Container};

    MockEntity = new Mock();
    MockEntity.Setup(x => x.CanModify).Returns(true);

    MockSession = new Mock();
    MockSession.Setup(
    x =>
    x.OpenView(It.IsAny(), It.IsAny(), It.IsAny(),
    It.IsAny(), It.IsAny(), It.IsAny())).Returns(MockEntity.Object);
    MockSession.Setup(x => x.GetActiveApplications()).Returns(new List());

    MockCustomerBalanceEntity = new Mock();
    MockCustomerBalanceEntity.Setup(x => x.ClearRecord());
    MockCustomerBalanceEntity.Setup(_setValueExpression);
    MockCustomerBalanceEntity.Setup(x => x.Process());

    MockAgeDocumentEntity = new Mock();
    MockAgeDocumentEntity.Setup(x => x.Init());
    MockAgeDocumentEntity.Setup(_setValueExpression);
    MockAgeDocumentEntity.Setup(x => x.Process());

    MockCustomerBalanceMapper = new Mock<CustomerBalanceMapper>(Context);

    MockAgeDocumentMapper = new Mock<AgeDocumentMapper>(Context);
    MockAgeDocumentMapper.Setup(x => x.Map(It.IsAny())).Returns(GetFakeAgeDocument());
    TestSubject = new CustomerRepository(Context, MockSession.Object,
    MockCustomerBalanceEntity.Object, MockCustomerBalanceMapper.Object, MockAgeDocumentEntity.Object,
    MockAgeDocumentMapper.Object);
    }

    #endregion

    [TestMethod]
    public void CanGetCustomerBalanceWithNoCalc()
    {
    //Arrange
    MockCustomerBalanceMapper.Setup(x => x.Map(It.IsAny()))
    .Returns(GetCustomerBalanceBaseOnCustomerNumber(“CalcNoOverPay”));
    //Act
    var result = TestSubject.GetCustomerBalance(“NoCalc”);

    //Assert
    MockCustomerBalanceEntity.Verify(x => x.ClearRecord(), Times.Once);
    MockCustomerBalanceEntity.Verify(_setValueExpression, Times.AtLeastOnce);
    MockCustomerBalanceEntity.Verify(x => x.Process(), Times.Once);
    MockCustomerBalanceMapper.Verify(x => x.Map(It.IsAny()), Times.Once);
    Assert.AreEqual(null, result.CustomerCreditMessage);
    Assert.AreEqual(null, result.NationalCreditMessage);
    }

    #region Sample Test Data

    private static CustomerBalance GetCustomerBalanceBaseOnCustomerNumber(string customerNumber)
    {
    switch (customerNumber)
    {
    case “NoCalc”:
    return new CustomerBalance
    {
    CalcCustomerOverdue = CalcCustomerOverdue.No,
    CalcNatAcctOverdue = CalcNatAcctOverdue.No
    };
    case “CalcNoOverPay”:
    return new CustomerBalance
    {
    CalcCustomerOverdue = CalcCustomerOverdue.Yes,
    CalcNatAcctOverdue = CalcNatAcctOverdue.Yes,
    CustomerBalanceOverdue = 0,
    CustomerAmountOverdue = 1,
    NationalAccountNumber = “any”,
    NatAcctBalanceOverdue = 0,
    NatAcctAmountOverdue = 1
    };
    default:
    return new CustomerBalance();
    }
    }

    private static AgeDocument GetFakeAgeDocument()
    {
    return new AgeDocument
    {
    CurrentAmountDueSource = 10,
    TotalForwardAgingSource = 10,
    CurrentAmountDueFunctional = 10,
    TotalForwardAgingFunctional = 10
    };
    }
    #endregion

    I hope this helps,
    John

    Like

  3. Hey JT,

    It will generate xxx_WorkerRole_Data.sql in Web root when we generate code with process code type, we should execute the sqls in sage portal DB. However, if the clients use our software, how the sql script to be execuated in client’s sage portal DB?

    Like

  4. Hey Shoufeng,

    It has been a while since I talked last with you and I trust you are doing well.

    The Code Generation Wizard for a Process Code Type will generate the SQL script that needs to be applied to the Portal/Landlord database as you indicated. On a developer machine, these steps are spelled out in the README file of the ClearStatistics sample of the Web SDK. And, I believe you understand this.

    For a customer, when you deliver your module (web screen assemblies, menu details XML, bootstrapper xml, etc.), you will also need to deliver your SQL script(s) and place it in the customer’s …\runtime\Database\Landlord\Scripts folder. Then, when the customer selects the Portal button on the Database Setup Screen in the desktop (or you do it for them), our scripts will be applied to the Portal/Landlord database as will yours because they are located in the same folder as ours. This is discovery and now your process information is in our workflow engine tables.

    So, the instructions in the README file are relevant for a developer wanting to test the sample and are MOSTLY relevant for a customer. I say mostly because the instructions include a step to manually stop the windows service. This is needed for a developer since binaries are being copied to the local installation’s worker folder. But, for a customer, these assemblies will not exist when you copy your module’s assemblies and therefore the service does not need to be stopped. So, the steps in that README file that are relevant for you to install your scripts to a customer is: ### Copy script to the Sage 300 Scripts folder, and ### Start the Sage CNA Windows Service and apply the new script.

    Does this make sense?

    Thanks,
    John

    Like

    1. Hey JT,

      It works well, thanks very much.

      We have same problems that others may have encountered,
      1. The “%” in “Property Name” was not replaced.
      2. We will get “The fields have invalid settings” when there are duplicate property names, there are too many property names, the message does not help to find the duplicate property names out.
      3. All enumerations will be generated in a single file, some enumerations will be replaced by other enumerations, it will be solved in next version?

      Like

  5. Hey Shoufeng,

    Excellent! On the items 1-3 that you have listed here, for #1, please show me what the Accpac Field Description is and what the wizard attempted to make the property name as we do have a filter routine that is suppose to strip off “invalid” characters; for #2, that makes sense and I will look at making the message more meaningful; for #3, we have not yet implemented that feature where all enumerations are created in a single file as they are now created in an enumeration based upon the field type created, so please provide an example.

    Thanks,
    JT

    Like

    1. Hey JT,

      Item 1. The “%” in “Property Name” was not replaced.

      The Accpac Field Description is “Percentage Allocation(%)”, I will get the Property Name “PercentageAllocation%” when I generate code, the code type are Flat, Process, Inquiry, HeaderDetail.

      Item 3. All enumerations will be generated in a single file, some enumerations will be replaced by other enumerations, it will be solved in next version?

      For Example

      There is an enumeration “Status” exists both in view “AM0352” and “AM0354”, I can only get the enumeration “Status” for view “AM0354” when I generate code with code type HeaderDetail. Beacuse they have the same enumberation named “Status” the enumeration “Status” for view “AM0354” overwrite the enumeration “Status” for view “AM0352”

      Like

  6. Hey Shoufeng, I will look into that first item as that should not be happening. So, both 1 and 2 will be corrected/addressed in the upcoming release. I now understand what you are stating for item #3. In this past release, I’ve introduced another option to the code generation wizard options tab which will allow enumerations to be added to a single file and thus avoid this issue. But, this option has not been implemented as of yet. I believe we should be abale to also get this addressed for the upcoming release in August. I appreciate you bringing these items to my attention!

    Thanks,
    JT

    Like

  7. Hey Shoufeng,

    I just corrected item #1 for the next release. And, remember that if you need it sooner, you have the source in the Web SDk and can make the change for yourself if needed and register the updates VSIX file 🙂 The change I made was in the CodeGenerationWizard projects BusinessViewHelper class at line 309 where I inserted the following .Replace(@”%”, “”)

    I cannot believe we replaced lots of other token but not the percentage symbol!!

    My apologies!

    JT

    Like

  8. Hey Shoufeng,

    For the next release I just addressed item #2 and will not display a message if a duplicate property is found: “The field ‘{0}’ is duplicated and fields must be unique.”

    JT

    Like

  9. Hi JT,

    Regarding design and best practices, where would you recommend we place calls to multiple repositories.

    For example, if I need to output a result that is a mixture of data from BK banks and AR customers, would you recommend that I:

    1) Place both these calls in the service project.

    2) Place both these calls in our business repository.

    The advantage I see with 1 is that I can decouple my code by using Unity to Resolve the correct repository. The service will handle the calls to (different) repositories, allowing me to keep my business repository fairly lean.

    My only concern is at what point do external API calls hit my project; at the business repository level or service level?

    Your thoughts?

    Thanks in advance.

    Like

  10. Hey Serge,

    Sorry I was not able to respond yesterday.

    Well, this is certainly the 64K dollar question. The Sage 300 web screens follow the pattern established by Microsoft for an MVC project: Controller –> Service –> Repository. In our 95% of our implementations, the Service layer is just a pass-through layer to get to the repositories. So, we have code in our controllers and code in our repositories.

    When a client invokes an endpoint, it comes into the controller which uses Unity to instantiate the Service which uses Unity to instantiate the Repository. We do not have any implementations where we publicly go directory to the Service from the client.

    So, either the controller or the service would be both acceptable places to do your work.

    But, it would also be acceptable to do this in the repository and might even be more efficient there because you can create a model that leverages data from both modules and populate it in the repository (i.e. let’s say you have a model that needs data from AR, BK and your module, then in the Mapper (part of the repository) as you are mapping your module then you invoke via Unity for a BK/AR repository to get the data at that moment so that when your module is returned, it is fully populated.

    But, as you can see, it is very subjective and Microsoft gives multiple acceptable patterns.

    But, I do agree that from a cleanliness standpoint, staying out of the repository is attractive.

    JT

    Like

    1. Thanks for clarifying the controller->service->repo work flow.

      I’ll continue with placing those calls in my service layer.

      At the end of the day it comes down to consistency and code readability; either place all your logic in the service or business repo.

      Like

  11. Currently Running Sage 300 Web API v1.0 | 6.4.0.20

    I’m currently working on a integration project where I will be will utilizing the Sage 300 Web API. This integration will be focusing on Order Entry where we can insert a new order (POST) and eventually we will need to be able to update an existing order (PUT / PATCH). With the current version of the Sage Web API the only supported verbs are GET and POST for OEOrders. Sage 300 2019 is development I was wondering if you could provide information on the improvements being made to the Sage 300 Web API. Are new verbs being introduced to any of the modules or more specifically are the verbs PUT and/or PATCH being introduced to the OEOrders module?

    Thanks!

    Liked by 1 person

  12. Hey, Sage 300 2019 (August 2018) does not include any new endpoints for the Web Api. We do have a couple being planned for 2019.1 and I will check with the team to see if any activity is currently planned for OE Orders.

    Liked by 1 person

    1. Thanks for the quick reply! Do you know when 2019.1 will be released?

      I’ve tried to think outside of the box as to how to update orders to keep our two systems in sync. Are there any other creative ways I could update an order?

      Liked by 1 person

  13. Hey,

    2019 is scheduled for August 9th and 2019.1 will be in December (typically the first week of December).

    The Web API has not exposed all of our endpoints. However, you could explore using our .NET API to do this work yourself. While it is not a Web Api, the .NET API is still a powerful programming model. So, the .NET API would be able to open the BusinessView(s) in order for you to program against the views. Typically, folks will run RVSpy while the Order Entry screen is running or during activity where they want to capture/view the interaction with the Business Layer and the database. This will give you an idea of what the screen is doing so that it can be replicated via the API layer.

    So, this is an option while the Web API endpoints are still being added to reflect the full functionality of the .NET API layer.

    I hope this helps.

    Liked by 1 person

    1. Good stuff!

      I’m more comfortable/familiar with the REST API but it does look to have limitations. I’m playing with the IC Module and there doesn’t seem to be a way to insert or update IC Pricing or IC Locations. Do you know if either of these are going to be added in the near future?

      Liked by 1 person

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s