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