Saturday, July 25, 2009

A Better Way To Print Receipts

There are two reasons I’m writing this post. The first is because I want to clarify some of the requirements I had in Ontempo Store before I write my next Pos .Net post. The second is because I’ve seen a lot of people on the ‘net asking how to drive POS receipt printers and their focus seems to be on how to access the device, which while important, isn’t the only issue you need to consider in a retail application.

With Ontempo Store we were trying to create a world class solution for tier 1 and 2 retailers, which meant merely printing fixed strings on a receipt wasn’t going to be good enough. Printing hard coded text with prices and quantities embedded is often what is shown in sample code, or in questions about how to drive receipt printers. In our case, we had the following additional requirements;

  • Customisation – we need our users to be able to customise parts of printed documents, such as the receipt header and footer, signature slips, terms and conditions for certain sale types, voucher and coupon formats etc. As well as letting them specify text for these things, we need to allow the user customising the receipt to include instructions like bold, underline, cuts, logo prints, barcodes to print etc.

  • Print Preview and Review – we need to be able to view printed information on screen, both before and after it’s printed in a WYSIWYG way. 

  • Print Auditing – we need to be able to store the data sent to the printer. This needs to be done as an audit, and to allow us to quickly reprint or view a transaction, voucher or other document at a later stage and know that we are seeing what was printed originally, not the “current” state. This is particularly important for ‘tax invoices’ which sometimes have legal requirements around re-prints matching the original.

  • Network Printing – we want to be able to print to a ‘shared’ printer. Our networking solution uses an asynchronous message based system, which means we must be able to pass our entire document as a single block of data (a single message). Multiple method calls remoted via one mechanism or another aren’t going to work, or be performant.

So what we came up with is ‘PML’. PML stands for Print Mark-up Language and is a simple way of creating a string that contains all the information needed to format a document for a receipt printer. It’s pretty simple, and most closely resembles XSL in that anything that isn’t a tag or tag data is written out to the printer as is, and xml style tags are used to control formatting.

Here’s some sample PML for a receipt header;

<align value="centre"><logo/><br/></align><align value="centre"><b>Westgate</b><br/><b>Phone</b> 649 555 5555 <b>Fax</b> 649 555 5551<br/>You were served by Yort<br/>GST# 55-555-555</align><br/>Docket #DF654542     18-07-2009 11:33:12<br/><u><repeat count="42"> </repeat></u><br/><br/>

The end result of this would print or preview something like this;

Receipt Header Sample

As an interesting side point, note the use of the ‘repeat’ tag. This tag has nothing to do with sending commands to the printer, but is used to repeat text or a block of PML between it’s opening and closing tags. In the case above it repeats an underlined space character 42 times, effectively drawing a horizontal line. We can also use this to repeat more complicated blocks of text or formatting, or to print multiple copies of an entire document.

So how do we use PML ? The PML for the document content itself is constructed by whatever component of our system is creating the document to be printed, but items like the header and footer of receipts are stored as system settings the user can edit as required, and are just prepended or appended to the beginning or end of the document as required.

We have a class called PrintFormatter (not the best name or design, but I didn’t create the original version and haven’t yet refactored it) which is responsible for parsing the PML. The parsing is done using regular expressions.

The PrintFormatter has two methods of operation. Regardless of which mode is being used, once the PrintFormatter is setup all you need to do to process the PML is pass it to a method called ProcessData.

String Builder Mode

Immediately after the PrintFormatter object is instantiated it is ‘configured’ by calls to a method called AddDirective. This method has several overloads, one that takes a tag name and an escape sequence, one that takes a tag name and two separate escape sequences (one for each of the start and end of the tag) and finally one that takes a tag name and and a delegate.

Whenever the PrintFormatter locates a tag (during the ProcessData method call) it either calls the delegate associated with the tag or replaces the tag and it’s contents with the escape code(s) provided.

In the case of the delegate, the return value replaces the tag and it’s contents. A delegate is usually used when a tag has attributes that alter the escape code that needs to be embedded, like when printing a barcode and you need to specify height, width, symbology etc.

The end result is a string (accessible via a property on the PrintFormatter object) which can be sent directly to the printer assuming an escape code or other embedded sequence is available for all print formatting functions.

Event Mode

Event mode is enabled by setting the UseEventMode property to true. In this case you don’t need to call AddDirective for each supported tag. Instead, the system raises either a ProcessTag, ProcessTagEnd or ProcessText event every time it finds a tag, closed tag, or data to be output as is.

The event arguments for ProcessTag and ProcessTagEnd contain the tag name, tag contents and a list of attribute names and values specified on the tag.

