Type A Solution tutorial

There are two ways that an accounting software could be in accordance with the fiscal law. The "type A" and the "type B". In type B the creator of the accounting software must modify his software in order to be aware of the EAFDSS device. This is considered to be the best approach. If you want to go that way please read the library tutorial. There are however some cases that the modification of the accounting software is not possible. In that case there is a need of another approach, the type A. In that method the software is not aware at all of what an EAFDSS is, and all requirements by the law should be taken care by an external system.

Usually the way to create such an external system is in the printing layer. What we should is the following:

  1. Intercept the invoice that it is to be printed
  2. Get a sign of the invoice using the EAFDSS library
  3. Save a copy of the invoice and it's signature
  4. Print the invoice with it's sign appended

Additionally in case you need a reprint of an invoice you should use another application that fetches the previously saved invoice (in step 3) and reprints it without getting a new signature this time.

In the next paragraph we will see how to roughly create such a system using the most commonly used printing system in modern linux systems - the CUPS.

In order to achieve step 1, we change the cups configuration files in order to create a pre-filter to the text to postscript converter. We modify "etc/cups/mime.convs"

  1. text/plain text/plain-eafdss 10 texteafdss
  2. text/plain-eafdss application/postscript 33 texttops

and create the "/etc/cups/local.types"

  1. text/plain-eafdss

This way when we print a text, before it becomes postscript it will go through our texteafdss filter. Now if you have the distribution of the EAFDSS library go to the "examples/TypeA" directory and run the "OpenEAFDSS-TypeA-Install.sh" script as root:

  1. #!/bin/sh
  2.  
  3. if [ `id -u` -ne 0 ]; then
  4. echo "You will need root priviledges for installation"
  5. exit;
  6. fi
  7.  
  8. if [ $1 ] && [ $1 = '-u' ] ; then
  9. rm -rf /etc/OpenEAFDSS /var/spool/eafdss /var/spool/eafdss-db /usr/lib/cups/filter/texteafdss /usr/local/bin/OpenEAFDSS-TypeA.pl
  10. else
  11. install -o lp -g lp -m 775 -d /var/spool/eafdss
  12. install -o lp -g lp -m 775 -d /var/spool/eafdss-db
  13.  
  14. install -o lp -g lp -m 775 -d /etc/OpenEAFDSS
  15.  
  16. install -o lp -g lp -m 774 OpenEAFDSS-TypeA-Filter.pl /usr/lib/cups/filter/texteafdss
  17. install -o lp -g lp -m 774 OpenEAFDSS-TypeA.ini /etc/OpenEAFDSS/OpenEAFDSS-TypeA.ini
  18. install -o lp -g lp -m 775 OpenEAFDSS-TypeA.pl /usr/local/bin/OpenEAFDSS-TypeA.pl
  19. fi

This will take care to install files with the correct permissions and directories according to the configuration file /etc/OpenEAFDSS/OpenEAFDSS-TypeA.ini

  1. [main]
  2. sqlite=/var/spool/eafdss-db/TypeA.sqlite
  3. abc_dir=/var/spool/eafdss
  4. charset=utf-8
  5.  
  6. [device]
  7. driver=SDNP
  8. param=miles
  9. sn=ABC02000001

Now, let's take a look at who "texteafdss" does it's job. At the beginning are just some code for taking the parameters from the CUPS system.

  1. unless ( defined $ENV{'TMPDIR'} ) {
  2. $ENV{'TMPDIR'} = "/tmp";
  3. }
  4. $sandbox = sprintf("%s/OpenEAFDSS-TMP-%s", $ENV{'TMPDIR'}, $$);
  5. umask(077);
  6. if (! mkdir($sandbox) ) {
  7. printf(STDERR "ERROR: [OpenEAFDSS] Cannot create temporary directory [%s]! Exiting\n", $sandbox);
  8. exit 1;
  9. }
  10.  
  11. if ($#ARGV < 5) {
  12. $fname = sprintf("%s/JOB-TEMP-FILE-01", $sandbox);
  13.  
  14. open(FIN, "<-") || die "Error Opening STDIN ($!)";
  15. open(FOUT, ">", $fname) || die "Error Opening TMPFILE ($!)";
  16. while (<FIN>) { printf(FOUT $_) };
  17. close(FOUT);
  18. close(FIN);
  19.  
  20. ($job_id, $user, $job_name, $copies, $options) = ('', '', '', '', '');
  21. } else {
  22. ($job_id, $user, $job_name, $copies, $options, $fname) = @ARGV;
  23. }

later we use a function as safety measure not to sign print jobs that don't look like invoices. So if we can't find the magic word "INVOICE" we bail out.

  1. unless ( isInvoice($fname) ) {
  2. printf(STDERR "NOTICE: [OpenEAFDSS] file is not an invoice\n");
  3. }
  4. .
  5. .
  6. .
  7.  
  8. sub isInvoice () {
  9. my($fname) = shift @_;
  10.  
  11. my($match) = 0;
  12. open(FH, $fname);
  13. while (<FH>) {
  14. if (m/INVOICE/) {
  15. return 1;
  16. }
  17. }
  18. close(FH);
  19.  
  20. return 0;
  21. }

