LinkedRecords: with_objects erlauben für shipped_qty
[kivitendo-erp.git] / SL / DB / OrderItem.pm
1 package SL::DB::OrderItem;
2
3 use strict;
4
5 use List::Util qw(sum);
6
7 use SL::DB::MetaSetup::OrderItem;
8 use SL::DB::Manager::OrderItem;
9 use SL::DB::DeliveryOrderItemsStock;
10 use SL::DB::Helper::ActsAsList;
11 use SL::DB::Helper::LinkedRecords;
12 use SL::DB::Helper::RecordItem;
13 use SL::DB::Helper::CustomVariables (
14   sub_module  => 'orderitems',
15   cvars_alias => 1,
16   overloads   => {
17     parts_id => {
18       class => 'SL::DB::Part',
19       module => 'IC',
20     }
21   },
22 );
23
24 __PACKAGE__->meta->initialize;
25
26 __PACKAGE__->configure_acts_as_list(group_by => [qw(trans_id)]);
27
28 sub is_price_update_available {
29   my $self = shift;
30   return $self->origprice > $self->part->sellprice;
31 }
32
33 sub shipped_qty {
34   my ($self) = @_;
35
36   my $d_orders = $self->order->linked_records(direction => 'to', to => 'SL::DB::DeliveryOrder', with_objects => [ 'orderitems' ]);
37   my @doi      = grep { $_->parts_id == $self->parts_id } map { $_->orderitems } @$d_orders;
38
39   return sum(map { AM->convert_unit($_->unit => $self->unit) * $_->qty } @doi);
40 }
41
42 sub linked_delivery_order_items {
43   my ($self) = @_;
44
45   return $self->linked_records(direction => 'to', to => 'SL::DB::DeliveryOrderItem');
46 }
47
48 sub delivered_qty {
49   # checks for delivery_order_stock_id entries, which have been converted to inventory entries
50   # uses several rose relationships
51   # doesn't differentiate between sales and orders
52
53   my ($self) = @_;
54   my $delivered_qty = 0;
55   foreach my $doi ( @{$self->linked_delivery_order_items} ) {
56     next unless scalar @{$doi->delivery_order_stock_entries};
57     $delivered_qty += sum map { $_->inventory ? $_->qty : 0 } @{$doi->delivery_order_stock_entries};
58   };
59   return $delivered_qty;
60 };
61
62 sub delivered_qty_sql {
63   # checks for delivery_order_stock_id entries, which have been converted to inventory entries
64   my ($self) = @_;
65
66 my $query = <<SQL;
67 SELECT (sum(i.qty) * CASE WHEN oe.customer_id IS NULL THEN 1 ELSE -1 END) AS delivered
68  FROM orderitems oi
69  INNER JOIN record_links rl                 ON (    oi.id             = rl.FROM_id
70                                                 and rl.FROM_table     = 'orderitems'
71                                                 and rl.to_table::text = 'delivery_order_items'::text
72                                                )
73  INNER JOIN delivery_order_items doi        ON (doi.id =rl.to_id)
74  INNER JOIN delivery_order_items_stock dois ON (dois.delivery_order_item_id = doi.id)
75  INNER JOIN inventory i                     ON (dois.id = i.delivery_order_items_stock_id)
76  INNER JOIN oe                              ON (oe.id = oi.trans_id)
77  WHERE oi.id = ?
78  GROUP BY oi.id, oe.id
79 SQL
80   my ($delivered_qty) = selectfirst_array_query($::form, $self->db->dbh, $query, $self->id);
81
82   return $delivered_qty;
83 };
84
85 sub delivered_qty_sql_multi {
86   # checks for delivery_order_stock_id entries, which have been converted to inventory entries
87   my ($self) = @_;
88
89 my $query = <<SQL;
90 SELECT sum(dois.qty) from delivery_order_items_stock dois
91   LEFT OUTER JOIN inventory i ON (dois.id = i.delivery_order_items_stock_id)
92 WHERE
93   dois.delivery_order_item_id in (
94 SELECT
95   to_id
96 FROM
97   record_links
98 WHERE
99   (
100     from_id = in AND
101     from_table = 'orderitems' AND
102     to_table = 'delivery_order_items'
103   )
104 )
105 SQL
106   my ($delivered_qty) = selectfirst_array_query($::form, $self->db->dbh, $query, $self->id);
107
108   return $delivered_qty;
109 };
110
111 sub record { goto &order }
112
113 1;
114
115 __END__
116
117 =pod
118
119 =head1 NAME
120
121 SL::DB::OrderItems: Rose model for orderitems
122
123 =head1 FUNCTIONS
124
125 =over 4
126
127 =item C<shipped_qty>
128
129 =item C<shipped_qty>
130
131 returns the number of orderitems which are already linked to Delivery Orders.
132 The linked key is parts_id and not orderitems (id) -> delivery_order_items (id).
133 Therefore this function is not safe for identical parts_id.
134 Sample call:
135 C<$::form-E<gt>format_amount(\%::myconfig, $_[0]-E<gt>shipped_qty);>
136
137 =item C<delivered_qty>
138
139 Returns the amount of this orderitem that has been delivered, meaning it
140 appears in a delivery order AND has been transferred. The delivery order items
141 are found by direct record_links from orderitems to delivery order items.
142 Delivery order items that were added manually and not via the record workflow
143 will therefore not be calculated correctly.
144
145 Orders that were created before the individual items were linked (this feature
146 was added in kivitendo 3.2.0) will therefore return incorrect results.
147
148 =item C<delivered_qty_sql>
149
150 Does the same as delivered_qty, but via sql.
151
152
153
154 =item C<delivered_qty_sql>
155
156 Returns the amount of the orderitem that has actually been shipped, not just where delivery_order_items exist (how delivered_qty works).
157
158 Doesn't deal with different units yet.
159
160 =back
161
162 =head1 TODO
163
164 Older versions of OrderItem.pm had more functions which where used for calculating the
165 qty for the different states of the Delivery Order.
166 For example to get the qty in already marked as delivered Delivery Orders:
167
168 C<delivered_qty>
169
170 return $self-E<gt>_delivered_qty;
171
172   sub _delivered_qty {
173   (..)
174     my @d_orders_delivered = grep { $_-E<gt>delivered } @$d_orders;
175     my @doi_delivered      = grep { $_-E<gt>parts_id == $self-E<gt>parts_id } map { $_-E<gt>orderitems } @d_orders_delivered;
176   }
177
178 In general the function C<shipped_qty> and all (project) related functions should be marked deprecate,
179  because of the better linked item to item data in the record_links table.
180
181 =head1 AUTHORS
182
183 G. Richardson E<lt>grichardson@kivitendo-premium.deE<gt>
184
185 =cut
186
187