When we’re doing a print preview, we handle these events and alter the current pen/brush and then call DrawString or DrawImage to display the actual content using the current settings. We also have to keep track of the current x and y co-ordinates for where we’re going to print next.

We also had to use this mechanism for printing via Pos .Net, as some Pos .Net commands are escape codes and some are method calls which couldn’t be embedded in a string to be sent to the printer, but still had to be processed in sequence. Also, Pos .Net doesn’t have escape codes to cancel some previous formatting commands, and it resets the print format to ‘normal’ after every call to PrintNormal.

As a result we couldn’t just build up a string with escape codes embedded, but rather had to keep track of the current print state by building a stack of unclosed tags for those commands that are represented by escape codes, and every time we call PrintNormal we prepend the escape sequences to the data being printed. On a tag close we pop last escape code sequence off the stack.  This allows correct processing of PML like this;

<b>Branch : </b> Westgate

Which should be displayed with Branch in bold and Westgate in the ‘normal’ format, like this;

Branch Westgate

The key point though, is that regardless of how the PML is processed we can represent an entire, formatted, document as a string. This allows us to store it, ship it across the network as a single data block, or re-print it in it’s original state at any time.

So, when designing a retail system that prints receipts or other documents on a receipt or sip printer, spend as much time architecting the printing processes as the rest of your application. They can be just as important, and failure to do so can leave you with a real problem when you try to implement other features later.


Technorati Tags: ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

Windows Live Tags: Formatting,Devices,Pos .Net,PosPrinter,PML,Print,Receipts,Ontempo,receipt,solution,tier,code,Customisation,documents,header,footer,signature,sale,voucher,coupon,user,logo,Preview,Review,WYSIWYG,printer,transaction,Network,mechanism,Language,Docket,commands,component,items,PrintFormatter,version,expressions,operation,mode,ProcessData,Builder,AddDirective,sequence,contents,width,Event,UseEventMode,ProcessTag,ProcessTagEnd,ProcessText,output,arguments,events,DrawImage,PrintNormal,Branch,failure,features,printers,retailers,users,sequences,codes

WordPress Tags: Formatting,Devices,Pos .Net,PosPrinter,PML,Print,Receipts,Ontempo,receipt,solution,tier,code,Customisation,documents,header,footer,signature,sale,voucher,coupon,user,logo,Preview,Review,WYSIWYG,printer,transaction,Network,mechanism,Language,Docket,commands,component,items,PrintFormatter,version,expressions,operation,mode,ProcessData,Builder,AddDirective,sequence,contents,width,Event,UseEventMode,ProcessTag,ProcessTagEnd,ProcessText,output,arguments,events,DrawImage,PrintNormal,Branch,failure,features,printers,retailers,users,sequences,codes

Blogger Labels: Formatting,Devices,Pos .Net,PosPrinter,PML,Print,Receipts,Ontempo,receipt,solution,tier,code,Customisation,documents,header,footer,signature,sale,voucher,coupon,user,logo,Preview,Review,WYSIWYG,printer,transaction,Network,mechanism,Language,Docket,commands,component,items,PrintFormatter,version,expressions,operation,mode,ProcessData,Builder,AddDirective,sequence,contents,width,Event,UseEventMode,ProcessTag,ProcessTagEnd,ProcessText,output,arguments,events,DrawImage,PrintNormal,Branch,failure,features,printers,retailers,users,sequences,codes