There is a requirement by the law to sign only documents encoded in the iso8859-7 character set. So in case our invoice is in another character set, like utf-8, we have to convert it before we sign it. Here we use the iconv command, so make sure to have it installed in the system.

  1. my($fname_conv) = sprintf("%s/JOB-TEMP-FILE-02", $sandbox);
  2. if ($CHARSET ne "iso8859-7") {
  3. printf(STDERR "NOTICE: [OpenEAFDSS] Converting invoice from %s to iso8859-7\n", $CHARSET);
  4. my($iconv_cmd) = sprintf("iconv -f %s -t iso8859-7 -o %s %s", $CHARSET, $fname_conv, $fname);
  5. printf(STDERR "DEBUG: [OpenEAFDSS] iconv command [%s]\n", $iconv_cmd);
  6. system($iconv_cmd);
  7. if ($? == -1) {
  8. printf(STDERR "ERROR: [OpenEAFDSS] Failed to execute iconv: $!\n");
  9. } elsif ($? & 127) {
  10. printf(STDERR "ERROR: [OpenEAFDSS] iconv died with signal %d\n", ($? & 127));
  11. } elsif ($? >> 8 != 0) {
  12. printf(STDERR "ERROR: [OpenEAFDSS] iconv failed with value %d\n", $? >> 8);
  13. } else {
  14. $fname = $fname_conv;
  15. }
  16. }

Check if this is a reprint, and raise a flag.

  1. my($reprint, $signature);
  2. if ( $options =~ m/eafddssreprint/ ) {
  3. $options =~ /eafddssreprint=(.*) /;
  4. $reprint = $1;
  5. } else {
  6. $reprint = 0;
  7. }

If this is not a reprint, sign the invoice

  1. if ($reprint) {
  2. printf(STDERR "NOTICE: [OpenEAFDSS] This is a reprint we will not sign again\n");
  3. $signature = $reprint;
  4. } else {
  5. umask(077);
  6. my($dh) = new EAFDSS(
  7. "DRIVER" => "EAFDSS::" . $DRIVER . "::" . $PARAM,
  8. "SN" => $SN,
  9. "DIR" => $ABC_DIR,
  10. "DEBUG" => $debug
  11. );
  12.  
  13. if (! $dh) {
  14. printf(STDERR "ERROR: [OpenEAFDSS]" . EAFDSS->error() ."\n");
  15. printf(STDERR "STATE: [OpenEAFDSS]" . EAFDSS->error() ."\n");
  16. exit 1;
  17. }
  18.  
  19. $signature = $dh->Sign($fname);
  20. if (! $signature) {
  21. my($errNo) = $dh->error();
  22. my($errMsg) = $dh->errMessage($errNo);
  23. printf(STDERR "ERROR: [OpenEAFDSS] [0x%02X] %s\n", $errNo, $errMsg);
  24. printf(STDERR "STATE: [OpenEAFDSS] [0x%02X] %s\n", $errNo, $errMsg);
  25. exit($errNo);
  26. } else {
  27. printf(STDERR "NOTICE: [OpenEAFDSS] Got sign [%s...]\n", substr($signature, 0, 20));
  28. }
  29. }

And then save a copy. Here we use sqlite, so make sure to also have it installed on your system.

  1. if ($reprint == 0) {
  2. my($insert) = "INSERT INTO invoices (tm, job_id, user, job_name, copies, options, signature, text) " .
  3. " VALUES ( date('now'), '$job_id', '$user', '$job_name', '$copies', '$options', '$signature', '$invoice');";
  4.  
  5. printf(STDERR "DEBUG: [OpenEAFDSS] SQL Insert [%s]\n", $insert);
  6. $dbh->do($insert) or die("NOTICE: [OpenEAFDSS] Insert Error [%s]\n", $dbh->errstr);
  7. }

Finally print the invoice and the document.

  1. print $invoice;
  2. printf(" %s \n", $signature);

In case there is a need for a reprint you can use the OpenEAFDSS-TypeA.pl utility

Select the "Type A" submenu
Main Menu

Browse the invoices
Submenu

Select the one you wish
Select invoice

View it, and optionally reprint it
View invoice

You should note that this solution is neither optimal nor complete. It is just helping hand to see what it takes more or less to develop such a system with the EAFDSS library.


Warning: Table './openeafdss/watchdog' is marked as crashed and should be repaired query: INSERT INTO watchdog (uid, type, message, variables, severity, link, location, referer, hostname, timestamp) VALUES (0, 'php', '%message in %file on line %line.', 'a:4:{s:6:\"%error\";s:12:\"user warning\";s:8:\"%message\";s:342:\"Table &#039;./openeafdss/accesslog&#039; is marked as crashed and should be repaired\nquery: INSERT INTO accesslog (title, path, url, hostname, uid, sid, timer, timestamp) values(&#039;Type A Solution tutorial&#039;, &#039;node/5&#039;, &#039;&#039;, &#039;54.92.170.142&#039;, 0, &#039;fc76bd8873c1c22956d8873ea829477a&#039;, 152, 1503343557)\";s:5:\"%file\";s:68:\"/var/www/openeafdss.gr/httpdocs/modules/statistics/statistics.module\";s:5:\"%line\";i:64;}', 3, '', 'http://openeafdss.gr/TypeA', '', '54.9 in /var/www/openeafdss.gr/httpdocs/includes/database.mysqli.inc on line 128