Implementation of Blue Prairie Forms is most easily performed by using an existing print program that does not currently support Blue Prairie Forms. We generally copy a legacy print program to a new name and then modify it to make it Blue Prairie Forms aware. We usually name the copied program BPI.<originalProgramName>. This makes it clear that the program is a special version of the original program that has been modified for Blue Prairie Forms
Basic Modification Steps
- Copy a legacy program to a new name
- Modify the legacy program as follows
- Insert the Blue Prairie Forms internal subroutines at the bottom of the program
- Comment-out all PRINTER ON, PRINTER OFF, PRINTER CLOSE statements
- Comment-out all PRINT statements and add equivalent calls to the Blue Prairie Forms bpi.set.tagval2 subroutine
- Call the MakeDocument routine
- Your done
Comment, don’t remove
The process of modifying a legacy print program for Blue Prairie Forms can take from 1-4 hours depending on the complexity of the print job, It is good practice to NOT remove any original code at first but instead to comment it out using a unique comment tag. Likewise, any added instructions should be commented at the end of the line with a readily identifiable tag.
Example:
*|||bpiforms|||PRINTER ON
*|||bpiforms|||PRINT “INVOICE: “: INVNO
CALL bpi.set.tagval2(blocks, tags, vals, \\, \%invNo%\, INVNO \\, vector, verbose);*|||bpiforms|||
*|||bpiforms|||PRINTER CLOSE
*|||bpiforms|||PRINTER OFF
As you can see, we have commented out the original code with the preceding comment text *|||bpiforms|||. We also used that comment tag on the line we added (at the end).
By commenting code this way, it is easy to follow and you can always refer back to what the original code was doing if you get lost or miss something during the integration. After the program is successfully working with Blue Prairie Forms, you can remove the commented lines to streamline the program.
We also recommend that you place the call to bpi.set.tagval2 after each PRINT directive you have commented. By keeping the new call together with its predecessor comment line, it’s easier to read the code, Remember that legacy print programs may print several variables with one print directive. In these cases, you may end up with multiple calls to bpi.set.tagval2 for a commented legacy PRINT directive. For purposes of documentation and style, we recommend adding a comment to the end of the instruction of ;*|||BPIFORMS|||.
Ultimate/AutoShims Transfer Ticket Printing
The Ultimate transfer processing program is XP.2.1 on most ultimate systems. The program that actually prints the transfer ticket is called from XP.2.1. A user may have a customized transfer ticket print program (or programs). These are defined in the CONTROL file in a item called COMPANY. Attributes 11 and 12 define names of the transfer print programs.
>ED CONTROL COMPANY
0001: ONLINEINV.WHSE:EAW5
0002: PRINT-INVOICE:AWI
0003: OLDINV.WHSE.AWI2
0004: OLDINV.STORE.API.EAW.ROUTE
0005: ONLINEORD.WHSE.AWI2
0006: PRINT-INVOICE:TRIAD2
0007: ROA.STORE.TRIAD
0008: ROA.STORE.TRIAD
0009: STATEMENTS:TRIAD:EAW
0010: AP-PRINT-CHECKS:LAAP2
0011: ONLINEXFER.WHSE.AWI.EAS ←- for the warehouse
0012: ONLINEXFER.STORE.EAW ←- for the store
0013: ONLINEINV.STORE.API
0014: ONLINEORD.STORE.API2
Bottom at line 14.
Attribute 11 is the name of the transfer print program for the warehouse and attribute 12 is the transfer print program for the store
CONTROL WHSE-TRANSFER-PRINTQ
This is a standard part of most Ultimate systems and has been around for years. This record defines the print queue names to be used when printing a ticket. There is one transfer printer per location. Attribute 1 of this record is multivalued and the queue is the ordinal position of the location number. So, if you are printing for location 4, then look in multivalue 4 and that is the queue number for the printer where the transfer ticket is to be printed.
CONTROL WHSE-TRANSFER-PRINTQ-BPI_FORMS
This is a new control record that I use to define whether a specific location is to use Blue Prairie Forms or the legacy print routine. It’s possible for some customers that they’ll install Blue Prairie Forms at one locations but not at another. This could be because they are rolling out laser printers one location at a time over a period of months. So, the integration needs to be smart enough to be able to enable Blue Prairie Forms at one location but not another.
This record contains only one attribute that is multivalued. Each multivalue position is a location where location 1 is the first multivalue and location 999 is the 999th multivalue position. You may place any value that evaluated to boolean @TRUE in the multivalue position for a location and this will enable Blue Prairie Forms for that location for transfer printing. Leaving a location’s multivalue position undefined (or boolean @FALSE) will cause the legacy print routine to be called.
Routing
I like to use routing to control whether my routine is to be called or the legacy application’s routines. A router is basically a subroutine that determines which routine should be called next. When I perform a tight integration of Blue Prairie Forms into a legacy application, I do this by replacing the first level call with a router. For example, in the above listing of CONTROL COMPANY, I’d replace attribute 12 with ONLINEXFER.STORE.EAW.ROUTE. This new program will perform some checks (such as checking the values in the above control records) and then either call my new BPI_FORMS enabled version of the print program or call the old legacy (character) print program. Here is an example of my router for ONLINEXFER.STORE.EAW.ROUTE
Example Router: ONLINEXFER.STORE.EAW.ROUTE
SUBROUTINE ONLINEXFER.STORE.EAW.ROUTE(arg1, arg2, arg3, arg4, arg5)
* Written by Bruce Decker, Blue Prairie, Inc.
* 1/12/2013 for Effingham Auto Warehouse.
* Source license to this work granted to Effingham Auto Warehouse
*
* This subroutine is simply a router meaning that it's sole roles is to determine
* which invoice print program should be called.
* At the time written, this router is to simply determine if the bpi_form version
* or the legacy character / preprinted / dot matrix form of the invoice is to
* be called.
*
* For testing, simply ensure that in the test user's environment, tht you define
* the environment variable BPI_FORMS_INVOICE to the name of the BPI_FORM enabled
* subroutine that you wish to have the router call. If the environment variable
* is defined, then it will be called, otherwise, the legacy routine will be called.
* Example: BPI_FORMS_INVOICE=OLDINV.STORE.API:EAW will cause the router
* to call ONLINEINV.STORE.API:EAW
*
* This program name should be placed in the appropriate attribute (usually 1 or 13)
* of the CONTROL COMPANY record. This is what the calling program references to
* understand which subroutine to call.
*
* ------------------------------------------------------------------------------
* Include the common variables just in case we want to reference something in
* in this router
$INCLUDE BP SOE.COMMON
$INCLUDE BP SOE.COMMON.EXPANSION
EQU colon TO CHAR(58); * colon
EQU period TO CHAR(46); * period
*
* ------------------------------------------------------------------------------
GOSUB Init
GOSUB CheckEnabled
GOSUB GetMethod
GOSUB Route
GOTO Exit
* ------------------------------------------------------------------------------
CheckEnabled:
* decide if this print is a 'from' location print or a 'to' location print
* so we can decide if bpi_forms enabled for this location for routing
* have to do it this way because app doesn't pass in this info and it's not
* discernable with exposed variables. This subroutine leaves bpi.forms.enabled
* set to value in WHSE-TRANSFER-PRINTQ-BPI_FORMS if that record exists in
* control. Otherwise it will default to @FALSE and bpi_forms will not function
queue = CHANGE( OCONV(arg3,\MCN\), \-\, \\); *strip out formatting, just num
READ whse.transfer.printq FROM F.CONTROL, \WHSE-TRANSFER-PRINTQ\ THEN
READ i.transfer FROM F.TRANSFER, arg1 THEN
BEGIN CASE
CASE whse.transfer.printq<1,i.transfer<1>> EQ queue
copy.for = \from\
pos = i.transfer<1>
CASE whse.transfer.printq<1,i.transfer<3>> EQ queue
copy.for = \to\
pos = i.transfer<3>
CASE 1
copy.for = \to\
pos = i.transfer<1>
END CASE
* if pos is 1, it's a from copy, if pos is 3, it's to copy.
READ i.control FROM F.CONTROL, \WHSE-TRANSFER-PRINTQ-BPI_FORMS\ THEN
bpi.forms.enabled = i.control<1,pos>
END ELSE
bpi.forms.enabled = @FALSE
END
END ELSE
bpi.forms.enabled = @FALSE
END
ENDRETURN
* ------------------------------------------------------------------------------
GetMethod:
* right now this looks at a env variable, but it could be changed to get from
* a database record if that works better for the user...
IF bpi.forms.enabled THEN
CALL bpi.GetEnv( \BPI_FORMS_METHOD_SUFFIX\, suffix, error )
END ELSE
suffix = \\
END
RETURN
* ------------------------------------------------------------------------------
Route:
method = \ONLINEXFER.STORE.EAW\
IF bpi.forms.enabled THEN
* the control record says this location is bpi_form enabled
IF suffix NE \\ THEN
* get rid of colons to make editing with unix editors and ftp client easier
method = CHANGE( method:suffix, colon, period)
END
END
CALL @method( arg1, arg2, arg3, arg4, arg5)
RETURN
* ------------------------------------------------------------------------------
Init:
OPEN 'TRANSFER' TO F.TRANSFER ELSE STOP 201, \TRANSFER\
RETURN
* ------------------------------------------------------------------------------
Exit:
RETURN
UltiForm Emulation
In release 2.1 of Blue Prairie Forms, we added a set of conversion tools that allow Ultimate/AutoShims users that are using the ULTIFORM templating system (also known as PP-TEMPLATE) to easily integrate and use Blue Prairie Forms instead. Details about this integration can be found in a separate technical note.
To determine if you are using the UltiForms system within your apps, login to you main account and type SORT PP-TEMPLATE. If this lists items, there is a good chance that you are using UltiForms and that the switch to Blue Prairie Forms will be easier than hand-coded integration.