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., 51 Franklin Street, Fifth Floor, Boston,
 
  30 #======================================================================
 
  32 # backend code for customers and vendors
 
  35 #   DS. 2000-07-04  Created
 
  37 #======================================================================
 
  45 use SL::Util qw(trim);
 
  51   $main::lxdebug->enter_sub();
 
  53   my ( $self, $myconfig, $form ) = @_;
 
  56   my $dbh = $form->dbconnect($myconfig);
 
  58   my $cv = $form->{db} eq "customer" ? "customer" : "vendor";
 
  59   my $join_records = $form->{l_invnumber} || $form->{l_ordnumber} || $form->{l_quonumber};
 
  64   my %allowed_sort_columns = (
 
  66       "customernumber"     => "ct.customernumber",
 
  67       "vendornumber"       => "ct.vendornumber",
 
  69       "contact"            => "ct.contact",
 
  70       "phone"              => "ct.phone",
 
  72       "email"              => "ct.email",
 
  73       "street"             => "ct.street",
 
  74       "taxnumber"          => "ct.taxnumber",
 
  75       "business"           => "b.description",
 
  76       "invnumber"          => "ct.invnumber",
 
  77       "ordnumber"          => "ct.ordnumber",
 
  78       "quonumber"          => "ct.quonumber",
 
  79       "zipcode"            => "ct.zipcode",
 
  81       "country"            => "ct.country",
 
  83       "discount"           => "ct.discount",
 
  84       "insertdate"         => "ct.itime",
 
  85       "salesman"           => "e.name",
 
  86       "payment"            => "pt.description",
 
  87       "pricegroup"         => "pg.pricegroup",
 
  88       "ustid"              => "ct.ustid",
 
  89       "creditlimit"        => "ct.creditlimit",
 
  90       "commercial_court"   => "ct.commercial_court",
 
  93   $form->{sort} ||= "name";
 
  95   if ( $join_records ) {
 
  96     # in UNION case order by hash key, e.g. salesman
 
  97     # the UNION created an implicit select around the result
 
  98     $sortorder = $allowed_sort_columns{$form->{sort}} ? $form->{sort} : "name";
 
 100     # in not UNION case order by hash value, e.g. e.name
 
 101     $sortorder = $allowed_sort_columns{$form->{sort}} ?  $allowed_sort_columns{$form->{sort}} : "ct.name";
 
 103   my $sortdir   = !defined $form->{sortdir} ? 'ASC' : $form->{sortdir} ? 'ASC' : 'DESC';
 
 105   if ($sortorder !~ /(business|creditlimit|id|discount|itime)/ && !$join_records) {
 
 106     $sortorder  = "lower($sortorder) ${sortdir}";
 
 108     $sortorder .= " ${sortdir}";
 
 111   if ($form->{"${cv}number"}) {
 
 112     $where .= " AND ct.${cv}number ILIKE ?";
 
 113     push(@values, like($form->{"${cv}number"}));
 
 116   foreach my $key (qw(name contact email)) {
 
 118       $where .= " AND ct.$key ILIKE ?";
 
 119       push(@values, like($form->{$key}));
 
 123   if ($form->{cp_name}) {
 
 124     $where .= " AND ct.id IN (SELECT cp_cv_id FROM contacts WHERE lower(cp_name) LIKE lower(?))";
 
 125     push @values, like($form->{cp_name});
 
 128   if ($form->{addr_street}) {
 
 129     $where .= qq| AND ((ct.street ILIKE ?) | .
 
 132               qq|         SELECT sc.trans_id FROM shipto sc | .
 
 133               qq|         WHERE (sc.module = 'CT') | .
 
 134               qq|           AND (sc.shiptostreet ILIKE ?) | .
 
 136     push @values, (like($form->{addr_street})) x 2;
 
 139   if ($form->{addr_zipcode}) {
 
 140     $where .= qq| AND ((ct.zipcode ILIKE ?) | .
 
 143               qq|         SELECT sc.trans_id FROM shipto sc | .
 
 144               qq|         WHERE (sc.module = 'CT') | .
 
 145               qq|           AND (sc.shiptozipcode ILIKE ?) | .
 
 147     push @values, (like($form->{addr_zipcode})) x 2;
 
 150   if ($form->{addr_city}) {
 
 151     $where .= " AND ((lower(ct.city) LIKE lower(?))
 
 156                         WHERE (sc.module = 'CT')
 
 157                           AND (lower(sc.shiptocity) LIKE lower(?))
 
 160     push @values, (like($form->{addr_city})) x 2;
 
 163   if ($form->{addr_country}) {
 
 164     $where .= " AND ((lower(ct.country) LIKE lower(?))
 
 169                         WHERE (so.module = 'CT')
 
 170                           AND (lower(so.shiptocountry) LIKE lower(?))
 
 173     push @values, (like($form->{addr_country})) x 2;
 
 176   if ($form->{addr_gln}) {
 
 177     $where .= " AND ((lower(ct.gln) LIKE lower(?))
 
 182                         WHERE (so.module = 'CT')
 
 183                           AND (lower(so.shiptogln) LIKE lower(?))
 
 186     push @values, (like($form->{addr_gln})) x 2;
 
 189   if ( $form->{status} eq 'orphaned' ) {
 
 191       qq| AND ct.id NOT IN | .
 
 192       qq|   (SELECT o.${cv}_id FROM oe o, $cv cv WHERE cv.id = o.${cv}_id)|;
 
 193     if ($cv eq 'customer') {
 
 195         qq| AND ct.id NOT IN | .
 
 196         qq| (SELECT a.customer_id FROM ar a, customer cv | .
 
 197         qq|  WHERE cv.id = a.customer_id)|;
 
 199     if ($cv eq 'vendor') {
 
 201         qq| AND ct.id NOT IN | .
 
 202         qq| (SELECT a.vendor_id FROM ap a, vendor cv | .
 
 203         qq|  WHERE cv.id = a.vendor_id)|;
 
 205     $form->{l_invnumber} = $form->{l_ordnumber} = $form->{l_quonumber} = "";
 
 208   if ($form->{obsolete} eq "Y") {
 
 209     $where .= qq| AND ct.obsolete|;
 
 210   } elsif ($form->{obsolete} eq "N") {
 
 211     $where .= qq| AND NOT ct.obsolete|;
 
 214   if ($form->{business_id}) {
 
 215     $where .= qq| AND (ct.business_id = ?)|;
 
 216     push(@values, conv_i($form->{business_id}));
 
 219   if ($form->{salesman_id}) {
 
 220     $where .= qq| AND (ct.salesman_id = ?)|;
 
 221     push(@values, conv_i($form->{salesman_id}));
 
 224   if($form->{insertdatefrom}) {
 
 225     $where .= qq| AND (ct.itime::DATE >= ?)|;
 
 226     push@values, conv_date($form->{insertdatefrom});
 
 229   if($form->{insertdateto}) {
 
 230     $where .= qq| AND (ct.itime::DATE <= ?)|;
 
 231     push @values, conv_date($form->{insertdateto});
 
 235     my @tokens = parse_line('\s+', 0, $form->{all});
 
 237           ct.${cv}number ILIKE ? OR
 
 240     push @values, ("%$_%")x2 for @tokens;
 
 243   if (($form->{create_zugferd_invoices} // '') ne '') {
 
 244     $where .= qq| AND (ct.create_zugferd_invoices = ?)|;
 
 245     push @values, $form->{create_zugferd_invoices};
 
 248   if ($form->{all_phonenumbers}) {
 
 249     my $search_term = trim($form->{all_phonenumbers});
 
 250     $search_term    =~ s{\p{WSpace}+}{}g;
 
 251     $search_term    = join ' *', split(//, $search_term);
 
 253     $where .= qq| AND (ct.phone ~* ? OR
 
 256                          (SELECT cp_cv_id FROM contacts
 
 257                           WHERE cp_phone1      ~* ? OR
 
 267     push @values, ($search_term)x10;
 
 270   my ($cvar_where, @cvar_values) = CVar->build_filter_query('module'         => 'CT',
 
 271                                                             'trans_id_field' => 'ct.id',
 
 275     $where .= qq| AND ($cvar_where)|;
 
 276     push @values, @cvar_values;
 
 279   my $pg_select = $form->{l_pricegroup} ? qq|, pg.pricegroup as pricegroup | : '';
 
 280   my $pg_join   = $form->{l_pricegroup} ? qq|LEFT JOIN pricegroup pg ON (ct.pricegroup_id = pg.id) | : '';
 
 282   my $main_cp_select = '';
 
 283   if ($form->{l_main_contact_person}) {
 
 284     $main_cp_select =  qq/, (SELECT concat(cp.cp_givenname, ' ', cp.cp_name, ' | ', cp.cp_email, ' | ', cp.cp_phone1)
 
 285                               FROM contacts cp WHERE ct.id=cp.cp_cv_id AND cp.cp_main LIMIT 1)
 
 286                               AS main_contact_person /;
 
 289     qq|SELECT ct.*, ct.itime::DATE AS insertdate, b.description AS business, e.name as salesman, | .
 
 290     qq|  pt.description as payment | .
 
 293     (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) .
 
 295     qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
 
 296     qq|LEFT JOIN employee e ON (ct.salesman_id = e.id) | .
 
 297     qq|LEFT JOIN payment_terms pt ON (ct.payment_id = pt.id) | .
 
 301   my @saved_values = @values;
 
 302   # redo for invoices, orders and quotations
 
 306     if ($form->{l_invnumber}) {
 
 307       my $ar = $cv eq 'customer' ? 'ar' : 'ap';
 
 308       my $module = $ar eq 'ar' ? 'is' : 'ir';
 
 309       push(@values, @saved_values);
 
 312         qq|SELECT ct.*, ct.itime::DATE AS insertdate, b.description AS business, e.name as salesman, | .
 
 313         qq|  pt.description as payment | .
 
 316         qq|, a.invnumber, a.ordnumber, a.quonumber, a.id AS invid, | .
 
 317         qq|  '$module' AS module, 'invoice' AS formtype, | .
 
 318         qq|  (a.amount = a.paid) AS closed | .
 
 320         qq|JOIN $ar a ON (a.${cv}_id = ct.id) | .
 
 321         qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
 
 322         qq|LEFT JOIN employee e ON (ct.salesman_id = e.id) | .
 
 323         qq|LEFT JOIN payment_terms pt ON (ct.payment_id = pt.id) | .
 
 325         qq|WHERE $where AND (a.invoice = '1')|;
 
 328     if ( $form->{l_ordnumber} ) {
 
 329       push(@values, @saved_values);
 
 332         qq|SELECT ct.*, ct.itime::DATE AS insertdate, b.description AS business, e.name as salesman, | .
 
 333         qq|  pt.description as payment | .
 
 336         qq|, ' ' AS invnumber, o.ordnumber, o.quonumber, o.id AS invid, | .
 
 337         qq|  'oe' AS module, 'order' AS formtype, o.closed | .
 
 339         qq|JOIN oe o ON (o.${cv}_id = ct.id) | .
 
 340         qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
 
 341         qq|LEFT JOIN employee e ON (ct.salesman_id = e.id) | .
 
 342         qq|LEFT JOIN payment_terms pt ON (ct.payment_id = pt.id) | .
 
 344         qq|WHERE $where AND (o.quotation = '0')|;
 
 347     if ( $form->{l_quonumber} ) {
 
 348       push(@values, @saved_values);
 
 351         qq|SELECT ct.*, ct.itime::DATE AS insertdate, b.description AS business, e.name as salesman, | .
 
 352         qq|  pt.description as payment | .
 
 355         qq|, ' ' AS invnumber, o.ordnumber, o.quonumber, o.id AS invid, | .
 
 356         qq|  'oe' AS module, 'quotation' AS formtype, o.closed | .
 
 358         qq|JOIN oe o ON (o.${cv}_id = ct.id) | .
 
 359         qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
 
 360         qq|LEFT JOIN employee e ON (ct.salesman_id = e.id) | .
 
 361         qq|LEFT JOIN payment_terms pt ON (ct.payment_id = pt.id) | .
 
 363         qq|WHERE $where AND (o.quotation = '1')|;
 
 367   $query .= qq| ORDER BY $sortorder|;
 
 369   $form->{CT} = selectall_hashref_query($form, $dbh, $query, @values);
 
 371   $main::lxdebug->leave_sub();
 
 375   $main::lxdebug->enter_sub();
 
 377   my ( $self, $myconfig, $form ) = @_;
 
 379   die 'Missing argument: cp_id' unless $::form->{cp_id};
 
 381   my $dbh   = SL::DB->client->dbh;
 
 383     qq|SELECT * FROM contacts c | .
 
 384     qq|WHERE cp_id = ? ORDER BY cp_id limit 1|;
 
 385   my $sth = prepare_execute_query($form, $dbh, $query, $form->{cp_id});
 
 386   my $ref = $sth->fetchrow_hashref("NAME_lc");
 
 388   map { $form->{$_} = $ref->{$_} } keys %$ref;
 
 390   $query = qq|SELECT COUNT(cp_id) AS used FROM (
 
 391     SELECT cp_id FROM oe UNION
 
 392     SELECT cp_id FROM ar UNION
 
 393     SELECT cp_id FROM ap UNION
 
 394     SELECT cp_id FROM delivery_orders
 
 395   ) AS cpid WHERE cp_id = ? OR ? = 0|;
 
 396   ($form->{cp_used}) = selectfirst_array_query($form, $dbh, $query, ($form->{cp_id})x2);
 
 400   $main::lxdebug->leave_sub();
 
 404   $main::lxdebug->enter_sub();
 
 409   Common::check_params(\%params, qw(vc id));
 
 411   my $myconfig = \%main::myconfig;
 
 412   my $form     = $main::form;
 
 414   my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
 
 416   my $table        = $params{vc} eq 'customer' ? 'customer' : 'vendor';
 
 417   my @ids          = ref $params{id} eq 'ARRAY' ? @{ $params{id} } : ($params{id});
 
 418   my $placeholders = join ", ", ('?') x scalar @ids;
 
 419   my $c_mandate    = $params{vc} eq 'customer' ? ', mandator_id, mandate_date_of_signature' : '';
 
 420   my $query        = qq|SELECT id, name, account_number, bank, bank_code, iban, bic ${c_mandate}
 
 422                         WHERE id IN (${placeholders})|;
 
 424   my $result       = selectall_hashref_query($form, $dbh, $query, map { conv_i($_) } @ids);
 
 426   if (ref $params{id} eq 'ARRAY') {
 
 427     $result = { map { $_->{id} => $_ } @{ $result } };
 
 429     $result = $result->[0] || { 'id' => $params{id} };
 
 432   $main::lxdebug->leave_sub();
 
 437 sub search_contacts {
 
 438   $::lxdebug->enter_sub;
 
 443   my $dbh       = $params{dbh} || $::form->get_standard_dbh;
 
 446     'cp_name'   => 'cp_name, cp_givenname',
 
 447     'vcname'    => 'vcname, cp_name, cp_givenname',
 
 448     'vcnumber'  => 'vcnumber, cp_name, cp_givenname',
 
 451   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);
 
 453   my $order_by  = $sortcols{$::form->{sort}} ? $::form->{sort} : 'cp_name';
 
 454   $::form->{sort} = $order_by;
 
 455   $order_by     = $sortspecs{$order_by} if ($sortspecs{$order_by});
 
 457   my $sortdir   = $::form->{sortdir} ? 'ASC' : 'DESC';
 
 458   $order_by     =~ s/,/ ${sortdir},/g;
 
 459   $order_by    .= " $sortdir";
 
 461   my @where_tokens = ();
 
 464   if ($params{search_term}) {
 
 467       'cp.cp_name      ILIKE ?',
 
 468       'cp.cp_givenname ILIKE ?',
 
 469       'cp.cp_email     ILIKE ?';
 
 470     push @values, (like($params{search_term})) x 3;
 
 472     if (($params{search_term} =~ m/\d/) && ($params{search_term} !~ m/[^\d \(\)+\-]/)) {
 
 473       my $number =  $params{search_term};
 
 474       $number    =~ s/[^\d]//g;
 
 475       $number    =  join '[ /\(\)+\-]*', split(m//, $number);
 
 477       push @tokens, map { "($_ ~ '$number')" } qw(cp_phone1 cp_phone2 cp_mobile1 cp_mobile2);
 
 480     push @where_tokens, map { "($_)" } join ' OR ', @tokens;
 
 483   my ($cvar_where, @cvar_values) = CVar->build_filter_query('module'         => 'Contacts',
 
 484                                                             'trans_id_field' => 'cp.cp_id',
 
 485                                                             'filter'         => $params{filter});
 
 488     push @where_tokens, $cvar_where;
 
 489     push @values, @cvar_values;
 
 492   if (my $filter = $params{filter}) {
 
 493     for (qw(name title givenname email project abteilung)) {
 
 494       next unless $filter->{"cp_$_"};
 
 495       add_token(\@where_tokens, \@values, col =>  "cp.cp_$_", val => $filter->{"cp_$_"}, method => 'ILIKE', esc => 'substr');
 
 498     push @where_tokens, 'cp.cp_cv_id IS NOT NULL' if $filter->{status} eq 'active';
 
 499     push @where_tokens, 'cp.cp_cv_id IS NULL'     if $filter->{status} eq 'orphaned';
 
 502   my $where = @where_tokens ? 'WHERE ' . join ' AND ', @where_tokens : '';
 
 504   my $query     = qq|SELECT cp.*,
 
 505                        COALESCE(c.id,             v.id)           AS vcid,
 
 506                        COALESCE(c.name,           v.name)         AS vcname,
 
 507                        COALESCE(c.customernumber, v.vendornumber) AS vcnumber,
 
 508                        CASE WHEN c.name IS NULL THEN 'vendor' ELSE 'customer' END AS db
 
 510                      LEFT JOIN customer c ON (cp.cp_cv_id = c.id)
 
 511                      LEFT JOIN vendor v   ON (cp.cp_cv_id = v.id)
 
 515   my $contacts  = selectall_hashref_query($::form, $dbh, $query, @values);
 
 517   $::lxdebug->leave_sub;
 
 519   return @{ $contacts };