1 #=====================================================================
 
   4 # Based on SQL-Ledger Version 2.1.9
 
   5 # Web http://www.lx-office.org
 
   7 #=====================================================================
 
   8 # SQL-Ledger Accounting
 
  11 #  Author: Dieter Simader
 
  12 #   Email: dsimader@sql-ledger.org
 
  13 #     Web: http://www.sql-ledger.org
 
  17 # This program is free software; you can redistribute it and/or modify
 
  18 # it under the terms of the GNU General Public License as published by
 
  19 # the Free Software Foundation; either version 2 of the License, or
 
  20 # (at your option) any later version.
 
  22 # This program is distributed in the hope that it will be useful,
 
  23 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  24 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  25 # GNU General Public License for more details.
 
  26 # You should have received a copy of the GNU General Public License
 
  27 # along with this program; if not, write to the Free Software
 
  28 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
  29 #======================================================================
 
  31 # backend code for customers and vendors
 
  34 #   DS. 2000-07-04  Created
 
  36 #======================================================================
 
  47   $main::lxdebug->enter_sub();
 
  49   my ( $self, $myconfig, $form ) = @_;
 
  52   my $dbh = $form->dbconnect($myconfig);
 
  54   my $cv = $form->{db} eq "customer" ? "customer" : "vendor";
 
  55   my $join_records = $form->{l_invnumber} || $form->{l_ordnumber} || $form->{l_quonumber};
 
  60   my %allowed_sort_columns = (
 
  62       "customernumber"     => "ct.customernumber",
 
  63       "vendornumber"       => "ct.vendornumber",
 
  65       "contact"            => "ct.contact",
 
  66       "phone"              => "ct.phone",
 
  68       "email"              => "ct.email",
 
  69       "street"             => "ct.street",
 
  70       "taxnumber"          => "ct.taxnumber",
 
  71       "business"           => "b.description",
 
  72       "invnumber"          => "ct.invnumber",
 
  73       "ordnumber"          => "ct.ordnumber",
 
  74       "quonumber"          => "ct.quonumber",
 
  75       "zipcode"            => "ct.zipcode",
 
  77       "country"            => "ct.country",
 
  78       "discount"           => "ct.discount",
 
  79       "salesman"           => "e.name",
 
  80       "payment"            => "pt.description"
 
  83   $form->{sort} ||= "name";
 
  85   if ( $join_records ) {
 
  86     # in UNION case order by hash key, e.g. salesman
 
  87     # the UNION created an implicit select around the result
 
  88     $sortorder = $allowed_sort_columns{$form->{sort}} ? $form->{sort} : "name";
 
  90     # in not UNION case order by hash value, e.g. e.name
 
  91     $sortorder = $allowed_sort_columns{$form->{sort}} ?  $allowed_sort_columns{$form->{sort}} : "ct.name";
 
  93   my $sortdir   = !defined $form->{sortdir} ? 'ASC' : $form->{sortdir} ? 'ASC' : 'DESC';
 
  95   if ($sortorder !~ /(business|id|discount)/ && !$join_records) {
 
  96     $sortorder  = "lower($sortorder) ${sortdir}";
 
  98     $sortorder .= " ${sortdir}";
 
 101   if ($form->{"${cv}number"}) {
 
 102     $where .= " AND ct.${cv}number ILIKE ?";
 
 103     push(@values, '%' . $form->{"${cv}number"} . '%');
 
 106   foreach my $key (qw(name contact email)) {
 
 108       $where .= " AND ct.$key ILIKE ?";
 
 109       push(@values, '%' . $form->{$key} . '%');
 
 113   if ($form->{cp_name}) {
 
 114     $where .= " AND ct.id IN (SELECT cp_cv_id FROM contacts WHERE lower(cp_name) LIKE lower(?))";
 
 115     push @values, '%' . $form->{cp_name} . '%';
 
 118   if ($form->{addr_city}) {
 
 119     $where .= " AND ((lower(ct.city) LIKE lower(?))
 
 124                         WHERE (sc.module = 'CT')
 
 125                           AND (lower(sc.shiptocity) LIKE lower(?))
 
 128     push @values, ('%' . $form->{addr_city} . '%') x 2;
 
 131   if ($form->{addr_country}) {
 
 132     $where .= " AND ((lower(ct.country) LIKE lower(?))
 
 137                         WHERE (so.module = 'CT')
 
 138                           AND (lower(so.shiptocountry) LIKE lower(?))
 
 141     push @values, ('%' . $form->{addr_country} . '%') x 2;
 
 144   if ( $form->{status} eq 'orphaned' ) {
 
 146       qq| AND ct.id NOT IN | .
 
 147       qq|   (SELECT o.${cv}_id FROM oe o, $cv cv WHERE cv.id = o.${cv}_id)|;
 
 148     if ($cv eq 'customer') {
 
 150         qq| AND ct.id NOT IN | .
 
 151         qq| (SELECT a.customer_id FROM ar a, customer cv | .
 
 152         qq|  WHERE cv.id = a.customer_id)|;
 
 154     if ($cv eq 'vendor') {
 
 156         qq| AND ct.id NOT IN | .
 
 157         qq| (SELECT a.vendor_id FROM ap a, vendor cv | .
 
 158         qq|  WHERE cv.id = a.vendor_id)|;
 
 160     $form->{l_invnumber} = $form->{l_ordnumber} = $form->{l_quonumber} = "";
 
 163   if ($form->{obsolete} eq "Y") {
 
 164     $where .= qq| AND ct.obsolete|;
 
 165   } elsif ($form->{obsolete} eq "N") {
 
 166     $where .= qq| AND NOT ct.obsolete|;
 
 169   if ($form->{business_id}) {
 
 170     $where .= qq| AND (ct.business_id = ?)|;
 
 171     push(@values, conv_i($form->{business_id}));
 
 174   # Nur Kunden finden, bei denen ich selber der Verkäufer bin
 
 175   # Gilt nicht für Lieferanten
 
 176   if ($cv eq 'customer' &&   !$main::auth->assert('customer_vendor_all_edit', 1)) {
 
 177     $where .= qq| AND ct.salesman_id = (select em.id from employee em where em.login = ?)|;
 
 178     push(@values, $form->{login});
 
 181   my ($cvar_where, @cvar_values) = CVar->build_filter_query('module'         => 'CT',
 
 182                                                             'trans_id_field' => 'ct.id',
 
 186     $where .= qq| AND ($cvar_where)|;
 
 187     push @values, @cvar_values;
 
 190   if ($form->{addr_street}) {
 
 191     $where .= qq| AND (ct.street ILIKE ?)|;
 
 192     push @values, '%' . $form->{addr_street} . '%';
 
 195   if ($form->{addr_zipcode}) {
 
 196     $where .= qq| AND (ct.zipcode ILIKE ?)|;
 
 197     push @values, $form->{addr_zipcode} . '%';
 
 201     qq|SELECT ct.*, b.description AS business, e.name as salesman, |.
 
 202     qq|  pt.description as payment | .
 
 203     (qq|, NULL AS invnumber, NULL AS ordnumber, NULL AS quonumber, NULL AS invid, NULL AS module, NULL AS formtype, NULL AS closed | x!! $join_records) .
 
 205     qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
 
 206     qq|LEFT JOIN employee e ON (ct.salesman_id = e.id) | .
 
 207     qq|LEFT JOIN payment_terms pt ON (ct.payment_id = pt.id) | .
 
 210   my @saved_values = @values;
 
 211   # redo for invoices, orders and quotations
 
 215     if ($form->{l_invnumber}) {
 
 216       my $ar = $cv eq 'customer' ? 'ar' : 'ap';
 
 217       my $module = $ar eq 'ar' ? 'is' : 'ir';
 
 218       push(@values, @saved_values);
 
 221         qq|SELECT ct.*, b.description AS business, e.name as salesman, |.
 
 222         qq|  pt.description as payment, | .
 
 223         qq|  a.invnumber, a.ordnumber, a.quonumber, a.id AS invid, | .
 
 224         qq|  '$module' AS module, 'invoice' AS formtype, | .
 
 225         qq|  (a.amount = a.paid) AS closed | .
 
 227         qq|JOIN $ar a ON (a.${cv}_id = ct.id) | .
 
 228         qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
 
 229         qq|LEFT JOIN employee e ON (ct.salesman_id = e.id) | .
 
 230         qq|LEFT JOIN payment_terms pt ON (ct.payment_id = pt.id) | .
 
 231         qq|WHERE $where AND (a.invoice = '1')|;
 
 234     if ( $form->{l_ordnumber} ) {
 
 235       push(@values, @saved_values);
 
 238         qq|SELECT ct.*, b.description AS business, e.name as salesman, |.
 
 239         qq|  pt.description as payment, | .
 
 240         qq|  ' ' AS invnumber, o.ordnumber, o.quonumber, o.id AS invid, | .
 
 241         qq|  'oe' AS module, 'order' AS formtype, o.closed | .
 
 243         qq|JOIN oe o ON (o.${cv}_id = ct.id) | .
 
 244         qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
 
 245         qq|LEFT JOIN employee e ON (ct.salesman_id = e.id) | .
 
 246         qq|LEFT JOIN payment_terms pt ON (ct.payment_id = pt.id) | .
 
 247         qq|WHERE $where AND (o.quotation = '0')|;
 
 250     if ( $form->{l_quonumber} ) {
 
 251       push(@values, @saved_values);
 
 254         qq|SELECT ct.*, b.description AS business, e.name as salesman, | .
 
 255         qq|  pt.description as payment, | .
 
 256         qq|  ' ' AS invnumber, o.ordnumber, o.quonumber, o.id AS invid, | .
 
 257         qq|  'oe' AS module, 'quotation' AS formtype, o.closed | .
 
 259         qq|JOIN oe o ON (o.${cv}_id = ct.id) | .
 
 260         qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
 
 261         qq|LEFT JOIN employee e ON (ct.salesman_id = e.id) | .
 
 262         qq|LEFT JOIN payment_terms pt ON (ct.payment_id = pt.id) | .
 
 263         qq|WHERE $where AND (o.quotation = '1')|;
 
 267   $query .= qq| ORDER BY $sortorder|;
 
 269   $form->{CT} = selectall_hashref_query($form, $dbh, $query, @values);
 
 271   $main::lxdebug->leave_sub();
 
 275   $main::lxdebug->enter_sub();
 
 277   my ( $self, $myconfig, $form ) = @_;
 
 279   die 'Missing argument: cp_id' unless $::form->{cp_id};
 
 281   my $dbh   = $form->dbconnect($myconfig);
 
 283     qq|SELECT * FROM contacts c | .
 
 284     qq|WHERE cp_id = ? ORDER BY cp_id limit 1|;
 
 285   my $sth = prepare_execute_query($form, $dbh, $query, $form->{cp_id});
 
 286   my $ref = $sth->fetchrow_hashref("NAME_lc");
 
 288   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
 290   $query = qq|SELECT COUNT(cp_id) AS used FROM (
 
 291     SELECT cp_id FROM oe UNION
 
 292     SELECT cp_id FROM ar UNION
 
 293     SELECT cp_id FROM ap UNION
 
 294     SELECT cp_id FROM delivery_orders
 
 295   ) AS cpid WHERE cp_id = ? OR ? = 0|;
 
 296   ($form->{cp_used}) = selectfirst_array_query($form, $dbh, $query, ($form->{cp_id})x2);
 
 301   $main::lxdebug->leave_sub();
 
 305   $main::lxdebug->enter_sub();
 
 310   Common::check_params(\%params, qw(vc id));
 
 312   my $myconfig = \%main::myconfig;
 
 313   my $form     = $main::form;
 
 315   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
 
 317   my $table        = $params{vc} eq 'customer' ? 'customer' : 'vendor';
 
 318   my @ids          = ref $params{id} eq 'ARRAY' ? @{ $params{id} } : ($params{id});
 
 319   my $placeholders = join ", ", ('?') x scalar @ids;
 
 320   my $c_mandate    = $params{vc} eq 'customer' ? ', mandator_id, mandate_date_of_signature' : '';
 
 321   my $query        = qq|SELECT id, name, account_number, bank, bank_code, iban, bic ${c_mandate}
 
 323                         WHERE id IN (${placeholders})|;
 
 325   my $result       = selectall_hashref_query($form, $dbh, $query, map { conv_i($_) } @ids);
 
 327   if (ref $params{id} eq 'ARRAY') {
 
 328     $result = { map { $_->{id} => $_ } @{ $result } };
 
 330     $result = $result->[0] || { 'id' => $params{id} };
 
 333   $main::lxdebug->leave_sub();
 
 338 sub search_contacts {
 
 339   $::lxdebug->enter_sub;
 
 344   my $dbh       = $params{dbh} || $::form->get_standard_dbh;
 
 347     'cp_name'   => 'cp_name, cp_givenname',
 
 348     'vcname'    => 'vcname, cp_name, cp_givenname',
 
 349     'vcnumber'  => 'vcnumber, cp_name, cp_givenname',
 
 352   my %sortcols  = map { $_ => 1 } qw(cp_name cp_givenname cp_phone1 cp_phone2 cp_mobile1 cp_email cp_street cp_zipcode cp_city cp_position vcname vcnumber);
 
 354   my $order_by  = $sortcols{$::form->{sort}} ? $::form->{sort} : 'cp_name';
 
 355   $::form->{sort} = $order_by;
 
 356   $order_by     = $sortspecs{$order_by} if ($sortspecs{$order_by});
 
 358   my $sortdir   = $::form->{sortdir} ? 'ASC' : 'DESC';
 
 359   $order_by     =~ s/,/ ${sortdir},/g;
 
 360   $order_by    .= " $sortdir";
 
 362   my @where_tokens = ();
 
 365   if ($params{search_term}) {
 
 368       'cp.cp_name      ILIKE ?',
 
 369       'cp.cp_givenname ILIKE ?',
 
 370       'cp.cp_email     ILIKE ?';
 
 371     push @values, ('%' . $params{search_term} . '%') x 3;
 
 373     if (($params{search_term} =~ m/\d/) && ($params{search_term} !~ m/[^\d \(\)+\-]/)) {
 
 374       my $number =  $params{search_term};
 
 375       $number    =~ s/[^\d]//g;
 
 376       $number    =  join '[ /\(\)+\-]*', split(m//, $number);
 
 378       push @tokens, map { "($_ ~ '$number')" } qw(cp_phone1 cp_phone2 cp_mobile1 cp_mobile2);
 
 381     push @where_tokens, map { "($_)" } join ' OR ', @tokens;
 
 384   my ($cvar_where, @cvar_values) = CVar->build_filter_query('module'         => 'Contacts',
 
 385                                                             'trans_id_field' => 'cp.cp_id',
 
 386                                                             'filter'         => $params{filter});
 
 389     push @where_tokens, $cvar_where;
 
 390     push @values, @cvar_values;
 
 393   if (my $filter = $params{filter}) {
 
 394     for (qw(name title givenname email project abteilung)) {
 
 395       next unless $filter->{"cp_$_"};
 
 396       add_token(\@where_tokens, \@values, col =>  "cp.cp_$_", val => $filter->{"cp_$_"}, method => 'ILIKE', esc => 'substr');
 
 399     push @where_tokens, 'cp.cp_cv_id IS NOT NULL' if $filter->{status} eq 'active';
 
 400     push @where_tokens, 'cp.cp_cv_id IS NULL'     if $filter->{status} eq 'orphaned';
 
 403   my $where = @where_tokens ? 'WHERE ' . join ' AND ', @where_tokens : '';
 
 405   my $query     = qq|SELECT cp.*,
 
 406                        COALESCE(c.id,             v.id)           AS vcid,
 
 407                        COALESCE(c.name,           v.name)         AS vcname,
 
 408                        COALESCE(c.customernumber, v.vendornumber) AS vcnumber,
 
 409                        CASE WHEN c.name IS NULL THEN 'vendor' ELSE 'customer' END AS db
 
 411                      LEFT JOIN customer c ON (cp.cp_cv_id = c.id)
 
 412                      LEFT JOIN vendor v   ON (cp.cp_cv_id = v.id)
 
 416   my $contacts  = selectall_hashref_query($::form, $dbh, $query, @values);
 
 418   $::lxdebug->leave_sub;
 
 420   return @{ $contacts };