b0a7c655235d8a7d190bb7040b49bec3bb9e77c0
[kivitendo-erp.git] / SL / Controller / CustomerVendorTurnover.pm
1 package SL::Controller::CustomerVendorTurnover;
2 use strict;
3 use parent qw(SL::Controller::Base);
4 use SL::DBUtils;
5 use SL::DB::AccTransaction;
6 use SL::DB::Invoice;
7 use SL::DB::Order;
8 use SL::DB::EmailJournal;
9 use SL::DB::Letter;
10 use SL::DB;
11
12 __PACKAGE__->run_before('check_auth');
13
14 sub action_list_turnover {
15   my ($self) = @_;
16
17   return $self->render('generic/error', { layout => 0 }, label_error => "list_transactions needs a trans_id") unless $::form->{id};
18
19   my $cv = $::form->{id} || {};
20   my $open_invoices;
21   if ( $::form->{db} eq 'customer' ) {
22   $open_invoices = SL::DB::Manager::Invoice->get_all(
23     query => [customer_id => $cv,
24                 or => [
25                       amount => { gt => \'paid'},
26                       amount => { lt => \'paid'},
27                     ],
28     ],
29     with_objects => ['dunnings'],
30   );
31   } else {
32     $open_invoices = SL::DB::Manager::PurchaseInvoice->get_all(
33       query   => [ vendor_id => $cv,
34                 or => [
35                       amount => { gt => \'paid'},
36                       amount => { lt => \'paid'},
37                     ],
38                ],
39       sort_by => 'invnumber DESC',
40     );
41   }
42   my $open_items;
43   if (@{$open_invoices}) {
44     return $self->render(\'', { type => 'json' }) unless scalar @{$open_invoices};
45     $open_items = $self->_list_open_items($open_invoices);
46   }
47   my $open_orders = $self->_get_open_orders();
48   return $self->render('customer_vendor_turnover/turnover', { header => 0 }, open_orders => $open_orders, open_items => $open_items, id => $cv);
49 }
50
51 sub _list_open_items {
52   my ($self, $open_items) = @_;
53
54   return $self->render('customer_vendor_turnover/_list_open_items', { output => 0 }, OPEN_ITEMS => $open_items, title => $::locale->text('Open Items') );
55 }
56
57 sub action_count_open_items_by_year {
58   my ($self) = @_;
59
60   return $self->render('generic/error', { layout => 0 }, label_error => "list_transactions needs a trans_id") unless $::form->{id};
61   my $dbh = SL::DB->client->dbh;
62
63   my $cv = $::form->{id} || {};
64
65   my $query = "SELECT EXTRACT (YEAR FROM d.transdate),
66     count(d.id),
67     max(d.dunning_level)
68     FROM dunning d
69     LEFT JOIN ar a
70     ON a.id = d.trans_id
71     LEFT JOIN customer c
72     ON a.customer_id = c.id
73     WHERE c.id = $cv
74     GROUP BY EXTRACT (YEAR FROM d.transdate), c.id
75     ORDER BY date_part DESC";
76
77    $self->{dun_statistic} = selectall_hashref_query($::form, $dbh, $query);
78    $self->render('customer_vendor_turnover/count_open_items_by_year', { layout => 0 });
79 }
80
81 sub action_count_open_items_by_month {
82
83   my ($self) = @_;
84
85   return $self->render('generic/error', { layout => 0 }, label_error => "list_transactions needs a trans_id") unless $::form->{id};
86   my $dbh = SL::DB->client->dbh;
87
88   my $cv = $::form->{id} || {};
89
90   my $query = "SELECT CONCAT(EXTRACT (MONTH FROM d.transdate),'/',EXTRACT (YEAR FROM d.transdate)) AS date_part,
91     count(d.id),
92     max(d.dunning_level)
93     FROM dunning d
94     LEFT JOIN ar a
95     ON a.id = d.trans_id
96     LEFT JOIN customer c
97     ON a.customer_id = c.id
98     WHERE c.id = $cv
99     GROUP BY EXTRACT (YEAR FROM d.transdate), EXTRACT (MONTH FROM d.transdate), c.id
100     ORDER BY EXTRACT (YEAR FROM d.transdate) DESC";
101
102    $self->{dun_statistic} = selectall_hashref_query($::form, $dbh, $query);
103    $self->render('customer_vendor_turnover/count_open_items_by_year', { layout => 0 });
104 }
105
106 sub action_turnover_by_month {
107
108   my ($self) = @_;
109
110   return $self->render('generic/error', { layout => 0 }, label_error => "list_transactions needs a trans_id") unless $::form->{id};
111
112   my $dbh = SL::DB->client->dbh;
113   my $cv = $::form->{id} || {};
114   my ($db, $cv_type);
115   if ($::form->{db} eq 'customer') {
116     $db      = "ar";
117     $cv_type = "customer_id";
118   } else {
119     $db      = "ap";
120     $cv_type = "vendor_id";
121   }
122   my $query = <<SQL;
123 SELECT CONCAT(EXTRACT (MONTH FROM transdate),'/',EXTRACT (YEAR FROM transdate)) AS date_part,
124     count(id) as count,
125     sum(amount) as amount,
126     sum(netamount) as netamount,
127     sum(paid) as paid
128     FROM $db WHERE $cv_type = $cv
129     GROUP BY EXTRACT (YEAR FROM transdate), EXTRACT (MONTH FROM transdate)
130     ORDER BY EXTRACT (YEAR FROM transdate) DESC, EXTRACT (MONTH FROM transdate) DESC
131 SQL
132    $self->{turnover_statistic} = selectall_hashref_query($::form, $dbh, $query);
133    $self->render('customer_vendor_turnover/count_turnover', { layout => 0 });
134 }
135
136 sub action_turnover_by_year {
137   my ($self) = @_;
138
139   return $self->render('generic/error', { layout => 0 }, label_error => "list_transactions needs a trans_id") unless $::form->{id};
140
141   my $dbh = SL::DB->client->dbh;
142   my $cv = $::form->{id} || {};
143   my ($db, $cv_type);
144   if ($::form->{db} eq 'customer') {
145     $db      = "ar";
146     $cv_type = "customer_id";
147   } else {
148     $db      = "ap";
149     $cv_type = "vendor_id";
150   }
151   my $query = <<SQL;
152 SELECT EXTRACT (YEAR FROM transdate) as date_part,
153     count(id) as count,
154     sum(amount) as amount,
155     sum(netamount) as netamount,
156     sum(paid) as paid
157     FROM $db WHERE $cv_type = $cv
158     GROUP BY date_part
159     ORDER BY date_part DESC
160 SQL
161    $self->{turnover_statistic} = selectall_hashref_query($::form, $dbh, $query);
162    $self->render('customer_vendor_turnover/count_turnover', { layout => 0 });
163 }
164
165 sub action_get_invoices {
166   my ($self) = @_;
167
168   return $self->render('generic/error', { layout => 0 }, label_error => "list_transactions needs a trans_id") unless $::form->{id};
169
170   my $cv = $::form->{id} || {};
171   my $invoices;
172   if ( $::form->{db} eq 'customer' ) {
173     $invoices = SL::DB::Manager::Invoice->get_all(
174       query => [ customer_id => $cv, ],
175       sort_by => 'invnumber DESC',
176     );
177   } else {
178     $invoices = SL::DB::Manager::PurchaseInvoice->get_all(
179       query => [ vendor_id => $cv, ],
180       sort_by => 'invnumber DESC',
181     );
182   }
183   $self->render('customer_vendor_turnover/invoices_statistic', { layout => 0 }, invoices => $invoices);
184 }
185
186 sub action_get_orders {
187   my ($self) = @_;
188
189   return $self->render('generic/error', { layout => 0 }, label_error => "list_transactions needs a trans_id") unless $::form->{id};
190
191   my $cv = $::form->{id} || {};
192   my $orders;
193   my $type = $::form->{type};
194   if ( $::form->{db} eq 'customer' ) {
195     $orders = SL::DB::Manager::Order->get_all(
196       query => [ customer_id => $cv,
197                  quotation   => ($type eq 'quotation' ? 'T' : 'F') ],
198       sort_by => ( $type eq 'order' ? 'ordnumber DESC' : 'quonumber DESC'),
199     );
200   } else {
201     $orders = SL::DB::Manager::Order->get_all(
202       query => [ vendor_id => $cv,
203                  quotation   => ($type eq 'quotation' ? 'T' : 'F') ],
204       sort_by => ( $type eq 'order' ? 'ordnumber DESC' : 'quonumber DESC'),
205     );
206   }
207   if ( $type eq 'order') {
208     $self->render('customer_vendor_turnover/order_statistic', { layout => 0 }, orders => $orders);
209   } else {
210     $self->render('customer_vendor_turnover/quotation_statistic', { layout => 0 }, orders => $orders);
211   }
212 }
213
214 sub _get_open_orders {
215   my ( $self ) = @_;
216
217   return $self->render('generic/error', { layout => 0 }, label_error => "list_transactions needs a trans_id") unless $::form->{id};
218   my $open_orders;
219   my $cv = $::form->{id} || {};
220
221   if ( $::form->{db} eq 'customer' ) {
222     $open_orders = SL::DB::Manager::Order->get_all(
223       query => [ customer_id => $cv,
224                    closed => 'F',
225                ],
226                sort_by => 'ordnumber DESC',
227                );
228   } else {
229     $open_orders = SL::DB::Manager::Order->get_all(
230       query => [ vendor_id => $cv,
231                    closed => 'F',
232                ],
233                sort_by => 'ordnumber DESC',
234                );
235   }
236
237   return 0 unless scalar @{$open_orders};
238   return $self->render('customer_vendor_turnover/_list_open_orders', { output => 0 }, orders => $open_orders, title => $::locale->text('Open Orders') );
239 }
240
241 sub action_get_mails {
242   my ( $self ) = @_;
243
244   my $dbh = SL::DB->client->dbh;
245   my $query;
246   my $cv = $::form->{id};
247
248   if ( $::form->{db} eq 'customer') {
249     $query = <<SQL;
250 WITH oe_emails_customer AS (SELECT rc.to_id, rc.from_id, oe.quotation, oe.quonumber, oe.ordnumber, c.id FROM
251 record_links rc
252 LEFT JOIN oe oe ON rc.from_id = oe.id
253 LEFT JOIN customer c ON oe.customer_id = c.id
254 WHERE rc.to_table = 'email_journal' AND rc.from_table ='oe'),
255
256 do_emails_customer AS (SELECT rc.to_id, rc.from_id, o.donumber, c.id FROM
257 record_links rc
258 LEFT JOIN delivery_orders o ON rc.from_id = o.id
259 LEFT JOIN customer c ON o.customer_id = c.id
260 WHERE rc.to_table = 'email_journal' AND rc.from_table = 'delivery_orders'),
261
262 inv_emails_customer AS (SELECT rc.to_id, rc.from_id, inv.type, inv.invnumber, c.id FROM
263 record_links rc
264 LEFT JOIN ar inv ON rc.from_id = inv.id
265 LEFT JOIN customer c ON inv.customer_id = c.id
266 WHERE rc.to_table = 'email_journal' AND rc.from_table = 'ar'),
267
268 letter_emails_customer AS (SELECT rc.to_id, rc.from_id, l.letternumber, c.id FROM
269 record_links rc
270 LEFT JOIN letter l ON rc.from_id = l.id
271 LEFT JOIN customer c ON l.customer_id = c.id
272 WHERE rc.to_table = 'email_journal' AND rc.from_table = 'letter')
273
274 SELECT ej.*, CASE
275   oec.quotation WHEN 'F' THEN 'Sales Order'
276                 ELSE 'Quotation'
277              END AS type,
278              CASE
279   oec.quotation WHEN 'F' THEN oec.ordnumber
280                 ELSE oec.quonumber
281              END AS recordnumber,
282 oec.id AS record_id FROM email_journal ej
283 LEFT JOIN oe_emails_customer oec ON ej.id = oec.to_id
284 WHERE oec.id = ?
285
286 UNION
287
288 SELECT ej.*, 'Delivery Order' AS type, dec.donumber AS recordnumber,dec.id AS record_id FROM email_journal ej
289 LEFT JOIN do_emails_customer dec ON ej.id = dec.to_id
290 WHERE dec.id = ?
291
292 UNION
293
294 SELECT ej.*, CASE
295   iec.type WHEN 'credit_note' THEN 'Credit Note'
296            WHEN 'invoice' THEN 'Invoice'
297            ELSE 'N/A'
298         END AS type,
299 iec.invnumber AS recordnumber,iec.id AS record_id FROM email_journal ej
300 LEFT JOIN inv_emails_customer iec ON ej.id = iec.to_id
301 WHERE iec.id = ?
302
303 UNION
304
305 SELECT ej.*, 'Letter' AS type, lec.letternumber AS recordnumber,lec.id AS record_id FROM email_journal ej
306 LEFT JOIN letter_emails_customer lec ON ej.id = lec.to_id
307 WHERE lec.id = ?
308 ORDER BY sent_on DESC
309 SQL
310   }
311   else {
312     $query = <<SQL;
313 WITH oe_emails_vendor AS (SELECT rc.to_id, rc.from_id, oe.quotation, oe.quonumber, oe.ordnumber, c.id FROM
314 record_links rc
315 LEFT JOIN oe oe ON rc.from_id = oe.id
316 LEFT JOIN vendor c ON oe.vendor_id = c.id
317 WHERE rc.to_table = 'email_journal' AND rc.from_table ='oe'),
318
319 do_emails_vendor AS (SELECT rc.to_id, rc.from_id, o.donumber, c.id FROM
320 record_links rc
321 LEFT JOIN delivery_orders o ON rc.from_id = o.id
322 LEFT JOIN vendor c ON o.vendor_id = c.id
323 WHERE rc.to_table = 'email_journal' AND rc.from_table = 'delivery_orders'),
324
325 inv_emails_vendor AS (SELECT rc.to_id, rc.from_id, inv.type, inv.invnumber, c.id FROM
326 record_links rc
327 LEFT JOIN ap inv ON rc.from_id = inv.id
328 LEFT JOIN vendor c ON inv.vendor_id = c.id
329 WHERE rc.to_table = 'email_journal' AND rc.from_table = 'ar'),
330
331 letter_emails_vendor AS (SELECT rc.to_id, rc.from_id, l.letternumber, c.id FROM
332 record_links rc
333 LEFT JOIN letter l ON rc.from_id = l.id
334 LEFT JOIN vendor c ON l.vendor_id = c.id
335 WHERE rc.to_table = 'email_journal' AND rc.from_table = 'letter')
336
337 SELECT ej.*, CASE
338   oec.quotation WHEN 'F' THEN 'Purchase Order'
339                 ELSE 'Request quotation'
340              END AS type,
341              CASE
342   oec.quotation WHEN 'F' THEN oec.ordnumber
343                 ELSE oec.quonumber
344              END AS recordnumber,
345 oec.id AS record_id FROM email_journal ej
346 LEFT JOIN oe_emails_vendor oec ON ej.id = oec.to_id
347 WHERE oec.id = ?
348
349 UNION
350
351 SELECT ej.*, 'Purchase Delivery Order' AS type, dec.donumber AS recordnumber, dec.id AS record_id FROM email_journal ej
352 LEFT JOIN do_emails_vendor dec ON ej.id = dec.to_id
353 WHERE dec.id = ?
354
355 UNION
356
357 SELECT ej.*, iec.type AS type, iec.invnumber AS recordnumber, iec.id AS record_id FROM email_journal ej
358 LEFT JOIN inv_emails_vendor iec ON ej.id = iec.to_id
359 WHERE iec.id = ?
360
361 UNION
362
363 SELECT ej.*, 'Letter' AS type, lec.letternumber AS recordnumber, lec.id AS record_id FROM email_journal ej
364 LEFT JOIN letter_emails_vendor lec ON ej.id = lec.to_id
365 WHERE lec.id = ?
366 ORDER BY sent_on DESC
367 SQL
368   }
369   my $emails = selectall_hashref_query($::form, $dbh, $query, $cv, $cv, $cv, $cv);
370   $self->render('customer_vendor_turnover/email_statistic', { layout => 0 }, emails => $emails);
371 }
372
373 sub action_get_letters {
374   my ($self) = @_;
375
376   return $self->render('generic/error', { layout => 0 }, label_error => "list_transactions needs a trans_id") unless $::form->{id};
377
378   my $cv = $::form->{id} || {};
379   my $letters;
380   my $type = $::form->{type};
381   if ( $::form->{db} eq 'customer' ) {
382     $letters = SL::DB::Manager::Letter->get_all(
383       query => [ customer_id => $cv, ],
384       sort_by => 'date DESC',
385     );
386   } else {
387     $letters = SL::DB::Manager::Letter->get_all(
388       query => [ vendor_id => $cv, ],
389       sort_by => 'date DESC',
390     );
391   }
392     $self->render('customer_vendor_turnover/letter_statistic', { layout => 0 }, letters => $letters);
393 }
394
395 sub _list_articles_by_invoice {
396 }
397 sub _list_count_articles_by_year {
398 }
399 sub check_auth {
400   $::auth->assert('general_ledger');
401 }
402 1;
403
404 __END__
405
406 =encoding utf-8
407
408 =head1 NAME
409
410 SL::Controller::CustomerVendorTurnover
411
412 =head1 DESCRIPTION
413
414 Gets all kinds of records like orders, request orders, quotations, invoices, emails, letters
415
416 wich belong to customer/vendor and displays them in an extra tab "Records".
417
418 =back
419
420 =head1 URL ACTIONS
421
422 =over 4
423
424 =item C<action_list_turnover>
425
426 Basic action wich displays open invoices and open orders if there are any and shows the tab menu for the other actions
427
428 =item C<action_count_open_items_by_month>
429
430 gets and shows a dunning statistic of the customer by month
431
432 =item C<action_count_open_items_by_year>
433
434 gets and shows a dunning statistic of the customer by year
435
436 =item C<action_turnover_by_month>
437
438 gets and shows an invoice statistic of customer/vendor by month
439
440 =item C<action_turnover_by_year>
441
442 gets and shows an invoice statistic of customer/vendor by year
443
444 =item C<action_get_invoices>
445
446 get and shows all invoices from the customer/vendor in an extra tab
447
448 =item C<action_get_orders>
449
450 get and shows all orders from the customer/vendor in an extra tab
451
452 =item C<action_get_letters>
453
454 get and shows all letters from the customer/vendor in an extra tab
455
456 =item C<action_get_mails>
457
458 get and shows all mails from the customer/vendor in an extra tab
459
460 =back
461
462 =head1 Functions
463
464 =over 4
465
466 =item C<_get_open_orders>
467
468 retrieves the open orders for customer/vendor to display them
469
470 =item C<_list_open_items>
471
472 retrieves open invoices with their dunnings to display them
473
474 =back
475
476 =head1 BUGS
477
478 None yet. :)
479
480 =head1 AUTHOR
481
482 W. Hahn E<lt>wh@futureworldsearch.netE<gt>
483
484 =back