Jazz On Line Programming, Part 3.  Handling Sets of Records

Jazz On Line Programming, Part 3.  Handling Sets of Records. 1

Dealing with More than one Record - Introduction. 1

Parent-Child Record Structures. 1

A.     Create an update program with a modified screen for the parent record. 2

B.     Define related records. 6

C.     Add a scrolling section to the screen to display them.. 7

D.    Displaying Repeating Lines. 9

E     Add Logic to Format a Repeating Line. 10

F.    Processing Orders – General Concepts, and Creating New Orders. 12

G.    Processing Existing Orders – Using the Line Function. 14

H.  Final Thoughts: Writing CICS4 and Order Processing, Deleting Records. 17

 

Prerequisite reading: Introduction to Jazz, Jazz On Line Programming, Introduction, Jazz On Line Programming, Part2.  Updating Records

Dealing with More than one Record - Introduction

In the previous chapter the introductory principles of on-line programming were extended to include on line updating. In both cases we dealt with a single record, looking up a CustF record from a VSAM file.

 

In this chapter we’ll cover the techniques of handling sets of records, developing screens and programs to display and update a record hierarchy, using the example of a customer record and the customer’s current orders. First we’ll develop a program that will display the customer information at the top and a scrolling section of orders lower down the screen. This program will then be developed to allow us to edit the customer information, or to add or change orders.  This chapter is about classical (3270) CICS programming: if your interest is in web services handling record hierarchies then you should read leave this chapter and read this instead.

Parent-Child Record Structures

A very common requirement is to show a variable length table that the user can scroll up and down with Page Up and Page Down (or PF7/PF8).  For example, here we are going to display a screen like this: -

 

Like the previous example the first part of the screen can update or create a CustF record. Then comes a scrolling section, where up to 12 order lines can be displayed.  You can do something with one of the orders – show it in more detail, process it (this might mean “dispatch it and invoice the customer”), delete it (subject to various rules), and so on.

 

This section will show you how to write such programs. Currently the option to generate such programs hasn’t been implemented for classical CICS programs (although it has for web services), so we’ll design the screen and write the program manually.  The process that we’ll follow is: -

A.                 Create an update program with a modified screen for the parent record

B.                 Define related records

C.                 Add a scrolling section to the screen to display them

D.                 Write logic into the program to handle this scrolling section

E.                 Add logic to create new orders

F.                  Add logic to process existing orders

A.     Create an update program with a modified screen for the parent record

This is the same logic before so the easiest way to start is to create a single-record update program.  We select New/CICS program and fill in options for a program called (e.g.) CICS3, to update a single file (Custf).  Jazz creates a program exactly as before: except for the program name being CICS3 this will be just like program CICS2 of the previous chapter.

 

The standard layout used by programs CICS2 assumed that the whole screen was available for updating CustF and arranged the screen accordingly.  However for CICS3 we don’t want the CustF record arranged vertically on the screen as this wouldn’t leave enough room for the orders section. We could edit the screen field by field, but here’s an easier way: -

 

1.                  From the Jazz workbench click the [Screen] button.  We want to delete the fields Region to DateCommenced, and re-insert them in a different layout, so we start by selecting the area containing them.  Press Delete to clear this area: -

 

 

2.                  Now, to reinsert the missing fields with the arrangement we want, we start by selecting Custf.  Select the whole record, don’t expand the record layout.  Drag it to line 5.  

This causes the Multi-item Drop Options form to be displayed.  Select two-column layout: -

 

3.            Click [Select Items], and then check or uncheck fields in the Select Fields form so that the fields that we want are checked.  Leave out the fields Account and Name as they are already on the form’s search line.  Click [Finish] to return to the Multi-Item Drop Options form

 

4.            With 2 Cols layout selected, click [Close]. The selected fields are dropped on to the screen with 2-column layout, so now the screen looks like this: -



5.            Save the screen and return to the program. The program was previously generated with an ACCEPT statement for all fields that were previously on the screen.  If our new screen has omitted some of these fields then we’ll need to correct the ACCEPT statement in the Update/Add section to remove references to omitted fields. With this correction (if necessary) we now have a program that functions just like CICS2 of the previous chapter except for the different layout.

