"EXECIO * DISKR ORDERDAT (STEM orderData."
if 0 <> RC then
do
say 'ERROR: Unable to read in the ORDERDAT file'
exit 8
end
/**************************/
/* Process the order data */
/**************************/
/* Initialise our known retailers list and totals */
retailers.0 = 0
cancelledOrders = 0
cancelledSales = 0
completedOrders = 0
completedSales = 0
/* Initialise the known items list */
items.0 = 0
/* Initialise the month names */
monthNames.0 = 12
monthNames.1 = 'January'
monthNames.2 = 'February'
monthNames.3 = 'March'
monthNames.4 = 'April'
monthNames.5 = 'May'
monthNames.6 = 'June'
monthNames.7 = 'July'
monthNames.8 = 'August'
monthNames.9 = 'September'
monthNames.10 = 'October'
monthNames.11 = 'November'
monthNames.12 = 'December'
/* Get the report month number from the parameters */
parse arg reportMonth .
/* Validate the month number */
if ( (datatype(reportMonth) <> 'NUM'),
| (reportMonth < 0),
| (reportMonth > monthNames.0) ) then
do
say 'ERROR: Invalid month number'
exit 8
end
/* Process each order data line */
do i = 1 to orderData.0
/* Skip lines that have an asterisk in column 1 */
if ( 1 = pos('*', orderData.i ) ) then
iterate
/* Parse the various fields out of the order data line */
parse var orderData.i,
orderNo','retailer','productID','productName','productPrice',',
quantity orderDate orderState
/* Check that the data looks valid */
if ( datatype(orderNo) <> 'NUM',
| orderNo < 0 ) then
do
say "ERROR: Invalid order number:" orderNo
exit 8
end
if ( length(productID) <> 5 ) then
do
say "ERROR: Invalid product ID:" productID
exit 8
end
if ( datatype(productPrice) <> 'NUM',
| productPrice < 0 ) then
do
say "ERROR: Invalid product price:" productPrice
exit 8
end
if ( datatype(quantity) <> 'NUM',
| quantity < 0 ) then
do
say "ERROR: Invalid order quantity:" quantity
exit 8
end
if ( length(orderState) <> 1 ) then
do
say "ERROR: Invalid order state:" orderState
exit 8
end
/* Check if the order is for the required month, if applicable */
if ( reportMonth > 0 ) then
do
parse var orderDate orderYear'-'orderMonth'-'orderDay
/* Verify that it looks like a valid date */
if ( datatype(orderDay) <> 'NUM',
| orderDay < 0 | orderDay > 31,
| datatype(orderMonth) <> 'NUM',
| orderMonth < 0 | orderMonth > 12,
| datatype(orderYear) <> 'NUM',
| orderYear < 0 ) then
do
say "ERROR: Invalid order date:" orderDate
exit 8
end
if ( reportMonth <> orderMonth ) then
iterate
end
/* Check if we've seen this retailer before */
retailerIdx = -1
do r = 1 to retailers.0
if ( retailers.r.name = retailer ) then
do
retailerIdx = r
leave r
end
end /* r = ... */
/* If we didn't find the retailer - add it */
if ( retailerIdx = -1 ) then
do
retailerIdx = retailers.0 + 1
retailers.0 = retailerIdx
retailers.retailerIdx.name = retailer
retailers.retailerIdx.sales = 0
retailers.retailerIdx.orders = 0
end
/* Check if we've seen this item before */
itemIdx = -1
do s = 1 to items.0
if ( items.s.code = productID ) then
do
itemIdx = s
leave s
end
end /* s = ... */
/* If we didn't find the item - add it */
if ( itemIdx = -1 ) then
do
itemIdx = items.0 + 1
items.0 = itemIdx
items.itemIdx.code = productId
items.itemIdx.name = productName
items.itemIdx.sales = 0
end
/* Check if the order was cancelled */
if ( orderState = 'C' ) then
do
cancelledOrders = cancelledOrders + 1
cancelledSales = cancelledSales + (productPrice * quantity)
end
else
do
/* Increment the number of orders */
retailers.retailerIdx.orders = retailers.retailerIdx.orders + 1
completedOrders = completedOrders + 1
/* Update the overall and retailer's sales totals */
retailers.retailerIdx.sales = retailers.retailerIdx.sales,
+ (productPrice * quantity)
completedSales = completedSales + (productPrice * quantity)
/* Update the total sales for this item */
items.itemIdx.sales = items.itemIdx.sales + quantity
end
end /* i = ... */
/**********************/
/* Sort the retailers */
/**********************/
call sortRetailers
/**********************************/
/* Sort the items by sales volume */
/**********************************/
call sortItems
/********************************/
/* Prepare the generated report */
/********************************/
/* First create the completed sales by retailer report */
reportTitle = 'Completed Sales by Retailer'
if ( reportMonth = 0 ) then
reportTitle = reportTitle' - All Dates'
else
reportTitle = reportTitle' - 'monthNames.reportMonth
queue reportTitle
queue copies('=', length(reportTitle))
queue ' '
queue 'Retailer Orders Total Sales'
queue '-------------------- ------ -----------'
do r = 1 to retailers.0
/* Format the retailer orders to right align it */
formattedOrders = format(retailers.r.orders, 6)
/* Format the sales figure to right align it with 2 decimal places */
formattedSales = format(retailers.r.sales / 100, 8, 2)
/* Generate the formatted line */
nextLine = retailers.r.name
nextLine = overlay(formattedOrders, nextLine, 23)
nextLine = overlay(formattedSales, nextLine, 31)
/* Output the formatted line */
queue nextLine
end /* r = ... */
queue '-------------------- ------ -----------'
/* Generate a line for the completed orders */
formattedOrders = format(completedOrders, 6)
formattedSales = format(completedSales / 100, 8, 2)
totalLine = overlay(formattedOrders, 'Total', 23)
totalLine = overlay(formattedSales, totalLine, 31)
queue totalLine
queue '-------------------- ------ -----------'
queue ' '
queue 'In addition 'cancelledOrders' order(s) totalling',
format(cancelledSales / 100, ,2)' were cancelled.'
/* Now display the best selling items */
reportTitle = 'Top 5 Items by Sales Volume'
if ( reportMonth = 0 ) then
reportTitle = reportTitle' - All Dates'
else
reportTitle = reportTitle' - 'monthNames.reportMonth
queue ' '
queue reportTitle
queue copies('=', length(reportTitle))
queue ' '
queue 'Item Code Item Name Quantity sold'
queue '--------- ----------------------- -------------'
do s = 1 to min(5, items.0)
/* Format the quantity sold to right align it */
formattedQuantity = format(items.s.sales, 6)
/* Generate the formatted line */
nextLine = items.s.code
nextLine = overlay(items.s.name, nextLine, 12)
nextLine = overlay(formattedQuantity, nextLine, 44)
/* Output the formatted line */
queue nextLine
end /* s = ... */
/* Now display the worst selling items */
reportTitle = 'Bottom 5 Items by Sales Volume'
if ( reportMonth = 0 ) then
reportTitle = reportTitle' - All Dates'
else
reportTitle = reportTitle' - 'monthNames.reportMonth
queue ' '
queue reportTitle
queue copies('=', length(reportTitle))
queue ' '
queue 'Item Code Item Name Quantity sold'
queue '--------- ----------------------- -------------'
do s = max(1, items.0 - 4) to items.0
/* Format the quantity sold to right align it */
formattedQuantity = format(items.s.sales, 6)
/* Generate the formatted line */
nextLine = items.s.code
nextLine = overlay(items.s.name, nextLine, 12)
nextLine = overlay(formattedQuantity, nextLine, 44)
/* Output the formatted line */
queue nextLine
end /* s = ... */
/* Generate a trailer indicating when report was generated */
queue ' '
queue 'Report generated on 'date('W')' 'date('N')' at 'time('C')
/*******************************/
/* Output the generated report */
/*******************************/
"EXECIO * DISKW REPORT (FINIS"
if rc <> 0 then
do
say 'ERROR: Unable to write to the REPORT file'
exit 8
end
/* All done */
exit 0
/******************************************************/
/* Subroutine to sort the retailers alphabetically by */
/* name using the simple insertion sort algorithm. */
/******************************************************/
sortRetailers: procedure expose retailers.
/* At the end of each iteration elements 1 to i will be sorted */
do i = 2 to retailers.0
/* Take a copy of the 'current' retailer */
tmpRetailer.name = retailers.i.name
tmpRetailer.orders = retailers.i.orders
tmpRetailer.sales = retailers.i.sales
/* Shuffle up all preceding retailers, as applicable, */
/* to position the 'current' retailer in the correct */
/* position relative to all of those prior to it in */
/* the original, unsorted, list. */
positioned = 0
j = i - 1
k = i
do until ( positioned = 1 )
if retailers.j.name > tmpRetailer.name then
do
retailers.k.name = retailers.j.name
retailers.k.orders = retailers.j.orders
retailers.k.sales = retailers.j.sales
j = j - 1
k = k - 1
if j < 1 then
positioned = 1
end
else
positioned = 1
end
retailers.k.name = tmpRetailer.name
retailers.k.orders = tmpRetailer.orders
retailers.k.sales = tmpRetailer.sales
end
return
/************************************************/
/* Subroutine to sort the items by sales volume */
/* using the simple insertion sort algorithm. */
/************************************************/
sortItems: procedure expose items.
/* At the end of each iteration elements 1 to i will be sorted */
do i = 2 to items.0
/* Take a copy of the 'current' retailer */
tmpItem.code = items.i.code
tmpItem.name = items.i.name
tmpItem.sales = items.i.sales
/* Shuffle up all preceding items, as applicable, */
/* to position the 'current' item in the correct */
/* position relative to all of those prior to it in */
/* the original, unsorted, list. */
positioned = 0
j = i - 1
k = i
do until ( positioned = 1 )
if items.j.sales > tmpItem.sales then
do
items.k.code = items.j.code
items.k.name = items.j.name
items.k.sales = items.j.sales
j = j - 1
k = k - 1
if j < 1 then
positioned = 1
end
else
positioned = 1
end
items.k.code = tmpItem.code
items.k.name = tmpItem.name
items.k.sales = tmpItem.sales
end
return