67b1c4871ff43c993c36401f777679058418d69c
[kivitendo-erp.git] / bin / mozilla / arap.pl
1 #=====================================================================
2 # LX-Office ERP
3 # Copyright (C) 2004
4 # Based on SQL-Ledger Version 2.1.9
5 # Web http://www.lx-office.org
6 #
7 #=====================================================================
8 # SQL-Ledger Accounting
9 # Copyright (c) 2002
10 #
11 #  Author: Dieter Simader
12 #   Email: dsimader@sql-ledger.org
13 #     Web: http://www.sql-ledger.org
14 #
15 #
16 # This program is free software; you can redistribute it and/or modify
17 # it under the terms of the GNU General Public License as published by
18 # the Free Software Foundation; either version 2 of the License, or
19 # (at your option) any later version.
20 #
21 # This program is distributed in the hope that it will be useful,
22 # but WITHOUT ANY WARRANTY; without even the implied warranty of
23 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 # GNU General Public License for more details.
25 # You should have received a copy of the GNU General Public License
26 # along with this program; if not, write to the Free Software
27 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 #======================================================================
29 #
30 # common routines for gl, ar, ap, is, ir, oe
31 #
32
33 use strict;
34
35 # any custom scripts for this one
36 if (-f "bin/mozilla/custom_arap.pl") {
37   eval { require "bin/mozilla/custom_arap.pl"; };
38 }
39 if (-f "bin/mozilla/$main::form->{login}_arap.pl") {
40   eval { require "bin/mozilla/$main::form->{login}_arap.pl"; };
41 }
42
43 1;
44
45 require "bin/mozilla/common.pl";
46
47 # end of main
48
49 sub check_name {
50   $main::lxdebug->enter_sub();
51
52   my $form     = $main::form;
53   my %myconfig = %main::myconfig;
54   my $locale   = $main::locale;
55
56   $main::auth->assert('general_ledger               | vendor_invoice_edit       | sales_order_edit    | invoice_edit |' .
57                 'request_quotation_edit       | sales_quotation_edit      | purchase_order_edit | cash         |' .
58                 'purchase_delivery_order_edit | sales_delivery_order_edit');
59
60   my ($name, %params) = @_;
61
62   $name = $name eq "customer" ? "customer" : "vendor";
63
64   my ($new_name,$new_id) = $form->{$name} =~ /^(.*?)--(\d+)$/;
65   my $i = 0;
66   # if we use a selection
67   if ($form->{"select$name"}) {
68     if ($form->{"old$name"} ne $form->{$name}) {
69
70       # this is needed for is, ir and oe
71       $form->{update} = 0;
72       # for credit calculations
73       $form->{oldinvtotal}  = 0;
74       $form->{oldtotalpaid} = 0;
75       $form->{calctax}      = 1;
76
77       $form->{"${name}_id"} = $new_id;
78
79       _reset_salesman_id();
80       IS->get_customer(\%myconfig, \%$form) if ($name eq 'customer');
81       IR->get_vendor(\%myconfig, \%$form) if ($name eq 'vendor');
82
83       $form->{$name} = $form->{"old$name"} = "$new_name--$new_id";
84
85       $i = 1;
86     }
87   } else {
88
89     # check name, combine name and id
90     if ($form->{"old$name"} ne qq|$form->{$name}--$form->{"${name}_id"}|) {
91
92       # this is needed for is, ir and oe
93       $form->{update} = 0;
94
95       # for credit calculations
96       $form->{oldinvtotal}  = 0;
97       $form->{oldtotalpaid} = 0;
98       $form->{calctax}      = 1;
99
100       # return one name or a list of names in $form->{name_list}
101       $i = $form->get_name(\%myconfig, $name);
102
103       if ($i > 1) {
104         if ($params{no_select}) {
105           # $locale->text('Customer')
106           # $locale->text('Vendor')
107           $form->error($locale->text("More than one #1 found matching, please be more specific.", $locale->text(ucfirst $name)));
108         } else {
109           &select_name($name);
110           ::end_of_request();
111         }
112       }
113
114       if ($i == 1) {
115
116         # we got one name
117         $form->{"${name}_id"} = $form->{name_list}[0]->{id};
118         $form->{$name}        = $form->{name_list}[0]->{name};
119         $form->{"old$name"}   = qq|$form->{$name}--$form->{"${name}_id"}|;
120
121         _reset_salesman_id();
122         IS->get_customer(\%myconfig, \%$form) if ($name eq 'customer');
123         IR->get_vendor(\%myconfig, \%$form) if ($name eq 'vendor');
124
125       } else {
126
127         # name is not on file
128         # $locale->text('Customer not on file or locked!')
129         # $locale->text('Vendor not on file or locked!')
130         my $msg = ucfirst $name . " not on file or locked!";
131         $form->error($locale->text($msg));
132       }
133     }
134   }
135   $form->language_payment(\%myconfig);
136
137   $main::lxdebug->leave_sub();
138
139   return $i;
140 }
141
142 # $locale->text('Customer not on file!')
143 # $locale->text('Vendor not on file!')
144
145 sub select_name {
146   $main::lxdebug->enter_sub();
147
148   my $form     = $main::form;
149   my $locale   = $main::locale;
150
151   $main::auth->assert('general_ledger         | vendor_invoice_edit  | sales_order_edit    | invoice_edit | sales_delivery_order_edit |' .
152                 'request_quotation_edit | sales_quotation_edit | purchase_order_edit | cash');
153
154   my ($table) = @_;
155
156   my @column_index = qw(ndx name address);
157
158   my $label             = ucfirst $table;
159   my %column_data;
160   $column_data{ndx}  = qq|<th>&nbsp;</th>|;
161   $column_data{name} =
162     qq|<th class=listheading>| . $locale->text($label) . qq|</th>|;
163   $column_data{address} =
164     qq|<th class=listheading>| . $locale->text('Address') . qq|</th>|;
165
166   # list items with radio button on a form
167   $form->header;
168
169   my $title = $locale->text('Select from one of the names below');
170
171   print qq|
172     <h1>$title</h1>
173
174 <form method=post action=$form->{script}>
175
176 <table width=100%>
177   <tr>
178     <td>
179       <table width=100%>
180         <tr class=listheading>|;
181
182   map { print "\n$column_data{$_}" } @column_index;
183
184   print qq|
185         </tr>
186 |;
187
188   my $i = 0;
189   my $j;
190   foreach my $ref (@{ $form->{name_list} }) {
191     my $checked = ($i++) ? "" : "checked";
192
193     $ref->{name} =~ s/\"/&quot;/g;
194
195     $column_data{ndx} =
196       qq|<td><input name=ndx class=radio type=radio value=$i $checked></td>|;
197     $column_data{name} =
198       qq|<td><input name="new_name_$i" type=hidden value="$ref->{name}">$ref->{name}</td>|;
199     $column_data{address} = qq|<td>$ref->{address}&nbsp;</td>|;
200
201     $j++;
202     $j %= 2;
203     print qq|
204         <tr class=listrow$j>|;
205
206     map { print "\n$column_data{$_}" } @column_index;
207
208     print qq|
209         </tr>
210
211 <input name="new_id_$i" type=hidden value=$ref->{id}>
212
213 |;
214
215   }
216
217   print qq|
218       </table>
219     </td>
220   </tr>
221   <tr>
222     <td><hr size=3 noshade></td>
223   </tr>
224 </table>
225
226 <input name=lastndx type=hidden value=$i>
227
228 |;
229
230   # delete variables
231   map { delete $form->{$_} } qw(action name_list header);
232
233   # save all other form variables
234   foreach my $key (keys %${form}) {
235     next if (($key eq 'login') || ($key eq 'password') || ('' ne ref $form->{$key}));
236     $form->{$key} =~ s/\"/&quot;/g;
237     print qq|<input name=$key type=hidden value="$form->{$key}">\n|;
238   }
239
240   print qq|
241 <input type=hidden name=nextsub value=name_selected>
242
243 <input type=hidden name=vc value=$table>
244 <br>
245 <input class=submit type=submit name=action value="|
246     . $locale->text('Continue') . qq|">
247 </form>
248 |;
249
250   $main::lxdebug->leave_sub();
251 }
252
253 sub name_selected {
254   $main::lxdebug->enter_sub();
255
256   my $form     = $main::form;
257   my %myconfig = %main::myconfig;
258
259   $main::auth->assert('general_ledger         | vendor_invoice_edit  | sales_order_edit    | invoice_edit | sales_delivery_order_edit | ' .
260                 'request_quotation_edit | sales_quotation_edit | purchase_order_edit | cash');
261
262   # replace the variable with the one checked
263
264   # index for new item
265   my $i = $form->{ndx};
266
267   _reset_salesman_id();
268
269   $form->{ $form->{vc} }    = $form->{"new_name_$i"};
270   $form->{"$form->{vc}_id"} = $form->{"new_id_$i"};
271   $form->{"old$form->{vc}"} =
272     qq|$form->{$form->{vc}}--$form->{"$form->{vc}_id"}|;
273
274   # delete all the new_ variables
275   for $i (1 .. $form->{lastndx}) {
276     map { delete $form->{"new_${_}_$i"} } qw(id name);
277   }
278
279   map { delete $form->{$_} } qw(ndx lastndx nextsub);
280
281   IS->get_customer(\%myconfig, \%$form) if ($form->{vc} eq 'customer');
282   IR->get_vendor(\%myconfig, \%$form) if ($form->{vc} eq 'vendor');
283
284   &update(1);
285
286   $main::lxdebug->leave_sub();
287 }
288
289 # Reset the $::form field 'salesman_id' to the ID of the currently
290 # logged in user. Useful when changing to a customer/vendor that has
291 # no salesman listed in their master data.
292 sub _reset_salesman_id {
293   my $current_employee   = SL::DB::Manager::Employee->current;
294   $::form->{salesman_id} = $current_employee->id if $current_employee && exists $::form->{salesman_id};
295 }
296
297 sub select_project {
298   $::lxdebug->enter_sub;
299
300   $::auth->assert('general_ledger         | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
301                   'request_quotation_edit | sales_quotation_edit | purchase_order_edit | cash         | report');
302
303   my ($is_global, $nextsub) = @_;
304   my $project_list = delete $::form->{project_list};
305
306   map { delete $::form->{$_} } qw(action header update);
307
308   my @hiddens;
309   for my $key (keys %$::form) {
310     next if $key eq 'login' || $key eq 'password' || '' ne ref $::form->{$key};
311     push @hiddens, { key => $key, value => $::form->{$key} };
312   }
313   push @hiddens, { key => 'is_global',                value => $is_global },
314                  { key => 'project_selected_nextsub', value => $nextsub };
315
316   $::form->header;
317   print $::form->parse_html_template('arap/select_project', { hiddens => \@hiddens, project_list => $project_list });
318
319   $::lxdebug->leave_sub;
320 }
321
322 sub project_selected {
323   $main::lxdebug->enter_sub();
324
325   my $form     = $main::form;
326
327   $main::auth->assert('general_ledger         | vendor_invoice_edit  | sales_order_edit    | invoice_edit |' .
328                 'request_quotation_edit | sales_quotation_edit | purchase_order_edit | cash         | report');
329
330   # replace the variable with the one checked
331
332   # index for new item
333   my $i = $form->{ndx};
334
335   my $prefix = $form->{"is_global"} ? "global" : "";
336   my $suffix = $form->{"is_global"} ? "" : "_$form->{rownumber}";
337
338   $form->{"${prefix}projectnumber${suffix}"} =
339     $form->{"new_projectnumber_$i"};
340   $form->{"old${prefix}projectnumber${suffix}"} =
341     $form->{"new_projectnumber_$i"};
342   $form->{"${prefix}project_id${suffix}"} = $form->{"new_id_$i"};
343
344   # delete all the new_ variables
345   for $i (1 .. $form->{lastndx}) {
346     map { delete $form->{"new_${_}_$i"} } qw(id projectnumber description);
347   }
348
349   my $nextsub = $form->{project_selected_nextsub} || 'update';
350
351   map { delete $form->{$_} } qw(ndx lastndx nextsub is_global project_selected_nextsub);
352
353   call_sub($nextsub);
354
355   $main::lxdebug->leave_sub();
356 }
357
358 sub continue       { call_sub($main::form->{"nextsub"}); }
359
360 1;
361
362 __END__
363
364 =head1 NAME
365
366 arap.pl - helper functions or customer/vendor retrieval
367
368 =head1 SYNOPSIS
369
370  check_name('vendor')
371
372 =head1 DESCRIPTION
373
374 Don't use anyting in this file without extreme care, and even then be prepared for massive headaches.
375
376 It's a collection of helper routines that wrap the customer/vendor dropdown/textfield duality into something even complexer.
377
378 =head1 FUNCTIONS
379
380 =head2 check_name customer|vendor
381
382 check_name was originally meant to update the selected customer or vendor. The
383 way it does that has generted more hate than almost any other part of this
384 software.
385
386 What it does is:
387
388 =over 4
389
390 =item *
391
392 It checks if a vendor or customer is given. No failsafe, vendor fallback if
393 $_[0] is something fancy.
394
395 =item *
396
397 It assumes, that there is a field named customer or vendor in $form.
398
399 =item *
400
401 It assumes, that this field is filled with name--id, and tries to split that.
402 sql ledger uses that combination to get ids into the select keys.
403
404 =item *
405
406 It looks for a field selectcustomer or selectvendor in $form. sql ledger used
407 to store a copy of the html select in there. (again, don't ask)
408
409 =item *
410
411 If this field exists, it looks for a field called oldcustomer or oldvendor, in
412 which the old name--id string was stored in sql ledger, and compares those.
413
414 =item *
415
416 if they don't match, it will set customer_id or vendor_id in $form, load the
417 entry (which will clobber everything in $form named like a column in customer
418 oder vendor) and return.
419
420 =item *
421
422 If there was no select* entry, it assumes that vclimit was lower than the
423 number of entries, and that an input field was generated. In that case the
424 splitting is omitted (since users don't generally include ids in entered names)
425
426 =item *
427
428 It looks for a *_id field, and combines it with the given input into a name--id
429 entry and compares it to the old* entry. (Missing any of these will instantly
430 break check_namea.
431
432 =item *
433
434 If those do not match, $form->get_name is called to get matching results.
435 get_name only matches by *number and name, not by id, don't try to get it to do
436 so.
437
438 =item *
439
440 The results are stored in $form>{name_list} but a count is returned, and
441 checked.
442
443 =item *
444
445 If only one result was found, *_id, * and old* are copied into $form, the entry
446 is loaded (like above, clobbering)
447
448 =item *
449
450 If there is more than one, a selection dialog is rendered
451
452 =item *
453
454 If none is found, an error is generated.
455
456 =back
457
458 =head3 I built a customer/vendor box somewhere and it doesn't work, what's wrong?
459
460 Make sure a select* field is given if and only if you render a select box. The
461 actual contents are ignored, but recognition fails if not present.
462
463 Make sure old* and *_id fields are set correctly (name--id form for old*). They
464 are necessary in all steps and branches.
465
466 Since get_customer and get_vendor clobber a lot of fields, make sure what
467 changes exactly.
468
469 =head3 select- version works fine, but things go awry when I use a textbox, any idea?
470
471 If there is more than one match, check_name will display a select form, that
472 will redirect to the original C<nextsub>. Unfortunately any hidden vars or
473 input fields will be lost in the process unless saved before in a callback.
474
475 If you still want to use it, you can disable this feature, like this:
476
477   check_name('customer', no_select => 1)
478
479 In that case multiple matches will trigger an error.
480
481 Otherwise you'll have to care to include a complete state in callback.
482
483 =cut