1# -- 2# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/ 3# -- 4# This software comes with ABSOLUTELY NO WARRANTY. For details, see 5# the enclosed file COPYING for license information (GPL). If you 6# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. 7# -- 8 9package Kernel::System::CustomerCompany::DB; 10 11use strict; 12use warnings; 13 14use Kernel::System::VariableCheck qw(:all); 15 16our @ObjectDependencies = ( 17 'Kernel::System::Cache', 18 'Kernel::System::DB', 19 'Kernel::System::DynamicField', 20 'Kernel::System::DynamicField::Backend', 21 'Kernel::System::Log', 22 'Kernel::System::Valid', 23); 24 25sub new { 26 my ( $Type, %Param ) = @_; 27 28 # allocate new hash for object 29 my $Self = {}; 30 bless( $Self, $Type ); 31 32 # get customer company map 33 $Self->{CustomerCompanyMap} = $Param{CustomerCompanyMap} || die "Got no CustomerCompanyMap!"; 34 35 # config options 36 $Self->{CustomerCompanyTable} = $Self->{CustomerCompanyMap}->{Params}->{Table} 37 || die "Need CustomerCompany->Params->Table in Kernel/Config.pm!"; 38 $Self->{CustomerCompanyKey} = $Self->{CustomerCompanyMap}->{CustomerCompanyKey} 39 || die "Need CustomerCompany->CustomerCompanyKey in Kernel/Config.pm!"; 40 $Self->{CustomerCompanyValid} = $Self->{CustomerCompanyMap}->{'CustomerCompanyValid'}; 41 $Self->{SearchListLimit} = $Self->{CustomerCompanyMap}->{'CustomerCompanySearchListLimit'} || 50000; 42 $Self->{SearchPrefix} = $Self->{CustomerCompanyMap}->{'CustomerCompanySearchPrefix'}; 43 44 if ( !defined( $Self->{SearchPrefix} ) ) { 45 $Self->{SearchPrefix} = ''; 46 } 47 $Self->{SearchSuffix} = $Self->{CustomerCompanyMap}->{'CustomerCompanySearchSuffix'}; 48 if ( !defined( $Self->{SearchSuffix} ) ) { 49 $Self->{SearchSuffix} = '*'; 50 } 51 52 # create cache object, but only if CacheTTL is set in customer config 53 if ( $Self->{CustomerCompanyMap}->{CacheTTL} ) { 54 $Self->{CacheObject} = $Kernel::OM->Get('Kernel::System::Cache'); 55 $Self->{CacheType} = 'CustomerCompany' . $Param{Count}; 56 $Self->{CacheTTL} = $Self->{CustomerCompanyMap}->{CacheTTL} || 0; 57 } 58 59 # get database object 60 $Self->{DBObject} = $Kernel::OM->Get('Kernel::System::DB'); 61 62 # create new db connect if DSN is given 63 if ( $Self->{CustomerCompanyMap}->{Params}->{DSN} ) { 64 $Self->{DBObject} = Kernel::System::DB->new( 65 DatabaseDSN => $Self->{CustomerCompanyMap}->{Params}->{DSN}, 66 DatabaseUser => $Self->{CustomerCompanyMap}->{Params}->{User}, 67 DatabasePw => $Self->{CustomerCompanyMap}->{Params}->{Password}, 68 Type => $Self->{CustomerCompanyMap}->{Params}->{Type} || '', 69 ) || die('Can\'t connect to database!'); 70 71 # remember that we have the DBObject not from parent call 72 $Self->{NotParentDBObject} = 1; 73 } 74 75 # this setting specifies if the table has the create_time, 76 # create_by, change_time and change_by fields of OTRS 77 $Self->{ForeignDB} = $Self->{CustomerCompanyMap}->{Params}->{ForeignDB} ? 1 : 0; 78 79 # defines if the database search will be performend case sensitive (1) or not (0) 80 $Self->{CaseSensitive} = $Self->{CustomerCompanyMap}->{Params}->{SearchCaseSensitive} 81 // $Self->{CustomerCompanyMap}->{Params}->{CaseSensitive} || 0; 82 83 # fetch names of configured dynamic fields 84 my @DynamicFieldMapEntries = grep { $_->[5] eq 'dynamic_field' } @{ $Self->{CustomerCompanyMap}->{Map} }; 85 $Self->{ConfiguredDynamicFieldNames} = { map { $_->[2] => 1 } @DynamicFieldMapEntries }; 86 87 return $Self; 88} 89 90sub CustomerCompanyList { 91 my ( $Self, %Param ) = @_; 92 93 # check needed stuff 94 my $Valid = 1; 95 if ( !$Param{Valid} && defined( $Param{Valid} ) ) { 96 $Valid = 0; 97 } 98 99 my $Limit = $Param{Limit} // $Self->{SearchListLimit}; 100 101 my $CacheType; 102 my $CacheKey; 103 104 # check cache 105 if ( $Self->{CacheObject} ) { 106 107 $CacheType = $Self->{CacheType} . '_CustomerCompanyList'; 108 $CacheKey = "CustomerCompanyList::${Valid}::${Limit}::" . ( $Param{Search} || '' ); 109 110 my $Data = $Self->{CacheObject}->Get( 111 Type => $CacheType, 112 Key => $CacheKey, 113 ); 114 return %{$Data} if ref $Data eq 'HASH'; 115 } 116 117 my $CustomerCompanyListFields = $Self->{CustomerCompanyMap}->{CustomerCompanyListFields}; 118 if ( !IsArrayRefWithData($CustomerCompanyListFields) ) { 119 $CustomerCompanyListFields = [ 'customer_id', 'name', ]; 120 } 121 122 # remove dynamic field names that are configured in CustomerCompanyListFields 123 # as they cannot be handled here 124 my @CustomerCompanyListFieldsWithoutDynamicFields 125 = grep { !exists $Self->{ConfiguredDynamicFieldNames}->{$_} } @{$CustomerCompanyListFields}; 126 127 # what is the result 128 my $What = join( 129 ', ', 130 @CustomerCompanyListFieldsWithoutDynamicFields 131 ); 132 133 # add valid option if required 134 my $SQL; 135 my @Bind; 136 my @Conditions; 137 138 if ( $Valid && $Self->{CustomerCompanyValid} ) { 139 140 # get valid object 141 my $ValidObject = $Kernel::OM->Get('Kernel::System::Valid'); 142 143 push @Conditions, "$Self->{CustomerCompanyValid} IN ( ${\(join ', ', $ValidObject->ValidIDsGet())} )"; 144 } 145 146 # where 147 if ( $Param{Search} ) { 148 149 # remove dynamic field names that are configured in CustomerCompanySearchFields 150 # as they cannot be retrieved here 151 my @CustomerCompanySearchFields = grep { !exists $Self->{ConfiguredDynamicFieldNames}->{$_} } 152 @{ $Self->{CustomerCompanyMap}->{CustomerCompanySearchFields} }; 153 154 my %QueryCondition = $Self->{DBObject}->QueryCondition( 155 Key => \@CustomerCompanySearchFields, 156 Value => $Param{Search}, 157 SearchPrefix => $Self->{SearchPrefix}, 158 SearchSuffix => $Self->{SearchSuffix}, 159 CaseSensitive => $Self->{CaseSensitive}, 160 BindMode => 1, 161 ); 162 163 if ( $QueryCondition{SQL} ) { 164 push @Conditions, " $QueryCondition{SQL}"; 165 push @Bind, @{ $QueryCondition{Values} }; 166 } 167 } 168 169 # dynamic field handling 170 my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend'); 171 172 my $DynamicFieldConfigs = $Kernel::OM->Get('Kernel::System::DynamicField')->DynamicFieldListGet( 173 ObjectType => 'CustomerCompany', 174 Valid => 1, 175 ); 176 my %DynamicFieldConfigsByName = map { $_->{Name} => $_ } @{$DynamicFieldConfigs}; 177 178 my @CustomerCompanyListFieldsDynamicFields 179 = grep { exists $Self->{ConfiguredDynamicFieldNames}->{$_} } @{$CustomerCompanyListFields}; 180 181 # sql 182 my $CompleteSQL = "SELECT $Self->{CustomerCompanyKey}, $What FROM $Self->{CustomerCompanyTable}"; 183 184 if (@Conditions) { 185 $SQL = join( ' AND ', @Conditions ); 186 $CompleteSQL .= " WHERE $SQL"; 187 } 188 189 # get data from customer company table 190 $Self->{DBObject}->Prepare( 191 SQL => $CompleteSQL, 192 Bind => \@Bind, 193 Limit => $Limit, 194 ); 195 196 my @CustomerCompanyData; 197 while ( my @Row = $Self->{DBObject}->FetchrowArray() ) { 198 push @CustomerCompanyData, [@Row]; 199 } 200 201 my %List; 202 203 CUSTOMERCOMPANYDATA: 204 for my $CustomerCompanyData (@CustomerCompanyData) { 205 my $CustomerCompanyID = shift @{$CustomerCompanyData}; 206 next CUSTOMERCOMPANYDATA if $List{$CustomerCompanyID}; 207 208 my %CompanyStringParts; 209 210 my $FieldCounter = 0; 211 for my $Field ( @{$CustomerCompanyData} ) { 212 $CompanyStringParts{ $CustomerCompanyListFieldsWithoutDynamicFields[$FieldCounter] } = $Field; 213 $FieldCounter++; 214 } 215 216 # fetch dynamic field values, if configured 217 if (@CustomerCompanyListFieldsDynamicFields) { 218 DYNAMICFIELDNAME: 219 for my $DynamicFieldName (@CustomerCompanyListFieldsDynamicFields) { 220 next DYNAMICFIELDNAME if !exists $DynamicFieldConfigsByName{$DynamicFieldName}; 221 222 my $Value = $DynamicFieldBackendObject->ValueGet( 223 DynamicFieldConfig => $DynamicFieldConfigsByName{$DynamicFieldName}, 224 ObjectName => $CustomerCompanyID, 225 ); 226 227 next DYNAMICFIELDNAME if !defined $Value; 228 229 if ( !IsArrayRefWithData($Value) ) { 230 $Value = [$Value]; 231 } 232 233 my @Values; 234 235 VALUE: 236 for my $CurrentValue ( @{$Value} ) { 237 next VALUE if !defined $CurrentValue || !length $CurrentValue; 238 239 my $ReadableValue = $DynamicFieldBackendObject->ReadableValueRender( 240 DynamicFieldConfig => $DynamicFieldConfigsByName{$DynamicFieldName}, 241 Value => $CurrentValue, 242 ); 243 244 next VALUE if !IsHashRefWithData($ReadableValue) || !defined $ReadableValue->{Value}; 245 246 my $IsACLReducible = $DynamicFieldBackendObject->HasBehavior( 247 DynamicFieldConfig => $DynamicFieldConfigsByName{$DynamicFieldName}, 248 Behavior => 'IsACLReducible', 249 ); 250 if ($IsACLReducible) { 251 my $PossibleValues = $DynamicFieldBackendObject->PossibleValuesGet( 252 DynamicFieldConfig => $DynamicFieldConfigsByName{$DynamicFieldName}, 253 ); 254 255 if ( 256 IsHashRefWithData($PossibleValues) 257 && defined $PossibleValues->{ $ReadableValue->{Value} } 258 ) 259 { 260 $ReadableValue->{Value} = $PossibleValues->{ $ReadableValue->{Value} }; 261 } 262 } 263 264 push @Values, $ReadableValue->{Value}; 265 } 266 267 $CompanyStringParts{$DynamicFieldName} = join ' ', @Values; 268 } 269 } 270 271 # assemble company string 272 my @CompanyStringParts; 273 CUSTOMERCOMPANYLISTFIELD: 274 for my $CustomerCompanyListField ( @{$CustomerCompanyListFields} ) { 275 next CUSTOMERCOMPANYLISTFIELD 276 if !exists $CompanyStringParts{$CustomerCompanyListField} 277 || !defined $CompanyStringParts{$CustomerCompanyListField} 278 || !length $CompanyStringParts{$CustomerCompanyListField}; 279 push @CompanyStringParts, $CompanyStringParts{$CustomerCompanyListField}; 280 } 281 282 $List{$CustomerCompanyID} = join ' ', @CompanyStringParts; 283 } 284 285 # cache request 286 if ( $Self->{CacheObject} ) { 287 $Self->{CacheObject}->Set( 288 Type => $CacheType, 289 Key => $CacheKey, 290 Value => \%List, 291 TTL => $Self->{CacheTTL}, 292 ); 293 } 294 295 return %List; 296} 297 298sub CustomerCompanySearchDetail { 299 my ( $Self, %Param ) = @_; 300 301 if ( ref $Param{SearchFields} ne 'ARRAY' ) { 302 $Kernel::OM->Get('Kernel::System::Log')->Log( 303 Priority => 'error', 304 Message => "SearchFields must be an array reference!", 305 ); 306 return; 307 } 308 309 my $Valid = defined $Param{Valid} ? $Param{Valid} : 1; 310 311 $Param{Limit} //= ''; 312 313 # Split the search fields in scalar and array fields. 314 my @ScalarSearchFields = grep { 'Input' eq $_->{Type} } @{ $Param{SearchFields} }; 315 my @ArraySearchFields = grep { 'Selection' eq $_->{Type} } @{ $Param{SearchFields} }; 316 317 # Verify that all passed array parameters contain an arrayref. 318 ARGUMENT: 319 for my $Argument (@ArraySearchFields) { 320 if ( !defined $Param{ $Argument->{Name} } ) { 321 $Param{ $Argument->{Name} } ||= []; 322 323 next ARGUMENT; 324 } 325 326 if ( ref $Param{ $Argument->{Name} } ne 'ARRAY' ) { 327 $Kernel::OM->Get('Kernel::System::Log')->Log( 328 Priority => 'error', 329 Message => "$Argument->{Name} must be an array reference!", 330 ); 331 return; 332 } 333 } 334 335 # Set the default behaviour for the return type. 336 my $Result = $Param{Result} || 'ARRAY'; 337 338 # Special handling if the result type is 'COUNT'. 339 if ( $Result eq 'COUNT' ) { 340 341 # Ignore the parameter 'Limit' when result type is 'COUNT'. 342 $Param{Limit} = ''; 343 344 # Delete the OrderBy parameter when the result type is 'COUNT'. 345 $Param{OrderBy} = []; 346 } 347 348 # Define order table from the search fields. 349 my %OrderByTable = map { $_->{Name} => $_->{DatabaseField} } @{ $Param{SearchFields} }; 350 351 for my $Field (@ArraySearchFields) { 352 353 my $SelectionsData = $Field->{SelectionsData}; 354 355 for my $SelectedValue ( @{ $Param{ $Field->{Name} } } ) { 356 357 # Check if the selected value for the current field is valid. 358 if ( !$SelectionsData->{$SelectedValue} ) { 359 $Kernel::OM->Get('Kernel::System::Log')->Log( 360 Priority => 'error', 361 Message => "The selected value $Field->{Name} is not valid!", 362 ); 363 return; 364 } 365 } 366 } 367 368 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 369 370 # Assemble the conditions used in the WHERE clause. 371 my @SQLWhere; 372 373 for my $Field (@ScalarSearchFields) { 374 375 # Search for scalar fields (wildcards are allowed). 376 if ( $Param{ $Field->{Name} } ) { 377 378 # Get like escape string needed for some databases (e.g. oracle). 379 my $LikeEscapeString = $DBObject->GetDatabaseFunction('LikeEscapeString'); 380 381 $Param{ $Field->{Name} } = $DBObject->Quote( $Param{ $Field->{Name} }, 'Like' ); 382 383 $Param{ $Field->{Name} } =~ s{ \*+ }{%}xmsg; 384 385 # If the field contains more than only '%'. 386 if ( $Param{ $Field->{Name} } !~ m{ \A %* \z }xms ) { 387 push @SQLWhere, 388 "LOWER($Field->{DatabaseField}) LIKE LOWER('$Param{ $Field->{Name} }') $LikeEscapeString"; 389 } 390 } 391 } 392 393 my $DynamicFieldObject = $Kernel::OM->Get('Kernel::System::DynamicField'); 394 my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend'); 395 396 # Check all configured change dynamic fields, build lookup hash by name. 397 my %CustomerCompanyDynamicFieldName2Config; 398 my $CustomerCompanyDynamicFields = $DynamicFieldObject->DynamicFieldListGet( 399 ObjectType => 'CustomerCompany', 400 ); 401 for my $DynamicField ( @{$CustomerCompanyDynamicFields} ) { 402 $CustomerCompanyDynamicFieldName2Config{ $DynamicField->{Name} } = $DynamicField; 403 } 404 405 my $SQLDynamicFieldFrom = ''; 406 my $SQLDynamicFieldWhere = ''; 407 my $DynamicFieldJoinCounter = 1; 408 409 DYNAMICFIELD: 410 for my $DynamicField ( @{$CustomerCompanyDynamicFields} ) { 411 412 my $SearchParam = $Param{ "DynamicField_" . $DynamicField->{Name} }; 413 414 next DYNAMICFIELD if ( !$SearchParam ); 415 next DYNAMICFIELD if ( ref $SearchParam ne 'HASH' ); 416 417 my $NeedJoin; 418 419 for my $Operator ( sort keys %{$SearchParam} ) { 420 421 my @SearchParams = ( ref $SearchParam->{$Operator} eq 'ARRAY' ) 422 ? @{ $SearchParam->{$Operator} } 423 : ( $SearchParam->{$Operator} ); 424 425 my $SQLDynamicFieldWhereSub = ''; 426 if ($SQLDynamicFieldWhere) { 427 $SQLDynamicFieldWhereSub = ' AND ('; 428 } 429 else { 430 $SQLDynamicFieldWhereSub = ' ('; 431 } 432 433 my $Counter = 0; 434 TEXT: 435 for my $Text (@SearchParams) { 436 next TEXT if ( !defined $Text || $Text eq '' ); 437 438 $Text =~ s/\*/%/gi; 439 440 # Check search attribute, we do not need to search for '*'. 441 next TEXT if $Text =~ /^\%{1,3}$/; 442 443 my $ValidateSuccess = $DynamicFieldBackendObject->ValueValidate( 444 DynamicFieldConfig => $DynamicField, 445 Value => $Text, 446 UserID => $Param{UserID} || 1, 447 ); 448 if ( !$ValidateSuccess ) { 449 $Kernel::OM->Get('Kernel::System::Log')->Log( 450 Priority => 'error', 451 Message => "Search not executed due to invalid value '" 452 . $Text 453 . "' on field '" 454 . $DynamicField->{Name} . "'!", 455 ); 456 return; 457 } 458 459 if ($Counter) { 460 $SQLDynamicFieldWhereSub .= ' OR '; 461 } 462 $SQLDynamicFieldWhereSub .= $DynamicFieldBackendObject->SearchSQLGet( 463 DynamicFieldConfig => $DynamicField, 464 TableAlias => "dfv$DynamicFieldJoinCounter", 465 Operator => $Operator, 466 SearchTerm => $Text, 467 ); 468 469 $Counter++; 470 } 471 $SQLDynamicFieldWhereSub .= ') '; 472 473 if ($Counter) { 474 $SQLDynamicFieldWhere .= $SQLDynamicFieldWhereSub; 475 $NeedJoin = 1; 476 } 477 } 478 479 if ($NeedJoin) { 480 $SQLDynamicFieldFrom .= " 481 INNER JOIN dynamic_field_value dfv$DynamicFieldJoinCounter 482 ON (df_obj_id_name.object_id = dfv$DynamicFieldJoinCounter.object_id 483 AND dfv$DynamicFieldJoinCounter.field_id = " 484 . $DBObject->Quote( $DynamicField->{ID}, 'Integer' ) . ") 485 "; 486 487 $DynamicFieldJoinCounter++; 488 } 489 } 490 491 # Execute a dynamic field search, if a dynamic field where statement exists. 492 if ( $SQLDynamicFieldFrom && $SQLDynamicFieldWhere ) { 493 494 my @DynamicFieldCustomerIDs; 495 496 # Sql uery for the dynamic fields. 497 my $SQLDynamicField 498 = "SELECT DISTINCT(df_obj_id_name.object_name) FROM dynamic_field_obj_id_name df_obj_id_name " 499 . $SQLDynamicFieldFrom 500 . " WHERE " 501 . $SQLDynamicFieldWhere; 502 503 my $UsedCache; 504 505 if ( $Self->{CacheObject} ) { 506 507 my $DynamicFieldSearchCacheData = $Self->{CacheObject}->Get( 508 Type => $Self->{CacheType} . '_CustomerSearchDetailDynamicFields', 509 Key => $SQLDynamicField, 510 ); 511 512 if ( defined $DynamicFieldSearchCacheData ) { 513 if ( ref $DynamicFieldSearchCacheData eq 'ARRAY' ) { 514 @DynamicFieldCustomerIDs = @{$DynamicFieldSearchCacheData}; 515 516 # Set the used cache flag. 517 $UsedCache = 1; 518 } 519 else { 520 $Kernel::OM->Get('Kernel::System::Log')->Log( 521 Priority => 'error', 522 Message => 'Invalid ref ' . ref($DynamicFieldSearchCacheData) . '!' 523 ); 524 return; 525 } 526 } 527 } 528 529 # Get the data only from database, if no cache entry exists. 530 if ( !$UsedCache ) { 531 532 return if !$DBObject->Prepare( 533 SQL => $SQLDynamicField, 534 ); 535 536 while ( my @Row = $DBObject->FetchrowArray() ) { 537 push @DynamicFieldCustomerIDs, $Row[0]; 538 } 539 540 if ( $Self->{CacheObject} ) { 541 $Self->{CacheObject}->Set( 542 Type => $Self->{CacheType} . '_CustomerSearchDetailDynamicFields', 543 Key => $SQLDynamicField, 544 Value => \@DynamicFieldCustomerIDs, 545 TTL => $Self->{CustomerCompanyMap}->{CacheTTL}, 546 ); 547 } 548 } 549 550 # Add the user logins from the dynamic fields, if a search result exists from the dynamic field search 551 # or skip the search and return a emptry array ref (or zero for the result 'COUNT', if no user logins exists 552 # from the dynamic field search. 553 if (@DynamicFieldCustomerIDs) { 554 555 my $SQLQueryInCondition = $Kernel::OM->Get('Kernel::System::DB')->QueryInCondition( 556 Key => $Self->{CustomerCompanyKey}, 557 Values => \@DynamicFieldCustomerIDs, 558 BindMode => 0, 559 ); 560 561 push @SQLWhere, $SQLQueryInCondition; 562 } 563 else { 564 return $Result eq 'COUNT' ? 0 : []; 565 } 566 } 567 568 FIELD: 569 for my $Field (@ArraySearchFields) { 570 571 next FIELD if !@{ $Param{ $Field->{Name} } }; 572 573 my $SQLQueryInCondition = $Kernel::OM->Get('Kernel::System::DB')->QueryInCondition( 574 Key => $Field->{DatabaseField}, 575 Values => $Param{ $Field->{Name} }, 576 BindMode => 0, 577 ); 578 579 push @SQLWhere, $SQLQueryInCondition; 580 } 581 582 # Add the valid option if needed. 583 if ( $Self->{CustomerCompanyMap}->{CustomerValid} && $Valid ) { 584 585 my $ValidObject = $Kernel::OM->Get('Kernel::System::Valid'); 586 587 push @SQLWhere, 588 "$Self->{CustomerCompanyMap}->{CustomerValid} IN (" . join( ', ', $ValidObject->ValidIDsGet() ) . ") "; 589 } 590 591 # Check if OrderBy contains only unique valid values. 592 my %OrderBySeen; 593 for my $OrderBy ( @{ $Param{OrderBy} } ) { 594 595 if ( !$OrderBy || $OrderBySeen{$OrderBy} ) { 596 597 $Kernel::OM->Get('Kernel::System::Log')->Log( 598 Priority => 'error', 599 Message => "OrderBy contains invalid value '$OrderBy' " 600 . 'or the value is used more than once!', 601 ); 602 return; 603 } 604 605 # Remember the value to check if it appears more than once. 606 $OrderBySeen{$OrderBy} = 1; 607 } 608 609 # Check if OrderByDirection array contains only 'Up' or 'Down'. 610 DIRECTION: 611 for my $Direction ( @{ $Param{OrderByDirection} } ) { 612 613 # Only 'Up' or 'Down' allowed. 614 next DIRECTION if $Direction eq 'Up'; 615 next DIRECTION if $Direction eq 'Down'; 616 617 # found an error 618 $Kernel::OM->Get('Kernel::System::Log')->Log( 619 Priority => 'error', 620 Message => "OrderByDirection can only contain 'Up' or 'Down'!", 621 ); 622 return; 623 } 624 625 # Build the sql statement for the search. 626 my $SQL = "SELECT DISTINCT($Self->{CustomerCompanyKey})"; 627 628 # Modify SQL when the result type is 'COUNT'. 629 if ( $Result eq 'COUNT' ) { 630 $SQL = "SELECT COUNT(DISTINCT($Self->{CustomerCompanyKey}))"; 631 } 632 633 my @SQLOrderBy; 634 635 # The Order by clause is not needed for the result type 'COUNT'. 636 if ( $Result ne 'COUNT' ) { 637 638 my $Count = 0; 639 640 ORDERBY: 641 for my $OrderBy ( @{ $Param{OrderBy} } ) { 642 643 # Set the default order direction. 644 my $Direction = 'DESC'; 645 646 # Add the given order direction. 647 if ( $Param{OrderByDirection}->[$Count] ) { 648 if ( $Param{OrderByDirection}->[$Count] eq 'Up' ) { 649 $Direction = 'ASC'; 650 } 651 elsif ( $Param{OrderByDirection}->[$Count] eq 'Down' ) { 652 $Direction = 'DESC'; 653 } 654 } 655 656 $Count++; 657 658 next ORDERBY if !$OrderByTable{$OrderBy}; 659 660 push @SQLOrderBy, "$OrderByTable{$OrderBy} $Direction"; 661 662 next ORDERBY if $OrderBy eq 'CustomerID'; 663 664 $SQL .= ", $OrderByTable{$OrderBy}"; 665 } 666 667 # If there is a possibility that the ordering is not determined 668 # we add an descending ordering by id. 669 if ( !grep { $_ eq 'CustomerID' } ( @{ $Param{OrderBy} } ) ) { 670 push @SQLOrderBy, "$Self->{CustomerCompanyKey} DESC"; 671 } 672 } 673 674 # Add form to the SQL after the order by creation. 675 $SQL .= " FROM $Self->{CustomerCompanyTable} "; 676 677 if (@SQLWhere) { 678 my $SQLWhereString = join ' AND ', map {"( $_ )"} @SQLWhere; 679 $SQL .= "WHERE $SQLWhereString "; 680 } 681 682 if (@SQLOrderBy) { 683 my $OrderByString = join ', ', @SQLOrderBy; 684 $SQL .= "ORDER BY $OrderByString"; 685 } 686 687 # Check if a cache exists before we ask the database. 688 if ( $Self->{CacheObject} ) { 689 690 my $CacheData = $Kernel::OM->Get('Kernel::System::Cache')->Get( 691 Type => $Self->{CacheType} . '_CustomerCompanySearchDetail', 692 Key => $SQL . $Param{Limit}, 693 ); 694 695 if ( defined $CacheData ) { 696 if ( ref $CacheData eq 'ARRAY' ) { 697 return $CacheData; 698 } 699 elsif ( ref $CacheData eq '' ) { 700 return $CacheData; 701 } 702 $Kernel::OM->Get('Kernel::System::Log')->Log( 703 Priority => 'error', 704 Message => 'Invalid ref ' . ref($CacheData) . '!' 705 ); 706 return; 707 } 708 } 709 710 return if !$DBObject->Prepare( 711 SQL => $SQL, 712 Limit => $Param{Limit}, 713 ); 714 715 my @IDs; 716 while ( my @Row = $DBObject->FetchrowArray() ) { 717 push @IDs, $Row[0]; 718 } 719 720 # Handle the diffrent result types. 721 if ( $Result eq 'COUNT' ) { 722 723 if ( $Self->{CacheObject} ) { 724 $Kernel::OM->Get('Kernel::System::Cache')->Set( 725 Type => $Self->{CacheType} . '_CustomerCompanySearchDetail', 726 Key => $SQL . $Param{Limit}, 727 Value => $IDs[0], 728 TTL => $Self->{CacheTTL}, 729 ); 730 } 731 732 return $IDs[0]; 733 } 734 735 else { 736 737 if ( $Self->{CacheObject} ) { 738 $Kernel::OM->Get('Kernel::System::Cache')->Set( 739 Type => $Self->{CacheType} . '_CustomerCompanySearchDetail', 740 Key => $SQL . $Param{Limit}, 741 Value => \@IDs, 742 TTL => $Self->{CacheTTL}, 743 ); 744 } 745 746 return \@IDs; 747 } 748} 749 750sub CustomerCompanyGet { 751 my ( $Self, %Param ) = @_; 752 753 # check needed stuff 754 if ( !$Param{CustomerID} ) { 755 $Kernel::OM->Get('Kernel::System::Log')->Log( 756 Priority => 'error', 757 Message => 'Need CustomerID!' 758 ); 759 return; 760 } 761 762 # check cache 763 if ( $Self->{CacheObject} ) { 764 my $Data = $Self->{CacheObject}->Get( 765 Type => $Self->{CacheType}, 766 Key => "CustomerCompanyGet::$Param{CustomerID}", 767 ); 768 return %{$Data} if ref $Data eq 'HASH'; 769 } 770 771 # build select 772 my @Fields; 773 my %FieldsMap; 774 775 ENTRY: 776 for my $Entry ( @{ $Self->{CustomerCompanyMap}->{Map} } ) { 777 next ENTRY if $Entry->[5] eq 'dynamic_field'; 778 push @Fields, $Entry->[2]; 779 $FieldsMap{ $Entry->[2] } = $Entry->[0]; 780 } 781 my $SQL = 'SELECT ' . join( ', ', @Fields ); 782 783 if ( !$Self->{ForeignDB} ) { 784 $SQL .= ", create_time, create_by, change_time, change_by"; 785 } 786 787 # this seems to be legacy, if Name is passed it should take precedence over CustomerID 788 my $CustomerID = $Param{Name} || $Param{CustomerID}; 789 790 $SQL .= " FROM $Self->{CustomerCompanyTable} WHERE "; 791 792 if ( $Self->{CaseSensitive} ) { 793 $SQL .= "$Self->{CustomerCompanyKey} = ?"; 794 } 795 else { 796 $SQL .= "LOWER($Self->{CustomerCompanyKey}) = LOWER( ? )"; 797 } 798 799 # get initial data 800 return if !$Self->{DBObject}->Prepare( 801 SQL => $SQL, 802 Bind => [ \$CustomerID ] 803 ); 804 805 # fetch the result 806 my %Data; 807 ROW: 808 while ( my @Row = $Self->{DBObject}->FetchrowArray() ) { 809 810 my $MapCounter = 0; 811 812 for my $Field (@Fields) { 813 $Data{ $FieldsMap{$Field} } = $Row[$MapCounter]; 814 $MapCounter++; 815 } 816 817 next ROW if $Self->{ForeignDB}; 818 819 for my $Key (qw(CreateTime CreateBy ChangeTime ChangeBy)) { 820 $Data{$Key} = $Row[$MapCounter]; 821 $MapCounter++; 822 } 823 } 824 825 # cache request 826 if ( $Self->{CacheObject} ) { 827 $Self->{CacheObject}->Set( 828 Type => $Self->{CacheType}, 829 Key => "CustomerCompanyGet::$Param{CustomerID}", 830 Value => \%Data, 831 TTL => $Self->{CacheTTL}, 832 ); 833 } 834 835 # return data 836 return (%Data); 837} 838 839sub CustomerCompanyAdd { 840 my ( $Self, %Param ) = @_; 841 842 # check ro/rw 843 if ( $Self->{ReadOnly} ) { 844 $Kernel::OM->Get('Kernel::System::Log')->Log( 845 Priority => 'error', 846 Message => 'CustomerCompany backend is read only!' 847 ); 848 return; 849 } 850 851 my @Fields; 852 my @Placeholders; 853 my @Values; 854 855 ENTRY: 856 for my $Entry ( @{ $Self->{CustomerCompanyMap}->{Map} } ) { 857 858 # ignore dynamic fields here 859 next ENTRY if $Entry->[5] eq 'dynamic_field'; 860 861 push @Fields, $Entry->[2]; 862 push @Placeholders, '?'; 863 push @Values, \$Param{ $Entry->[0] }; 864 } 865 if ( !$Self->{ForeignDB} ) { 866 push @Fields, qw(create_time create_by change_time change_by); 867 push @Placeholders, qw(current_timestamp ? current_timestamp ?); 868 push @Values, ( \$Param{UserID}, \$Param{UserID} ); 869 } 870 871 # build insert 872 my $SQL = "INSERT INTO $Self->{CustomerCompanyTable} ("; 873 $SQL .= join( ', ', @Fields ) . " ) VALUES ( " . join( ', ', @Placeholders ) . " )"; 874 875 return if !$Self->{DBObject}->Do( 876 SQL => $SQL, 877 Bind => \@Values, 878 ); 879 880 # log notice 881 $Kernel::OM->Get('Kernel::System::Log')->Log( 882 Priority => 'info', 883 Message => 884 "CustomerCompany: '$Param{CustomerCompanyName}/$Param{CustomerID}' created successfully ($Param{UserID})!", 885 ); 886 887 $Self->_CustomerCompanyCacheClear( CustomerID => $Param{CustomerID} ); 888 889 return $Param{CustomerID}; 890} 891 892sub CustomerCompanyUpdate { 893 my ( $Self, %Param ) = @_; 894 895 # check ro/rw 896 if ( $Self->{ReadOnly} ) { 897 $Kernel::OM->Get('Kernel::System::Log')->Log( 898 Priority => 'error', 899 Message => 'Customer backend is read only!' 900 ); 901 return; 902 } 903 904 # check needed stuff 905 for my $Entry ( @{ $Self->{CustomerCompanyMap}->{Map} } ) { 906 if ( 907 !$Param{ $Entry->[0] } 908 && $Entry->[5] ne 'dynamic_field' # ignore dynamic fields here 909 && $Entry->[4] 910 && $Entry->[0] ne 'UserPassword' 911 ) 912 { 913 $Kernel::OM->Get('Kernel::System::Log')->Log( 914 Priority => 'error', 915 Message => "Need $Entry->[0]!" 916 ); 917 return; 918 } 919 } 920 921 my @Fields; 922 my @Values; 923 924 FIELD: 925 for my $Entry ( @{ $Self->{CustomerCompanyMap}->{Map} } ) { 926 next FIELD if $Entry->[0] =~ /^UserPassword$/i; 927 next FIELD if $Entry->[5] eq 'dynamic_field'; # skip dynamic fields 928 push @Fields, $Entry->[2] . ' = ?'; 929 push @Values, \$Param{ $Entry->[0] }; 930 } 931 if ( !$Self->{ForeignDB} ) { 932 push @Fields, ( 'change_time = current_timestamp', 'change_by = ?' ); 933 push @Values, \$Param{UserID}; 934 } 935 936 # create SQL statement 937 my $SQL = "UPDATE $Self->{CustomerCompanyTable} SET "; 938 $SQL .= join( ', ', @Fields ); 939 940 if ( $Self->{CaseSensitive} ) { 941 $SQL .= " WHERE $Self->{CustomerCompanyKey} = ?"; 942 } 943 else { 944 $SQL .= " WHERE LOWER($Self->{CustomerCompanyKey}) = LOWER( ? )"; 945 } 946 push @Values, \$Param{CustomerCompanyID}; 947 948 return if !$Self->{DBObject}->Do( 949 SQL => $SQL, 950 Bind => \@Values, 951 ); 952 953 # log notice 954 $Kernel::OM->Get('Kernel::System::Log')->Log( 955 Priority => 'info', 956 Message => 957 "CustomerCompany: '$Param{CustomerCompanyName}/$Param{CustomerID}' updated successfully ($Param{UserID})!", 958 ); 959 960 $Self->_CustomerCompanyCacheClear( CustomerID => $Param{CustomerID} ); 961 if ( $Param{CustomerCompanyID} ne $Param{CustomerID} ) { 962 $Self->_CustomerCompanyCacheClear( CustomerID => $Param{CustomerCompanyID} ); 963 } 964 965 return 1; 966} 967 968sub _CustomerCompanyCacheClear { 969 my ( $Self, %Param ) = @_; 970 971 return if !$Self->{CacheObject}; 972 973 if ( !$Param{CustomerID} ) { 974 $Kernel::OM->Get('Kernel::System::Log')->Log( 975 Priority => 'error', 976 Message => 'Need CustomerID!' 977 ); 978 return; 979 } 980 981 $Self->{CacheObject}->Delete( 982 Type => $Self->{CacheType}, 983 Key => "CustomerCompanyGet::$Param{CustomerID}", 984 ); 985 986 # delete all search cache entries 987 $Self->{CacheObject}->CleanUp( 988 Type => $Self->{CacheType} . '_CustomerCompanyList', 989 ); 990 991 for my $Function (qw(CustomerCompanyList)) { 992 for my $Valid ( 0 .. 1 ) { 993 $Self->{CacheObject}->Delete( 994 Type => $Self->{CacheType}, 995 Key => "${Function}::${Valid}", 996 ); 997 } 998 } 999 1000 return 1; 1001} 1002 1003sub DESTROY { 1004 my $Self = shift; 1005 1006 # disconnect if it's not a parent DBObject 1007 if ( $Self->{NotParentDBObject} ) { 1008 if ( $Self->{DBObject} ) { 1009 $Self->{DBObject}->Disconnect(); 1010 } 1011 } 1012 1013 return 1; 1014} 1015 10161; 1017