|
1 |
package SL::Controller::BankTransaction;
|
|
2 |
|
|
3 |
# idee- möglichkeit bankdaten zu übernehmen in stammdaten
|
|
4 |
# erst Kontenabgleich, um alle gl-Einträge wegzuhaben
|
|
5 |
use strict;
|
|
6 |
|
|
7 |
use parent qw(SL::Controller::Base);
|
|
8 |
|
|
9 |
use SL::Controller::Helper::GetModels;
|
|
10 |
use SL::Controller::Helper::ReportGenerator;
|
|
11 |
use SL::ReportGenerator;
|
|
12 |
|
|
13 |
use SL::DB::BankTransaction;
|
|
14 |
use SL::Helper::Flash;
|
|
15 |
use SL::Locale::String;
|
|
16 |
use SL::SEPA;
|
|
17 |
use SL::DB::Invoice;
|
|
18 |
use SL::DB::PurchaseInvoice;
|
|
19 |
use SL::DB::RecordLink;
|
|
20 |
use SL::JSON;
|
|
21 |
use SL::DB::Chart;
|
|
22 |
use SL::DB::AccTransaction;
|
|
23 |
use SL::DB::Tax;
|
|
24 |
use SL::DB::Draft;
|
|
25 |
use SL::DB::BankAccount;
|
|
26 |
|
|
27 |
use Rose::Object::MakeMethods::Generic
|
|
28 |
(
|
|
29 |
'scalar --get_set_init' => [ qw(models) ],
|
|
30 |
);
|
|
31 |
|
|
32 |
__PACKAGE__->run_before('check_auth');
|
|
33 |
|
|
34 |
|
|
35 |
#
|
|
36 |
# actions
|
|
37 |
#
|
|
38 |
|
|
39 |
sub action_search {
|
|
40 |
my ($self) = @_;
|
|
41 |
|
|
42 |
my $bank_accounts = SL::DB::Manager::BankAccount->get_all();
|
|
43 |
|
|
44 |
$self->render('bank_transactions/search',
|
|
45 |
label_sub => sub { t8('#1 - Account number #2, bank code #3, #4', $_[0]->name, $_[0]->account_number, $_[0]->bank_code, $_[0]->bank, )},
|
|
46 |
BANK_ACCOUNTS => $bank_accounts);
|
|
47 |
}
|
|
48 |
|
|
49 |
sub action_list_all {
|
|
50 |
my ($self) = @_;
|
|
51 |
|
|
52 |
my $transactions = $self->models->get;
|
|
53 |
|
|
54 |
$self->make_filter_summary;
|
|
55 |
$self->prepare_report;
|
|
56 |
|
|
57 |
$self->report_generator_list_objects(report => $self->{report}, objects => $transactions);
|
|
58 |
}
|
|
59 |
|
|
60 |
sub action_list {
|
|
61 |
my ($self) = @_;
|
|
62 |
|
|
63 |
if (!$::form->{filter}{bank_account}) {
|
|
64 |
flash('error', t8('No bank account chosen!'));
|
|
65 |
$self->action_search;
|
|
66 |
return;
|
|
67 |
}
|
|
68 |
|
|
69 |
my $sort_by = $::form->{sort_by} || 'transdate';
|
|
70 |
$sort_by = 'transdate' if $sort_by eq 'proposal';
|
|
71 |
$sort_by .= $::form->{sort_dir} ? ' DESC' : ' ASC';
|
|
72 |
|
|
73 |
my $fromdate = $::locale->parse_date_to_object(\%::myconfig, $::form->{filter}->{fromdate});
|
|
74 |
my $todate = $::locale->parse_date_to_object(\%::myconfig, $::form->{filter}->{todate});
|
|
75 |
$todate->add( days => 1 ) if $todate;
|
|
76 |
|
|
77 |
my @where = ();
|
|
78 |
push @where, (transdate => { ge => $fromdate }) if ($fromdate);
|
|
79 |
push @where, (transdate => { lt => $todate }) if ($todate);
|
|
80 |
|
|
81 |
my $bank_transactions = SL::DB::Manager::BankTransaction->get_all(where => [ amount => {ne => \'invoice_amount'},
|
|
82 |
local_bank_account_id => $::form->{filter}{bank_account},
|
|
83 |
@where ],
|
|
84 |
with_objects => [ 'local_bank_account', 'currency' ],
|
|
85 |
sort_by => $sort_by, limit => 10000);
|
|
86 |
|
|
87 |
my $all_open_ar_invoices = SL::DB::Manager::Invoice->get_all(where => [amount => { gt => \'paid' }], with_objects => 'customer');
|
|
88 |
my $all_open_ap_invoices = SL::DB::Manager::PurchaseInvoice->get_all(where => [amount => { gt => \'paid' }], with_objects => 'vendor');
|
|
89 |
|
|
90 |
my @all_open_invoices;
|
|
91 |
push @all_open_invoices, @{ $all_open_ar_invoices };
|
|
92 |
push @all_open_invoices, @{ $all_open_ap_invoices };
|
|
93 |
|
|
94 |
foreach my $bt (@{ $bank_transactions }) {
|
|
95 |
next unless $bt->{remote_name}; # bank has no name, usually fees, use create invoice to assign
|
|
96 |
foreach my $open_invoice (@all_open_invoices){
|
|
97 |
$open_invoice->{agreement} = 0;
|
|
98 |
|
|
99 |
#compare banking arrangements
|
|
100 |
my ($bank_code, $account_number);
|
|
101 |
$bank_code = $open_invoice->customer->bank_code if $open_invoice->is_sales;
|
|
102 |
$account_number = $open_invoice->customer->account_number if $open_invoice->is_sales;
|
|
103 |
$bank_code = $open_invoice->vendor->bank_code if ! $open_invoice->is_sales;
|
|
104 |
$account_number = $open_invoice->vendor->account_number if ! $open_invoice->is_sales;
|
|
105 |
($bank_code eq $bt->remote_bank_code
|
|
106 |
&& $account_number eq $bt->remote_account_number) ? ($open_invoice->{agreement} += 2) : ();
|
|
107 |
|
|
108 |
my $datediff = $bt->transdate->{utc_rd_days} - $open_invoice->transdate->{utc_rd_days};
|
|
109 |
$open_invoice->{datediff} = $datediff;
|
|
110 |
|
|
111 |
#compare amount
|
|
112 |
# (abs($open_invoice->amount) == abs($bt->amount)) ? ($open_invoice->{agreement} += 2) : ();
|
|
113 |
# do we need double abs here?
|
|
114 |
(abs(abs($open_invoice->amount) - abs($bt->amount)) < 0.01) ? ($open_invoice->{agreement} += 4) : ();
|
|
115 |
|
|
116 |
#search invoice number in purpose
|
|
117 |
my $invnumber = $open_invoice->invnumber;
|
|
118 |
# possible improvement: match has to have more than 1 character?
|
|
119 |
$bt->purpose =~ /\b$invnumber\b/i ? ($open_invoice->{agreement} += 2) : ();
|
|
120 |
|
|
121 |
#check sign
|
|
122 |
if ( $open_invoice->is_sales && $bt->amount < 0 ) {
|
|
123 |
$open_invoice->{agreement} -= 1;
|
|
124 |
};
|
|
125 |
if ( ! $open_invoice->is_sales && $bt->amount > 0 ) {
|
|
126 |
$open_invoice->{agreement} -= 1;
|
|
127 |
};
|
|
128 |
|
|
129 |
#search customer/vendor number in purpose
|
|
130 |
my $cvnumber;
|
|
131 |
$cvnumber = $open_invoice->customer->customernumber if $open_invoice->is_sales;
|
|
132 |
$cvnumber = $open_invoice->vendor->vendornumber if ! $open_invoice->is_sales;
|
|
133 |
$bt->purpose =~ /\b$cvnumber\b/i ? ($open_invoice->{agreement}++) : ();
|
|
134 |
|
|
135 |
#compare customer/vendor name and account holder
|
|
136 |
my $cvname;
|
|
137 |
$cvname = $open_invoice->customer->name if $open_invoice->is_sales;
|
|
138 |
$cvname = $open_invoice->vendor->name if ! $open_invoice->is_sales;
|
|
139 |
$bt->remote_name =~ /\b$cvname\b/i ? ($open_invoice->{agreement}++) : ();
|
|
140 |
|
|
141 |
#Compare transdate of bank_transaction with transdate of invoice
|
|
142 |
#Check if words in remote_name appear in cvname
|
|
143 |
$open_invoice->{agreement} += &check_string($bt->remote_name,$cvname);
|
|
144 |
|
|
145 |
$open_invoice->{agreement} -= 1 if $datediff < -5; # dies hebelt eventuell Vorkasse aus
|
|
146 |
$open_invoice->{agreement} += 1 if $datediff < 30; # dies hebelt eventuell Vorkasse aus
|
|
147 |
|
|
148 |
# only if we already have a good agreement, let date further change value of agreement.
|
|
149 |
# this is so that if there are several open invoices which are all equal (rent jan, rent feb...) the one with the best date match is chose over the others
|
|
150 |
# another way around this is to just pre-filter by periods instead of matching everything
|
|
151 |
if ( $open_invoice->{agreement} > 5 ) {
|
|
152 |
if ( $datediff == 0 ) {
|
|
153 |
$open_invoice->{agreement} += 3;
|
|
154 |
} elsif ( $datediff > 0 and $datediff <= 14 ) {
|
|
155 |
$open_invoice->{agreement} += 2;
|
|
156 |
} elsif ( $datediff >14 and $datediff < 35) {
|
|
157 |
$open_invoice->{agreement} += 1;
|
|
158 |
} elsif ( $datediff >34 and $datediff < 120) {
|
|
159 |
$open_invoice->{agreement} += 1;
|
|
160 |
} elsif ( $datediff < 0 ) {
|
|
161 |
$open_invoice->{agreement} -= 1;
|
|
162 |
} else {
|
|
163 |
# e.g. datediff > 120
|
|
164 |
};
|
|
165 |
};
|
|
166 |
|
|
167 |
#if ($open_invoice->transdate->{utc_rd_days} == $bt->transdate->{utc_rd_days}) {
|
|
168 |
#$open_invoice->{agreement} += 4;
|
|
169 |
#print FH "found matching date for invoice " . $open_invoice->invnumber . " ( " . $bt->transdate->{utc_rd_days} . " . \n";
|
|
170 |
#} elsif (($open_invoice->transdate->{utc_rd_days} + 30) < $bt->transdate->{utc_rd_days}) {
|
|
171 |
#$open_invoice->{agreement} -= 1;
|
|
172 |
#} else {
|
|
173 |
#$open_invoice->{agreement} -= 2;
|
|
174 |
#print FH "found nomatch date -2 for invoice " . $open_invoice->invnumber . " ( " . $bt->transdate->{utc_rd_days} . " . \n";
|
|
175 |
#};
|
|
176 |
#print FH "agreement after date_agreement: " . $open_invoice->{agreement} . "\n";
|
|
177 |
|
|
178 |
|
|
179 |
|
|
180 |
}
|
|
181 |
# finished going through all open_invoices
|
|
182 |
|
|
183 |
# go through each bt
|
|
184 |
# for each open_invoice try to match it to each open_invoice and store agreement in $open_invoice->{agreement} (which gets overwritten each time for each bt)
|
|
185 |
# calculate
|
|
186 |
#
|
|
187 |
|
|
188 |
$bt->{proposals} = [];
|
|
189 |
my $agreement = 11;
|
|
190 |
# wird nie ausgeführt, bzw. nur ganz am Ende
|
|
191 |
# oder einmal am Anfang?
|
|
192 |
# es werden maximal 7 vorschläge gemacht?
|
|
193 |
# 7 mal wird geprüft, ob etwas passt
|
|
194 |
while (scalar @{ $bt->{proposals} } < 1 && $agreement-- > 0) {
|
|
195 |
$bt->{proposals} = [ grep { $_->{agreement} > $agreement } @all_open_invoices ];
|
|
196 |
#Kann wahrscheinlich weg:
|
|
197 |
# map { $_->{style} = "green" } @{ $bt->{proposals} } if $agreement >= 5;
|
|
198 |
# map { $_->{style} = "orange" } @{ $bt->{proposals} } if $agreement < 5 and $agreement >= 3;
|
|
199 |
# map { $_->{style} = "red" } @{ $bt->{proposals} } if $agreement < 3;
|
|
200 |
$bt->{agreement} = $agreement; # agreement value at cutoff, will correspond to several results if threshold is 7 and several are already above 7
|
|
201 |
}
|
|
202 |
} # finished one bt
|
|
203 |
# finished all bt
|
|
204 |
|
|
205 |
# separate filter for proposals (second tab, agreement >= 5 and exactly one match)
|
|
206 |
# to qualify as a proposal there has to be
|
|
207 |
# * agreement >= 5
|
|
208 |
# * there must be only one exact match
|
|
209 |
# * depending on whether sales or purchase the amount has to have the correct sign (so Gutschriften don't work?)
|
|
210 |
|
|
211 |
my @proposals = grep { $_->{agreement} >= 5
|
|
212 |
and 1 == scalar @{ $_->{proposals} }
|
|
213 |
and (@{ $_->{proposals} }[0]->is_sales ? abs(@{ $_->{proposals} }[0]->amount - $_->amount) < 0.01 : abs(@{ $_->{proposals} }[0]->amount + $_->amount) < 0.01) } @{ $bank_transactions };
|
|
214 |
|
|
215 |
#Sort bank transactions by quality of proposal
|
|
216 |
$bank_transactions = [ sort { $a->{agreement} <=> $b->{agreement} } @{ $bank_transactions } ] if $::form->{sort_by} eq 'proposal' and $::form->{sort_dir} == 1;
|
|
217 |
$bank_transactions = [ sort { $b->{agreement} <=> $a->{agreement} } @{ $bank_transactions } ] if $::form->{sort_by} eq 'proposal' and $::form->{sort_dir} == 0;
|
|
218 |
|
|
219 |
|
|
220 |
$self->render('bank_transactions/list',
|
|
221 |
title => t8('List of bank transactions'),
|
|
222 |
BANK_TRANSACTIONS => $bank_transactions,
|
|
223 |
PROPOSALS => \@proposals,
|
|
224 |
bank_account => SL::DB::Manager::BankAccount->find_by(id => $::form->{filter}{bank_account}) );
|
|
225 |
}
|
|
226 |
|
|
227 |
sub check_string {
|
|
228 |
my $bankstring = shift;
|
|
229 |
my $namestring = shift;
|
|
230 |
return 0 unless $bankstring and $namestring;
|
|
231 |
|
|
232 |
my @bankwords = grep(/^\w+$/, split(/\b/,$bankstring));
|
|
233 |
|
|
234 |
my $match = 0;
|
|
235 |
foreach my $bankword ( @bankwords ) {
|
|
236 |
# only try to match strings with more than 2 characters
|
|
237 |
next unless length($bankword)>2;
|
|
238 |
if ( $namestring =~ /\b$bankword\b/i ) {
|
|
239 |
$match++;
|
|
240 |
};
|
|
241 |
};
|
|
242 |
return $match;
|
|
243 |
};
|
|
244 |
|
|
245 |
sub action_assign_invoice {
|
|
246 |
my ($self) = @_;
|
|
247 |
|
|
248 |
$self->{transaction} = SL::DB::Manager::BankTransaction->find_by(id => $::form->{bt_id});
|
|
249 |
|
|
250 |
$self->render('bank_transactions/assign_invoice', { layout => 0 },
|
|
251 |
title => t8('Assign invoice'),);
|
|
252 |
}
|
|
253 |
|
|
254 |
sub action_create_invoice {
|
|
255 |
my ($self) = @_;
|
|
256 |
my %myconfig = %main::myconfig;
|
|
257 |
|
|
258 |
$self->{transaction} = SL::DB::Manager::BankTransaction->find_by(id => $::form->{bt_id});
|
|
259 |
my $vendor_of_transaction = SL::DB::Manager::Vendor->find_by(account_number => $self->{transaction}->{remote_account_number});
|
|
260 |
|
|
261 |
my $drafts = SL::DB::Manager::Draft->get_all(where => [ module => 'ap'] , with_objects => 'employee');
|
|
262 |
|
|
263 |
my @filtered_drafts;
|
|
264 |
|
|
265 |
foreach my $draft ( @{ $drafts } ) {
|
|
266 |
my $draft_as_object = YAML::Load($draft->form);
|
|
267 |
my $vendor = SL::DB::Manager::Vendor->find_by(id => $draft_as_object->{vendor_id});
|
|
268 |
$draft->{vendor} = $vendor->name;
|
|
269 |
$draft->{vendor_id} = $vendor->id;
|
|
270 |
push @filtered_drafts, $draft;
|
|
271 |
}
|
|
272 |
|
|
273 |
#Filter drafts
|
|
274 |
@filtered_drafts = grep { $_->{vendor_id} == $vendor_of_transaction->id } @filtered_drafts if $vendor_of_transaction;
|
|
275 |
|
|
276 |
my $all_vendors = SL::DB::Manager::Vendor->get_all();
|
|
277 |
|
|
278 |
$self->render('bank_transactions/create_invoice', { layout => 0 },
|
|
279 |
title => t8('Create invoice'),
|
|
280 |
DRAFTS => \@filtered_drafts,
|
|
281 |
vendor_id => $vendor_of_transaction ? $vendor_of_transaction->id : undef,
|
|
282 |
vendor_name => $vendor_of_transaction ? $vendor_of_transaction->name : undef,
|
|
283 |
ALL_VENDORS => $all_vendors,
|
|
284 |
limit => $myconfig{vclimit},
|
|
285 |
callback => $self->url_for(action => 'list',
|
|
286 |
'filter.bank_account' => $::form->{filter}->{bank_account},
|
|
287 |
'filter.todate' => $::form->{filter}->{todate},
|
|
288 |
'filter.fromdate' => $::form->{filter}->{fromdate}),
|
|
289 |
);
|
|
290 |
}
|
|
291 |
|
|
292 |
sub action_filter_drafts {
|
|
293 |
my ($self) = @_;
|
|
294 |
|
|
295 |
$self->{transaction} = SL::DB::Manager::BankTransaction->find_by(id => $::form->{bt_id});
|
|
296 |
my $vendor_of_transaction = SL::DB::Manager::Vendor->find_by(account_number => $self->{transaction}->{remote_account_number});
|
|
297 |
|
|
298 |
my $drafts = SL::DB::Manager::Draft->get_all(with_objects => 'employee');
|
|
299 |
|
|
300 |
my @filtered_drafts;
|
|
301 |
|
|
302 |
foreach my $draft ( @{ $drafts } ) {
|
|
303 |
my $draft_as_object = YAML::Load($draft->form);
|
|
304 |
my $vendor = SL::DB::Manager::Vendor->find_by(id => $draft_as_object->{vendor_id});
|
|
305 |
$draft->{vendor} = $vendor->name;
|
|
306 |
$draft->{vendor_id} = $vendor->id;
|
|
307 |
push @filtered_drafts, $draft;
|
|
308 |
}
|
|
309 |
|
|
310 |
my $vendor_name = $::form->{vendor};
|
|
311 |
my $vendor_id = $::form->{vendor_id};
|
|
312 |
|
|
313 |
#Filter drafts
|
|
314 |
@filtered_drafts = grep { $_->{vendor_id} == $vendor_id } @filtered_drafts if $vendor_id;
|
|
315 |
@filtered_drafts = grep { $_->{vendor} =~ /$vendor_name/i } @filtered_drafts if $vendor_name;
|
|
316 |
|
|
317 |
my $output = $self->render(
|
|
318 |
'bank_transactions/filter_drafts',
|
|
319 |
{ output => 0 },
|
|
320 |
DRAFTS => \@filtered_drafts,
|
|
321 |
);
|
|
322 |
|
|
323 |
my %result = ( count => 0, html => $output );
|
|
324 |
|
|
325 |
$self->render(\to_json(\%result), { type => 'json', process => 0 });
|
|
326 |
}
|
|
327 |
|
|
328 |
sub action_ajax_add_list {
|
|
329 |
my ($self) = @_;
|
|
330 |
|
|
331 |
my @where_sale = (amount => { ne => \'paid' });
|
|
332 |
my @where_purchase = (amount => { ne => \'paid' });
|
|
333 |
|
|
334 |
if ($::form->{invnumber}) {
|
|
335 |
push @where_sale, (invnumber => { ilike => '%' . $::form->{invnumber} . '%'});
|
|
336 |
push @where_purchase, (invnumber => { ilike => '%' . $::form->{invnumber} . '%'});
|
|
337 |
}
|
|
338 |
|
|
339 |
if ($::form->{amount}) {
|
|
340 |
push @where_sale, (amount => $::form->parse_amount(\%::myconfig, $::form->{amount}));
|
|
341 |
push @where_purchase, (amount => $::form->parse_amount(\%::myconfig, $::form->{amount}));
|
|
342 |
}
|
|
343 |
|
|
344 |
if ($::form->{vcnumber}) {
|
|
345 |
push @where_sale, ('customer.customernumber' => { ilike => '%' . $::form->{vcnumber} . '%'});
|
|
346 |
push @where_purchase, ('vendor.vendornumber' => { ilike => '%' . $::form->{vcnumber} . '%'});
|
|
347 |
}
|
|
348 |
|
|
349 |
if ($::form->{vcname}) {
|
|
350 |
push @where_sale, ('customer.name' => { ilike => '%' . $::form->{vcname} . '%'});
|
|
351 |
push @where_purchase, ('vendor.name' => { ilike => '%' . $::form->{vcname} . '%'});
|
|
352 |
}
|
|
353 |
|
|
354 |
if ($::form->{transdatefrom}) {
|
|
355 |
my $fromdate = $::locale->parse_date_to_object(\%::myconfig, $::form->{transdatefrom});
|
|
356 |
push @where_sale, ('transdate' => { ge => $fromdate});
|
|
357 |
push @where_purchase, ('transdate' => { ge => $fromdate});
|
|
358 |
}
|
|
359 |
|
|
360 |
if ($::form->{transdateto}) {
|
|
361 |
my $todate = $::locale->parse_date_to_object(\%::myconfig, $::form->{transdateto});
|
|
362 |
$todate->add(days => 1);
|
|
363 |
push @where_sale, ('transdate' => { lt => $todate});
|
|
364 |
push @where_purchase, ('transdate' => { lt => $todate});
|
|
365 |
}
|
|
366 |
|
|
367 |
my $all_open_ar_invoices = SL::DB::Manager::Invoice->get_all(where => \@where_sale, with_objects => 'customer');
|
|
368 |
my $all_open_ap_invoices = SL::DB::Manager::PurchaseInvoice->get_all(where => \@where_purchase, with_objects => 'vendor');
|
|
369 |
|
|
370 |
my @all_open_invoices;
|
|
371 |
push @all_open_invoices, @{ $all_open_ar_invoices };
|
|
372 |
push @all_open_invoices, @{ $all_open_ap_invoices };
|
|
373 |
|
|
374 |
@all_open_invoices = sort { $a->id <=> $b->id } @all_open_invoices;
|
|
375 |
#my $all_open_invoices = SL::DB::Manager::Invoice->get_all(where => \@where);
|
|
376 |
|
|
377 |
my $output = $self->render(
|
|
378 |
'bank_transactions/add_list',
|
|
379 |
{ output => 0 },
|
|
380 |
INVOICES => \@all_open_invoices,
|
|
381 |
);
|
|
382 |
|
|
383 |
my %result = ( count => 0, html => $output );
|
|
384 |
|
|
385 |
$self->render(\to_json(\%result), { type => 'json', process => 0 });
|
|
386 |
}
|
|
387 |
|
|
388 |
sub action_ajax_accept_invoices {
|
|
389 |
my ($self) = @_;
|
|
390 |
|
|
391 |
my @selected_invoices;
|
|
392 |
foreach my $invoice_id (@{ $::form->{invoice_id} || [] }) {
|
|
393 |
my $invoice_object = SL::DB::Manager::Invoice->find_by(id => $invoice_id);
|
|
394 |
$invoice_object ||= SL::DB::Manager::PurchaseInvoice->find_by(id => $invoice_id);
|
|
395 |
|
|
396 |
push @selected_invoices, $invoice_object;
|
|
397 |
}
|
|
398 |
|
|
399 |
$self->render('bank_transactions/invoices', { layout => 0 },
|
|
400 |
INVOICES => \@selected_invoices,
|
|
401 |
bt_id => $::form->{bt_id} );
|
|
402 |
}
|
|
403 |
|
|
404 |
sub action_save_invoices {
|
|
405 |
my ($self) = @_;
|
|
406 |
|
|
407 |
my $invoice_hash = delete $::form->{invoice_ids};
|
|
408 |
|
|
409 |
while ( my ($bt_id, $invoice_ids) = each(%$invoice_hash) ) {
|
|
410 |
my $bank_transaction = SL::DB::Manager::BankTransaction->find_by(id => $bt_id);
|
|
411 |
my $sign = $bank_transaction->amount < 0 ? -1 : 1;
|
|
412 |
my $amount_of_transaction = $sign * $bank_transaction->amount;
|
|
413 |
|
|
414 |
my @invoices;
|
|
415 |
foreach my $invoice_id (@{ $invoice_ids }) {
|
|
416 |
push @invoices, (SL::DB::Manager::Invoice->find_by(id => $invoice_id) || SL::DB::Manager::PurchaseInvoice->find_by(id => $invoice_id));
|
|
417 |
}
|
|
418 |
@invoices = sort { return 1 if ($a->is_sales and $a->amount > 0);
|
|
419 |
return 1 if (!$a->is_sales and $a->amount < 0);
|
|
420 |
return -1; } @invoices if $bank_transaction->amount > 0;
|
|
421 |
@invoices = sort { return -1 if ($a->is_sales and $a->amount > 0);
|
|
422 |
return -1 if (!$a->is_sales and $a->amount < 0);
|
|
423 |
return 1; } @invoices if $bank_transaction->amount < 0;
|
|
424 |
|
|
425 |
foreach my $invoice (@invoices) {
|
|
426 |
if ($amount_of_transaction == 0) {
|
|
427 |
flash('warning', $::locale->text('There are invoices which could not be payed by bank transaction #1 (Account number: #2, bank code: #3)!',
|
|
428 |
$bank_transaction->purpose,
|
|
429 |
$bank_transaction->remote_account_number,
|
|
430 |
$bank_transaction->remote_bank_code));
|
|
431 |
last;
|
|
432 |
}
|
|
433 |
#pay invoice or go to the next bank transaction if the amount is not sufficiently high
|
|
434 |
if ($invoice->amount <= $amount_of_transaction) {
|
|
435 |
$invoice->pay_invoice(chart_id => $bank_transaction->local_bank_account->chart_id, trans_id => $invoice->id, amount => $invoice->amount, transdate => $bank_transaction->transdate);
|
|
436 |
if ($invoice->is_sales) {
|
|
437 |
$amount_of_transaction -= $sign * $invoice->amount;
|
|
438 |
$bank_transaction->invoice_amount($bank_transaction->invoice_amount + $invoice->amount);
|
|
439 |
} else {
|
|
440 |
$amount_of_transaction += $sign * $invoice->amount if (!$invoice->is_sales);
|
|
441 |
$bank_transaction->invoice_amount($bank_transaction->invoice_amount - $invoice->amount);
|
|
442 |
}
|
|
443 |
} else {
|
|
444 |
$invoice->pay_invoice(chart_id => $bank_transaction->local_bank_account->chart_id, trans_id => $invoice->id, amount => $amount_of_transaction, transdate => $bank_transaction->transdate);
|
|
445 |
$bank_transaction->invoice_amount($bank_transaction->amount) if $invoice->is_sales;
|
|
446 |
$bank_transaction->invoice_amount($bank_transaction->amount) if !$invoice->is_sales;
|
|
447 |
$amount_of_transaction = 0;
|
|
448 |
}
|
|
449 |
|
|
450 |
#Record a link from the bank transaction to the invoice
|
|
451 |
my @props = (
|
|
452 |
from_table => 'bank_transactions',
|
|
453 |
from_id => $bt_id,
|
|
454 |
to_table => $invoice->is_sales ? 'ar' : 'ap',
|
|
455 |
to_id => $invoice->id,
|
|
456 |
);
|
|
457 |
|
|
458 |
my $existing = SL::DB::Manager::RecordLink->get_all(where => \@props, limit => 1)->[0];
|
|
459 |
|
|
460 |
SL::DB::RecordLink->new(@props)->save if !$existing;
|
|
461 |
}
|
|
462 |
$bank_transaction->save;
|
|
463 |
}
|
|
464 |
|
|
465 |
$self->action_list();
|
|
466 |
}
|
|
467 |
|
|
468 |
sub action_save_proposals {
|
|
469 |
my ($self) = @_;
|
|
470 |
|
|
471 |
foreach my $bt_id (@{ $::form->{proposal_ids} }) {
|
|
472 |
#mark bt as booked
|
|
473 |
my $bt = SL::DB::Manager::BankTransaction->find_by(id => $bt_id);
|
|
474 |
$bt->invoice_amount($bt->amount);
|
|
475 |
$bt->save;
|
|
476 |
|
|
477 |
#pay invoice
|
|
478 |
my $arap = SL::DB::Manager::Invoice->find_by(id => $::form->{"proposed_invoice_$bt_id"});
|
|
479 |
$arap = SL::DB::Manager::PurchaseInvoice->find_by(id => $::form->{"proposed_invoice_$bt_id"}) if not defined $arap;
|
|
480 |
$arap->pay_invoice(chart_id => $bt->local_bank_account->chart_id,
|
|
481 |
trans_id => $arap->id,
|
|
482 |
amount => $arap->amount,
|
|
483 |
transdate => $bt->transdate);
|
|
484 |
$arap->save;
|
|
485 |
|
|
486 |
#create record link
|
|
487 |
my @props = (
|
|
488 |
from_table => 'bank_transactions',
|
|
489 |
from_id => $bt_id,
|
|
490 |
to_table => $arap->is_sales ? 'ar' : 'ap',
|
|
491 |
to_id => $arap->id,
|
|
492 |
);
|
|
493 |
|
|
494 |
my $existing = SL::DB::Manager::RecordLink->get_all(where => \@props, limit => 1)->[0];
|
|
495 |
|
|
496 |
SL::DB::RecordLink->new(@props)->save if !$existing;
|
|
497 |
}
|
|
498 |
|
|
499 |
flash('ok', t8('#1 proposal(s) saved.', scalar @{ $::form->{proposal_ids} }));
|
|
500 |
|
|
501 |
$self->action_list();
|
|
502 |
}
|
|
503 |
|
|
504 |
#
|
|
505 |
# filters
|
|
506 |
#
|
|
507 |
|
|
508 |
sub check_auth {
|
|
509 |
$::auth->assert('bank_transaction');
|
|
510 |
}
|
|
511 |
|
|
512 |
#
|
|
513 |
# helpers
|
|
514 |
#
|
|
515 |
|
|
516 |
sub make_filter_summary {
|
|
517 |
my ($self) = @_;
|
|
518 |
|
|
519 |
my $filter = $::form->{filter} || {};
|
|
520 |
my @filter_strings;
|
|
521 |
|
|
522 |
my @filters = (
|
|
523 |
[ $filter->{"transdate:date::ge"}, $::locale->text('Transdate') . " " . $::locale->text('From Date') ],
|
|
524 |
[ $filter->{"transdate:date::le"}, $::locale->text('Transdate') . " " . $::locale->text('To Date') ],
|
|
525 |
[ $filter->{"valutadate:date::ge"}, $::locale->text('Valutadate') . " " . $::locale->text('From Date') ],
|
|
526 |
[ $filter->{"valutadate:date::le"}, $::locale->text('Valutadate') . " " . $::locale->text('To Date') ],
|
|
527 |
[ $filter->{"amount:number"}, $::locale->text('Amount') ],
|
|
528 |
[ $filter->{"bank_account_id:integer"}, $::locale->text('Local bank account') ],
|
|
529 |
);
|
|
530 |
|
|
531 |
for (@filters) {
|
|
532 |
push @filter_strings, "$_->[1]: $_->[0]" if $_->[0];
|
|
533 |
}
|
|
534 |
|
|
535 |
$self->{filter_summary} = join ', ', @filter_strings;
|
|
536 |
}
|
|
537 |
|
|
538 |
sub prepare_report {
|
|
539 |
my ($self) = @_;
|
|
540 |
|
|
541 |
my $callback = $self->models->get_callback;
|
|
542 |
|
|
543 |
my $report = SL::ReportGenerator->new(\%::myconfig, $::form);
|
|
544 |
$self->{report} = $report;
|
|
545 |
|
|
546 |
my @columns = qw(transdate valudate remote_name remote_account_number remote_bank_code amount invoice_amount invoices currency purpose local_account_number local_bank_code id);
|
|
547 |
my @sortable = qw(transdate valudate remote_name remote_account_number remote_bank_code amount purpose local_account_number local_bank_code);
|
|
548 |
|
|
549 |
my %column_defs = (
|
|
550 |
transdate => { sub => sub { $_[0]->transdate_as_date } },
|
|
551 |
valutadate => { sub => sub { $_[0]->valutadate_as_date } },
|
|
552 |
remote_name => { },
|
|
553 |
remote_account_number => { },
|
|
554 |
remote_bank_code => { },
|
|
555 |
amount => { sub => sub { $_[0]->amount_as_number },
|
|
556 |
align => 'right' },
|
|
557 |
invoice_amount => { sub => sub { $_[0]->invoice_amount_as_number },
|
|
558 |
align => 'right' },
|
|
559 |
invoices => { sub => sub { $_[0]->linked_invoices } },
|
|
560 |
currency => { sub => sub { $_[0]->currency->name } },
|
|
561 |
purpose => { },
|
|
562 |
local_account_number => { sub => sub { $_[0]->local_bank_account->account_number } },
|
|
563 |
local_bank_code => { sub => sub { $_[0]->local_bank_account->bank_code } },
|
|
564 |
id => {},
|
|
565 |
);
|
|
566 |
|
|
567 |
map { $column_defs{$_}->{text} ||= $::locale->text( $self->models->get_sort_spec->{$_}->{title} ) } keys %column_defs;
|
|
568 |
|
|
569 |
$report->set_options(
|
|
570 |
std_column_visibility => 1,
|
|
571 |
controller_class => 'BankTransaction',
|
|
572 |
output_format => 'HTML',
|
|
573 |
top_info_text => $::locale->text('Bank transactions'),
|
|
574 |
title => $::locale->text('Bank transactions'),
|
|
575 |
allow_pdf_export => 1,
|
|
576 |
allow_csv_export => 1,
|
|
577 |
);
|
|
578 |
$report->set_columns(%column_defs);
|
|
579 |
$report->set_column_order(@columns);
|
|
580 |
$report->set_export_options(qw(list filter));
|
|
581 |
$report->set_options_from_form;
|
|
582 |
$self->models->disable_pagination if $report->{options}{output_format} =~ /^(pdf|csv)$/i;
|
|
583 |
$self->models->set_report_generator_sort_options(report => $report, sortable_columns => \@sortable);
|
|
584 |
|
|
585 |
my $bank_accounts = SL::DB::Manager::BankAccount->get_all();
|
|
586 |
my $label_sub = sub { t8('#1 - Account number #2, bank code #3, #4', $_[0]->name, $_[0]->account_number, $_[0]->bank_code, $_[0]->bank )};
|
|
587 |
|
|
588 |
$report->set_options(
|
|
589 |
raw_top_info_text => $self->render('bank_transactions/report_top', { output => 0 }, BANK_ACCOUNTS => $bank_accounts, label_sub => $label_sub),
|
|
590 |
raw_bottom_info_text => $self->render('bank_transactions/report_bottom', { output => 0 }),
|
|
591 |
);
|
|
592 |
}
|
|
593 |
|
|
594 |
sub init_models {
|
|
595 |
my ($self) = @_;
|
|
596 |
|
|
597 |
SL::Controller::Helper::GetModels->new(
|
|
598 |
controller => $self,
|
|
599 |
sorted => {
|
|
600 |
_default => {
|
|
601 |
by => 'transdate',
|
|
602 |
dir => 1,
|
|
603 |
},
|
|
604 |
transdate => t8('Transdate'),
|
|
605 |
remote_name => t8('Remote name'),
|
|
606 |
amount => t8('Amount'),
|
|
607 |
invoice_amount => t8('Assigned'),
|
|
608 |
invoices => t8('Linked invoices'),
|
|
609 |
valutadate => t8('Valutadate'),
|
|
610 |
remote_account_number => t8('Remote account number'),
|
|
611 |
remote_bank_code => t8('Remote bank code'),
|
|
612 |
currency => t8('Currency'),
|
|
613 |
purpose => t8('Purpose'),
|
|
614 |
local_account_number => t8('Local account number'),
|
|
615 |
local_bank_code => t8('Local bank code'),
|
|
616 |
},
|
|
617 |
with_objects => [ 'local_bank_account', 'currency' ],
|
|
618 |
);
|
|
619 |
}
|
|
620 |
|
|
621 |
1;
|
Bankerweiterung - Zwischenstand, erster Entwurf
Erstellung von Tabelle bank_transactions
Import von Bankbewegungen (in Tabelle bank_transactions)
Menu-Eintrag war noch nicht commitet
Controller für die Bank-Transaktionen
Dialog hin- und her
Achtung: noch mit Debug-Statements!
Dies und das für Bank_transactions...
BankTransaction in RecordLinks
Kann verknüpfte Belege Speichern
Man kann Rechnungen mehr oder weniger schon als bezahlt markieren
Erweiterung für EK-Rechnungen (funktioniert noch nicht ganz)
EK-Rechnungen und erste Vorschläge für Rechnung bezahlen
Information von Rechnungen + Javascript statt Ajax
Style als Link lassen
Deckt verschiedene Spezialfälle ab
Datums- und Zahlenformatierungen (noch nicht fertig)
Datumsformat und Übersetzungen
Sub date wieder aus LxERP entfernt
Logik für automatisches Zuweisen
Bericht für BTs (noch nicht ganz fertig)
Formatierungen für Zeilen mit ReportGenerator
Löschen-Knopf und paar Sachen
Entwurf laden und mit Parametern aus form überschreiben
Aufruf mit Parametern als get für Kreditorenbuchung:
ap.pl?action=load_draft&id=ap-invoice-1385202327-644205-8150&invnumber=dsfdf&remove_draft=0&paid_1=123,45
Rechnung aus Bankbeleg erstellen
Bankkonten-Filter und id auf bank_account statt local...
Verknüpfte Belege mit id-Verknüpfung zu local_bank_account
CsvImport mit ID auf BankAccounts (noch nicht getestet)
Behebt Bugs bei Csv-Import von Bankbewegungen
Währungs-ID statt Währungsstring benutzen
Passt den Bankbewegungs-Import an die neuen Änderungen der Helfer an
Filter für create_invoice
Vergessene Templates
Filter für create invoice funktionier halb
Rest für den Filter von create Invoice
Auswahllistenbegrenzer bei Lieferantenfilter beachten
Mehr Daten bei 'create invoice' übernehmen
Wenn man eine Kreditorenbuchung aus einer Bankbewegung erstellt,
werden nun mehr Daten aus der Bankbewegung in die Vorlage über-
nommen.
Änderungen in drafts.pl (gehören zu letztem Commit)
Betrag richtig formatieren und Form submitten
Bei assign invoice werden jetzt Rechnungsbeträge richtig formatiert
und es werden Rechnungen gesucht, wenn man auf 'Enter' drückt.
Weiterleitung auf List und Rechnungsbezahlen repariert
Vorzeichen wechseln bei create invoice
Das Vorzeichen von der Bankbewegung muss geändert werden, wenn man
aus einer Bankbewegung eine Kreditorenbuchung erstellt.
Sortierung von Spalten bei Bankbewegungen
Geoffery's Änderungen bzgl. Vorschlagsuche
BankTransaction - create_invoice filtert für Kreditorenbuchungen
Im Bank-Dropdown Bankname zuerst anzeigen
Und die Breite vom Dropdown angepasst.
Bankauszug verbuchen Menüpunkt nicht unter Berichte
Banktransactions - Spalten in Tabellen umsortiert
Banktransactions Tooltip - bt-Info in Tooltip Fenster aufnehmen
Damit man innerhalb des Tooltip Fensters die wichtigsten Infos auf einen
Blick hat.
Sortierreihenfolge
Es wird jetzt zuerst nach Alphabet, dann gegen das Alphabet sortiert.
Banktransactions
Verbuchte Beträge werden jetzt in der BankTransaction gespeichert.
Sortierung auf DB-Ebene, falls möglich
Anzeige von verbuchten Beträgen der BankTransactions
Kleinerer Bug
Ein paar Debug-Statements entfernt
Verknüpfte Rechnungen im BankTransaction-Bericht anzeigen.
Kontenabgleich
Erste Schritte zum Kontenabgleich.
Kontenabgleich funktioniert schon ganz gut.
TODO: nochmal Funktionen checken
TODO: Filter hinzufügen
Kontenabgleich
Filter für BT und PR im Kontenabgleich.
TODO: Datumsfilter für beide gemeinsam umschreiben und Bilanzierung anzeigen.
Kontenabgleich übergreifender Datumsfilter
Das transdate wird jetzt auch übergreifend für Bankbewegungen und
verbuchte Zahlungen gesetzt.
TODO: Nach Änderung dieser Daten sollten die Tabellen neugeladen
und alle Teilfilter zurück auf 0 gesetzt werden.
Kontenabgleich - ein paar Sachen ausprobiert
Ist nur zum weitermachen (alle Änderungen nur Tests).
Kontenabgleich Kleiner Bug in Search
Kontenabgleich - Erste Übersicht
Kontenabgleich Anzeige von abgeglichenen Buchungen mit Bankbuchungen
funktioniert schonmal
Nächstes: Filter.
Kontenabgleich Filtern ist jetzt in der Übersicht möglich.
Next: Spalte reconciliation_link durch group oder so ersetzen.
Kontenabgleich In rec_group in reconciliation_links
In der Tabelle reconciliation_links werden jetzt keine ids mehr auf
reconciliation_links gespeichert. Stattdessen erkennt man an der
rec_group, welche Zeilen zusammengehören.
Kontenabgleich Berechnung von Summen
Jetzt werden Summen von Bankbewegungen und cleared payments angezeigt.
Next: Anhaken und abgleichen implementieren.
Kontenabgleich Checkboxen fügen Elemente zur Tabelle
Es gibt jetzt Checkboxen neben BT's und BB's. Wenn man sie anhakt,
wird die BT bzw. die BB in eine Tabelle zum abgleichen gesteckt.
TODO: Button zum abgleichen programmieren.
Kontenabgleich Man kann jetzt auch im Report abgleichen
Es fehlt noch: Abbruch-Action, falls beim Abgleichen etwas fehlerhaft ist.
Kontenabgleich Manager für ReconciliationLink
Wurde vergessen zu committen
Kontenabgleich Vorzeichenfehler bei AccTransactions behoben.
In der Anzeige muss das Vorzeichen von AccTransactions bei Buchungen
auf Bank geändert werden.
Kontenabgleich Code aufräumen und Sortierung nach Datum
Es wird jetzt immer nach Datum sortiert. Weiterhin wurde im Code
eine sub von actions nach helpers geschoben.
Kontenabgleich Abbruch nach Fehlern beim Abgleichen
Wenn beim Abgleichen Fehler auftreten, wird man jetzt auf die Über-
sichtsseite geleitet.
Kontenabgleich/BankTransactions Upgrade-Script für Tabellen anpassen
Einige Änderungen der Tabellen sind in den Scripten jetzt enthalten.
Kontenabgleich Farbliche Hinterlegung und Entfernung von Debug-Code
Nicht zugewiesene BankTransactions und Buchungen auf Bankkonten
werden im Kontenabgleich jetzt rot hinterlegt.
Weiterhin wurden noch Debug-Statements entfernt.
TODO: Erweiterung auf andere css Klassen (nicht nur kivitendo, sondern
auch mobile/alte lx-office-styles etc...)
Kontenabgleich Behebt Bug
Unter gewissen Umständen wurden nach der Filterung noch alte Daten
beibehalten. Jetzt wird alles erneuert.
Kontenabgleich Filter für cleared
Man kann jetzt in der Übersicht auch nach cleared und uncleared filtern.
Kontenabgleich Erste Schritte für Automatischen Abgleich
Bisher werden Vorschläge nur dargestellt.
TODO: Button 'Abgleichen' für Vorschläge programmieren.
Kontenabgleich Vorschläge können jetzt abgeglichen werden
Vorschläge können jetzt auch automatisch abgeglichen werden, wenn
man sie anhakt und danach auf abgleichen klickt.
Kontenabgleich Anzeige von Reference
Es gibt jetzt einen Link im Kontenabgleich auf ar/ap/gl.
Kontenabgleich Kunden-/Lieferantennamen
Kunden- und Lieferantennamen werden jetzt für AccTransactions an-
gezeigt. Im Falle einer Dialogbuchung erscheint ihre Beschreibung.
Kontenabgleich Untersortierung nach Betrag
Bisher wurde nur nach Datum sortiert. Innerhalb eines Datums wird
jetzt zusätzlich nach Betrag sortiert.
Kontenabgleich/BankTransactions Entfernung Debug-Statements
Kontenabgleich BankTransactions als verbucht markieren
BankTransactions werden jetzt als verbucht markiert, wenn sie abge-
glichen sind. Ansonsten wurde noch ein kleiner Syntax-Fehler behoben.
Kontenabgleich Bilanz über alle Buchungen berechnen
Die Bilanz wird jetzt unabhängig vom Filter sowohl für cleared als
auch uncleared berechnet. Weiterhin wurde noch ein Vorzeichenfehler
in der Bilanz für Bankbewegungen behoben und der Code etwas verschoben.
Kontenabgleich Verlinkungen aufheben
Man kann jetzt auch Verlinkungen nach dem Abgleichen aufheben.
Kontenabgleich Code-Formatierung und kleine Verbesserung in der Anzeige
Formatierung von Code wurde geändert, sowie einige kleine Besserungen
in der Anzeige (zum Beispiel sind Beträge jetzt rechts orientiert
in der Tabellenzeile).
Kontenabgleich Tabellenhöhe mit relativer Größe
Die Tabellenhöhe hängt jetzt relativ von der Größe des Bildschirms
ab anstatt von einer festen Pixel-Anzahl.
Kontenabgleich Ok message für Flash eingebaut
Kontenabgleich gehört noch zum Flash-message-Commit
Kontenabgleich Zusammenführen verschiedener Abgleichmöglichkeiten
Bisher wurden verschiedene Methoden implementiert, den Kontenabgleich
zu machen. In diesem Commit werden zwei verschiedene Möglichkeiten
unter einen Hut gebracht. Es ist auf der erstellten Seite auch ohne
weiteres Möglich weitere Möglichkeiten hinzuzufügen.
Kontenabgleich Anzeige von Overview umbauen
Die Anzeige von Overview wurde verändert, so dass man jetzt noch
schneller abgleichen kann.
TODO: Anzeige von Proposals der Anzeige von Overview angleichen.
Kontenabgleich Behebt Syntaxfehler
Kontenabgleich Umgang mit Stornos ändern
Der Umgang mit Stornos wurde geändert. Statt Stornos nicht anzuzeigen,
gibt es jetzt einen Filter dafür. Der Saldo von BBs und BTs errechnet
sich jetzt nur noch aus den gefilterten Objekten.
Weiterhin gibt es jetzt eine onchange-Action auf den Datumsfeldern
im Filter und der Filter-Button wird nicht mehr angezeigt.
Kontenabgleich Anpassung der proposals an neue Ansicht
Automatische Vorschläge werden jetzt auch in der neuen Darstellung
angezeigt.
Kontenabgleich Mastercheckbox wieder da und Spaltenreihenfolge vertauscht
Die Checkbox, bei der man alle Vorschläge an-/abhaken kann, wird
jetzt wieder angezeigt. Weiterhin wird jetzt auch der Betrag und
das Belegdatum weiter vorne angezeigt.
Kontenabgleich Saldo in der richtigen Spalte
Der Saldo wird jetzt in der richtigen Spalte angezeigt.
Kontenabgleich Buchungen außerhalb des Filters ausgrauen
Bisher kam es vor, dass Buchungen, die in einen Zeitraum außerhalb
des Filters fallen (weil ihre Gegenbuchung in den gefilterten Zeitraum
fällt), trotzdem angezeigt wurden, aber nicht in der
Summe mitgerechnet wurden. Solche Buchungen werden jetzt nur noch
in grauer Schrift angezeigt.
Kontenabgleich Abgeglichene Buchungen besser Filtern
Es kam bisher vor, dass abgeglichene Buchungen, bei denen eine Buchung
nach dem gefilterten Zeitraum un eine Buchung vor dem gefilterten
Zeitraum lag, angezeigt wurden. Dabei war es bisher nicht erforderlich,
dass eine Buchung im gefilterten Zeitraum lag. Jetzt muss mindestens
eine Buchung im gefilterten Zeitraum liegen, damit die abgeglichenen
Buchungen auch angezeigt werden.
Kontenabgleich Absolute Bilanz anzeigen
Jetzt wird auch immer die Summe von BB's und BT's von Beginn der
Buchungen bis zum "Todate" angezeigt (inklusive Stornos).
Banktransactions nach Datum filtern
Man kann jetzt Bankbewegungen nach Datum filtern. Weiterhin funktioniert
jetzt auch der Callback, nachdem man eine Debitorenbuchung erstellt.
Banktransactions: Datumsfilter nach Sortierung beibehalten
Bisher ging der Datumsfilter nach der Sortierung verloren, jetzt
wird er beibehalten.
Kontenabgleich Mehr Vorschläge machen
Bisher wurden nur Vorschläge gemacht, wenn Rechnungen via Bankbewegungen
bezahlt wurden. Jetzt werden auch Vorschläge gemacht, wenn Beträge
deckungsgleich sind und Kontoverbindung von Kunde/Lieferant und
Bankbeleg übereinstimmen.
Kontenabgleich Reconciliate-Button taucht nicht auf
Behebt einen Bug, bei dem der Abgleichen-Knopf nicht auftaucht,
obwohl er das sollte. Das Problem lag daran, dass die beiden Zahlen
6.286,18 und -6.286,18 aufaddiert in Perl nicht Null ergaben.
Kontenabgleich Fügt mehr Proposals hinzu
Auf diese Weise werden noch mehr Übereinstimmungen gefunden.
Banktransactions Teilzahlungen funktionieren jetzt besser
Bisher haben Teilzahlungen zwar funktioniert, jedoch tauchten die
Bankbewegungen, mit denen sie erstellt wurden immer wieder in der
Liste auf. Es lag daran, dass invoice_amount in der Tabelle
bank_transactions falsch gesetzt wurde.
Banktransactions 40 statt 5 Bankbewegungen pro Seite anzeigen
Kontenabgleich Entfernen von Tests
Entfernt alten Code, der die ersten Tests enthielt.
Kontenabgleich Umbenennung von Controller
Der Controller SL/Controller/Reconciliation_3.pm wird umbenannt in
SL/Controller/Reconciliation.pm
Kontenabgleich Umbenennung von Ordner whole_reconciliation
Der Order whole_reconciliation wurde in reconciliation umbenannt.
Banktransactions Minuspunkte für transdate vergeben
Wenn eine Rechnung nicht 30 Tage vor der Bankbewegung liegt, so
wird jetzt ein Minuspunkt für die Vorschläge vergeben.
Kontenabgleich/Banktransaction Rechte hinzufügen
Bank CSV Import - Purpose zusammengefügt
Icons bei Reconciliation
Kontenabgleich Icons in Vorschlägen übernehmen
Icons werden jetzt auch bei Vorschlägen benutzt. Weiterhin wurde
unsinniges Attribut bei Icons im Overview entfernt.
Kontenabgleich bei Import Standard-Währung setzen
Beim Import wird jetzt die Standard-Währung eingetragen, wenn keine
andere Währung vorhanden ist. Weiterhin ist die Währung jetzt auch ein
Pflichtfeld durch ein NOT NULL-Constraint.
Kontenabgleich Spalte in Summenzeile ergänzen
Aufgrund der neu hinzugekommenen Icons musste noch eine Spalte in
der Zeile eingefügt werden, wo die Summen angezeigt werden.
Banktransaction Betrag im Filter parsen
Beim Suchen von Rechnungen im "Rechnung hinzufügen"-Modus wurde der
Betrag im Filter nicht geparst. Man musste bisher also immer einen
Punkt statt einem Komma eingeben.
Kontenabgleich CSS verbessern
Bisher konnte man nicht bis an den unteren Bildschirmrand scrollen.
Dieser Commit versucht dies zu beheben. Allerdings ist es unklar,
ob das Problem durch den Commit behoben ist.
Banktransactions Automatisches bezahlen von Vorschlägen
Banktransactions Speichern von Vorschlägen
Automatische Vorschläge, die kivitendo schon macht, können jetzt
auch benutzt werden, um vorgeschlagene Rechnungen direkt zu speichern.
Banktransactions Bugfix
Bisher wurden der "Rechnung speichern"-Button und der "Save proposals"-
Button nur getogglet. Das hat dazu geführt, dass wenn man zweimal
auf den Reiter "Proposals" drückt, der Rechnung speichern-Butten
angezeigt wurde, obwohl der Save proposals-Button angezeigt werden
musste. Jetzt werden die Buttons versteckt und angezeigt, was den
Fehler behebt.
Banktransactions - kein von und bis wenn leer
Die Wörter "von" und "bis" nur anzeigen, wenn auch ein von- oder
bis-Datum gesetzt ist.
Bankbewegungen - in Tooltip Tagesdelta anzeigen
Anzahl der Tage zwischen (vorgeschlagenem) Rechnungsdatum und
Bankeingangsdatum wird in Klammern hinter dem Bankdatum angezeigt.
Banktransactions - bei Proposals trotz sub-cent Matchen
Übereinstimmung muß nicht genau sein, sondern kleiner 1 Cent.
Wegen Rundungsproblematik.
String-Vergleich bei Banktransactions - mind. 3 Zeichen
Mindestlänge für Wortvergleich.
testing - agreement modifying tests
Banktransactions Belegdatum bei Rechnung zuweisen
Wenn man auf Rechnung zuweisen klickt, wird jetzt sowohl von dem
Bankbeleg als auch von den Rechnungen das Belegdatum angezeigt.
Weiterhin wurde ein Filter für das Datum hinzugefügt.
Kontenabgleich/Banktransactions
Reiter 'Set cleared entfernen' im Kontenabgleich.
Bei Vorgeschlagenen Rechnungen anzeigen, ob EK oder VK.
Deutsche Übersetzungen
VERSION angepasst
MT940 Importer der aqbanking-cli über CSV-Import aufruft
Noch alles hartkodiert
Kein Dublettencheck
MT940 Importer der aqbanking-cli über CSV-Import aufruft
Noch alles hartkodiert
Kein Dublettencheck
Bank - in Bankkontodropdowns Kontoname berücksichtigen
Bankerweiterung - Offener Betrag bei Rechnungsfilter
wenn man aus Bankbuchungen eine Rechnung zuweisen möchte.
RB - corrected all after rebase
RB - GLTransaction.pm nach Rebase gefixed