| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | #! perl --			-*- coding: utf-8 -*- | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 1 |  |  | 1 |  | 6 | use utf8; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 5 |  | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | # Booking.pm -- Base class for Bookings. | 
| 6 |  |  |  |  |  |  | # Author          : Johan Vromans | 
| 7 |  |  |  |  |  |  | # Created On      : Sat Oct 15 23:36:51 2005 | 
| 8 |  |  |  |  |  |  | # Last Modified By: Johan Vromans | 
| 9 |  |  |  |  |  |  | # Last Modified On: Thu Jan 26 16:39:38 2017 | 
| 10 |  |  |  |  |  |  | # Update Count    : 226 | 
| 11 |  |  |  |  |  |  | # Status          : Unknown, Use with caution! | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  | package main; | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | our $cfg; | 
| 16 |  |  |  |  |  |  | our $dbh; | 
| 17 |  |  |  |  |  |  |  | 
| 18 |  |  |  |  |  |  | package EB::Booking; | 
| 19 |  |  |  |  |  |  |  | 
| 20 | 1 |  |  | 1 |  | 55 | use strict; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 18 |  | 
| 21 | 1 |  |  | 1 |  | 4 | use warnings; | 
|  | 1 |  |  |  |  | 1 |  | 
|  | 1 |  |  |  |  | 21 |  | 
| 22 |  |  |  |  |  |  |  | 
| 23 | 1 |  |  | 1 |  | 4 | use EB; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 225 |  | 
| 24 | 1 |  |  | 1 |  | 7 | use EB::Format; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 113 |  | 
| 25 | 1 |  |  | 1 |  | 440 | use EB::Tools::Attachments; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 3252 |  | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | sub new { | 
| 28 | 0 |  |  | 0 | 0 |  | my ($class) = @_; | 
| 29 | 0 |  | 0 |  |  |  | $class = ref($class) || $class; | 
| 30 | 0 |  |  |  |  |  | return bless {} => $class; | 
| 31 |  |  |  |  |  |  | } | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | sub adm_open { | 
| 34 | 0 |  |  | 0 | 0 |  | my ($self) = @_; | 
| 35 | 0 | 0 |  |  |  |  | unless ( $dbh->adm_open ) { | 
| 36 | 0 |  |  |  |  |  | warn("?"._T("De administratie is nog niet geopend")."\n"); | 
| 37 | 0 |  |  |  |  |  | return; | 
| 38 |  |  |  |  |  |  | } | 
| 39 | 0 |  |  |  |  |  | 1; | 
| 40 |  |  |  |  |  |  | } | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  | sub check_bsk_nr { | 
| 43 | 0 |  |  | 0 | 0 |  | my ($self, $opts) = @_; | 
| 44 | 0 |  |  |  |  |  | my $bsk_nr = $opts->{boekstuk}; | 
| 45 | 0 |  |  |  |  |  | my $bky = $opts->{boekjaar}; | 
| 46 | 0 | 0 |  |  |  |  | $bky = $dbh->adm("bky") unless defined($bky); | 
| 47 | 0 |  |  |  |  |  | my $dbk = $opts->{dagboek}; | 
| 48 | 0 |  |  |  |  |  | my $rr = $dbh->do("SELECT count(*) FROM Boekstukken". | 
| 49 |  |  |  |  |  |  | " WHERE bsk_nr = ? AND bsk_dbk_id = ? AND bsk_bky = ?", | 
| 50 |  |  |  |  |  |  | $bsk_nr, $dbk, $bky); | 
| 51 | 0 | 0 | 0 |  |  |  | return 1 if defined($rr) && $rr->[0] == 0; | 
| 52 | 0 |  |  |  |  |  | warn("?".__x("Boekstuk {bsk} is reeds in gebruik", | 
| 53 |  |  |  |  |  |  | bsk => join(":", | 
| 54 |  |  |  |  |  |  | $dbh->lookup($dbk, qw(Dagboeken dbk_id dbk_desc)), | 
| 55 |  |  |  |  |  |  | $bsk_nr))."\n"); | 
| 56 | 0 |  |  |  |  |  | return; | 
| 57 |  |  |  |  |  |  | } | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | sub bsk_nr { | 
| 60 | 0 |  |  | 0 | 0 |  | my ($self, $opts) = @_; | 
| 61 | 0 |  |  |  |  |  | my $bsk_nr; | 
| 62 | 0 |  | 0 |  |  |  | my $prev = defined($opts->{boekjaar}) && $opts->{boekjaar} ne $dbh->adm("bky"); | 
| 63 | 0 |  |  |  |  |  | $bsk_nr = $opts->{boekstuk}; | 
| 64 | 0 | 0 |  |  |  |  | if ( defined $bsk_nr ) { | 
|  |  | 0 |  |  |  |  |  | 
| 65 | 0 | 0 |  |  |  |  | unless ( $bsk_nr =~ /^[0-9]+$/ ) { | 
| 66 | 0 |  |  |  |  |  | warn("?"._T("Het boekstuknummer moet een geheel getal (volgnummer) zijn")."\n"); | 
| 67 | 0 |  |  |  |  |  | return; | 
| 68 |  |  |  |  |  |  | } | 
| 69 | 0 | 0 |  |  |  |  | return unless $self->check_bsk_nr($opts); | 
| 70 | 0 | 0 |  |  |  |  | my $t = $prev ? "0" : $opts->{dagboek}; | 
| 71 | 0 |  |  |  |  |  | $dbh->set_sequence("bsk_nr_${t}_seq", $bsk_nr+1) | 
| 72 |  |  |  |  |  |  | #	  if $dbh->get_sequence("bsk_nr_${t}_seq", "noincr") < $bsk_nr; | 
| 73 |  |  |  |  |  |  | } | 
| 74 |  |  |  |  |  |  | elsif ( $prev ) { | 
| 75 | 0 |  |  |  |  |  | warn("?"._T("Boekstukken in voorafgaande boekjaren moeten verplicht worden voorzien van een boekstuknummer")."\n"); | 
| 76 | 0 |  |  |  |  |  | return; | 
| 77 |  |  |  |  |  |  | #$bsk_nr = $dbh->get_sequence("bsk_nr_0_seq"); | 
| 78 |  |  |  |  |  |  | } | 
| 79 |  |  |  |  |  |  | else { | 
| 80 | 0 |  |  |  |  |  | $bsk_nr = $dbh->get_sequence("bsk_nr_".$opts->{dagboek}."_seq"); | 
| 81 | 0 |  |  |  |  |  | $opts->{boekstuk} = $bsk_nr; | 
| 82 | 0 | 0 |  |  |  |  | return unless $self->check_bsk_nr($opts); | 
| 83 |  |  |  |  |  |  | } | 
| 84 | 0 |  |  |  |  |  | $bsk_nr; | 
| 85 |  |  |  |  |  |  | } | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  | sub begindate { | 
| 88 | 0 |  |  | 0 | 0 |  | my ($self) = @_; | 
| 89 |  |  |  |  |  |  |  | 
| 90 | 0 |  |  |  |  |  | my $begin; | 
| 91 |  |  |  |  |  |  | my $end; | 
| 92 | 0 | 0 |  |  |  |  | if ( $self->{bky} ne $dbh->adm("bky") ) { | 
|  |  | 0 |  |  |  |  |  | 
| 93 | 0 |  |  |  |  |  | my ($b, $e, $c) = @{$dbh->do("SELECT bky_begin, bky_end, bky_closed". | 
| 94 |  |  |  |  |  |  | " FROM Boekjaren". | 
| 95 | 0 |  |  |  |  |  | " WHERE bky_code = ?", $self->{bky})}; | 
| 96 | 0 | 0 |  |  |  |  | if ( $c ) { | 
| 97 |  |  |  |  |  |  | warn("?".__x("Boekjaar {code} is gesloten, er kan niet meer in worden gewijzigd", | 
| 98 | 0 |  |  |  |  |  | code => $self->{bky})."\n"); | 
| 99 | 0 |  |  |  |  |  | return; | 
| 100 |  |  |  |  |  |  | } | 
| 101 | 0 |  |  |  |  |  | $begin = $b; | 
| 102 | 0 |  |  |  |  |  | $end = $e; | 
| 103 |  |  |  |  |  |  | } | 
| 104 |  |  |  |  |  |  | elsif ( $dbh->adm("closed") ) { | 
| 105 | 0 |  |  |  |  |  | warn("?"._T("De administratie is gesloten en kan niet meer worden gewijzigd")."\n"); | 
| 106 | 0 |  |  |  |  |  | return; | 
| 107 |  |  |  |  |  |  | } | 
| 108 | 0 |  | 0 |  |  |  | $begin ||= $dbh->adm("begin"); | 
| 109 | 0 | 0 |  |  |  |  | return $begin unless wantarray; | 
| 110 | 0 |  | 0 |  |  |  | $end ||= $dbh->adm("end"); | 
| 111 | 0 |  |  |  |  |  | ($begin, $end); | 
| 112 |  |  |  |  |  |  | } | 
| 113 |  |  |  |  |  |  |  | 
| 114 |  |  |  |  |  |  | sub in_bky { | 
| 115 | 0 |  |  | 0 | 0 |  | my ($self, $date, $begin, $end) = @_; | 
| 116 | 0 | 0 |  |  |  |  | if ( $date lt $begin ) { | 
| 117 | 0 |  |  |  |  |  | warn("?".__x("De boekingsdatum {date} valt vóór aanvang van dit boekjaar", | 
| 118 |  |  |  |  |  |  | date => datefmt_full($date))."\n"); | 
| 119 | 0 |  |  |  |  |  | return; | 
| 120 |  |  |  |  |  |  | } | 
| 121 | 0 | 0 |  |  |  |  | if ( $date gt $end ) { | 
| 122 | 0 |  |  |  |  |  | warn("?".__x("De boekingsdatum {date} valt na het einde van dit boekjaar", | 
| 123 |  |  |  |  |  |  | date => datefmt_full($date))."\n"); | 
| 124 | 0 |  |  |  |  |  | return; | 
| 125 |  |  |  |  |  |  | } | 
| 126 | 0 |  |  |  |  |  | 1; | 
| 127 |  |  |  |  |  |  | } | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | sub amount_with_btw { | 
| 130 | 0 |  |  | 0 | 0 |  | my ($self, $amt, $btw_spec) = @_; | 
| 131 | 0 |  |  |  |  |  | my $explicit; | 
| 132 | 0 | 0 |  |  |  |  | if ( $amt =~ /^(.+)\@(.+)$/ ) { | 
| 133 | 0 |  |  |  |  |  | $amt = $1; | 
| 134 | 0 |  |  |  |  |  | $btw_spec = $2; | 
| 135 | 0 |  |  |  |  |  | $explicit = $btw_spec !~ /^[hlgn]?[-+]?[ko]?$/i; | 
| 136 |  |  |  |  |  |  | } | 
| 137 | 0 |  |  |  |  |  | return (amount($amt), $btw_spec, $explicit); | 
| 138 |  |  |  |  |  |  | } | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | sub parse_btw_spec { | 
| 141 | 0 |  |  | 0 | 0 |  | my ($self, $spec, $btw_id, $kstomz) = @_; | 
| 142 | 0 | 0 |  |  |  |  | return (0, undef) unless defined($spec); | 
| 143 | 0 |  |  |  |  |  | $spec = lc($spec); | 
| 144 |  |  |  |  |  |  |  | 
| 145 |  |  |  |  |  |  | # Quickie for G/N. | 
| 146 | 0 | 0 | 0 |  |  |  | if ( $spec =~ /^([gn])$/ ) { | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 147 | 0 |  |  |  |  |  | return (0, undef); | 
| 148 |  |  |  |  |  |  | } | 
| 149 |  |  |  |  |  |  | # Quickie for K/O. | 
| 150 |  |  |  |  |  |  | elsif ( $spec =~ /^([ko])$/ ) { | 
| 151 | 0 |  |  |  |  |  | return ($btw_id, $1 eq 'k'); | 
| 152 |  |  |  |  |  |  | } | 
| 153 |  |  |  |  |  |  | # Strip off trailing K|O. | 
| 154 |  |  |  |  |  |  | elsif ( $spec =~ /^([hl]|\d+)([-+]?)([ko])$/ || $spec =~ /^(\w+)([-+])([ko])$/ ) { | 
| 155 | 0 |  |  |  |  |  | $kstomz = $3 eq 'k'; | 
| 156 | 0 |  |  |  |  |  | $spec = $1.$2; | 
| 157 |  |  |  |  |  |  | } | 
| 158 |  |  |  |  |  |  |  | 
| 159 |  |  |  |  |  |  | =begin deprecated | 
| 160 |  |  |  |  |  |  |  | 
| 161 |  |  |  |  |  |  | # Deprecated since several years... | 
| 162 |  |  |  |  |  |  | elseif ( $spec =~ /^(.*)([iv])(.*)$/ ) { | 
| 163 |  |  |  |  |  |  | $kstomz = $2 eq 'i'; | 
| 164 |  |  |  |  |  |  | $spec = $1.$3; | 
| 165 |  |  |  |  |  |  | warn("!".__x("BTW specificatie {spec}: Gebruik K of O in plaats van I of V", | 
| 166 |  |  |  |  |  |  | spec => $_[0])."\n"); | 
| 167 |  |  |  |  |  |  | } | 
| 168 |  |  |  |  |  |  |  | 
| 169 |  |  |  |  |  |  | =cut | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | # Examine rest. Numeric -> BTW id. | 
| 172 | 0 | 0 | 0 |  |  |  | if ( $spec =~ /^(\d+)([-+])?$/ ) { | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 173 | 0 |  |  |  |  |  | $btw_id = $1; | 
| 174 | 0 | 0 |  |  |  |  | if ( defined $2 ) { | 
| 175 | 0 |  |  |  |  |  | my $excl = $2 eq '-'; | 
| 176 | 0 |  |  |  |  |  | my $res = $dbh->do("SELECT btw_perc, btw_tariefgroep FROM BTWTabel". | 
| 177 |  |  |  |  |  |  | " WHERE btw_id = ?", | 
| 178 |  |  |  |  |  |  | $btw_id); | 
| 179 | 0 | 0 |  |  |  |  | return unless $res; | 
| 180 | 0 | 0 |  |  |  |  | $res = $dbh->do("SELECT btw_id FROM BTWTabel". | 
| 181 |  |  |  |  |  |  | " WHERE btw_perc = ? AND btw_tariefgroep = ?". | 
| 182 |  |  |  |  |  |  | "  AND ".($excl?"NOT ":"")."btw_incl", | 
| 183 |  |  |  |  |  |  | $res->[0], $res->[1]); | 
| 184 | 0 | 0 |  |  |  |  | return unless $res; | 
| 185 | 0 |  |  |  |  |  | $btw_id = $res->[0]; | 
| 186 |  |  |  |  |  |  | } | 
| 187 |  |  |  |  |  |  | } | 
| 188 |  |  |  |  |  |  | # H L H- L- H+ L+ | 
| 189 |  |  |  |  |  |  | elsif ( $spec =~ /^([hl])([-+])?$/ ) { | 
| 190 | 0 |  |  |  |  |  | $btw_id = $1; | 
| 191 | 0 |  |  |  |  |  | my $excl; | 
| 192 | 0 | 0 |  |  |  |  | $excl = $2 eq '-' if defined $2; | 
| 193 | 0 | 0 |  |  |  |  | my $res = $dbh->da("SELECT btw_id, btw_alias, btw_desc FROM BTWTabel". | 
|  |  | 0 |  |  |  |  |  | 
| 194 |  |  |  |  |  |  | " WHERE btw_tariefgroep = ?". | 
| 195 |  |  |  |  |  |  | " AND ".($excl?"NOT ":"")."btw_incl". | 
| 196 |  |  |  |  |  |  | " ORDER BY btw_id ASC", | 
| 197 |  |  |  |  |  |  | $btw_id eq "h" ? BTWTARIEF_HOOG : BTWTARIEF_LAAG); | 
| 198 |  |  |  |  |  |  | warn("!".__x("BTW aanduiding \"{spec}\" kent meerdere tariefcodes: {list} (code {code} \"{desc}\" is gebruikt)", | 
| 199 |  |  |  |  |  |  | spec => $spec, | 
| 200 | 0 | 0 |  |  |  |  | list => join(" ", map { defined($_->[1]) ? $_->[1] : $_->[0] } @$res), | 
|  | 0 | 0 |  |  |  |  |  | 
| 201 |  |  |  |  |  |  | code => $res->[0]->[0], | 
| 202 |  |  |  |  |  |  | desc => $res->[0]->[2], | 
| 203 |  |  |  |  |  |  | )."\n") if @$res != 1; | 
| 204 | 0 |  |  |  |  |  | $btw_id = $res->[0]->[0]; | 
| 205 |  |  |  |  |  |  | } | 
| 206 |  |  |  |  |  |  | # alias | 
| 207 |  |  |  |  |  |  | elsif ( $spec =~ /^(\w\w+)([-+])?$/ ) { | 
| 208 |  |  |  |  |  |  | # warn("SPEC: $spec\n"); $dbh->trace(1); | 
| 209 | 0 |  |  |  |  |  | my $res = $dbh->do("SELECT btw_id, btw_perc, btw_tariefgroep FROM BTWTabel". | 
| 210 |  |  |  |  |  |  | " WHERE btw_alias = ?", | 
| 211 |  |  |  |  |  |  | lc $1); | 
| 212 |  |  |  |  |  |  | # $dbh->trace(0); | 
| 213 | 0 | 0 |  |  |  |  | return unless $res; | 
| 214 |  |  |  |  |  |  |  | 
| 215 | 0 |  |  |  |  |  | $btw_id = $res->[0]; | 
| 216 | 0 | 0 |  |  |  |  | if ( defined $2 ) { | 
| 217 | 0 |  |  |  |  |  | my $excl = $2 eq '-'; | 
| 218 |  |  |  |  |  |  | # $dbh->trace(1); | 
| 219 | 0 | 0 |  |  |  |  | $res = $dbh->do("SELECT btw_id FROM BTWTabel". | 
| 220 |  |  |  |  |  |  | " WHERE btw_perc = ? AND btw_tariefgroep = ?". | 
| 221 |  |  |  |  |  |  | "  AND ".($excl?"NOT ":"")."btw_incl", | 
| 222 |  |  |  |  |  |  | $res->[1], $res->[2]); | 
| 223 |  |  |  |  |  |  | # $dbh->trace(0); | 
| 224 | 0 | 0 |  |  |  |  | return unless $res; | 
| 225 | 0 |  |  |  |  |  | $btw_id = $res->[0]; | 
| 226 |  |  |  |  |  |  | } | 
| 227 |  |  |  |  |  |  | # warn("SPEC: $spec => $btw_id\n"); | 
| 228 |  |  |  |  |  |  | } | 
| 229 |  |  |  |  |  |  | # + - | 
| 230 |  |  |  |  |  |  | elsif ( $spec =~ /^([-+])$/ && $btw_id ) { | 
| 231 | 0 | 0 |  |  |  |  | my $res = $dbh->da("SELECT btw_id, btw_desc FROM BTWTabel". | 
| 232 |  |  |  |  |  |  | " WHERE btw_tariefgroep =". | 
| 233 |  |  |  |  |  |  | " ( SELECT btw_tariefgroep FROM BTWTabel". | 
| 234 |  |  |  |  |  |  | " WHERE btw_id = ? )". | 
| 235 |  |  |  |  |  |  | " AND ".($1 eq '-'?"NOT ":"")."btw_incl", | 
| 236 |  |  |  |  |  |  | $btw_id); | 
| 237 |  |  |  |  |  |  | warn("!".__x("BTW aanduiding \"{spec}\" kent meerdere tariefcodes: {list} (code {code} \"{desc}\" is gebruikt)", | 
| 238 |  |  |  |  |  |  | spec => $spec, | 
| 239 | 0 | 0 |  |  |  |  | list => join(" ", map { $_->[0] } @$res), | 
|  | 0 |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | code => $res->[0]->[0], | 
| 241 |  |  |  |  |  |  | desc => $res->[0]->[1], | 
| 242 |  |  |  |  |  |  | )."\n") if @$res != 1; | 
| 243 | 0 |  |  |  |  |  | $btw_id = $res->[0]->[0]; | 
| 244 |  |  |  |  |  |  | } | 
| 245 |  |  |  |  |  |  | elsif ( $spec ne '' ) { | 
| 246 | 0 |  |  |  |  |  | return; | 
| 247 |  |  |  |  |  |  | } | 
| 248 | 0 |  |  |  |  |  | ($btw_id, $kstomz); | 
| 249 |  |  |  |  |  |  | } | 
| 250 |  |  |  |  |  |  |  | 
| 251 |  |  |  |  |  |  | #### Class method | 
| 252 |  |  |  |  |  |  | sub norm_btw { | 
| 253 | 0 |  |  | 0 | 0 |  | my ($self, $bsr_amt, $bsr_btw_id) = @_; | 
| 254 | 0 |  |  |  |  |  | my ($btw_perc, $btw_incl); | 
| 255 | 0 | 0 |  |  |  |  | if ( $bsr_btw_id ) { | 
| 256 | 0 |  |  |  |  |  | my $rr = $dbh->do("SELECT btw_perc, btw_incl, btw_tariefgroep". | 
| 257 |  |  |  |  |  |  | " FROM BTWTabel". | 
| 258 |  |  |  |  |  |  | " WHERE btw_id = ?", $bsr_btw_id); | 
| 259 | 0 | 0 |  |  |  |  | confess( "Unknown BTW: $bsr_btw_id" ) unless $rr; | 
| 260 | 0 |  |  |  |  |  | ($btw_perc, $btw_incl) = @$rr; | 
| 261 |  |  |  |  |  |  | } | 
| 262 |  |  |  |  |  |  |  | 
| 263 | 0 | 0 |  |  |  |  | return [ $bsr_amt, 0 ] unless $btw_perc; | 
| 264 |  |  |  |  |  |  |  | 
| 265 | 0 |  |  |  |  |  | my $bruto = $bsr_amt; | 
| 266 | 0 |  |  |  |  |  | my $netto = $bsr_amt; | 
| 267 |  |  |  |  |  |  |  | 
| 268 | 0 | 0 |  |  |  |  | if ( $btw_incl ) { | 
| 269 | 0 |  |  |  |  |  | $netto = numround($bruto * (1 / (1 + $btw_perc/BTWSCALE))); | 
| 270 |  |  |  |  |  |  | } | 
| 271 |  |  |  |  |  |  | else { | 
| 272 | 0 |  |  |  |  |  | $bruto = numround($netto * (1 + $btw_perc/BTWSCALE)); | 
| 273 |  |  |  |  |  |  | } | 
| 274 |  |  |  |  |  |  |  | 
| 275 | 0 |  |  |  |  |  | [ $bruto, $bruto - $netto, $btw_perc ]; | 
| 276 |  |  |  |  |  |  | } | 
| 277 |  |  |  |  |  |  |  | 
| 278 |  |  |  |  |  |  | #### Class method | 
| 279 |  |  |  |  |  |  | sub dcfromtd { | 
| 280 |  |  |  |  |  |  | # Calculate a (debet,credit) pair from a (total,debet) pair. | 
| 281 | 0 |  |  | 0 | 0 |  | my ($total, $debet) = @_; | 
| 282 | 0 | 0 |  |  |  |  | return ($debet, $debet-$total) if defined($debet); | 
| 283 | 0 | 0 |  |  |  |  | return ($total, 0) if $total >= 0; | 
| 284 | 0 |  |  |  |  |  | (0, -$total); | 
| 285 |  |  |  |  |  |  | } | 
| 286 |  |  |  |  |  |  |  | 
| 287 |  |  |  |  |  |  | #### Class method | 
| 288 |  |  |  |  |  |  | sub journalise { | 
| 289 | 0 |  |  | 0 | 0 |  | my ($self, $bsk_id, $iv, $total) = @_; | 
| 290 | 0 | 0 | 0 |  |  |  | $total = -$total if defined($total) && !$iv; | 
| 291 |  |  |  |  |  |  |  | 
| 292 |  |  |  |  |  |  | # date  bsk_id  bsr_seq(0)   dbk_id  (acc_id) amount debcrd desc(bsk) (rel) | 
| 293 |  |  |  |  |  |  | # date (bsk_id) bsr_seq(>0) (dbk_id)  acc_id  amount debcrd desc(bsr) rel(acc=1200/1600) | 
| 294 | 0 |  |  |  |  |  | my ($jnl_date, $jnl_bsk_id, $jnl_dbk_id, $jnl_acc_id, | 
| 295 |  |  |  |  |  |  | $jnl_amount, $jnl_desc, $jnl_rel); | 
| 296 |  |  |  |  |  |  |  | 
| 297 | 0 |  |  |  |  |  | my $rr = $::dbh->do("SELECT bsk_nr, bsk_desc, bsk_dbk_id, bsk_date, bsk_ref". | 
| 298 |  |  |  |  |  |  | " FROM Boekstukken". | 
| 299 |  |  |  |  |  |  | " WHERE bsk_id = ?", $bsk_id); | 
| 300 | 0 |  |  |  |  |  | my ($bsk_nr, $bsk_desc, $bsk_dbk_id, $bsk_date, $bsk_ref) = @$rr; | 
| 301 |  |  |  |  |  |  |  | 
| 302 |  |  |  |  |  |  | my ($dbktype, $dbkdcsplit, $dbk_acc_id) = | 
| 303 | 0 |  |  |  |  |  | @{$::dbh->do("SELECT dbk_type, dbk_dcsplit, dbk_acc_id". | 
|  | 0 |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | " FROM Dagboeken". | 
| 305 |  |  |  |  |  |  | " WHERE dbk_id = ?", $bsk_dbk_id)}; | 
| 306 | 0 |  |  |  |  |  | my $sth = $::dbh->sql_exec("SELECT bsr_nr, bsr_date, ". | 
| 307 |  |  |  |  |  |  | "bsr_desc, bsr_amount, bsr_btw_class, bsr_btw_id, ". | 
| 308 |  |  |  |  |  |  | "bsr_btw_acc, bsr_type, bsr_acc_id, bsr_rel_code, bsr_dbk_id". | 
| 309 |  |  |  |  |  |  | " FROM Boekstukregels". | 
| 310 |  |  |  |  |  |  | " WHERE bsr_bsk_id = ?", $bsk_id); | 
| 311 |  |  |  |  |  |  |  | 
| 312 | 0 |  |  |  |  |  | my $ret = []; | 
| 313 | 0 |  |  |  |  |  | my $tot = 0; | 
| 314 | 0 |  |  |  |  |  | my ($dtot, $ctot) = (0, 0); | 
| 315 | 0 |  |  |  |  |  | my ($vhtot, $vltot) = (0, 0); | 
| 316 | 0 |  |  |  |  |  | my $nr = 1; | 
| 317 | 0 |  |  |  |  |  | my $vat; 			# for automatic rounding VAT calc | 
| 318 |  |  |  |  |  |  | my $g_bsr_rel_code; | 
| 319 |  |  |  |  |  |  |  | 
| 320 | 0 |  |  |  |  |  | while ( $rr = $sth->fetchrow_arrayref ) { | 
| 321 | 0 |  |  |  |  |  | my ($bsr_nr, $bsr_date, $bsr_desc, $bsr_amount, $bsr_btw_class, | 
| 322 |  |  |  |  |  |  | $bsr_btw_id, $bsr_btw_acc, $bsr_type, $bsr_acc_id, $bsr_rel_code, | 
| 323 |  |  |  |  |  |  | $bsr_rel_dbk) = @$rr; | 
| 324 | 0 |  |  |  |  |  | my $bsr_bsk_id = $bsk_id; | 
| 325 | 0 |  |  |  |  |  | my $btw = 0; | 
| 326 | 0 |  |  |  |  |  | my $amt = $bsr_amount; | 
| 327 | 0 |  |  |  |  |  | my $btw_intra = ($bsr_btw_class & BTWKLASSE_TYPE_BITS) == BTWTYPE_INTRA; | 
| 328 | 0 | 0 | 0 |  |  |  | $g_bsr_rel_code = $bsr_rel_code if defined $iv && $bsr_rel_code; | 
| 329 |  |  |  |  |  |  |  | 
| 330 | 0 | 0 | 0 |  |  |  | if ( ($bsr_btw_class & BTWKLASSE_BTW_BIT) && $bsr_btw_id && $bsr_btw_acc && !$btw_intra ) { | 
|  |  |  | 0 |  |  |  |  | 
|  |  |  | 0 |  |  |  |  | 
| 331 |  |  |  |  |  |  | ( $bsr_amount, $btw, my $perc ) = | 
| 332 | 0 |  |  |  |  |  | @{$self->norm_btw($bsr_amount, $bsr_btw_id)}; | 
|  | 0 |  |  |  |  |  |  | 
| 333 | 0 |  |  |  |  |  | $amt = $bsr_amount - $btw; | 
| 334 | 0 |  |  |  |  |  | $vat->{$bsr_btw_acc}->{amt} += $amt; | 
| 335 | 0 |  |  |  |  |  | $vat->{$bsr_btw_acc}->{btw} += $btw; | 
| 336 | 0 |  |  |  |  |  | $vat->{$bsr_btw_acc}->{prc} = $perc; | 
| 337 |  |  |  |  |  |  | } | 
| 338 | 0 |  |  |  |  |  | $tot += $bsr_amount; | 
| 339 | 0 | 0 |  |  |  |  | $dtot += $bsr_amount if $bsr_amount < 0; | 
| 340 | 0 | 0 |  |  |  |  | $ctot += $bsr_amount if $bsr_amount > 0; | 
| 341 | 0 |  |  |  |  |  | my $btwtag = _T("BTW "); | 
| 342 | 0 | 0 |  |  |  |  | push(@$ret, [$bsk_date, $bsk_dbk_id, $bsk_id, $bsr_date, $bsr_nr, $nr++, | 
| 343 |  |  |  |  |  |  | 0, $bsr_acc_id, | 
| 344 |  |  |  |  |  |  | $bsr_amount - $btw, undef, $bsr_desc, | 
| 345 |  |  |  |  |  |  | $bsr_type ? ($bsr_rel_code, $bsr_rel_dbk) : (undef, undef), undef]); | 
| 346 | 0 | 0 |  |  |  |  | push(@$ret, [$bsk_date,  $bsk_dbk_id, $bsk_id, $bsr_date, $bsr_nr, $nr++, | 
| 347 |  |  |  |  |  |  | 1, $bsr_btw_acc, | 
| 348 |  |  |  |  |  |  | $btw, undef, $btwtag.$bsr_desc, | 
| 349 |  |  |  |  |  |  | undef, undef, undef]) if $btw; | 
| 350 |  |  |  |  |  |  | } | 
| 351 |  |  |  |  |  |  |  | 
| 352 | 0 | 0 | 0 |  |  |  | if ( defined($total) && $tot != $total | 
|  |  |  | 0 |  |  |  |  | 
| 353 |  |  |  |  |  |  | && $cfg->val(qw(strategy iv_vc), 1) | 
| 354 |  |  |  |  |  |  | ) { # mismatch! | 
| 355 |  |  |  |  |  |  | #warn("=> $tot <-> $total\n"); | 
| 356 |  |  |  |  |  |  | # Vaak het gevolg van verschil in BTW berekening per | 
| 357 |  |  |  |  |  |  | # boekingsregel versus per boekstuktotaal. | 
| 358 |  |  |  |  |  |  |  | 
| 359 | 0 |  |  |  |  |  | while ( my($k,$v) = each(%$vat) ) { | 
| 360 |  |  |  |  |  |  | # Bereken BTW over totaal van deze tariefgroep. | 
| 361 | 0 |  |  |  |  |  | my $t = numround($v->{amt} * ($v->{prc}/BTWSCALE)); | 
| 362 | 0 | 0 |  |  |  |  | if ( $t != $v->{btw} ) { # Aha! | 
| 363 |  |  |  |  |  |  | #warn("=> [$k] $v->{btw} <-> $t\n"); | 
| 364 |  |  |  |  |  |  | # Corrigeer het totaal, en maak een correctieboekstukregel. | 
| 365 | 0 |  |  |  |  |  | $tot -= $v->{btw} - $t; | 
| 366 |  |  |  |  |  |  | push(@$ret, [$bsk_date,  $bsk_dbk_id, $bsk_id, $bsk_date, undef, $nr++, | 
| 367 |  |  |  |  |  |  | 1, $k, | 
| 368 | 0 |  |  |  |  |  | $t - $v->{btw}, undef, _T("BTW Afr. ").$bsk_desc, | 
| 369 |  |  |  |  |  |  | undef, undef, undef]); | 
| 370 |  |  |  |  |  |  | warn("!".__x("BTW rek. nr. {acct}, correctie van {amt} uitgevoerd", | 
| 371 | 0 |  |  |  |  |  | acct => $k, amt => numfmt($t-$v->{btw}))."\n"); | 
| 372 |  |  |  |  |  |  | } | 
| 373 |  |  |  |  |  |  | } | 
| 374 |  |  |  |  |  |  | } | 
| 375 |  |  |  |  |  |  |  | 
| 376 | 0 | 0 |  |  |  |  | if ( $dbk_acc_id ) { | 
| 377 | 0 | 0 |  |  |  |  | if ( $dbkdcsplit ) { | 
| 378 | 0 |  |  |  |  |  | push(@$ret, [$bsk_date,  $bsk_dbk_id, $bsk_id, $bsk_date, undef, $nr++, | 
| 379 |  |  |  |  |  |  | 0, $dbk_acc_id, | 
| 380 |  |  |  |  |  |  | -$tot, -$dtot, $bsk_desc, undef, undef, undef]); | 
| 381 |  |  |  |  |  |  | } | 
| 382 |  |  |  |  |  |  | else { | 
| 383 | 0 |  |  |  |  |  | push(@$ret, [$bsk_date,  $bsk_dbk_id, $bsk_id, $bsk_date, undef, $nr++, | 
| 384 |  |  |  |  |  |  | 0, $dbk_acc_id, | 
| 385 |  |  |  |  |  |  | -$tot, undef, $bsk_desc, undef, undef, undef]); | 
| 386 |  |  |  |  |  |  | } | 
| 387 |  |  |  |  |  |  | } | 
| 388 |  |  |  |  |  |  |  | 
| 389 | 0 |  |  |  |  |  | unshift(@$ret, [$bsk_date, $bsk_dbk_id, $bsk_id, $bsk_date, undef, 0, 0, undef, | 
| 390 |  |  |  |  |  |  | undef, undef, $bsk_desc, $g_bsr_rel_code, undef, $bsk_ref]); | 
| 391 |  |  |  |  |  |  |  | 
| 392 | 0 |  |  |  |  |  | $ret; | 
| 393 |  |  |  |  |  |  | } | 
| 394 |  |  |  |  |  |  |  | 
| 395 |  |  |  |  |  |  | sub check_attachment { | 
| 396 | 0 |  |  | 0 | 0 |  | my ( $self, $att ) = @_; | 
| 397 | 0 | 0 |  |  |  |  | return 1 unless defined $att; | 
| 398 |  |  |  |  |  |  |  | 
| 399 | 0 | 0 |  |  |  |  | return 1 if $att =~ m;^(\w+)://(.+);; # URI | 
| 400 |  |  |  |  |  |  |  | 
| 401 | 0 | 0 | 0 |  |  |  | if ( ! ( -f $att && -r _ ) ) { | 
| 402 | 0 |  |  |  |  |  | warn("?".__x("Boekingsbijlage kan niet worden gevonden: {att}", | 
| 403 |  |  |  |  |  |  | att => $att)."\n"); | 
| 404 | 0 |  |  |  |  |  | return; | 
| 405 |  |  |  |  |  |  | } | 
| 406 |  |  |  |  |  |  |  | 
| 407 | 0 |  |  |  |  |  | return 1; | 
| 408 |  |  |  |  |  |  | } | 
| 409 |  |  |  |  |  |  |  | 
| 410 |  |  |  |  |  |  | sub add_attachment { | 
| 411 | 0 |  |  | 0 | 0 |  | my ( $self, $att, $bsk_id ) = @_; | 
| 412 | 0 | 0 |  |  |  |  | return unless defined $att; | 
| 413 | 0 |  |  |  |  |  | my $att_id; | 
| 414 |  |  |  |  |  |  |  | 
| 415 | 0 | 0 |  |  |  |  | if ( $att =~ m;^(\w+)://(.+); ) { # URI | 
| 416 | 0 | 0 | 0 |  |  |  | if ( $1 eq "int" && $2 =~ m;^(\d+)/.+; ) { | 
| 417 | 0 |  |  |  |  |  | $att_id = $1; | 
| 418 |  |  |  |  |  |  | } | 
| 419 |  |  |  |  |  |  | else { | 
| 420 | 0 |  |  |  |  |  | $att_id = EB::Tools::Attachments->new->store_from_uri($att); | 
| 421 |  |  |  |  |  |  | } | 
| 422 |  |  |  |  |  |  | } | 
| 423 |  |  |  |  |  |  | else { | 
| 424 |  |  |  |  |  |  | # We may at some point in time decide to turn $file into | 
| 425 |  |  |  |  |  |  | # file://$url and treat as such. | 
| 426 | 0 |  |  |  |  |  | $att_id = EB::Tools::Attachments->new->store_from_file($att); | 
| 427 |  |  |  |  |  |  | } | 
| 428 | 0 |  |  |  |  |  | $dbh->sql_exec("UPDATE Boekstukken SET bsk_att = ? WHERE bsk_id = ?", | 
| 429 |  |  |  |  |  |  | $att_id, $bsk_id); | 
| 430 |  |  |  |  |  |  | } | 
| 431 |  |  |  |  |  |  |  | 
| 432 |  |  |  |  |  |  | sub find_attachment { | 
| 433 | 0 |  |  | 0 | 0 |  | my ( $self, $bsk_id ) = @_; | 
| 434 | 0 |  |  |  |  |  | $dbh->lookup( $bsk_id, qw(Boekstukken bsk_id bsk_att =) ); | 
| 435 |  |  |  |  |  |  | } | 
| 436 |  |  |  |  |  |  |  | 
| 437 |  |  |  |  |  |  | 1; |