1 package SL::Helper::QrBill;
 
  10   cross_file => 'image/CH-Kreuz_7mm.png',
 
  11   out_file   => 'out.png',
 
  17   my $self = bless {}, $class;
 
  19   $self->_init_check(@_);
 
  27   my ($biller_information, $biller_data, $payment_information, $invoice_recipient_data, $ref_nr_data) = @_;
 
  29   $self->{data}{header} = [
 
  34   $self->{data}{biller_information} = [
 
  35     $biller_information->{iban},
 
  37   $self->{data}{biller_data} = [
 
  38     $biller_data->{address_type},
 
  39     $biller_data->{company},
 
  40     $biller_data->{address_row1},
 
  41     $biller_data->{address_row2},
 
  44     $biller_data->{countrycode},
 
  46   $self->{data}{payment_information} = [
 
  47     $payment_information->{amount},
 
  48     $payment_information->{currency},
 
  50   $self->{data}{invoice_recipient_data} = [
 
  51     $invoice_recipient_data->{address_type},
 
  52     $invoice_recipient_data->{name},
 
  53     $invoice_recipient_data->{address_row1},
 
  54     $invoice_recipient_data->{address_row2},
 
  57     $invoice_recipient_data->{countrycode},
 
  59   $self->{data}{ref_nr_data} = [
 
  61     $ref_nr_data->{ref_number},
 
  63   $self->{data}{additional_information} = [
 
  65     'EPD', # End Payment Data
 
  71   my ($biller_information, $biller_data, $payment_information, $invoice_recipient_data, $ref_nr_data) = @_;
 
  74     my ($group, $href, $elem, $regex) = @_;
 
  75     defined $href->{$elem} && $href->{$elem} =~ $regex
 
  76       or die "field '$elem' in group '$group' not valid", "\n";
 
  79   my $group = 'biller information';
 
  80   $check_re->($group, $biller_information, 'iban', qr{^(?:CH|LI)[0-9a-zA-Z]{19}$});
 
  82   $group = 'biller data';
 
  83   $check_re->($group, $biller_data, 'address_type', qr{^[KS]$});
 
  84   $check_re->($group, $biller_data, 'company', qr{^.{1,70}$});
 
  85   $check_re->($group, $biller_data, 'address_row1', qr{^.{0,70}$});
 
  86   $check_re->($group, $biller_data, 'address_row2', qr{^.{0,70}$});
 
  87   $check_re->($group, $biller_data, 'countrycode', qr{^[A-Z]{2}$});
 
  89   $group = 'payment information';
 
  90   $check_re->($group, $payment_information, 'amount', qr{^(?:(?:0|[1-9][0-9]{0,8})\.[0-9]{2})?$});
 
  91   $check_re->($group, $payment_information, 'currency', qr{^(?:CHF|EUR)$});
 
  93   $group = 'invoice recipient data';
 
  94   $check_re->($group, $invoice_recipient_data, 'address_type', qr{^[KS]$});
 
  95   $check_re->($group, $invoice_recipient_data, 'name', qr{^.{1,70}$});
 
  96   $check_re->($group, $invoice_recipient_data, 'address_row1', qr{^.{0,70}$});
 
  97   $check_re->($group, $invoice_recipient_data, 'address_row2', qr{^.{0,70}$});
 
  98   $check_re->($group, $invoice_recipient_data, 'countrycode', qr{^[A-Z]{2}$});
 
 100   $group = 'reference number data';
 
 101   my %ref_nr_regexes = (
 
 105   $check_re->($group, $ref_nr_data, 'type', qr{^(?:QRR|SCOR|NON)$});
 
 106   $check_re->($group, $ref_nr_data, 'ref_number', $ref_nr_regexes{$ref_nr_data->{type}});
 
 111   my $out_file = $_[0] // $Config{out_file};
 
 113   $self->{qrcode} = $self->_qrcode();
 
 114   $self->{cross}  = $self->_cross();
 
 115   $self->{img}    = $self->_plot();
 
 118   $self->_write($out_file);
 
 124   return Imager::QRCode->new(
 
 134   my $cross = Imager->new();
 
 135   $cross->read(file => $Config{cross_file}) or die $cross->errstr, "\n";
 
 137   return $cross->scale(xpixels => 35, ypixels => 35, qtype => 'mixing');
 
 144     @{$self->{data}{header}},
 
 145     @{$self->{data}{biller_information}},
 
 146     @{$self->{data}{biller_data}},
 
 147     ('') x 7, # for future use
 
 148     @{$self->{data}{payment_information}},
 
 149     @{$self->{data}{invoice_recipient_data}},
 
 150     @{$self->{data}{ref_nr_data}},
 
 151     @{$self->{data}{additional_information}},
 
 161   my $text = join "\015\012", @data;
 
 163   return $self->{qrcode}->plot($text);
 
 170     src  => $self->{cross},
 
 171     left => ($self->{img}->getwidth  / 2) - ($self->{cross}->getwidth  / 2),
 
 172     top  => ($self->{img}->getheight / 2) - ($self->{cross}->getheight / 2),
 
 180   $self->{img}->write(file => $out_file) or die $self->{img}->errstr, "\n";
 
 191 SL::Helper::QrBill - Helper methods for generating Swiss QR-Code
 
 195      use SL::Helper::QrBill;
 
 198        my $qr_image = SL::Helper::QrBill->new(
 
 199          \%biller_information,
 
 201          \%payment_information,
 
 202          \%invoice_recipient_data,
 
 205        $qr_image->generate($out_file);
 
 207        local $_ = $@; chomp; my $error = $_;
 
 208        $::form->error($::locale->text('QR-Image generation failed: ' . $error));
 
 213 This module generates the Swiss QR-Code with data provided to the constructor.
 
 219 Creates a new object. Expects five references to hashes as arguments.
 
 221 The hashes are structured as follows:
 
 225 =item C<%biller_information>
 
 233 Fixed length; 21 alphanumerical characters, only IBANs with CH- or LI-
 
 238 =item C<%biller_data>
 
 240 Fields: address_type, company, address_row1, address_row2 and countrycode.
 
 244 =item C<address_type>
 
 246 Fixed length; 1-digit, alphanumerical. 'K' implemented only.
 
 250 Maximum of 70 characters, name (surname allowable) or company.
 
 252 =item C<address_row1>
 
 254 Maximum of 70 characters, street/nr.
 
 256 =item C<address_row2>
 
 258 Maximum of 70 characters, postal code/place.
 
 262 2-digit country code according to ISO 3166-1.
 
 266 =item C<%payment_information>
 
 268 Fields: amount and currency.
 
 274 Decimal, no leading zeroes, maximum of 12 digits (inclusive decimal
 
 275 separator and places). Only dot as decimal separator is permitted.
 
 283 =item C<%invoice_recipient_data>
 
 285 Fields: address_type, name, address_row1, address_row2 and countrycode.
 
 289 =item C<address_type>
 
 291 Fixed length; 1-digit, alphanumerical. 'K' implemented only.
 
 295 Maximum of 70 characters, name (surname allowable) or company.
 
 297 =item C<address_row1>
 
 299 Maximum of 70 characters, street/nr.
 
 301 =item C<address_row2>
 
 303 Maximum of 70 characters, postal code/place.
 
 307 2-digit country code according to ISO 3166-1.
 
 311 =item C<%ref_nr_data>
 
 313 Fields: type and ref_number.
 
 319 Maximum of 4 characters, alphanumerical. QRR/SCOR/NON.
 
 323 QR-Reference: 27 characters, numerical; without Reference: empty.
 
 331 Generates the QR-Code image. Accepts filename of image as argument.
 
 332 Defaults to C<out.png>.
 
 336 Steven Schubiger E<lt>stsc@refcnt.orgE<gt>