Our program so far, generated by Jazz and identical in function to CICS2, looks like this: -

*# Last Updated by robertb at 24/02/2016 3:14:46 p.m.

PROGRAM CICS3 CICS INSCREEN(CICS3S) TRANSID(TRN3) COMMAREA(CICS3C) EXIT(menu1);

ACCEPT (CICS3S.Function);

CASE (CICS3C.Function);

    WHEN (Enquiry);

        ACCEPT (CICS3S.Account OR CICS3S.Name);

            DEFINE TS1 TS DATA(

            Account LIKE CustF.Account);

        GET custf KEY(CustF.Account OR CustF.Name) SAVECOPY CICS3C.SAVE TS(1);

            #373 I GET statement returns one record at a time for Name

        END GET custf RESETFUNCTION;

    WHEN (Update);

        GET custf WHERE(CustF.Account=CICS3C.Save.Account) REWRITE CHECKCOPY(CICS3C.SAVE);

            ACCEPT (CICS3S.Region,CICS3S.District, CICS3S.Name, CICS3S.SalesThisMonth, CICS3S.SalesYTD, CICS3S.Billingcycle, CICS3S.DateCommenced);

        END GET custf REWRITE RESETFUNCTION;

    WHEN (Add);

        CustF.Account = custf.$LastKey + 1; [Will need to be changed if key is not a number

        #361 E Assignment to a key field

        GET custf KEY(CustF.Account) CREATE;

            ACCEPT (CICS3S.Region,CICS3S.District, CICS3S.Name, CICS3S.SalesThisMonth, CICS3S.SalesYTD, CICS3S.Billingcycle, CICS3S.DateCommenced) SETMDT;

        END GET custf CREATE RESETFUNCTION;

    WHEN (Delete);

        DELETE custf WHERE(CustF.Account=CICS3C.Save.Account) CHECKCOPY(CICS3C.SAVE) RESETFUNCTION;

END CASE;

SEND Inscreen;

B.     Define related records

For this example the Orders record is defined like this:-

*# Last Updated by IBMUSER at 7/10/2014 5:30:19 p.m.

COPY Custf;

COPY Parts;

DEFINE Orders VSAM DATA(

    OrdNbr INTEGER KEY HEADING 'Order Number',

    OrdCust LIKE custf.account DKEY 'ibmuser.vsam.Orders1',

    ordDate CHAR(12), 

    OrdPart LIKE parts.partnbr EXISTS Parts.Partnbr,

    OrdQty SMALLINT,

    OrdDiscount DECIMAL (6,4) HEADING 'Order Discount',

    OrdField(2) SMALLINT,

    OrdStatus CHAR(10))

    DSNAME 'ibmuser.vsam.Orders';

Note the following: -

1                    Like any VSAM record there must be a primary key.  For the Orders record this is

        OrdNbr INTEGER KEY HEADING 'Order Number',

2                    OrdCustid is the linking field that relates an order record to a customer record. 

a.      By defining this LIKE custf.account we have ensured that it has the same format as the field in Custf.  This means that there must be a preceding definition of CustF in our program: once again we’ve used the trick of including COPY here, knowing that if the program already has this definition the duplication is harmlessly ignored.

b.      DKEY OrdCust defines it as an alternate index and gives the index path name.  The linking field must be a key of some kind to be valid for use in a PROCESS statement in a CICS program. 

3                    OrdPart is defined with EXISTS Parts.Partnbr. This means that it is a “Foreign Key”, i.e. the key of another record.  Here there is a record called “Parts” with primary key Parts.Partnbr.  Because these fields must have the same format you should, as here, define the subordinate field with LIKE.  That not only ensures that its definition is the same, but will change the definition if the parent field definition is changed.  Because of this definition, we need to ensure that the definition for PARTS is included in the program and once again we’ve put COPY into the record definition. 

4                    For a real situation there would be a lot more information in the Parts record like the quantity on hand, lead time for more deliveries, …  anything that relates to the part itself.  For this example we’ve defined only StandardPrice and PartName: -

*# Last Updated by IBMUSER at 8/01/2015 5:31:30 p.m.

DEFINE Parts VSAM DATA(

    Partnbr INTEGER KEY,

    PartName CHAR(30),

    StandardPrice DECIMAL(7,2))

    DSNAME 'ibmuser.vsam.Parts';

 

You can see that we’ve defined a database schema like this: -

This means that we create separate orders for each part that a customer orders: not terribly realistic, more likely our system will have an ORDER-LINE record to allow one order to have many lines, each line linking to a different part.  However this schema without order lines is sufficient for our purpose which is to demonstrate how to manage scrolling sections.

C.     Add a scrolling section to the screen to display them

We add COPY Orders; to our program, and then click [Screen] again to create the repeating line.

 

1.      Drag Orders to line 9. This causes the “Multi Drop Options form to be displayed.  We select “Scrolling” layout from the Arrange Items alternatives: -

           

Note that if we simply click [Close] now we’ll be attempting to create a line of 117 characters, more than the 80 characters maximum width. This will not be permitted unless we check Allow Line Overflow. More likely, we’ll want to reduce the line size by selecting which fields we want, and by shortening over-long headings.

 

2.      Click [Select fields] to choose the fields that we want to have displayed across the line.  We don’t need to display OrdCustId as this will be the linking field, and would have the same value as Custf.Account” in every line. There may be other fields that we don’t want to see, such as OrdField1 and OrdField2.  Uncheck the fields that we don’t want

 

3.      This would have reduced the line size to 75, but we add 2 more characters by checking “Function Code at Left”.  We also specify how many free lines we want at the end of the repeating section.  We can remove more characters by shortening the headings that take up more room than their fields, such as “Order Discount”, but since we’re already down to 77 characters we mightn’t bother.  It only remains to enter the condition that joins the orders record to the data already read, and we’re ready to click [Close]



4.      When we click [Close] Jazz adds the repeating section to the screen.

 

5.      We save the screen, and return to program CICS3

D.    Displaying Repeating Lines

We have now created the screen layout that we want, but there is no logic in our program to put data into the repeating lines.  We need to modify the Enquiry case to support this.  Jazz has initially given us: -

    WHEN (Enquiry);

        ACCEPT (CICS3S.Account OR CICS3S.Name);

        DEFINE TS1 TS DATA(

            Account LIKE CustF.Account);

        GET custf KEY(CustF.Account OR CustF.Name) SAVECOPY CICS3C.SAVE TS(1);

            #373 I GET statement returns one record at a time for Name

        END GET custf RESETFUNCTION;

 

Whenever a GET statement in a Classical CICS program could return several records Jazz

1.                  Creates logic that will return the first record, but page through next/previous records with PF10/11

2.                  Add a definition for a TS (Temporary Storage) file that will hold the record keys of these records

3.                  Add a TS option to the GET statement

4.                  Insert END GET following GET.

All this is omitted when the GET can only ever read one record, as with

GET custf KEY(CustF.Account) …

 

So this automatically handles the possibility that there might be one or zero Custf records, or some indefinite number.   Next: we want to get the related Orders records for the current Custf record.   We write this logic within the GET group: -

        GET custf KEY(CustF.Account OR CustF.Name) SAVECOPY CICS3C.SAVE TS(1);

            #373 I GET statement returns one record at a time for Name

*                Logic to get related Orders records to be written here

        END GET custf RESETFUNCTION;

 

We use PROCESS to read a set of records, writing PROCESS and END PROCESS.  We write: -

            PROCESS Orders WHERE (Orders.ordcustid = Custf.Account) INDEX;

Jazz parses this and adds a TS option: -

        GET custf KEY(CustF.Account OR CustF.Name) SAVECOPY CICS3C.SAVE TS(1);

            #373 I GET statement returns one record at a time for Name

                DEFINE TS2 TS DATA(

                OrdNbr LIKE Orders.OrdNbr);

            PROCESS Orders WHERE (orders.ordcustid = custf.account) INDEX TS(2);

            END PROCESS orders;

        END GET custf RESETFUNCTION;

 

Firstly, notice that, as it did for GET, Jazz has added TS(2) to the PROCESS statement and created a definition for the temporary storage file TS2. Our screen can display up to 13 lines of orders, but a customer may have many more. Or none at all. So we need to use logic that can handle these extremes and everything in between. The concept is simple: when we read a CustF record we’ll also read all the corresponding Orders records, storing their record keys in “Temporary Storage”. Then, when the screen is displayed the program will read the keys of up to 13 records from temporary storage and read the corresponding ORDERS records. Jazz creates PF7/8 (up/down) paging logic automatically.

 

Secondly, by writing the PROCESS between GET custf and END GET custf they are included in the ‘GET Block”, telling Jazz that these statements are related.  If we use PF11(Next) or PF10(Previous) paging then as we move forwards or backwards through Custf the Orders list is refreshed, so we’ll always have the orders corresponding to the current Custf record.

 

Just as we’ve written logic into the GET block, we can write logic between PROCESS/END PROCESS.  For example, if we’d wanted to include Parts.PartName in the display line we’d have written: -

            PROCESS Orders WHERE orders.ordcustid = custf.account INDEX TS(2);

                GET PARTS WHERE(Parts.Partnbr = Orders.OrdPart);

            END PROCESS orders;

(Actually I’d have written GET PARTS WHERE (Parts.? = Orders.?) and clicked [Check] to invoke selection dialogs to choose the field names that I wanted)

E    Prevent Invalid Deleting

One more change before we leave “Handling Custf”.  We need enhance Delete logic to check that there are no related orders.  We don’t want to delete Custf records for which there are Orders records, as this would leave orphaned orders. We add NOCHILDREN(Orders) to the DELETE statement

      DELETE custf WHERE(CustF.Account=CICS3C.Save.Account) CHECKCOPY(CICS3C.SAVE)

            NOCHILDREN(Orders) RESETFUNCTION;

 

Now if there any Orders the DELETE will be refused and a message returned.  With CHECKCOPY, which is the same as in in program CICS2, the DELETE will also be refused with a message if the record has changed since the Enquiry.

 

Here is the complete program so far.  At this stage it will read a customer and their related orders, and if there are more than 13 orders you can use PF7 and PF8 to go up and down through the list of orders.  We can also update the customer record.  However we haven’t yet provided any way of doing anything except looking at the orders.  We can’t process an order, or create new ones.  That will come next.

*# Last Updated by IBMUSER at 20/04/2016 10:21:05 a.m.

PROGRAM CICS3 CICS INSCREEN(CICS3S) TRANSID(TRN3) COMMAREA(CICS3C) EXIT(menu1);

COPY Orders;

ACCEPT (CICS3S.Function);

CASE (CICS3C.Function);

    WHEN (Enquiry);

        ACCEPT (CICS3S.Account OR CICS3S.Name);

        DEFINE TS1 TS DATA(

            Account LIKE CustF.Account);

        GET custf KEY(CustF.Account OR CustF.Name) SAVECOPY CICS3C.SAVE TS(1);

            #373 I GET statement returns one record at a time for Name

            DEFINE TS2 TS DATA(

                OrdNbr LIKE Orders.OrdNbr);

            PROCESS Orders WHERE (orders.ordcustid = custf.account) TS(2) INDEX;

                #082 W Default name 'JZ-INDEX' used for INDEX option

            END PROCESS orders;

        END GET custf RESETFUNCTION;

    WHEN (Update);

        GET custf WHERE(CustF.Account=CICS3C.Save.Account) REWRITE CHECKCOPY(CICS3C.SAVE);

            ACCEPT (CICS3S.Region,CICS3S.District, CICS3S.Name, CICS3S.SalesThisMonth, CICS3S.SalesYTD, CICS3S.Billingcycle, CICS3S.DateCommenced);

        END GET custf REWRITE RESETFUNCTION;

    WHEN (Add);

        CustF.Account = custf.$LastKey + 1; [Will need to be changed if key is not a number

        #361 E Assignment to a key field

        GET custf KEY(CustF.Account) CREATE;

            ACCEPT (CICS3S.Region,CICS3S.District, CICS3S.Name, CICS3S.SalesThisMonth, CICS3S.SalesYTD, CICS3S.Billingcycle, CICS3S.DateCommenced) SETMDT;

        END GET custf CREATE RESETFUNCTION;

    WHEN (Delete);

        DELETE custf WHERE(CustF.Account=CICS3C.Save.Account) CHECKCOPY(CICS3C.SAVE)

            NOCHILDREN(Orders) RESETFUNCTION;

END CASE;

SEND Inscreen;

 Testing our program so far

Although there is further logic to be added to this program, we’ll compile and test it before completing it.  An Orders test file is defined with IDCAMS, test data created, and relevant entries are defined into our CICS group with these CEDA commands: -

·         DEF PROGRAM(CICS3) GROUP(MANAJAZZ)

·         DEF MAPSET(CICS3S) GROUP(MANAJAZZ)  

·         DEF TRANS(TRN3) PROGRAM(CICS3) GROUP(MANAJAZZ)

·         DEF FILE(ORDERS) GROUP(MANAJAZZ) DSNAME(IBMUSER.VSAM.ORDERS)

·         DEF FILE(ORDERS1) GROUP(MANAJAZZ) DSNAME(IBMUSER.VSAM.ORDERS1)

·         DEF FILE(ORDERS2) GROUP(MANAJAZZ) DSNAME(IBMUSER.VSAM.ORDERS2)

·         ALT file(ORDERS) GROUP(MANAJAZZ) ADD(YES)

·         ALT file(ORDERS) GROUP(MANAJAZZ) BROWSE(YES)

·         ALT file(ORDERS) GROUP(MANAJAZZ) UPDATE(YES)

·         Similarly, give ADD, BROWSE, and UPDATE rights to ORDERS1 and ORDERS2,

·         Follow this up with INSTALL GROUP(MANAJAZZ)

Because ORDERS was defined with two alternate indexes the relevant paths should be defined.  At this stage we’re not using the 2nd path, which provides access to ORDERS by ORDPartNbr, so we could have omitted DEF FILE(ORDERS2).  However since the AIX exists we may as well define it now.  And while ORDERS doesn’t  need ADD and UPDATE rights yet, it will later. 

 

Here is a display from the program so far.  I asked for Name “APTHORPE”: there are several such records in my test data.  I clicked PF11 to take me to the second of these, which has 32 orders, and I clicked PF8 to show lines 13 to 24 of these records: -

 

Now it only remains to add logic to create new orders and process the existing ones to complete this program

E.    Processing Orders – General Concepts, and Processing Orders

The business rules around creating and processing an order make the process more complicated than simply creating an order record in a VSAM file.  Does the customer have an adequate credit status?  Can you supply stock?  When? Having created the order it will go through a life cycle, often something like “Initial => Order Accepted => Despatched => Invoiced => Payment received and so instead of simply CHAR(10) you’ll probably define Orders.OrdStatus as a coded field.  There will be various situations like part supply or part payment, the customer may pay for several orders on one invoice, several invoices on one statement, and so on.  We’ll want to build these rules into our programs so that we don’t accept an order from a customer who doesn’t exist, or has been denied credit, and we can’t despatch an order that hasn’t been accepted.  So rather than write a fully detailed program that inevitably would not reflect your particular situation, this tutorial will show you the general principles of a solution leaving it to you to apply your particular rules.

 

When screen CICS3S was defined we placed a function code at the left of every detail line.  Here’s what we want to do: if we’re in enquiry mode and there is an “S” against an order we want to invoke a program (CICS4) to process that order: -

 

The first issue: how do we detect that the line command for the 3rd line has value “S”, and relate this to the 27th order for this customer which has OrdNbr = 31? It’s easy and automatic if we write our code within the PROCESS Orders logic.  This is currently: -

            PROCESS Orders WHERE (orders.ordcustid = custf.account) TS(2) INDEX;

                #082 W Default name 'JZ-INDEX' used for INDEX option

            END PROCESS orders;

 

Within the PROCESS block write an IF statement like this. 

                IF CICS3S.Line-Function(JZ.JZ-index) = 'S' THEN;

            * Do something

                END IF;

Hint: start by writing IF CICS3S.?  Jazz responds to ? with a list of the data defined in your program, and you can select the line function. Then add “(JZ-INDEX)” which Jazz will qualify to “JZ-JZ-Index).  If you’re like me, you’ll have difficulty remembering the correct names or typing them exactly.  Fortunately you don’t have to.

 

At * Do something we want to invoke a program called “CICS4”, so we’ll start by writing this program as we did CICS2 in the previous chapter: -

Except for program and file names, this is exactly like program CICS2 shown in the previous chapter. This won’t be what we want but it’s a start, and we’ll now have a basic program and screen that we can invoke from CICS3 or run independently.  The logic of CICS4 will evolve as we learn more about the problem, and how Jazz can help.  As we develop CICS4 we may come back to CICS3 several times, adding function and data. 

 

We now have a program CICS4 that uses a screen CICS4S and a COMMAREA CICS4C that is invoked with Trancode Trn4.  We define these to CICS, so that we could execute program CICS4 by entering transaction Trn4.  Here are the CEDA commands that I used (yours may be different): -

·         DEF PROGRAM(CICS4) GROUP(MANAJAZZ)

·         DEF MAPSET(CICS4S) GROUP(MANAJAZZ)

·         DEF TRANS(TRN4) PROGRAM(CICS4) GROUP(MANAJAZZ)

 

Coming back to program CICS3, we add

COPY CICS4S;

COPY CICS4C;

and within the IF block we write a couple of statements to set up the Commarea, and a SEND statement to invoke the program: -

                IF CICS3S.Line-Function(JZ.JZ-index) = 'S' THEN;

                    CICS4C.function = update;

                    CICS4C.save = Orders;

                    SEND CICS4S (CICS4S.*) TRANSID(TRN4) COMMAREA(CICS4C); 

                END IF;

 

Process this and it’s ready to test: enter “S” as shown above and CICS4 is invoked: -

 

Our initial test shows that this works well, picking up the correct order even when we have used PF7/8 to page up and down, or PF10/11 to go forward or backward through the customer file.  However we find a problem: the order number and the account number are unprotected, and if users change them our database would be seriously compromised.  We need to protect these fields.  If we edit screen CICS4S so that they are always protected then program CICS4 can’t be used for enquiries, so instead we protect them by amending our SEND statement: -

                   SEND CICS4S (CICS4S.*, CICS4S.OrdNbr PROT, CICS4S.OrdCustid PROT) TRANSID(TRN4) COMMAREA(CICS4C); 

F.    Creating new Orders

To create a new order we need to provide another case.  We add another function to CICS3’s Commarea: -

*# Created by IBMUSER at 8/01/2015 3:48:04 p.m.

COPY Custf;

DEFINE CICS3C COMMAREA DATA(

    Function CHAR(1) CODES (E:Enquiry,U:Update,A:Add,D:Delete,R:Order) VALUE Enquiry,

    SAVE LIKE Custf.*,

    JZ-XCTL LIKE Jazz.Flag);

I have added “R” for “Order” because I have an aversion to using “O” which is easily confused with “0”.

 

We should add “R” to the text in the screen: -

 

[Process] the screen so that it is saved and the physical map created, and return to our program logic.

 

We add another CASE to the logic of CICS3 to handle this: -

    WHEN (Order);

      

Logic for this case is very similar to that for handling an existing order.  We initialize an orders record then invoke program CICS4 as we did before, but with function code Add: -

   WHEN (Order);

        INITIALISE(Orders);

        Orders.ordcustid = custf.account;

        Cics4c.save = Orders;

        Cics4c.function = add;

        SEND CICS4S (CICS4S.*, CICS4S.OrdNbr PROT, CICS4S.OrdCustid PROT) TRANSID(TRN4) COMMAREA(CICS4C); 

 

Of course the actual logic of program CICS4 hasn’t been properly developed yet, there is only the automatically-created logic which won’t be correct for this situation, but we’ve finished with CICS3.  Here is the complete program: -

*# Last Updated by IBMUSER at 24/04/2016 3:01:18 p.m.

PROGRAM CICS3 CICS INSCREEN(CICS3S) TRANSID(TRN3) COMMAREA(CICS3C) EXIT(menu1);

COPY Orders;

COPY CICS4S;

COPY CICS4C;

#036 W More than one TYPE(COMMAREA) definition. CICS4C treated as Working Data

ACCEPT (CICS3S.Function);

CASE (CICS3C.Function);

    WHEN (Enquiry);

        ACCEPT (CICS3S.Account OR CICS3S.Name);

        DEFINE TS1 TS DATA(

            Account LIKE CustF.Account);

        GET custf KEY(CustF.Account OR CustF.Name) SAVECOPY CICS3C.SAVE TS(1);

            #373 I GET statement returns one record at a time for Name

            DEFINE TS2 TS DATA(

                OrdNbr LIKE Orders.OrdNbr);

            PROCESS Orders WHERE orders.ordcustid = custf.account TS(2) INDEX;

                #082 W Default name 'JZ-INDEX' used for INDEX option

                IF CICS3S.Line-Function(JZ.JZ-index) = 'S' THEN;

                    CICS4C.Function = Update;

                    CICS4C.Save = Orders;

                    SEND CICS4S (CICS4S.*, CICS4S.OrdNbr PROT, CICS4S.OrdCustid PROT) TRANSID(TRN4) COMMAREA(CICS4C); 

                END IF;

            END PROCESS orders;

        END GET custf RESETFUNCTION;

    WHEN (Update);

        GET custf WHERE(CustF.Account=CICS3C.Save.Account) REWRITE CHECKCOPY(CICS3C.SAVE);

            ACCEPT (CICS3S.Region,CICS3S.District,CICS3S.Name,  

                 CICS3S.SalesThisMonth,CICS3S.SalesYTD,CICS3S.Billingcycle,CICS3S.DateCommenced);

        END GET custf REWRITE RESETFUNCTION;

    WHEN (Add);

        CustF.Account = custf.$LastKey + 1; [Will need to be changed if key is not a number

        #361 E Assignment to a key field

        GET custf KEY(CustF.Account) CREATE;

            ACCEPT (CICS3S.Region,CICS3S.District,CICS3S.Name,CICS3S.SalesThisMonth,

                CICS3S.SalesYTD,CICS3S.Billingcycle,CICS3S.DateCommenced) SETMDT;

        END GET custf CREATE RESETFUNCTION;

    WHEN (Delete);

        DELETE custf WHERE(CustF.Account=CICS3C.Save.Account) CHECKCOPY(CICS3C.SAVE)

            NOCHILDREN(Orders) RESETFUNCTION;

    WHEN (Order);

        INITIALISE(Orders);

        Orders.ordcustid = custf.account;

        Cics4c.save = Orders;

        Cics4c.function = add;

        SEND CICS4S (CICS4S.*, CICS4S.OrdNbr PROT, CICS4S.OrdCustid PROT) TRANSID(TRN4) COMMAREA(CICS4C); 

END CASE;

SEND Inscreen;

 

These 44 lines of Jazz (some of which were inserted automatically by the Jazz workbench) result in this COBOL program of 2713 lines of COBOL.

G.  Final Thoughts: Writing CICS4 and Order Processing, Deleting Records.

We’re now at the stage where we’ve finished program CICS3, which will invoke program CICS4 both to create a new order and to process an existing one.  This tutorial won’t continue with the detail of CICS4: you now have enough tools to write it yourself, and its details will depend on your business rules such as the rules that allow it to progress from Initial to “Approved” to “Actioned” to “Invoiced” to “Completed”? Can you delete an Order once it progresses from its initial state?  Can you delete a Custf record?  Programs CICS2 and CICS3 allow users to simply delete records without any checks, not even an “Are you sure” message.  This might be OK for demonstration programs, but unlikely to be satisfactory solutions in the real world.   Still, you should now have enough tools to write whatever logic you need to within the classical CICS world of 3270 screens.

 

In the next chapter we’ll start considering how you write and implement programs that provide or use web services.