|
1 |
package ARAP;
|
|
2 |
|
|
3 |
use SL::AM;
|
|
4 |
use SL::Common;
|
|
5 |
use SL::DBUtils;
|
|
6 |
use SL::MoreCommon;
|
|
7 |
use Data::Dumper;
|
|
8 |
|
|
9 |
sub close_orders_if_billed {
|
|
10 |
$main::lxdebug->enter_sub();
|
|
11 |
|
|
12 |
my $self = shift;
|
|
13 |
my %params = @_;
|
|
14 |
|
|
15 |
Common::check_params(\%params, qw(arap_id table));
|
|
16 |
|
|
17 |
my $myconfig = \%main::myconfig;
|
|
18 |
my $form = $main::form;
|
|
19 |
|
|
20 |
my $dbh = $params{dbh} || $form->get_standard_dbh($myconfig);
|
|
21 |
|
|
22 |
# First, find all order IDs from which this invoice has been
|
|
23 |
# created. Either directly by a conversion from an order to this invoice
|
|
24 |
# or indirectly from an order to one or more delivery orders and
|
|
25 |
# from those to this invoice.
|
|
26 |
|
|
27 |
# Direct conversion "order -> invoice":
|
|
28 |
my @links = RecordLinks->get_links('dbh' => $dbh,
|
|
29 |
'from_table' => 'oe',
|
|
30 |
'to_table' => $params{table},
|
|
31 |
'to_id' => $params{arap_id});
|
|
32 |
|
|
33 |
my %oe_id_map = map { $_->{from_id} => 1 } @links;
|
|
34 |
|
|
35 |
# Indirect conversion "order -> delivery orders -> invoice":
|
|
36 |
my @do_links = RecordLinks->get_links('dbh' => $dbh,
|
|
37 |
'from_table' => 'delivery_orders',
|
|
38 |
'to_table' => $params{table},
|
|
39 |
'to_id' => $params{arap_id});
|
|
40 |
|
|
41 |
foreach my $do_link (@do_links) {
|
|
42 |
@links = RecordLinks->get_links('dbh' => $dbh,
|
|
43 |
'from_table' => 'oe',
|
|
44 |
'to_table' => 'delivery_orders',
|
|
45 |
'to_id' => $do_link->{from_id});
|
|
46 |
|
|
47 |
map { $oe_id_map{$_->{from_id}} = 1 } @links;
|
|
48 |
}
|
|
49 |
|
|
50 |
my @oe_ids = keys %oe_id_map;
|
|
51 |
|
|
52 |
# $main::lxdebug->dump(0, "oe_ids", \@oe_ids);
|
|
53 |
|
|
54 |
# No orders found? Nothing to do then, so let's return.
|
|
55 |
return $main::lxdebug->leave_sub() if (!scalar @oe_ids);
|
|
56 |
|
|
57 |
my $all_units = AM->retrieve_all_units();
|
|
58 |
|
|
59 |
my $qtyfactor = $params{table} eq 'ap' ? '* -1' : '';
|
|
60 |
my $q_billed = qq|SELECT i.parts_id, i.qty ${qtyfactor} AS qty, i.unit, p.unit AS partunit
|
|
61 |
FROM invoice i
|
|
62 |
LEFT JOIN parts p ON (i.parts_id = p.id)
|
|
63 |
WHERE i.trans_id = ?|;
|
|
64 |
my $h_billed = prepare_query($form, $dbh, $q_billed);
|
|
65 |
|
|
66 |
my $q_ordered = qq|SELECT oi.parts_id, oi.qty, oi.unit, p.unit AS partunit
|
|
67 |
FROM orderitems oi
|
|
68 |
LEFT JOIN parts p ON (oi.parts_id = p.id)
|
|
69 |
WHERE oi.trans_id = ?|;
|
|
70 |
my $h_ordered = prepare_query($form, $dbh, $q_ordered);
|
|
71 |
|
|
72 |
my @close_oe_ids;
|
|
73 |
|
|
74 |
# Interate over each order and look up all invoices created for
|
|
75 |
# said order. Again consider both direct conversions and indirect
|
|
76 |
# conversions via delivery orders.
|
|
77 |
foreach my $oe_id (@oe_ids) {
|
|
78 |
# Direct conversions "order -> invoice":
|
|
79 |
@links = RecordLinks->get_links('dbh' => $dbh,
|
|
80 |
'from_table' => 'oe',
|
|
81 |
'from_id' => $oe_id,
|
|
82 |
'to_table' => $params{table},);
|
|
83 |
|
|
84 |
my %arap_id_map = map { $_->{to_id} => 1 } @links;
|
|
85 |
|
|
86 |
# Indirect conversions "order -> delivery orders -> invoice":
|
|
87 |
@do_links = RecordLinks->get_links('dbh' => $dbh,
|
|
88 |
'from_table' => 'oe',
|
|
89 |
'from_id' => $oe_id,
|
|
90 |
'to_table' => 'delivery_orders',);
|
|
91 |
foreach my $do_link (@do_links) {
|
|
92 |
@links = RecordLinks->get_links('dbh' => $dbh,
|
|
93 |
'from_table' => 'delivery_orders',
|
|
94 |
'from_id' => $do_link->{to_id},
|
|
95 |
'to_table' => $params{table},);
|
|
96 |
|
|
97 |
map { $arap_id_map{$_->{to_id}} = 1 } @links;
|
|
98 |
}
|
|
99 |
|
|
100 |
my @arap_ids = keys %arap_id_map;
|
|
101 |
|
|
102 |
# $main::lxdebug->dump(0, "for $oe_id arap_ids", \@arap_ids);
|
|
103 |
|
|
104 |
next if (!scalar @arap_ids);
|
|
105 |
|
|
106 |
# Retrieve all positions for this order. Calculate the ordered quantity for each position.
|
|
107 |
my %ordered = ();
|
|
108 |
|
|
109 |
do_statement($form, $h_ordered, $q_ordered, $oe_id);
|
|
110 |
|
|
111 |
while (my $ref = $h_ordered->fetchrow_hashref()) {
|
|
112 |
$ref->{baseqty} = $ref->{qty} * $all_units->{$ref->{unit}}->{factor} / $all_units->{$ref->{partunit}}->{factor};
|
|
113 |
|
|
114 |
if ($ordered{$ref->{parts_id}}) {
|
|
115 |
$ordered{$ref->{parts_id}}->{baseqty} += $ref->{baseqty};
|
|
116 |
} else {
|
|
117 |
$ordered{$ref->{parts_id}} = $ref;
|
|
118 |
}
|
|
119 |
}
|
|
120 |
|
|
121 |
# Retrieve all positions for all invoices that have been created from this order.
|
|
122 |
my %billed = ();
|
|
123 |
|
|
124 |
foreach my $arap_id (@arap_ids) {
|
|
125 |
do_statement($form, $h_billed, $q_billed, $arap_id);
|
|
126 |
|
|
127 |
while (my $ref = $h_billed->fetchrow_hashref()) {
|
|
128 |
$ref->{baseqty} = $ref->{qty} * $all_units->{$ref->{unit}}->{factor} / $all_units->{$ref->{partunit}}->{factor};
|
|
129 |
|
|
130 |
if ($billed{$ref->{parts_id}}) {
|
|
131 |
$billed{$ref->{parts_id}}->{baseqty} += $ref->{baseqty};
|
|
132 |
} else {
|
|
133 |
$billed{$ref->{parts_id}} = $ref;
|
|
134 |
}
|
|
135 |
}
|
|
136 |
}
|
|
137 |
|
|
138 |
# Check all ordered positions. If all positions have been billed completely then this order can be closed.
|
|
139 |
my $all_billed = 1;
|
|
140 |
foreach my $part (values %ordered) {
|
|
141 |
if (!$billed{$part->{parts_id}} || ($billed{$part->{parts_id}}->{baseqty} < $part->{baseqty})) {
|
|
142 |
$all_billed = 0;
|
|
143 |
last;
|
|
144 |
}
|
|
145 |
}
|
|
146 |
|
|
147 |
# $main::lxdebug->message(0, "all_billed $all_billed");
|
|
148 |
# $main::lxdebug->dump(0, "ordered", \%ordered);
|
|
149 |
# $main::lxdebug->dump(0, "billed", \%billed);
|
|
150 |
|
|
151 |
push @close_oe_ids, $oe_id if ($all_billed);
|
|
152 |
}
|
|
153 |
|
|
154 |
$h_billed->finish();
|
|
155 |
$h_ordered->finish();
|
|
156 |
|
|
157 |
# Close orders that have been billed fully.
|
|
158 |
if (scalar @close_oe_ids) {
|
|
159 |
my $query = qq|UPDATE oe SET closed = TRUE WHERE id IN (| . join(', ', ('?') x scalar @close_oe_ids) . qq|)|;
|
|
160 |
do_query($form, $dbh, $query, @close_oe_ids);
|
|
161 |
|
|
162 |
$dbh->commit() unless ($params{dbh});
|
|
163 |
}
|
|
164 |
|
|
165 |
$main::lxdebug->leave_sub();
|
|
166 |
}
|
|
167 |
|
|
168 |
1;
|
Beim Umwandeln von Aufträgen in Rechnungen nicht sofort den Auftrag schließen. Beim Buchen von Rechnungen die Aufträge schließen, aus denen die Rechnung erzeugt wurde (auch mit Umweg über Lieferscheine), sofern der Auftrag damit vollständig abgerechnet wurde.