1 package SL::Controller::ScanQRBill;
4 use parent qw(SL::Controller::Base);
6 use List::Util qw(first);
9 use SL::Helper::QrBillParser;
13 use SL::DB::ValidityToken;
15 use Rose::Object::MakeMethods::Generic(
17 'scalar --get_set_init' => [ qw(vendors accounts_AP_amount accounts_AP taxcharts) ],
21 __PACKAGE__->run_before(sub { $::auth->assert('ap_transactions'); });
23 ################ actions #################
25 sub action_scan_view {
28 $::request->layout->add_javascripts('html5-qrcode.js');
29 $::request->layout->add_javascripts('kivi.ScanQRBill.js');
31 $self->render('scan_qrbill/scan_view',
32 transaction_success => $::form->{transaction_success} // '0',
33 invoice_number => $::form->{invnumber} // '',
34 developer => $::auth->assert('developer', 1) ? '1' : '0',
38 sub action_handle_scan_result {
41 my $qrtext = $::form->{qrtext};
43 # load text into object
44 $self->{qr_obj} = SL::Helper::QrBillParser->new($qrtext);
46 # check if valid qr-bill
47 if (!$self->{qr_obj}->is_valid) {
49 ->run('kivi.ScanQRBill.popupInvalidQRBill', $self->{qr_obj}->error)
53 my $vendor_name = $self->{qr_obj}->{creditor}->{name};
54 $self->{vendor} = first { $_->{name} eq $vendor_name } @{ $self->vendors };
56 if (!$self->{vendor}) {
58 ->run('kivi.ScanQRBill.popupVendorNotFound', $vendor_name)
62 $self->prepare_add_purchase_transaction();
65 ################# internal ###############
67 sub prepare_add_purchase_transaction {
70 my $qr_obj = $self->{qr_obj};
72 my $token = SL::DB::ValidityToken->create(scope => SL::DB::ValidityToken::SCOPE_PURCHASE_INVOICE_POST())->token;
74 my $html = $self->render('scan_qrbill/_add_purchase_transaction',
77 name => $self->{vendor}->{name},
78 number => $self->{vendor}->{vendornumber},
79 id => $self->{vendor}->{id},
82 unstructured_message => $qr_obj->{additional_information}->{unstructured_message},
83 reference_type => $qr_obj->{payment_reference}->{reference_type},
84 reference => $qr_obj->{payment_reference}->{reference},
85 amount => $qr_obj->{payment_amount_information}->{amount},
86 currency => $qr_obj->{payment_amount_information}->{currency},
87 data_encoded => uri_escape($qr_obj->raw_data),
89 accounts_AP_amount => $self->accounts_AP_amount,
90 accounts_AP => $self->accounts_AP,
91 taxcharts => $self->taxcharts,
92 form_validity_token => $token,
95 $self->js->html('#main-content', $html)->render();
99 SL::DB::Manager::Vendor->get_all();
102 sub init_accounts_AP_amount {
104 text => "$_->{accno} - $_->{description}",
105 accno => $_->{accno},
107 chart_id => $_->{id},
108 } } @{ SL::DB::Manager::Chart->get_all(
109 query => [ SL::DB::Manager::Chart->link_filter('AP_amount') ],
110 sort_by => 'accno ASC') }
114 sub init_accounts_AP {
116 text => "$_->{accno} - $_->{description}",
117 accno => $_->{accno},
119 chart_id => $_->{id},
120 } } @{ SL::DB::Manager::Chart->get_all(
121 query => [ SL::DB::Manager::Chart->link_filter('AP') ],
122 sort_by => 'accno ASC') }
128 text => "$_->{taxkey} - $_->{taxdescription} " . ($_->{rate} * 100) .' %',
129 id => "$_->{id}--$_->{rate}",
130 } } @{ SL::DB::Manager::Tax->get_all(
131 where => [ chart_categories => { like => '%E%' }],
132 sort_by => 'taxkey, rate') }
146 SL::Controller::ScanQRBill - Controller for scanning swiss QR-Bills using the mobile template
150 Renders the scan view in the mobile template and handles the scan result.
152 The scanned QR-Bill data is parsed and the vendor is searched in the database.
154 If everything is valid an add purchase transaction view is rendered and
155 the QR-Bill can be saved as a purchase transaction.
157 The post function from ap.pl is used to save the purchase transaction.
159 The raw data of the QR-Bill is stored with the purchase transaction in the ap table
160 in the field qrbill_data.
161 The data can later be accessed again using the parser module SL::Helper::QrBillParser.
163 =head1 SECURITY CONSIDERATIONS
165 In theory an attacker could try to insert a malicious Javascript code into a qr code,
166 that is then scanned, and redisplayed in the browser (XSS).
168 Therefore it is important to escape any data coming from the qr code when it is rendered
169 in the templates. For this we use the template toolkit html filter: [% qrdata | html %],
170 Jquery's text function: $('#qrdata').text(qrdata);, and URI::Escape; for the raw data.
172 For database insertion we use prepared statements (AP.pm).
176 To simplify testing the scan view shows some buttons to send example qr codes, when in
177 developer mode. Sending is implemented in Javascript in js/kivi.ScanQRBill.js.
185 Renders the scan view in the mobile template.
187 =item C<handle_scan_result>
189 Handles the scan result and renders the add purchase transaction view.
195 =head2 Additional features:
199 =item * automatically extract invoice number and dates etc. from "SWICO-String" if present
201 =item * Option to add the vendor if not found
211 Cem Aydin E<lt>cem.aydin@revamp-it.chE<gt>