Composing Views in the Sage 300 ERP .Net API

5 minute read time.

Introduction

In the past couple of weeks we’ve had a look at opening sessions with the Sage 300 ERP .Net API and then opening a View and doing some simple View operations. This week we are going to start looking at the more complicated case of document entry which involves “header/detail” type Views as well as composing multiple Views together. I talked a bit about these concepts in this article on entering O/E Orders via the COM API.

Composing Views

Composing Views is a topic that usually confuses people that are new to using the Sage 300 API. It is a basic mechanism to allow multiple Views to work together with each other as well as to work with the person calling the Views via the API. Roughly for data Views, each View corresponds to a database table. But when we are doing document entry like A/R Invoices or O/E Orders, multiple Views must be used together to build up the document. Further we want to write the document in a single database transaction (we wouldn’t want some tables updated and others not). We also want to ensure that the various Views are used in such a way to avoid multi-user problems like deadlocks.

View composition is the basic mechanism that enables this functionality. It is really a way of sharing View objects, so that everyone is using the same copy rather than opening their own copies. So who is everyone? There is only me the programmer. Well not only do you call Views via the API, but Views call each other all the time. We will look at why they do this in the next section.

Our convention is that the person using the API is responsible for opening all the Views that will be shared. This is just via regular OpenView method calls from a DBLink object. Then we give a reference to all these Views to everyone else via the View’s compose method.

Let’s look at an example for opening and composing the Views required to enter A/R Invoices:

// Open the A/R Invoice Entry Views

arInvoiceBatch = mDBLinkCmpRW.OpenView("AR0031");

arInvoiceHeader = mDBLinkCmpRW.OpenView("AR0032");

arInvoiceDetail = mDBLinkCmpRW.OpenView("AR0033");

arInvoicePaymentSchedules = mDBLinkCmpRW.OpenView("AR0034");

arInvoiceHeaderOptFields = mDBLinkCmpRW.OpenView("AR0402");

arInvoiceDetailOptFields = mDBLinkCmpRW.OpenView("AR0401");

 

// Compose the Batch, Header and Detail views together.

arInvoiceBatch.Compose(new ACCPAC.Advantage.View[] { arInvoiceHeader });

arInvoiceHeader.Compose(new ACCPAC.Advantage.View[] { arInvoiceBatch, arInvoiceDetail,
    arInvoicePaymentSchedules, arInvoiceHeaderOptFields });

arInvoiceDetail.Compose(new ACCPAC.Advantage.View[] { arInvoiceHeader,
     arInvoiceBatch, arInvoiceDetailOptFields });

arInvoicePaymentSchedules.Compose(new ACCPAC.Advantage.View[] {
     arInvoiceHeader });

arInvoiceHeaderOptFields.Compose(new ACCPAC.Advantage.View[] { arInvoiceHeader });

arInvoiceDetailOptFields.Compose(new ACCPAC.Advantage.View[] { arInvoiceDetail });

To work with A/R Invoices requires using six Views which we open first. Now we as the caller of the API have a View object for each of these. So we can go ahead and make method calls to all these Views. However, these Views need to know about each other so they can work together. There may be fields in the header that the details need to update as they are updated, deleted or inserted, like totals for each invoice. When we save the invoice, it must be able to start a database transaction and save all the other Views as well as itself to work correctly. So basically the compose calls are giving the Views the ability to use the other Views they need that we opened. For instance the first Compose call is the batch.Compose which gives the A/R Invoice Batch View access to the A/R Invoice Header View that we opened. Now the batch View can call the same instance of the header View that we opened and if we look at the fields in the header View we will see the values set by the batch View before things are saved to the disk.

But the code above does seem rather magic. How did I know which Views to open and how did I know which Views to compose? It is very important that you compose the correct Views and the order the Views appear in the array passed into the Compose call is very important. The way I create these, is to run macro recording on the regular UI that uses the document I am programming. Then I get all the correct open and compose calls in VBA syntax which is quite easy to translate into C# and then I have something I know will work. Sometimes you can leave out composite views that aren’t used in a situation, but I find that leads to more problems than its worth, so I generally just include them all. Similarly the ViewDoc and the Application Object Model list all the Views a View will compose with, but I find translating this information into code more tedious.

Header/Detail

Within the Sage 300 system, most accounting documents use a header/detail structure. This means that we have a single header record for the document (like an Invoice) and then multiple detail lines, one for each of the line item detail lines. This gets more complicated since details can have sub-details and so on, but the basic concept is the same. We often are using View composition to get header and detail Views to work together to correctly insert, delete and edit accounting documents.

As an example of header/detail we have the Order Header and then its detail lines. The Order header has information that there is one of for the order. The details then contain data that there are many of. The Order Header contains information like the customer id and the ship-to address. Then each detail line contains an I/C Item number and quantity. So for an order you can order as many items as you like.

The Order Header also stores information like various totals. So as each detail line is added, updated or deleted these header totals have to be updated to keep them correct. Details are always associated with their header by having their primary key start with the header’s primary key, then just adding an uniquifier or counter. This is show in the diagram below:

Sample Program

The sample code for this article is the ARInvEntryWinForms sample on the GDrive here. This sample opens and composes the A/R Invoice Views, then it goes a bit further to create a batch with a single entry for the customer number you enter on the form and then inserts one detail line with a fixed item number (the quantity is defaulted to 1 by the detail View). There is a bit of error handling. In future articles we will talk in detail about the protocol for entering header/detail documents, we will also talk a lot about exception handling and debugging in a future article. But just describing the View composing and header/detail concepts has already lead to a full article. But I did want to include a bit more code than just opening and composing the Views, so it would really do something. You need to go into A/R Invoice Entry to see the invoices created.

Summary

This article covered the basic concepts of View composition and of header/detail relationships. We will start to use these frequently in future articles. These are an important building block to much more sophisticated programs.