14 comments:

  1. Hi Yort,
    Great post! We're using OPOS .Net and TM-T88IV as Thermal Printer. We're facing a requirement to display a preview, specially when customer do not have a Thermal Printer Connected to their workstation. How do you achieve this requirement? We implemented our custom PML, that way customer can customize the receipt format (Bold, alignment, etc), then during printing process we parse the PML to have the appropriated escape commands. So I believe we are on the correct path, the only issue is the preview. We don't know how to provide a easy preview implementation... Any thought will be really appreciated.

    Regards,
    Carlos.

    ReplyDelete
  2. Hi Charlie,

    Thanks for the comment.

    I've been thinking about producing a (simple) sample PML with a parser and output components for both previous and Pos .Net, but I haven't gotten around to it yet.

    Basically what you need to do is build a user control that parses the PML (or intercepts events from an external parser component) and then performs drawing commands on itself. Use the Graphics.DrawString command to paint text, and DrawImage to do pictures and barcodes. The rest of the code just needs to track the position, font style and alignment that is currently in use.

    We use a 'stack' for holding the current formatting style, and then as each PML tag is closed we 'pop' the last command of the stack to arrive at the new style to use.

    It's a little bit of work, but it's not rocket science and you can get a pretty decent preview out of it.

    Good luck.

    PS: If I get chance to work on the sample I'll do so and post about it as soon as I can.

    ReplyDelete
  3. Great article! Thank you! Waiting for you sample post...

    ReplyDelete
  4. Have you implemented tables, margin, foreach statement etc.? If yes, than is will be nice to see some samples of created xml tags and elements.

    ReplyDelete
  5. Hi,

    I haven't implemented tables because they haven't been a requirement, but they would not be hard to do.

    For margins, since receipt printers almost always use fixed width fonts we just pad our strings with spaces (.Net's string class has pad left and right functions)... and so margins aren't really a requirement either, but again you could implement something if the printer/pos .net etc. allow you to do so.

    I'm not sure what you meant about the for each statement, that's part of C#/.Net and may be used by our code but isn't something we had to create any implementation for.

    ReplyDelete
  6. Thanks for a great post. I was hoping to get your advice on something before we run down a technical cul-de-sac with our project. We need to capture all the information printed on a receipt from any POS application for a plug in we provide. Can you think of a sensible way to do this?

    Thanks,
    Richard

    ReplyDelete
  7. Hi Richard,

    Thanks for posting the comment.

    Sadly, I can't think of any good way of doing this.

    You could try intercepting data going to a serial port, but that will only work for serial printers and I don't know specifcally how to do it.

    You could try writing a Pos .Net service object that is a 'pass-thru', i.e your service object would record all the commands given to it and then pass them on to another service object. However, you'd have to have some way of creating an initialising the other service object and then you'd have the overhead of implementing the full service object interface. Even if you succeed at that, it will only work for Pos .Net integration... you will likely need to do similar work for OPOS/JPOS etc.

    There might be a way to intercept documents from the Windows print spooler, but that only works where a Windows printer driver is used and the document is printed through the spooler. Even then, I'm not sure what the format of the spooler document is (some kind of EMF graphics file ?).

    I would suggest a better idea would be to make a 'plug-in' for each POS system you want to integrate to which gets whatever data you need from the actual POS database, rather than the receipt text (which may or may not contain the info you want, and in a variety of formats each of which you'll have to understand anyway). Of course I don't really know what you're trying to do, so maybe that plan doesn't work for you either.

    Good luck.

    ReplyDelete
  8. Is it possible to get an example of how to create a PML and use it? I have looked but there seems to be no other information on it other than this blog post. If this is just comment on how to approach it, then I'll make my own. Thanks.

    ReplyDelete
    Replies
    1. Hi,

      I've been meaning to make an example PML with code to parse and output it, but haven't gotten around to it. It is a fair amount of work to do a good job, but less work than supporting multiple printer methods and print preview without one. As you've suggested, this is just a comment on how to approach the problem to avoid duplicated code and constant maintenance hassles.

      The closest thing I've found to an actual example (and it's not quite what I'd do, but probably good enough for a starting point) is this code project article;

      http://www.codeproject.com/Articles/34582/Kube-Receipt-Printer

      Delete
  9. Sometimes this isnt possible. Sometimes native printer fonts suck and you get complaints. Also some fiscal devices work only with graphics mode...

    ReplyDelete
    Replies
    1. Hi,

      Thanks for your comment, it's useful to know about the fiscal devices (I'm lucky enough not to have come across one).

      Yes, sometimes the built in fonts are bad, but for the most part we've found them acceptable and the graphics modes can, on at least some printers, be intolerably slow so we avoid it almost entirely. Having said that, there are some things that are only possible in graphics mode.

      Technically you could use this architecture and still output the result in graphics mode, that's effectively what a print preview for PML does just to the screen instead of the printer. It would be a lot more work and would be terribly inefficient for describing actual images. but it could work fine for general layout, text and styling etc.

      Thanks for pointing out those issues though.

      Delete
  10. Hi there, I want to change the font family of my Epson TM T88IV receipt printer. Chan you please help me?
    Thanks.

    ReplyDelete
  11. Hi,

    I haven't ever done that myself and I'm not in a position at the moment to try it sorry. I believe there Epson ESC codes you can use to change the font (you should get some documentation about those with the Epson ADK download). Alternatively I think POS .Net/OPOS also have functions to do this, but I've never used them and don't know if the Epson service objects support them. You'd have to try to find out - the POS .Net documentation should cover the methods you need to call to do it.

    I'm also not sure whether you want to use a pre-loaded font (there are only a few loaded in most receipt printers), or a custom one - and I'm not sure what's possible with custom fonts. I think many people who what custom fonts end up creating images and printing the images instead.

    Good luck!

    ReplyDelete
    Replies
    1. Thank you for your response Yort.
      OK I'm trying to learn OPOS ADK for .NET to achieve my task.

      Delete