guides:o4w:examples:example_invoice

Invoice Form Example    

Below is code for a sample Invoice display screen for use with an O4W application.
 

 

Subroutine O4W_INVOICE_REPORT(CTRLENTID, EVENT, REQUEST)

* Demonstration routine

$Insert O4WCOMMON

$Insert O4WEQUATES

Declare Function UCase

 

* Open our tables (otherwise we can't generate any report)

Open 'INVOICES' To INV.FL Then

Open 'DICT.INVOICES' To @DICT Else

O4WError("Unable to open DICT.INVOICES table - cannot proceed!")

Return 0

End

End Else

O4WError("Unable to open INVOICES table - cannot proceed!")

Return 0

End

 

* Define some style variables that we'll use repeatedly

* This creates some "temporary" unnamed styles that we can reuse

rightAlignStyle = O4WTextOptions("", "","1"):O4WAlignStyle("", O4W_ALIGN_RIGHT$)

greenbarStyle = o4wcolorstyle("", "lightgreen")

* Alternatively, this creates a named style ("overallSection") that we can reuse

O4WTableStyle("overallSection", "", "", O4W_ALIGN_CENTER$)

O4WSizeStyle("overallSection", "90%")

* This creates some named styles ("invoiceSection", "headingOverride") with some explicit CSS commands

* These could also go directly into our stylesheet

O4WRawStyle("invoiceSection", "margin-left":@fm:"margin-right":@fm:"text-align", "0px":@FM:"0px":@FM:"left")

O4WRawStyle("headingOverride", "padding", "8px 0px")

 

Begin Case

Case event _EQC "CREATE" ; Gosub Create_Event

Case event _eqc "CLICK" ; Gosub Click_Event

End Case

 

Return 0

 

CREATE_EVENT:

* Create event should always use O4WForm call (optionally specifying the template to use)

O4WFORM()

* Load in the stylesheet that will "dress up" our output

* CSS derived from editable invoice example at http://www.css-tricks.com (lots of good information there!)

O4WStyleSheet("../stylesheet/invoicereport.css")

O4WHeader("Invoice Report", 3)

O4WBreak()

O4WBreak()

* In the CREATE event, we will define a section for our prompt

* In the later pages, this section will be replaced with the invoice report output

*

* Only take up 90% of the page, and center this section

O4WSectionStart("invOutput", O4WMarkedOptions('1'):"overallSection")

* Allow for override in URL for the number of invoices per page

nppg = O4WGetValue("PPG")

If nppg = "" Or Not(Num(nppg)) Then nppg = 10

* Store this away so our later pages know how many should be shown

O4WStore(nppg, "inv_per_page", "inv_per_page")

O4WStore("1", "pageno", "pageno")

* Build a table to display the prompts

O4WTableStart("paramTable")

O4WText("Enter starting date: ")

O4WSetCell()

* As a further enhancement, this could be a 'datepicker' control

O4WTextbox(Oconv(DATE(), "D4/"), "", "", "STDATE")

O4WSetCell(2)

O4WText("Enter ending date: ")

O4WSetCell()

O4WTEXTBOX(Oconv(DATE(), "D4/"), "", "", "EDDATE")

O4WSetCell(3, 2)

* Display the button...

O4WButton("Go...", "BTN_GO")

* ... and associate it with the "CLICK" action

O4WQualifyEvent("BTN_GO", "CLICK")

O4WTableend("paramTable")

O4WSectionEnd("invOutput")

RETURN

 

CLICK_EVENT:

* CLICK event handler

* This may be invoked either when navigating back and forth, or when first submitting the report parameters

Begin Case

Case ctrlentid _eqc "BTN_GO"

* Called after submitting the report parameters

/*

When responding to an event, we will almost always need the O4WResponse() call (comparable to the O4WForm() call on the CREATE event)

*/

o4wresponse()

* determine which invoices fall in our date (if any)

STDATE = O4WGETVALUE("STDATE")

EDDATE = O4WGETVALUE("EDDATE")

* As an enhancement, we chould check that these are valid, and if not, return an error...

* "normal" OpenInsight programming is used here

stmt = 'SELECT INVOICES BY INVOICE_DATE BY CUST_NAME'

DELIM = ""

If stdate <> "" Then

stmt := ' WITH INVOICE_DATE >= "':STDATE:'"'

DELIM = ' AND'

End

If eddate <> "" Then

stmt := DELIM:' WITH INVOICE_DATE <= "':EDDATE:'"'

End

* Get the unique ID that O4W has already generated for this page

* Use this as the key to store the selected IDs

UniqueID = ucase(o4wgetvalue("O4WUniqueID"))

LISTID = UniqueID:"*LIST"

Call Rlist(STMT, 4, LISTID, '', '')

* did we select anything?

/*

Note: this only works if we don't span multiple records; in newer versions of OpenInsight, use RTI_LIST instead to read in the entire list.

*/

listinfo = Xlate("SYSLISTS", LISTID, "", "X")

If listinfo = "" Then

* Return an error

o4wError("No invoices selected; please retry")

End Else

* Preserve the list of IDs in the O4WTEMP table

listinfo = Delete(listinfo, 1, 0, 0) ;* First, remove the "list header" from field 1

Write listinfo On O4WTempFile%, LISTID

/*

Some browsers may have available the parameters from the URL even on our AJAX events

O4W will make multiple occurences of the same parameter available as @VM delimited values

Make sure, then, that if we have more than one hanging around, we operate on only one

*/

invperpage = o4wgetvalue("inv_per_page")<1,1>

If invperpage = "" Or Not(Num(invperpage)) Then

invperpage = 10

End

pageno = o4wgetvalue("pageno")<1,1>

If pageno = "" Or Not(Num(pageno)) Then

pageno = 1

End

* The "buildInvoices" subroutine will generate the invoices for the current page

Gosub buildInvoices

End

Case ctrlentid _eqc "BTN_NEXT"

* Called by the NEXT button

o4wresponse()

* make sure, if we have more than one hanging around, we only get one

invperpage = o4wgetvalue("inv_per_page")<1,1>

If invperpage = "" Or Not(Num(invperpage)) Then

invperpage = 10

End

pageno = o4wgetvalue("pageno")<1,1>

If pageno = "" Or Not(Num(pageno)) Then

pageno = 1

End

* Increment the page number that we were on

pageno += 1

* Build the invoices for this page

Gosub buildInvoices

Case ctlrentid _eqc "BTN_PREV"

* Called by the PREV button

o4wresponse()

* make sure, if we have more than one hanging around, we only get one

invperpage = o4wgetvalue("inv_per_page")<1,1>

If invperpage = "" Or Not(Num(invperpage)) Then

invperpage = 10

End

pageno = o4wgetvalue("pageno")<1,1>

If pageno = "" Or Not(Num(pageno)) Then

pageno = 1

End

* Decrement the page number that we were on

pageno -= 1

* Sanity check of the results

If pageno < 1 Then pageno = 1

* Build the invoices for this page

Gosub buildInvoices

End case

RETURN

 

buildInvoices:

* Tell O4W that we want to replace the "invOutput" section of the displayed browser page

O4WSectionStart("invOutput", O4WResponseOptions():O4WMarkedOptions('1'):"overallSection")

* Preserve the values we want to pass in on the "Next" or "Prev" button presses

O4WStore(invperpage, "inv_per_page", "inv_per_page")

O4WStore(pageno, "pageno", "pageno")

* Retrieve the unique ID that O4W has generated for this form

UniqueID = ucase(o4wgetvalue("O4WUniqueID"))

LISTID = UniqueID:"*LIST"

* Try to retrieve the list of selected invoices we generated previously

Read listInfo From O4WTempFile%, ListID Else listInfo = ""

* Is that list missing or empty?  => Error

If listInfo = "" Then

O4WError("Error: No items selected, or list item lost")

Return

End

* Calculate how many invoices are in the list, and which ones in the list we should process for this page

num.items = dcount(listInfo, @FM)

stno = (pageno-1)*invperpage + 1

edno = stno + invperpage - 1

* Sanity check - are we beyond the end of the list?

If stno > num.items Then

O4WError("Error: Invalid page number")

Return

End

* If the last page has fewer than our maximum to display, adjust ourselves accordingly

If edno > num.items Then edno = num.items

cntr = 0

/*

For each ID in our list, we will read the invoice record, pull out its information (and associated information from the CUSTOMERS table), and display it in appropriate sections

*/

For each.invoice = stno To edno

@ID = listInfo<each.invoice>

Read @record From INV.FL, @ID Else

@RECORD = "Record ":@ID:" not found"

End

cntr += 1

* get all the details

INV_DATE = {INVOICE_DATE}

CUST_NO = {CUST_NO}

CUST_NAME = {CUST_NAME}

ORD_DATE = {ORDER_DATE}

ORD_NUM = {ORDER_NUMBER}

DUE_DATE = {DUE_DATE}

PAID_DATE = {PAID_DATE}

QTYS = {QTYS}

DESCS = {DESCS}

ITEMS = {ITEMS}

PRICES = {PRICES}

EXTENDED = {EXT_COSTS}

AMOUNT = {AMOUNT}

* get address information

CUSTINFO = Xlate("CUSTOMERS", CUST_NO, "", "X")

ADD1 = CUSTINFO<3>

ADD2 = CUSTINFO<4>

CITY = CUSTINFO<5>

ST = CUSTINFO<6>

ZIP = CUSTINFO<7>

COUNTRY = CUSTINFO<8>

* Display this invoice in its own section

* "Green bar" the output for easier identification

invcolor = ""

If cntr/2 = int(cntr/2) Then

* change the background color of this section

invcolor = greenbarStyle

End

* Insert a few blank lines

O4WBreak()

O4WBreak()

O4WBreak()

* Each invoice will go into its own section

* Note the use of the CNTR variable - this makes sure that each element has a unique ID (as required)

o4wsectionstart("invoice_":cntr, "invoiceSection":@SVM:invcolor)

/*

Display the word "INVOICE", and assign it to the "hdr" style

We also assign it to the "headerOverride" style (dynamically created at the top of this report) to override the padding setting in our template's css

*/

o4wtext("INVOICE", "", "headingOverride":@SVM:O4WTextOptions("","","1"):"hdr")

O4WBreak()

O4WBreak()

* Create a section to hold who we are, assigning it to the "identity" class

O4WSectionStart("identity_":cntr, "identity")

* Create a section for the address itself, assigning it to the "address" class

O4WsectionStart("address_":cntr, "address")

* ...and output our address information

O4WText("Revelation Software")

o4wbreak()

O4WText("99 Kinderkamack Rd.")

O4WBreak()

O4WText("First Floor")

O4WBreak()

O4WText("Westwood, NJ 07675")

O4WSectionEnd("address_":cntr)

* Display a logo with the "logo" class

O4WSectionStart("logo_":cntr, "logo")

o4wimage("logo", "../images/logo.gif")

O4WSectionEnd("logo_":cntr)

O4WSectionEnd("identity_":cntr)

* Some css to make things align properly

o4wsectionstart("clearing_":cntr, O4WPositionStyle("","","","","","both"));o4wsectionend("clearing_":cntr)

* Create the customer section using the "customer" class

O4WSectionStart("customer_":cntr, "customer")

* Output the customer information, assigned to the "customer-title" class

* O4W will automatically make each value its own line in the display

* Let's put this all together

custOutput = ""

custOutput<1,-1> = CUST_NAME

custOutput<1,-1> = TRIM(ADD1)

If trim(ADD2) <> "" Then custOutput<1,-1> = TRIM(ADD2)

custOutput<1,-1> = CITY:", ":ST:"  ":ZIP

If COUNTRY _eqc "US" or COUNTRY _eqc "USA" Then

country = ""

End

If trim(COUNTRY) <> "" Then custOutput<1,-1> = COUNTRY

O4WText(custOutput, "", "customer-title")

* Display a table of overall information about this invoice

O4WTableStart("meta_":cntr, "meta")

* Move to cell (1,1), and assign that cell to the "meta-head" class

O4WSetCell(1,1,"","meta-head")

O4WText("Invoice #")

* Shorthand to move to the next cell - (1,2) in this case

O4WSetCell()

O4WText(@ID)

O4WSetCell(2, 1, "", "meta-head")

O4WText("Date")

O4WSetCell()

O4WText(Oconv(INV_DATE, "D"))

O4WSetCell(3, 1, "", "meta-head")

O4WText("Amount Due")

O4WSetCell()

O4WText(Oconv(AMOUNT, "MD2,$"))

O4WTableEnd("meta_":cntr)

O4WSectionEnd("customer_":cntr)

* Create a table to display the line items, and the subtotals/totals

O4WTableStart("items_":cntr, "items")

* Display the column headings

O4WTableHeader("Item")

O4WTableHeader("Description")

O4WTableHeader("Unit Price")

O4WTableHeader("Quantity")

O4WTableHeader("Ext")

num.lines = dcount(items, @VM)

total = 0

For each.item = 1 To num.lines

O4WSetCell(each.item, 1, "", "item-name")

o4wtext(items<1,each.item>)

O4WSetCell(each.item, 2, "", "description")

O4WText(descs<1,each.item>)

O4WSetCell(each.item, 3, "", "cost")

O4WText(Oconv(PRICEs<1,EACH.ITEM>, "MD2,$"), "", rightAlignStyle)

O4WSetCell(each.item, 4, "", "qty")

O4WText(qtys<1,each.item>, "", rightAlignStyle)

O4WSetCell(each.item, 5, "", "price")

O4WText(Oconv(extended<1,each.item>, "MD2,$"), "", rightAlignStyle)

total += extended<1,each.item>

Next each.item

/*

Move to the next row, first column, and use "column spanning" to consume 2 columns; also, mark this as the "blank" style

*/

O4WSetCell(num.items+1, 1, "", O4WTableCellOptions(2):"blank")

* Move to the 3rd column, and use column spanning to consume 2 more columnes; mark this as the "total-line" style

O4WSetCell("", 3, "", O4WTableCellOptions(2):"total-line")

O4WText("Subtotal")

O4WSetCell("", 5, "", "total-value")

O4WText(Oconv(total, "MD2,$"), "", rightAlignStyle)

O4WSetCell(num.items+2, 1, "", O4WTableCellOptions(2):"blank")

O4WSetCell("", 3, "", O4WTableCellOptions(2):"total-line")

O4WText("Total")

O4WSetCell("", 5, "", "total-value")

O4WText(Oconv(total, "MD2,$"), "", rightAlignStyle)

O4WTableEnd("items_":cntr)

* Done with the line items and subtotals/totals

* Start the terms section, assigning it to the "terms" style

O4WSectionStart("terms_":cntr, "terms")

O4WHeader("Terms", 5)

O4WText("NET 30 days. Finance charges of 1.5% will be made on unpaid balances after 30 days")

O4WSectionEnd("terms_":cntr)

o4wsectionend("invoice_":cntr)

O4WBreak()

O4WBreak()

* Finally, display a line using the "dashes" style

O4WDivider("", "dashes")

Next each.invoice

 

* Display our forward/back buttons

* Only enable them, though, if appropriate

If stno > 1 Then

* Create the button, and make sure it's enabled

O4WButton("< Back", "BTN_PREV", O4WInputStyle("","1", "0"))

O4WQualifyEvent("BTN_PREV", "CLICK")

End Else

* Create the button, but make it disabled and read-only

O4WButton("< Back", "BTN_PREV", O4WInputStyle("", "0","1"))

End

o4wspace(5)

If edno < num.items Then

O4WButton("Next >", "BTN_NEXT", O4WInputStyle("","1","0"))

O4WQualifyEvent("BTN_NEXT", "CLICK")

End Else

O4WButton("Next >", "BTN_NEXT", O4WInputStyle("", "0","1"))

End

 

O4WSectionEnd("invOutput")

Return

 

  • guides/o4w/examples/example_invoice.txt
  • Last modified: 2024/06/19 20:19
  • by 127.0.0.1