1. Rechnungen, die bereits gemahnt wurden, wurden zu früh erneut zur Mahnung angeboten, weil der Mahnzeitraum auf das ursprüngliche Fälligkeitsdatum der Rechnung bezogen wurde und nicht auf das Fälligkeitsdatum der vorhergehenden Mahnstufe.
2. Wurden gleichzeitig Mahnungen für mehrere Mahnstufen generiert, so wurden die falschen Vorlagen benutzt.
3. Die kummulierten Mahnkosten und die Zinsen wurden in der Liste der neu zu erstellenden Mahnungen falsch angezeigt.
Weiterhin wurde die Dokumentation für die Vorlagenvariablen um eine Sektion über Mahnungen erweitert.
foreach my $ref (@{ $form->{DUNNING} }) {
$ref->{fee} = $form->format_amount($myconfig, $ref->{fee}, 2);
- $ref->{interest} = $form->format_amount($myconfig, ($ref->{interest} * 100));
+ $ref->{interest_rate} = $form->format_amount($myconfig, ($ref->{interest_rate} * 100));
}
$dbh->disconnect();
for my $i (1 .. $form->{rowcount}) {
$form->{"fee_$i"} = $form->parse_amount($myconfig, $form->{"fee_$i"}) * 1;
- $form->{"interest_$i"} = $form->parse_amount($myconfig, $form->{"interest_$i"}) / 100;
+ $form->{"interest_rate_$i"} = $form->parse_amount($myconfig, $form->{"interest_rate_$i"}) / 100;
if (($form->{"dunning_level_$i"} ne "") &&
($form->{"dunning_description_$i"} ne "")) {
@values = (conv_i($form->{"dunning_level_$i"}), $form->{"dunning_description_$i"},
$form->{"email_subject_$i"}, $form->{"email_body_$i"},
- $form->{"template_$i"}, $form->{"fee_$i"}, $form->{"interest_$i"},
+ $form->{"template_$i"}, $form->{"fee_$i"}, $form->{"interest_rate_$i"},
$form->{"active_$i"} ? 't' : 'f', $form->{"auto_$i"} ? 't' : 'f', $form->{"email_$i"} ? 't' : 'f',
$form->{"email_attachment_$i"} ? 't' : 'f', conv_i($form->{"payment_terms_$i"}), conv_i($form->{"terms_$i"}));
if ($form->{"id_$i"}) {
qq|UPDATE dunning_config SET
dunning_level = ?, dunning_description = ?,
email_subject = ?, email_body = ?,
- template = ?, fee = ?, interest = ?,
+ template = ?, fee = ?, interest_rate = ?,
active = ?, auto = ?, email = ?,
email_attachment = ?, payment_terms = ?, terms = ?
WHERE id = ?|;
$query =
qq|INSERT INTO dunning_config
(dunning_level, dunning_description, email_subject, email_body,
- template, fee, interest, active, auto, email,
+ template, fee, interest_rate, active, auto, email,
email_attachment, payment_terms, terms)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)|;
}
my ($dunning_id) = selectrow_query($form, $dbh, qq|SELECT nextval('id')|);
+ my $q_update_ar = qq|UPDATE ar SET dunning_config_id = ? WHERE id = ?|;
+ my $h_update_ar = prepare_query($form, $dbh, $q_update_ar);
+
+ my $q_insert_dunning =
+ qq|INSERT INTO dunning (dunning_id, dunning_config_id, dunning_level,
+ trans_id, fee, interest, transdate, duedate)
+ VALUES (?, ?,
+ (SELECT dunning_level FROM dunning_config WHERE id = ?),
+ ?,
+ (SELECT SUM(fee)
+ FROM dunning_config
+ WHERE dunning_level <= (SELECT dunning_level FROM dunning_config WHERE id = ?)),
+ (SELECT (amount - paid) * (current_date - transdate) FROM ar WHERE id = ?)
+ * (SELECT interest_rate FROM dunning_config WHERE id = ?)
+ / 360,
+ current_date,
+ current_date + (SELECT payment_terms FROM dunning_config WHERE id = ?))|;
+ my $h_insert_dunning = prepare_query($form, $dbh, $q_insert_dunning);
+
+ my @invoice_ids;
+ my ($next_dunning_config_id, $customer_id);
+ my $send_email = 0;
+
foreach my $row (@{ $rows }) {
+ push @invoice_ids, $row->{invoice_id};
+ $next_dunning_config_id = $row->{next_dunning_config_id};
+ $customer_id = $row->{customer_id};
+
+ @values = ($row->{next_dunning_config_id}, $row->{invoice_id});
+ do_statement($form, $h_update_ar, $q_update_ar, @values);
+
+ $send_email |= $row->{email};
- $form->{"interest_$row"} = $form->parse_amount($myconfig,$form->{"interest_$row"});
- $form->{"fee_$row"} = $form->parse_amount($myconfig,$form->{"fee_$row"});
- $form->{send_email} = $form->{"email_$row"};
-
- $query = qq|UPDATE ar SET dunning_config_id = ? WHERE id = ?|;
- @values = ($form->{"next_dunning_config_id_$row"},
- $form->{"inv_id_$row"});
- do_query($form, $dbh, $query, @values);
-
- $query =
- qq|INSERT INTO dunning (dunning_id, dunning_config_id, dunning_level,
- trans_id, fee, interest, transdate, duedate)
- VALUES (?, ?, (SELECT dunning_level FROM dunning_config WHERE id = ?),
- ?, ?, ?, current_date, ?)|;
- @values = ($dunning_id,
- conv_i($form->{"next_dunning_config_id_$row"}),
- conv_i($form->{"next_dunning_config_id_$row"}),
- conv_i($form->{"inv_id_$row"}), $form->{"fee_$row"},
- $form->{"interest_$row"},
- conv_date($form->{"next_duedate_$row"}));
- do_query($form, $dbh, $query, @values);
+ my $next_config_id = conv_i($row->{next_dunning_config_id});
+ my $invoice_id = conv_i($row->{invoice_id});
+
+ @values = ($dunning_id, $next_config_id, $next_config_id,
+ $invoice_id, $next_config_id, $invoice_id,
+ $next_config_id, $next_config_id);
+ do_statement($form, $h_insert_dunning, $q_insert_dunning, @values);
}
+ $h_update_ar->finish();
+ $h_insert_dunning->finish();
+
my $query =
- qq|SELECT invnumber, ordnumber, customer_id, amount, netamount,
- ar.transdate, ar.duedate, paid, amount - paid AS open_amount,
- template AS formname, email_subject, email_body, email_attachment,
- da.fee, da.interest, da.transdate AS dunning_date,
- da.duedate AS dunning_duedate,
- c.name, c.street, c.zipcode, c.city, c.country, c.department_1, c.department_2
+ qq|SELECT
+ ar.invnumber, ar.ordnumber, ar.amount, ar.netamount,
+ ar.transdate, ar.duedate, ar.paid, ar.amount - ar.paid AS open_amount,
+ da.fee, da.interest, da.transdate AS dunning_date, da.duedate AS dunning_duedate
FROM ar
- LEFT JOIN dunning_config ON (dunning_config.id = ar.dunning_config_id)
- LEFT JOIN dunning da ON (ar.id = da.trans_id AND dunning_config.dunning_level = da.dunning_level)
- LEFT JOIN customer c ON (ar.customer_id = c.id)
+ LEFT JOIN dunning_config cfg ON (cfg.id = ar.dunning_config_id)
+ LEFT JOIN dunning da ON (ar.id = da.trans_id AND cfg.dunning_level = da.dunning_level)
WHERE ar.id IN (|
- . join(", ", map("?", @{ $form->{"inv_ids"} })) . qq|)|;
+ . join(", ", map { "?" } @invoice_ids) . qq|)|;
- my $sth = prepare_execute_query($form, $dbh, $query, @{ $form->{"inv_ids"} });
+ my $sth = prepare_execute_query($form, $dbh, $query, @invoice_ids);
my $first = 1;
while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
if ($first) {
map({ $form->{"dn_$_"} = []; } keys(%{$ref}));
$first = 0;
}
+
+ $ref->{interest_rate} = $form->format_amount($myconfig, $ref->{interest_rate} * 100);
map { $ref->{$_} = $form->format_amount($myconfig, $ref->{$_}, 2) } qw(amount netamount paid open_amount fee interest);
- map { $form->{$_} = $ref->{$_} } keys %$ref;
- #print(STDERR Dumper($ref));
map { push(@{ $form->{"dn_$_"} }, $ref->{$_})} keys %$ref;
+ map { $form->{$_} = $ref->{$_} } keys %{ $ref };
}
$sth->finish;
- IS->customer_details($myconfig,$form);
- #print(STDERR Dumper($form->{dn_invnumber}));
- $form->{templates} = "$myconfig->{templates}";
-
-
+ $query =
+ qq|SELECT id AS customer_id, name, street, zipcode, city, country, department_1, department_2, email
+ FROM customer
+ WHERE id = ?|;
+ $ref = selectfirst_hashref_query($form, $dbh, $query, $customer_id);
+ map { $form->{$_} = $ref->{$_} } keys %{ $ref };
- $form->{language} = $form->get_template_language(\%myconfig);
+ $query =
+ qq|SELECT
+ cfg.interest_rate, cfg.template AS formname,
+ cfg.email_subject, cfg.email_body, cfg.email_attachment,
+ (SELECT fee
+ FROM dunning
+ WHERE dunning_id = ?
+ LIMIT 1)
+ AS fee,
+ (SELECT SUM(interest)
+ FROM dunning
+ WHERE dunning_id = ?)
+ AS total_interest,
+ (SELECT SUM(amount) - SUM(paid)
+ FROM ar
+ WHERE id IN (| . join(", ", map { "?" } @invoice_ids) . qq|))
+ AS total_open_amount
+ FROM dunning_config cfg
+ WHERE id = ?|;
+ $ref = selectfirst_hashref_query($form, $dbh, $query, $dunning_id, $dunning_id, @invoice_ids, $next_dunning_config_id);
+ map { $form->{$_} = $ref->{$_} } keys %{ $ref };
+
+ $form->{interest_rate} = $form->format_amount($myconfig, $ref->{interest_rate} * 100);
+ $form->{fee} = $form->format_amount($myconfig, $ref->{fee}, 2);
+ $form->{total_interest} = $form->format_amount($myconfig, $form->round_amount($ref->{total_interest}, 2), 2);
+ $form->{total_open_amount} = $form->format_amount($myconfig, $form->round_amount($ref->{total_open_amount}, 2), 2);
+ $form->{total_amount} = $form->format_amount($myconfig, $form->round_amount($ref->{fee} + $ref->{total_interest} + $ref->{total_open_amount}, 2), 2);
+
+ $form->{templates} = "$myconfig->{templates}";
+ $form->{language} = $form->get_template_language(\%myconfig);
$form->{printer_code} = $form->get_printer_code(\%myconfig);
if ($form->{language} ne "") {
$form->{"IN"} =~ s/html$/odt/;
}
- if ($form->{"send_email"} && ($form->{email} ne "")) {
+ if ($send_email && ($form->{email} ne "")) {
$form->{media} = 'email';
}
# connect to database
my $dbh = $form->dbconnect($myconfig);
- my $where =
- qq| WHERE (a.paid < a.amount)
- AND (a.duedate < current_date)
- AND (dnn.id =
- (SELECT id FROM dunning_config
- WHERE dunning_level >
- (SELECT
- CASE
- WHEN a.dunning_config_id IS NULL
- THEN 0
- ELSE (SELECT dunning_level
- FROM dunning_config
- WHERE id = a.dunning_config_id
- ORDER BY dunning_level
- LIMIT 1)
- END
- FROM dunning_config LIMIT 1)
- LIMIT 1)) |;
+ my $where;
my @values;
$form->{customer_id} = $1 if ($form->{customer} =~ /--(\d+)$/);
push(@values, $form->{minamount});
}
- $paymentdate = $form->{paymentuntil} ? $dbh->quote($form->{paymentuntil}) :
- "current_date";
-
$query =
- qq|SELECT a.id, a.ordnumber, a.transdate, a.invnumber, a.amount,
+ qq|SELECT
+ a.id, a.ordnumber, a.transdate, a.invnumber, a.amount,
ct.name AS customername, a.customer_id, a.duedate,
- da.fee AS old_fee, dnn.active, dnn.email, dnn.fee + da.fee AS fee,
- dn.dunning_description, da.transdate AS dunning_date, da.duedate AS dunning_duedate,
- a.duedate + dnn.terms - current_date AS nextlevel,
- $paymentdate - a.duedate AS pastdue, dn.dunning_level,
- current_date + dnn.payment_terms AS next_duedate,
- dnn.dunning_description AS next_dunning_description, dnn.id AS next_dunning_config_id,
- dnn.interest AS interest_rate, dnn.terms
- FROM dunning_config dnn, ar a
- JOIN customer ct ON (a.customer_id = ct.id)
- LEFT JOIN dunning_config dn ON (dn.id = a.dunning_config_id)
- LEFT JOIN dunning da ON ((da.trans_id = a.id) AND (dn.dunning_level = da.dunning_level))
+
+ cfg.dunning_description, cfg.dunning_level,
+
+ d.transdate AS dunning_date, d.duedate AS dunning_duedate,
+ d.fee, d.interest,
+
+ a.duedate + cfg.terms - current_date AS nextlevel,
+ current_date - COALESCE(d.duedate, a.duedate) AS pastdue,
+ current_date + cfg.payment_terms AS next_duedate,
+
+ nextcfg.dunning_description AS next_dunning_description,
+ nextcfg.id AS next_dunning_config_id,
+ nextcfg.terms, nextcfg.active, nextcfg.email
+
+ FROM ar a
+
+ LEFT JOIN customer ct ON (a.customer_id = ct.id)
+ LEFT JOIN dunning_config cfg ON (a.dunning_config_id = cfg.id)
+ LEFT JOIN dunning_config nextcfg ON
+ (nextcfg.id =
+ (SELECT id
+ FROM dunning_config
+ WHERE dunning_level >
+ COALESCE((SELECT dunning_level
+ FROM dunning_config
+ WHERE id = a.dunning_config_id
+ ORDER BY dunning_level DESC
+ LIMIT 1),
+ 0)
+ LIMIT 1))
+ LEFT JOIN dunning d ON ((d.trans_id = a.id) AND (cfg.dunning_level = d.dunning_level))
+
+ WHERE (a.paid < a.amount)
+ AND (a.duedate < current_date)
+
$where
- ORDER BY a.id, transdate, duedate, name|;
+ ORDER BY a.id, transdate, duedate, name|;
my $sth = prepare_execute_query($form, $dbh, $query, @values);
$form->{DUNNINGS} = [];
while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
- $ref->{interest} = ($ref->{amount} * $ref->{pastdue} * $ref->{interest_rate}) / 360;
+ next if !$ref->{terms} || ($ref->{pastdue} < $ref->{terms});
+
$ref->{interest} = $form->round_amount($ref->{interest}, 2);
- map({ $ref->{$_} = $form->format_amount($myconfig, $ref->{$_}, 2)} qw(amount fee interest));
- if ($ref->{pastdue} >= $ref->{terms}) {
- push(@{ $form->{DUNNINGS} }, $ref);
- }
+ push(@{ $form->{DUNNINGS} }, $ref);
}
$sth->finish;
sub print_dunning {
$main::lxdebug->enter_sub();
- my ($self, $myconfig, $form, $dunning_id, $userspath,$spool, $sendmail) = @_;
+ my ($self, $myconfig, $form, $dunning_id, $userspath, $spool, $sendmail) = @_;
# connect to database
my $dbh = $form->dbconnect_noauto($myconfig);
}
$sth->finish;
- IS->customer_details($myconfig,$form);
+ $query =
+ qq|SELECT id AS customer_id, name, street, zipcode, city, country, department_1, department_2, email
+ FROM customer
+ WHERE id =
+ (SELECT customer_id
+ FROM dunning d
+ LEFT JOIN ar ON (d.trans_id = ar.id)
+ WHERE d.id = ?)|;
+ $ref = selectfirst_hashref_query($form, $dbh, $query, $dunning_id);
+ map { $form->{$_} = $ref->{$_} } keys %{ $ref };
+
+ $query =
+ qq|SELECT
+ cfg.interest_rate, cfg.template AS formname,
+ cfg.email_subject, cfg.email_body, cfg.email_attachment,
+ d.fee, d.dunning_date,
+ (SELECT SUM(interest)
+ FROM dunning
+ WHERE dunning_id = ?)
+ AS total_interest,
+ (SELECT SUM(amount) - SUM(paid)
+ FROM ar
+ WHERE id IN
+ (SELECT trans_id
+ FROM dunning
+ WHERE dunning_id = ?))
+ AS total_open_amount
+ FROM dunning d
+ LEFT JOIN dunning_config cfg ON (d.dunning_config_id = cfg.id)
+ WHERE d.dunning_id = ?
+ LIMIT 1|;
+ $ref = selectfirst_hashref_query($form, $dbh, $query, $dunning_id, $dunning_id, $dunning_id);
+ map { $form->{$_} = $ref->{$_} } keys %{ $ref };
+
+ $form->{interest_rate} = $form->format_amount($myconfig, $ref->{interest_rate} * 100);
+ $form->{fee} = $form->format_amount($myconfig, $ref->{fee}, 2);
+ $form->{total_interest} = $form->format_amount($myconfig, $form->round_amount($ref->{total_interest}, 2), 2);
+ $form->{total_open_amount} = $form->format_amount($myconfig, $form->round_amount($ref->{total_open_amount}, 2), 2);
+ $form->{total_amount} = $form->format_amount($myconfig, $form->round_amount($ref->{fee} + $ref->{total_interest} + $ref->{total_open_amount}, 2), 2);
+
+
$form->{templates} = "$myconfig->{templates}";
$form->{language} = $form->get_template_language(\%myconfig);
"$form->{script}?action=edit_config&login=$form->{login}&password=$form->{password}"
unless $form->{callback};
- @column_index = qw(dunning_level dunning_description active auto email payment_terms terms fee interest template);
+ @column_index = qw(dunning_level dunning_description active auto email payment_terms terms fee interest_rate template);
$column_header{dunning_level} =
qq|<th class=listheading>|
qq|<th class=listheading>|
. $locale->text('Fee')
. qq|</th>|;
- $column_header{interest} =
+ $column_header{interest_rate} =
qq|<th class=listheading>|
. $locale->text('Interest Rate')
. qq|</th>|;
$column_data{payment_terms} = qq|<td><input name=payment_terms_$i size=3 value="$ref->{payment_terms}"></td>|;
$column_data{terms} = qq|<td><input name=terms_$i size=3 value="$ref->{terms}"></td>|;
$column_data{fee} = qq|<td><input name=fee_$i size=5 value="$ref->{fee}"></td>|;
- $column_data{interest} = qq|<td><input name=interest_$i size=4 value="$ref->{interest}">%</td>|;
+ $column_data{interest_rate} = qq|<td><input name=interest_rate_$i size=4 value="$ref->{interest}">%</td>|;
$column_data{template} = qq|<td><input name=template_$i value="$ref->{template}"></td>|;
$column_data{payment_terms} = qq|<td><input size=3 name=payment_terms_$i></td>|;
$column_data{terms} = qq|<td><input size=3 name=terms_$i></td>|;
$column_data{fee} = qq|<td><input size=5 name=fee_$i></td>|;
- $column_data{interest} = qq|<td><input size=4 name=interest_$i>%</td>|;
+ $column_data{interest_rate} = qq|<td><input size=4 name=interest_rate_$i>%</td>|;
$column_data{template} = qq|<td><input name=template_$i></td>|;
<td colspan=3><select name=department>$form->{selectdepartment}</select></td>
</tr>
| if $form->{selectdepartment};
- $form->{title} = $locale->text('Start Dunning Process');
- $form->{nextsub} = "show_invoices";
-
- # use JavaScript Calendar or not
- $form->{jsscript} = $jscalendar;
- $jsscript = "";
- if ($form->{jsscript}) {
-
- # with JavaScript Calendar
- $button1 = qq|
- <td><input name=paymentuntil id=paymentuntil size=11 title="$myconfig{dateformat}" onBlur=\"check_right_date_format(this)\">
- <input type=button name=paymentuntil id="trigger1" value=|
- . $locale->text('button') . qq|></td>
- |;
- #write Trigger
- $jsscript =
- Form->write_trigger(\%myconfig, "1", "paymentuntil", "BR", "trigger1");
- } else {
+ $form->{title} = $locale->text('Start Dunning Process');
+ $form->{nextsub} = "show_invoices";
- # without JavaScript Calendar
- $button1 =
- qq|<td><input name=paymentuntil id=paymentuntil size=11 title="$myconfig{dateformat}" onBlur=\"check_right_date_format(this)\"></td>|;
- }
- $form->{fokus} = "search.customer";
+ $form->{jsscript} = 1;
+ $form->{fokus} = "search.customer";
$form->{javascript} .= qq|<script type="text/javascript" src="js/common.js"></script>|;
- $form->header;
+ $form->header();
+
$onload = qq|focus()|;
$onload .= qq|;setupDateFormat('|. $myconfig{dateformat} .qq|', '|. $locale->text("Falsches Datumsformat!") .qq|')|;
$onload .= qq|;setupPoints('|. $myconfig{numberformat} .qq|', '|. $locale->text("wrongformat") .qq|')|;
+
print qq|
<body onLoad="$onload">
<th align=right nowrap>| . $locale->text('Notes') . qq|</th>
<td colspan=3><input name=notes size=40></td>
</tr>
- <tr>
- <th align=right nowrap>| . $locale->text('Payment until') . qq|</th>
- $button1
- </tr>
</table>
</td>
</tr>
"$form->{script}?action=show_invoices&login=$form->{login}&password=$form->{password}&customer=$form->{customer}&invnumber=$form->{invnumber}&ordnumber=$form->{ordnumber}&paymentuntil=$form->{paymentuntil}&groupinvoices=$form->{groupinvoices}&minamount=$form->{minamount}&dunning_level=$form->{dunning_level}¬es=$form->{notes}"
unless $form->{callback};
- @column_index = qw(dunning_description active email customername invnumber invdate inv_duedate invamount next_duedate fee interest );
+ @column_index = qw(dunning_description dunning_description_next active email customername invnumber invdate inv_duedate amount next_duedate fee interest );
$column_header{dunning_description} =
- qq|<th class=listheading>|
+ qq|<th class="listheading" colspan="2">|
. $locale->text('Current / Next Level')
. qq|</th>|;
$column_header{active} =
qq|<th class=listheading>|
. NTI($cgi->checkbox('-name' => 'selectall_active',
'-label' => $locale->text('Active?'),
- '-checked' => 1,
+ '-checked' => 0,
'-onclick' => "checkbox_check_all('selectall_active', 'active_', 1, " . scalar(@{ $form->{DUNNINGS} }) . ")"))
. qq|</th>|;
$column_header{email} =
qq|<th class=listheading>|
. $locale->text('Invdate')
. qq|</th>|;
- $column_header{invamount} =
+ $column_header{amount} =
qq|<th class=listheading>|
. $locale->text('Amount')
. qq|</th>|;
. qq|</th>|;
$column_header{interest} =
qq|<th class=listheading>|
- . $locale->text('Total Interest')
+ . $locale->text('Interest')
. qq|</th>|;
$form->header;
<table width=100%>
<tr>
- <th class=listtop colspan=11>$form->{title}</th>
+ <th class=listtop colspan=12>$form->{title}</th>
</tr>
<tr height="5"></tr>
<tr>|;
- map { print "$column_header{$_}\n" } @column_index;
+ map { print "$column_header{$_}\n" if $column_header{$_}; } @column_index;
print qq|
</tr>
<tr valign=top class=listrow$j>
|;
- $form->{selectdunning} =~ s/ selected//g;
- if ($ref->{next_dunning_config_id} ne "") {
- $form->{selectdunning} =~ s/value=$ref->{next_dunning_config_id}/value=$ref->{next_dunning_config_id} selected/;
- }
-
-
- $dunning = qq|<select name=next_dunning_config_id_$i>$form->{selectdunning}</select>|;
-
+ $form->{selectdunning} =~ s/ selected//g;
+ if ($ref->{next_dunning_config_id} ne "") {
+ $form->{selectdunning} =~ s/value=$ref->{next_dunning_config_id}/value=$ref->{next_dunning_config_id} selected/;
+ }
- $column_data{dunning_description} = qq|<td><input type=hidden name=inv_id_$i size=2 value="$ref->{id}"><input type=hidden name=customer_id_$i size=2 value="$ref->{customer_id}">$ref->{dunning_level}: $dunning</td>|;
+ $column_data{dunning_description} =
+ qq|<td>|
+ . qq|<input type=hidden name=inv_id_$i size=2 value="$ref->{id}">|
+ . qq|<input type=hidden name=customer_id_$i size=2 value="$ref->{customer_id}">|
+ . ($ref->{dunning_level} ? $ref->{dunning_level} : " ")
+ . qq|</td>|;
+ $column_data{dunning_description_next} =
+ qq|<td>|
+ . qq|<select name=next_dunning_config_id_$i>$form->{selectdunning}</select>|
+ . qq|</td>|;
my $active = ($ref->{active}) ? "checked" : "";
$column_data{active} =
qq|<td><input type=checkbox name=active_$i value=1 $active></td>|;
my $email = ($ref->{email}) ? "checked" : "";
- $column_data{email} =
- qq|<td><input type=checkbox name=email_$i value=1 $email></td>|;
- $column_data{next_duedate} = qq|<td><input type=hidden name=next_duedate_$i size=6 value="$ref->{next_duedate}">$ref->{next_duedate}</td>|;
+ $column_data{email} =
+ qq|<td><input type=checkbox name=email_$i value=1 $email></td>|;
+ $column_data{next_duedate} = qq|<td>$ref->{next_duedate}</td>|;
$column_data{inv_duedate} = qq|<td><input type=hidden name=inv_duedate_$i size=6 value="$ref->{duedate}">$ref->{duedate}</td>|;
$column_data{invdate} = qq|<td><input type=hidden name=invdate_$i size=6 value="$ref->{transdate}">$ref->{transdate}</td>|;
$column_data{invnumber} = qq|<td><input type=hidden name=invnumber_$i size=6 value="$ref->{invnumber}">$ref->{invnumber}</td>|;
$column_data{customername} = qq|<td><input type=hidden name=customername_$i size=6 value="$ref->{customername}">$ref->{customername}</td>|;
- $column_data{invamount} = qq|<td><input type=hidden name=invamount_$i size=6 value="$ref->{amount}">$ref->{amount}</td>|;
- $column_data{fee} = qq|<td><input type=hidden name=fee_$i size=5 value="$ref->{fee}">$ref->{fee}</td>|;
- $column_data{interest} = qq|<td><input type=hidden name=interest_$i size=4 value="$ref->{interest}">$ref->{interest}</td>|;
-
+ map { $column_data{$_} =
+ qq|<td align="right">|
+ . H($form->format_amount(\%myconfig, $ref->{$_} * 1, -2))
+ . qq|</td>|
+ } qw(amount fee interest);
map { print "$column_data{$_}\n" } @column_index;
my $active=1;
my @rows = ();
undef($form->{DUNNING_PDFS});
+
if ($form->{groupinvoices}) {
- while ($active) {
- $lastcustomer = 0;
- $form->{inv_ids} = [];
- $active = 0;
- @rows = ();
- for my $i (1 .. $form->{rowcount}) {
- $form->{"active_$i"} *= 1;
- $lastcustomer = $form->{"customer_id_$i"} unless ($lastcustomer);
- if ($form->{"active_$i"} && ($form->{"customer_id_$i"} == $lastcustomer)) {
- push(@{ $form->{inv_ids} }, $form->{"inv_id_$i"});
- $form->{"active_$i"} = 0;
- $form->{"customer_id_$i"} = 0;
- push(@rows, $i);
- } elsif ($form->{"active_$i"}) {
- $active = 1;
- } else {
- $form->{"customer_id_$i"} = 0;
- }
- }
- if (scalar(@{ $form->{inv_ids} }) != 0) {
- DN->save_dunning(\%myconfig, \%$form, \@rows, $userspath, $spool, $sendmail);
+ my %dunnings_for;
+
+ for my $i (1 .. $form->{rowcount}) {
+ next unless ($form->{"active_$i"});
+
+ $dunnings_for{$form->{"customer_id_$i"}} ||= {};
+ my $dunning_levels = $dunnings_for{$form->{"customer_id_$i"}};
+
+ $dunning_levels->{$form->{"next_dunning_config_id_$i"}} ||= [];
+ my $level = $dunning_levels->{$form->{"next_dunning_config_id_$i"}};
+
+ push @{ $level }, { "row" => $i,
+ "invoice_id" => $form->{"inv_id_$i"},
+ "customer_id" => $form->{"customer_id_$i"},
+ "next_dunning_config_id" => $form->{"next_dunning_config_id_$i"},
+ "email" => $form->{"email_$i"}, };
+ }
+
+ foreach my $levels (values %dunnings_for) {
+ foreach my $level (values %{ $levels }) {
+ next unless scalar @{ $level };
+
+ DN->save_dunning(\%myconfig, \%$form, $level, $userspath, $spool, $sendmail);
}
}
+
} else {
for my $i (1 .. $form->{rowcount}) {
- if ($form->{"active_$i"}) {
- @rows = ();
- $form->{inv_ids} = [ $form->{"inv_id_$i"} ];
- push(@rows, $i);
- DN->save_dunning(\%myconfig, \%$form, \@rows, $userspath, $spool, $sendmail);
- }
+ next unless $form->{"active_$i"};
+
+ my $level = [ { "row" => $i,
+ "invoice_id" => $form->{"inv_id_$i"},
+ "customer_id" => $form->{"customer_id_$i"},
+ "next_dunning_config_id" => $form->{"next_dunning_config_id_$i"},
+ "email" => $form->{"email_$i"}, } ];
+ DN->save_dunning(\%myconfig, \%$form, $level, $userspath, $spool, $sendmail);
}
}
+
if($form->{DUNNING_PDFS}) {
DN->melt_pdfs(\%myconfig, \%$form,$spool);
}
+
# saving the history
if(!exists $form->{addition} && $form->{id} ne "") {
$form->{snumbers} = qq|dunning_id_| . $form->{"dunning_id"};
$form->{addition} = "DUNNING STARTED";
$form->save_history($form->dbconnect(\%myconfig));
}
- # /saving the history
+ # /saving the history
+
$form->redirect($locale->text('Dunning Process started for selected invoices!'));
$lxdebug->leave_sub();
}
-
+
sub set_email {
$lxdebug->enter_sub();
. qq|</th>|;
$column_header{interest} =
qq|<th class=listheading>|
- . $locale->text('Total Interest')
+ . $locale->text('Interest')
. qq|</th>|;
$form->header;
- foreach (qw(dunning_date dunning_duedate duedate transdate customername
- amount fee interest)) {
+ foreach (qw(dunning_date dunning_duedate duedate transdate customername amount fee interest)) {
my $col = $columns{$_} ? $columns{$_} : $_;
$column_data{$col} = "<td>" . H($ref->{$_}) . "</td>";
}
</ol>
</li>
+ <li><a href="dokumentenvorlagen-und-variablen.html#dunning">
+ Variablen in Mahnungen</a>
+
+ <ol>
+ <li><a href="dokumentenvorlagen-und-variablen.html#dunning_allgemein">
+ Allgemeine Variablen</a></li>
+
+ <li><a href="dokumentenvorlagen-und-variablen.html#dunning_details">
+ Variablen für jede gemahnte Rechnung</a></li>
+ </ol>
+ </li>
+
<li><a href="dokumentenvorlagen-und-variablen.html#anderevorlagen">
Variablen in anderen Vorlagen</a></li>
zum Inhaltsverzeichnis</a></small><br>
<hr>
+ <h2><a name="dunning">Variablen in Mahnungen</a></h2>
+
+ <h3><a name="dunning_allgemein">Allgemeine Variablen:</a></h3>
+
+ <p>Die Variablen des Verkäufers stehen wie gewohnt
+ als <code>employee_...</code> zur Verfügung. Die Adressdaten des
+ Kunden stehen als Variablen <code>name</code>, <code>street</code>,
+ <code>zipcode</code>, <code>city</code>, <code>country</code>,
+ <code>department_1</code>, <code>department_2</code>, und
+ <code>email</code> zur Verfügung.
+ </p>
+
+ <p>Weitere Variablen beinhalten:</p>
+
+ <p>
+ <table border="1">
+ <tr><th>Variablenname</th><th>Bedeutung</th></tr>
+ <tr>
+ <td><code>dunning_date</code></td>
+ <td>Datum der Mahnung</td>
+ </tr>
+ <tr>
+ <td><code>dunning_duedate</code></td>
+ <td>Fälligkeitsdatum für diese Mahhnung</td>
+ </tr>
+ <tr>
+ <td><code>fee</code></td>
+ <td>Kummulative Mahngebühren</td>
+ </tr>
+ <tr>
+ <td><code>interest_rate</code></td>
+ <td>Zinssatz per anno in Prozent</td>
+ </tr>
+ <tr>
+ <td><code>total_amount</code></td>
+ <td>Gesamter noch zu zahlender Betrag als <code>fee</code> + <code>total_interest</code> + <code>total_open_amount</code></td>
+ </tr>
+ <tr>
+ <td><code>total_interest</code></td>
+ <td>Zinsen per anno über alle Rechnungen</td>
+ </tr>
+ <tr>
+ <td><code>total_open_amount</code></td>
+ <td>Summe über alle offene Beträge der Rechnungen</td>
+ </tr>
+ </table>
+ </p>
+
+ <h3><a name="dunning_details">
+ Variablen für jede gemahnte Rechnung:</a></h3>
+
+ <p>
+ <table border="1">
+ <tr><th>Variablenname</th><th>Bedeutung</th></tr>
+ <tr>
+ <td><code>dn_amount</code></td>
+ <td>Rechnungssumme (brutto)</td>
+ </tr>
+ <tr>
+ <td><code>dn_duedate</code></td>
+ <td>Originales Fälligkeitsdatum der Rechnung</td>
+ </tr>
+ <tr>
+ <td><code>dn_dunning_date</code></td>
+ <td>Datum der Mahnung</td>
+ </tr>
+ <tr>
+ <td><code>dn_dunning_duedate</code></td>
+ <td>Fälligkeitsdatum der Mahnung</td>
+ </tr>
+ <tr>
+ <td><code>dn_fee</code></td>
+ <td>Kummulative Mahngebühr (ist die gleiche wie für die ganze Mahnung, da die Gebühr nur einmal pro Mahnung erhoben wird)</td>
+ </tr>
+ <tr>
+ <td><code>dn_interest</code></td>
+ <td>Zinsen per anno f&uum;r diese Rechnung</td>
+ </tr>
+ <tr>
+ <td><code>dn_invnumber</code></td>
+ <td>Rechnungsnummer</td>
+ </tr>
+ <tr>
+ <td><code>dn_netamount</code></td>
+ <td>Rechnungssumme (netto)</td>
+ </tr>
+ <tr>
+ <td><code>dn_open_amount</code></td>
+ <td>Offener Rechnungsbetrag</td>
+ </tr>
+ <tr>
+ <td><code>dn_ordnumber</code></td>
+ <td>Bestellnummer</td>
+ </tr>
+ <tr>
+ <td><code>dn_transdate</code></td>
+ <td>Rechnungsdatum</td>
+ </tr>
+ </table>
+ </p>
+
+ <small><a href="dokumentenvorlagen-und-variablen.html#inhaltsverzeichnis">
+ zum Inhaltsverzeichnis</a></small><br>
+ <hr>
+
<h2><a name="anderevorlagen">
Variablen in anderen Vorlagen</a></h2>
'Increase' => 'Erhöhen',
'Individual Items' => 'Einzelteile',
'Information' => 'Information',
+ 'Interest' => 'Zinsen',
'Interest Rate' => 'Zinssatz',
'Internal Notes' => 'interne Bemerkungen',
'International' => 'Ausland',
'Payment date missing!' => 'Tag der Zahlung fehlt!',
'Payment posted!' => 'Zahlung gebucht!',
'Payment terms deleted!' => 'Zahlungskonditionen gelöscht!',
- 'Payment until' => 'Zahlungseingänge bis',
'Payments' => 'Zahlungsausgänge',
'Pg Database Administration' => 'Datenbankadministration',
'Phone' => 'Telefon',
'Tax number' => 'Steuernummer',
'Tax paid' => 'Vorsteuer',
'Tax-o-matic Account' => 'Automatikbuchung auf Konto',
- 'Tax-o-matic Account: ' => '',
'Taxaccount_coa' => 'Automatikkonto',
'Taxation' => 'Versteuerungs Verfahren',
'Taxdescription_coa' => 'Steuer',
'Top Level' => 'Hauptartikelbezeichnung',
'Total' => 'Summe',
'Total Fees' => 'Kumulierte Gebühren',
- 'Total Interest' => 'Kumulierte Zinsen',
'Trade Discount' => 'Rabatt',
'Transaction Date missing!' => 'Buchungsdatum fehlt!',
'Transaction deleted!' => 'Buchung gelöscht!',
'<%total%> -- Amount payable' => '<%total%> -- Noch zu bezahlender Betrag',
'A unit with this name does already exist.' => 'Eine Einheit mit diesem Namen existiert bereits.',
'ADDED' => 'Hinzugefügt',
- 'AP' => 'Einkauf',
- 'AR' => 'Verkauf',
'Account' => 'Konto',
'Account Category A' => 'Aktiva/Mittelverwendung',
'Account Category C' => 'Kosten',
'Account Category I' => 'Erlöskonto',
'Account Category L' => 'Passiva/Mittelherkunft',
'Account Category Q' => 'Passiva',
+ 'Account Description missing!' => 'Beschreibung fehlt!',
'Account Link AP' => 'Einkauf',
'Account Link AP_amount' => 'Verbindlichkeiten Aufwand/Anlagen',
'Account Link AP_paid' => 'Verbindlichkeiten Zahlungsausgang',
'Account Link IC_sale' => 'Warenliste Erlöskonto',
'Account Link IC_taxpart' => 'Warenliste Steuer',
'Account Link IC_taxservice' => 'Dienstleistungen Steuer',
- 'Account Number' => 'Kontonummer',
'Account Number missing!' => 'Kontonummer fehlt!',
- 'Account Type' => 'Kontoart',
'Account Type missing!' => 'Kontoart fehlt!',
'Account deleted!' => 'Konto gelöscht!',
'Account saved!' => 'Konto gespeichert!',
'Aufwand EU m. UStId' => 'Aufwand EU m. UStId',
'Aufwand EU o. UStId' => 'Aufwand EU o. UStId',
'Aufwand Inland' => 'Aufwand Inland',
- 'BWA' => 'BWA',
'Bestandskonto' => 'Bestandskonto',
- 'Bilanz' => 'Bilanz',
'Books are open' => 'Die Bücher sind geöffnet.',
'Buchungsgruppe' => 'Buchungsgruppe',
'Buchungsgruppe bearbeiten' => 'Buchungsgruppe bearbeiten',
'Dropdown Limit' => 'Auswahllistenbegrenzung',
'E-mail' => 'eMail',
'ELSE' => 'Zusatz',
- 'EUER' => 'Einnahmen-/Überschussrechnung',
'Edit Account' => 'Kontodaten bearbeiten',
'Edit Buchungsgruppe' => 'Buchungsgruppe bearbeiten',
'Edit Business' => 'Kunden-/Lieferantentyp bearbeiten',
'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
'Expense' => 'Aufwandskonto',
'Expense Account' => 'Aufwandskonto',
- 'Expense/Asset' => 'Aufwand/Anlagen',
'Fax' => 'Fax',
- 'Folgekonto' => 'Folgekonto',
'Foreign Exchange Gain' => 'Wechselkurserträge',
'Foreign Exchange Loss' => 'Wechselkursaufwendungen',
'Form details (second row)' => 'Formulardetails (zweite Positionszeile)',
- 'Gültig ab' => 'Gültig ab',
- 'Heading' => 'Überschrift',
+ 'Header' => 'Überschrift',
'Hide by default' => 'Standardmäßig verstecken',
'History' => 'Historie',
'History Search' => 'Historien Suche',
- 'Include in drop-down menus' => 'In Aufklappmenü aufnehmen',
'Inventory' => 'Inventar',
'Inventory Account' => 'Warenbestand',
- 'Is this a summary account to record' => 'Buchungskonto in',
'Language' => 'Sprache',
'Language deleted!' => 'Sprache gelöscht!',
'Language missing!' => 'Sprache fehlt!',
'No employee was found matching the search parameters.' => 'Es wurde kein Angestellter gefunden, auf den die Suchparameter zutreffen.',
'No part was found matching the search parameters.' => 'Es wurde kein Artikel gefunden, auf den die Suchparameter zutreffen.',
'No project was found matching the search parameters.' => 'Es wurde kein Projekt gefunden, auf das die Suchparameter zutreffen.',
+ 'None' => 'Kein',
'Number' => 'Nummer',
'Number Format' => 'Zahlenformat',
'Number of copies' => 'Anzahl Kopien',
+ 'Off' => 'Aus',
'Old (on the side)' => 'Alt (seitlich)',
'On' => 'An',
'OpenDocument/OASIS' => 'OpenDocument/OASIS',
'PRINTED' => 'Gedruckt',
'Part Number' => 'Artikelnummer',
'Part description' => 'Artikelbeschreibung',
- 'Parts Inventory' => 'Warenliste',
'Password' => 'Passwort',
- 'Payables' => 'Verbindlichkeiten',
- 'Payment' => 'Zahlungsausgang',
'Payment Terms' => 'Zahlungskonditionen',
'Payment Terms saved!' => 'Zahlungskonditionen gespeichert!',
'Payment terms deleted!' => 'Zahlungskonditionen gelöscht!',
'Project description' => 'Projektbeschreibung',
'Queue' => 'Warteschlange',
'Rate' => 'Rate',
- 'Receipt' => 'Zahlungseingang',
- 'Receivables' => 'Forderungen',
'Revenue' => 'Erlöskonto',
'Revenue Account' => 'Erlöskonto',
'SAVED' => 'Gespeichert',
'Select a part' => 'Artikel auswählen',
'Select a project' => 'Projekt auswählen',
'Select an employee' => 'Angestellten auswählen',
- 'Service Items' => 'Dienstleistungen',
'Setup Menu' => 'Menüsetup',
'Show by default' => 'Standardmäßig anzeigen',
'Signature' => 'Unterschrift',
'Skonto' => 'Skonto',
'Skonto Terms' => 'Zahlungsziel Skonto',
- 'Steuersatz' => 'Steuersatz',
'Stylesheet' => 'Stilvorlage',
- 'Tax' => 'Steuer',
'Tax Accounts' => 'Steuerkonto',
+ 'Tax-o-matic Account' => 'Automatikbuchung auf Konto',
'Template Code' => 'Vorlagenkürzel',
'Template Code missing!' => 'Vorlagenkürzel fehlt!',
'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
'Translation (%s)' => 'Übersetzung (%s)',
'Trying to call a sub without a name' => 'Es wurde versucht, eine Unterfunktion ohne Namen aufzurufen.',
'Type of Business' => 'Kunden-/Lieferantentyp',
- 'UStVA-Nr. 35' => 'Kz. 35',
- 'UStVA-Nr. 36' => 'Kz. 36',
- 'UStVA-Nr. 39' => 'Kz. 37',
- 'UStVA-Nr. 41' => 'Kz. 41',
- 'UStVA-Nr. 42' => 'Kz. 42',
- 'UStVA-Nr. 43' => 'Kz. 43',
- 'UStVA-Nr. 44' => 'Kz. 44',
- 'UStVA-Nr. 45' => 'Kz. 45',
- 'UStVA-Nr. 48' => 'Kz. 48',
- 'UStVA-Nr. 49' => 'Kz. 49',
- 'UStVA-Nr. 51 left' => 'Kz. 51 links',
- 'UStVA-Nr. 51 right' => 'Kz. 51 rechts',
- 'UStVA-Nr. 52' => 'Kz. 52',
- 'UStVA-Nr. 53' => 'Kz. 53',
- 'UStVA-Nr. 59' => 'Kz. 59',
- 'UStVA-Nr. 60' => 'Kz. 60',
- 'UStVA-Nr. 61' => 'Kz. 61',
- 'UStVA-Nr. 62' => 'Kz. 62',
- 'UStVA-Nr. 63' => 'Kz. 63',
- 'UStVA-Nr. 64' => 'Kz. 64',
- 'UStVA-Nr. 65' => 'Kz. 65',
- 'UStVA-Nr. 66' => 'Kz. 66',
- 'UStVA-Nr. 67' => 'Kz. 67',
- 'UStVA-Nr. 69' => 'Kz. 69',
- 'UStVA-Nr. 73' => 'Kz. 73',
- 'UStVA-Nr. 74' => 'Kz. 74',
- 'UStVA-Nr. 76' => 'Kz. 76',
- 'UStVA-Nr. 77' => 'Kz. 77',
- 'UStVA-Nr. 80' => 'Kz. 80',
- 'UStVA-Nr. 81 left' => 'UStVA-Nr. 81 left',
- 'UStVA-Nr. 81 right' => 'UStVA-Nr. 81 right',
- 'UStVA-Nr. 84' => 'Kz. 84',
- 'UStVA-Nr. 85' => 'Kz. 85',
- 'UStVA-Nr. 86 left' => 'Kz. 86 links',
- 'UStVA-Nr. 86 right' => 'Kz. 86 rechts',
- 'UStVA-Nr. 89 left' => 'UStVA-Nr. 89 left',
- 'UStVA-Nr. 89 right' => 'UStVA-Nr. 89 right',
- 'UStVA-Nr. 91' => 'Kz. 91',
- 'UStVA-Nr. 93 left' => 'Kz. 93 left',
- 'UStVA-Nr. 93 right' => 'Kz. 93 right',
- 'UStVA-Nr. 94' => 'Kz. 94',
- 'UStVA-Nr. 95' => 'Kz. 95',
- 'UStVA-Nr. 96' => 'Kz. 96',
- 'UStVA-Nr. 97 links' => 'Kz. 97 links',
- 'UStVA-Nr. 97 rechts' => 'Kz. 97 rechts',
- 'UStVA-Nr. 98' => 'Kz. 98',
- 'Umsatzsteuervoranmeldung' => 'Umsatzsteuervoranmeldung',
'Unit' => 'Einheit',
'Unknown Category' => 'Unbekannte Kategorie',
'Unknown Link' => 'Unbekannte Verknüpfung',
'language_header' => 'language_header',
'lead_header' => 'lead_header',
'list_account' => 'list_account',
+ 'list_account_details' => 'list_account_details',
'list_buchungsgruppe' => 'list_buchungsgruppe',
'list_business' => 'list_business',
'list_department' => 'list_department',
'Group Invoices' => 'Rechnungen zusammenfassen',
'History' => 'Historie',
'In-line' => 'im Text',
+ 'Interest' => 'Zinsen',
'Interest Rate' => 'Zinssatz',
'Inv. Duedate' => 'Rg. Fälligkeit',
'Invdate' => 'Rechnungsdatum',
'Part Number' => 'Artikelnummer',
'Part description' => 'Artikelbeschreibung',
'Payment Terms missing in row ' => 'Zahlungsfrist fehlt in Zeile ',
- 'Payment until' => 'Zahlungseingänge bis',
'Phone' => 'Telefon',
'Pick List' => 'Sammelliste',
'Please enter values' => 'Bitte Werte eingeben',
'The dunning process started' => 'Der Mahnprozess ist gestartet.',
'To' => 'An',
'Total Fees' => 'Kumulierte Gebühren',
- 'Total Interest' => 'Kumulierte Zinsen',
'Trying to call a sub without a name' => 'Es wurde versucht, eine Unterfunktion ohne Namen aufzurufen.',
'Unit' => 'Einheit',
'Unknown dependency \'%s\'.' => 'Unbekannte Abhängigkeit \'%s\'.',
'E-mail address missing!' => 'E-Mail-Adresse fehlt!',
'ELSE' => 'Zusatz',
'Edit Vendor Invoice' => 'Einkaufsrechnung bearbeiten',
+ 'Employee' => 'Bearbeiter',
'Enter longdescription' => 'Langtext eingeben',
'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
'Exch' => 'Wechselkurs.',
--- /dev/null
+-- @tag: dunning_config_interest_rate
+-- @description: In der Tabelle dunning_config ist interest falsch benannt.
+-- @depends: release_2_4_2
+ALTER TABLE dunning_config RENAME interest TO interest_rate;