diff --git a/agc_2-X/trunk/UPGRADE b/agc_2-X/trunk/UPGRADE index 42cf16cf..5baa6c85 100644 --- a/agc_2-X/trunk/UPGRADE +++ b/agc_2-X/trunk/UPGRADE @@ -899,6 +899,9 @@ OTHER CHANGES: 256. Added In-Group "Transfer Talk Minimum" features, allowing for restruction on agent screen transfers before talk time threshold. +257. Added Web Lead Loader feature to auto-detect custom column layouts in lead + files, as well as new load loading process rejection summaries + diff --git a/agc_2-X/trunk/extras/MySQL_AST_CREATE_tables.sql b/agc_2-X/trunk/extras/MySQL_AST_CREATE_tables.sql index 596353a0..1810432d 100644 --- a/agc_2-X/trunk/extras/MySQL_AST_CREATE_tables.sql +++ b/agc_2-X/trunk/extras/MySQL_AST_CREATE_tables.sql @@ -5890,6 +5890,7 @@ INSERT INTO vicidial_settings_containers(container_id,container_notes,container_ INSERT INTO vicidial_settings_containers(container_id,container_notes,container_type,user_group,container_entry) VALUES ('VERM_STATUS_NAMES_OVERRIDE','Override dialer status names in enhanced reporting','OTHER','---ALL---','; For each status name you want overridden, type the status followed by\r\n; a pipe, then the new status name\r\n; Ex:\r\n; NZ|Taumatawhakatangihangakoauauotamateaturipukakapikimaungahoronukupoka\r\n201214|Request To Cancel\r\n210200|No Answer-Incomplete Call\r\n210201|Contact Established\r\n210202|Provider Review - HB\r\n210203|Promise to Pay\r\n210204|Setup Payment Plan\r\n210205|Research-Inquiry\r\n210206|Voice Mail Left - HB\r\n210207|Do Not Call\r\n210208|Appeal Verification\r\n210209|Bad Phone\r\n210210|Bad Address\r\n210211|Direct Pay Verification\r\n210213|Provider Approved\r\n210215|Update Notes Only\r\n210216|Voicemail-No Status Change\r\n210217|Sent Letter Request - HB\r\n210218|Auto VoiceMail Left - HB\r\n210219|Auto VoiceMail-No Status Change\r\n210302|Provider Review - LB\r\n210306|Voice Mail Left - LB\r\n210317|Sent Letter Request - LB\r\n210318|Auto VoiceMail Left - LB\r\n211503|Provider - COVID-19\r\n211603|Transferred Call to MLA\r\n'), ('VERM_REPORT_OPTIONS','Container for customizing VERM report output','OTHER','---ALL---','; This is the report queue used if none is chosen by the user\r\n; It\'s preloaded in some forms as well\r\nVERM_default_report_queue => ALL\r\n\r\n; If there are statuses to exclude from reports, list them here\r\n; Separate with commas. Default is AFTHRS\r\nexc_addtl_statuses => AFTHRS\r\n\r\n; Set the below value to 1 (or anything non-blank/non-zero) in order to \r\n; show the agents ID in addition to their full name in the report results\r\nshow_full_agent_info => 1\r\n\r\n; Some reports count \"lost\" calls - which are defined by the below variable\r\n; listing what you define as \"lost\" dispos. Separate with commas.\r\nlost_statuses => LOST,210208,DISPO\r\n\r\n; You can create a detailed IVR survey report for ingroups by defining\r\n; \"ivr_survey_ingroups_detail\" and \"ivr_survey_ingroups_voicemails.\"\r\n; For \"details\", supply an ingroup used as a tracking group on call menus.\r\n; Then, add a pipe and after that list all call menus that use the ingroup\r\n; as the tracking group, separating each with a comma\r\n; To track whether the calls went to voicemail, list every call menu/option\r\n; combination that goes to voicemail, separating the call menu from the \r\n; option with a pipe. One callmenu/option combo per line.\r\nivr_survey_ingroups_detail => 521205|561401,561402,561403,561404,561505\r\nivr_survey_ingroups_voicemails => 561505|t\r\n\r\n; #####################################################\r\n; # ALL of the below are used in the wallboard report #\r\n; #####################################################\r\nVERM_default_outb_widget_queue => ALL_OUT\r\nVERM_default_inb_widget_queue1 => 514915v_USA_Shared\r\nVERM_default_inb_widget_queue2 => 515915v_MLA_Shared\r\n\r\n; Used specifically for the SLA widget\r\n; Uses ingroups - separate multiple ingroups by commas\r\n; Comment out or leave blank to count all ingroups\r\nSLA_LEVEL_PCT_ingroups => 514915v,515915v\r\n\r\n; This removes remote agents from the wallboard reports\r\n; Comment out to include remote agents (or set to zero)\r\nomit_remote_agents => 1\r\n\r\n\r\n; #### AUTO DOWNLOAD ####\r\n; If the "total calls" value on any report requested exceeds the below \r\n; limit, automatically download the three "DETAILS" reports instead\r\n; of attempting to display that many records on-screen\r\nauto_download_limit => 50000\r\n\r\n; #### OUTCOMES report overrides ####\r\n; Use "outcome_lagged_status_overrides" for conditions where the call \r\n; record in the vicidial_log or vicidial_closer_log table has no uniqueid\r\n; value despite having a status/outcome, which can indicate a call \r\n; affected by network lag for certain statuses. This will change the call \r\n; status to "LAGGED". Separate statuses with commas. Default is the \r\n; automatic "PU" status.\r\noutcome_lagged_status_overrides => PU\r\n\r\n; Use "unknown_network_statuses" to change call statuses to read "Network/\r\n; LAGGED" on the OUTCOMES report. Separate statuses with commas.\r\n; IMPORTANT: if you are using the outcome_lagged_status_overrides option \r\n; above, make sure "LAGGED" is one of the unknown_network_statuses here\r\n; unknown_network_statuses => LAGGED\r\n\r\n; Use "outcome_status_overrides" to change one status to another on the \r\n; OUTCOMES report. Overrides are comma-separated pairs of dispositions \r\n; where the first disposition is the disposition to change, and the second\r\n; is the disposition to change to. Separate pairs with a pipe character as\r\n; in the below example. Off by default.\r\n; outcome_status_overrides => CBHOLD,DISPO|XFER,AL'); INSERT INTO vicidial_settings_containers(container_id,container_notes,container_type,user_group,container_entry) VALUES ('VICIDIAL_TIMEOFF_SETTINGS','Settings for time-off admin utility','OTHER','---ALL---','; Comma-delimited time-off codes - MANDATORY, must have at least one defined. \r\n; Default is \'VAC\' for vacation\r\ntimeoff_types => VAC\r\n\r\n; optional, if set to \'1\' will show all viewable agents, even ones with no \r\n; time off for month. Default is 0\r\ndisplay_all_agents => 0\r\n\r\n; optional, used to filter users displayed, in addition to user_group \r\n; permissions\r\nuser_filter_SQL => \r\n\r\n; optional, uses columns from vicidial_users table. Defaults to \r\n; full_name asc, user asc if commented out or non-existent\r\n; sort_SQL => full_name asc, user asc\r\n\r\n; include custom coding for misc download coding where \"custom_download\" \r\n; marked in agent_timeoff_script.php - DO NOT USE WITHOUT CODING KNOWLEDGE\r\n; set to \'1\' to activate\r\ncustom_download => 0'); INSERT INTO vicidial_settings_containers(container_id,container_notes,container_type,user_group,container_entry) VALUES ('FAILED_DIAL_MESSAGE_OVERRIDE','Failed Dial Message Override','OTHER','---ALL---',"Unable to complete the call at this time.\nPlease try again later."); +INSERT INTO vicidial_settings_containers(container_id,container_notes,container_type,user_group,container_entry) VALUES ('LISTLOADER_AUTO_MAPPING', 'Contains aliases for auto-mapping fields in listloader', 'OTHER', '---ALL---', '; Use this to auto-map fields in the listloader when you attempt to load\r\n; a file. This will populate the \'File data\' dropdown menus \r\n; You may define additional aliases by adding them to the below list.\r\n; They must be of the form \"alias => vicidial_field\". One per line.\r\n; The \"vicidial_field\" value must match the name of a column in the\r\n; vicidial_list table\r\n\r\n\'phone\' => \'phonenumber\'\r\n\'phoneno\' => \'phonenumber\'\r\n\'phone1\' => \'phonenumber\'\r\n\'primaryphone\' => \'phonenumber\'\r\n\'mainphone\' => \'phonenumber\'\r\n\'telephone\' => \'phonenumber\'\r\n\'tel\' => \'phonenumber\'\r\n\'cell\' => \'phonenumber\'\r\n\'cellphone\' => \'phonenumber\'\r\n\'mobile\' => \'phonenumber\'\r\n\'mobilephone\' => \'phonenumber\'\r\n\'workphone\' => \'phonenumber\'\r\n\'homephone\' => \'phonenumber\'\r\n\'fname\' => \'firstname\'\r\n\'first\' => \'firstname\'\r\n\'givenname\' => \'firstname\'\r\n\'lname\' => \'lastname\'\r\n\'last\' => \'lastname\'\r\n\'surname\' => \'lastname\'\r\n\'familyname\' => \'lastname\'\r\n\'mi\' => \'middleinitial\'\r\n\'middle\' => \'middleinitial\'\r\n\'middlename\' => \'middleinitial\'\r\n\'minit\' => \'middleinitial\'\r\n\'addr\' => \'address1\'\r\n\'addr1\' => \'address1\'\r\n\'street\' => \'address1\'\r\n\'streetaddress\' => \'address1\'\r\n\'address\' => \'address1\'\r\n\'addr2\' => \'address2\'\r\n\'street2\' => \'address2\'\r\n\'suite\' => \'address2\'\r\n\'apt\' => \'address2\'\r\n\'apartment\' => \'address2\'\r\n\'unit\' => \'address2\'\r\n\'addr3\' => \'address3\'\r\n\'zip\' => \'postalcode\'\r\n\'zipcode\' => \'postalcode\'\r\n\'postcode\' => \'postalcode\'\r\n\'postalzip\' => \'postalcode\'\r\n\'st\' => \'state\'\r\n\'stateprovince\' => \'state\'\r\n\'region\' => \'state\'\r\n\'prov\' => \'province\'\r\n\'country\' => \'countrycode\'\r\n\'countrycd\' => \'countrycode\'\r\n\'cc\' => \'countrycode\'\r\n\'sex\' => \'gender\'\r\n\'dob\' => \'dateofbirth\'\r\n\'birthday\' => \'dateofbirth\'\r\n\'birthdate\' => \'dateofbirth\'\r\n\'birth\' => \'dateofbirth\'\r\n\'altphone\' => \'altphone\'\r\n\'phone2\' => \'altphone\'\r\n\'secondaryphone\' => \'altphone\'\r\n\'otherphone\' => \'altphone\'\r\n\'alternatephone\' => \'altphone\'\r\n\'emailaddress\' => \'email\'\r\n\'emailaddr\' => \'email\'\r\n\'mail\' => \'email\'\r\n\'note\' => \'comments\'\r\n\'notes\' => \'comments\'\r\n\'comment\' => \'comments\'\r\n\'remark\' => \'comments\'\r\n\'remarks\' => \'comments\'\r\n\'description\' => \'comments\'\r\n\'vendorcode\' => \'vendorleadcode\'\r\n\'vendorid\' => \'vendorleadcode\'\r\n\'vendorleadid\' => \'vendorleadcode\'\r\n\'leadcode\' => \'vendorleadcode\'\r\n\'externalid\' => \'vendorleadcode\'\r\n\'sourcecode\' => \'sourceid\'\r\n\'source\' => \'sourceid\'\r\n\'leadsource\' => \'sourceid\'\r\n\'listid\' => \'listid\'\r\n\'list\' => \'listid\'\r\n\'phonecode\' => \'phonecode\'\r\n\'dialcode\' => \'phonecode\'\r\n\'countrydialing\' => \'phonecode\'\r\n\'prefix\' => \'title\'\r\n\'salutation\' => \'title\'\r\n\'mr\' => \'title\'\r\n\'securityphrase\' => \'securityphrase\'\r\n\'security\' => \'securityphrase\'\r\n\'pin\' => \'securityphrase\'\r\n\'password\' => \'securityphrase\'\r\n\'priority\' => \'rank\'\r\n\'score\' => \'rank\'\r\n\'weight\' => \'rank\'\r\n\'agent\' => \'owner\'\r\n\'assignedto\' => \'owner\'\r\n\'rep\' => \'owner\'\r\n\'town\' => \'city\'\r\n\r\n\r\n; This is the minimum required score that the header field must return\r\n; when processed with the Levenshtein distance algorithm. Default is 70.\r\n; If you wish to raise or lower it, uncomment the below line and change the \r\n; score value to whatever you wish\r\n; minimum_required_score => 70\r\n'); INSERT INTO `wallboard_widgets` VALUES ('queues_widget_1','AGENTS_AND_QUEUES','queues','','TEXT',5,'N',1,'Queue Information','','',NULL,'','',NULL,2),('queues_widget_0','AGENTS_AND_QUEUES','queues','','LOGO',2,'N',1,NULL,'','',NULL,'','',NULL,1),('queues_widget_2','AGENTS_AND_QUEUES','queues','SLA Level %','SLA_LEVEL_PCT',1,'N',1,NULL,'','>60',NULL,'','',NULL,3),('queues_widget_3','AGENTS_AND_QUEUES','queues','Outbound calls','LIVE_QUEUE_INFO',1,'N',1,'','201201','','','','','yellow_alarm,|red_alarm,',4),('queues_widget_4','AGENTS_AND_QUEUES','queues','USA Ded Inbound','LIVE_QUEUE_INFO',1,'N',1,'','ALL_IN','','','','','yellow_alarm,|red_alarm,',5),('queues_widget_5','AGENTS_AND_QUEUES','queues','MLA Ded Inbound','LIVE_QUEUE_INFO',1,'N',1,'','514911','','','','','yellow_alarm,|red_alarm,',6),('queues_widget_6','AGENTS_AND_QUEUES','queues','N Waiting Calls','N_WAITING_CALLS',1,'N',1,NULL,'','',NULL,'','',NULL,7),('queues_widget_7','AGENTS_AND_QUEUES','queues','Offered Calls','OFFERED_CALLS',1,'N',1,NULL,'','',NULL,'','',NULL,8),('queues_widget_8','AGENTS_AND_QUEUES','queues','Answered Calls','ANSWERED_CALLS',1,'N',1,NULL,'','',NULL,'','',NULL,9),('queues_widget_9','AGENTS_AND_QUEUES','queues','Lost Calls','LOST_CALLS',1,'N',1,NULL,'','',NULL,'','',NULL,10),('queues_widget_10','AGENTS_AND_QUEUES','queues','Longest Wait','LONGEST_WAIT',1,'N',1,NULL,'','',NULL,'','',NULL,11),('queues_widget_11','AGENTS_AND_QUEUES','queues','Live Queues','LIVE_QUEUES',1,'Y',1,NULL,'','',NULL,'','',NULL,12),('queues_widget_12','AGENTS_AND_QUEUES','queues','Live Calls','LIVE_CALLS',1,'Y',2,NULL,'','',NULL,'','',NULL,13),('agent_widget_0','AGENTS_AND_QUEUES','agents','','LOGO',2,'N',1,NULL,'','',NULL,'','',NULL,1),('agent_widget_1','AGENTS_AND_QUEUES','agents','N Waiting Calls','N_WAITING_CALLS',1,'N',1,NULL,'','',NULL,'','',NULL,2),('agent_widget_2','AGENTS_AND_QUEUES','agents','Agents Ready','AGENTS_READY',1,'N',1,NULL,'','',NULL,'','',NULL,3),('agent_widget_3','AGENTS_AND_QUEUES','agents','Agents On Call','N_AGENTS_ON_CALL',1,'N',1,NULL,'','',NULL,'','',NULL,4),('agent_widget_4','AGENTS_AND_QUEUES','agents','N Answered Calls','N_ANSWERED_CALLS',1,'N',1,NULL,'','',NULL,'','',NULL,5),('agent_widget_5','AGENTS_AND_QUEUES','agents','Clock','CLOCK',1,'N',1,NULL,'','',NULL,'','',NULL,6),('agent_widget_6','AGENTS_AND_QUEUES','agents','Live Agents','LIVE_AGENTS',1,'Y',3,NULL,'','',NULL,'','',NULL,7); @@ -5897,4 +5898,4 @@ INSERT INTO `wallboard_reports` VALUES ('AGENTS_AND_QUEUES','Agents and Queues', UPDATE system_settings set vdc_agent_api_active='1'; -UPDATE system_settings SET db_schema_version='1739',db_schema_update_date=NOW(),reload_timestamp=NOW(); +UPDATE system_settings SET db_schema_version='1740',db_schema_update_date=NOW(),reload_timestamp=NOW(); diff --git a/agc_2-X/trunk/extras/upgrade_2.14.sql b/agc_2-X/trunk/extras/upgrade_2.14.sql index 8e66270e..5a526b3b 100644 --- a/agc_2-X/trunk/extras/upgrade_2.14.sql +++ b/agc_2-X/trunk/extras/upgrade_2.14.sql @@ -3084,3 +3084,7 @@ index (status) ALTER TABLE system_settings ADD max_inbound_auto_reenable ENUM('0','1','2','3','4','5','6') default '1'; UPDATE system_settings SET db_schema_version='1739',db_schema_update_date=NOW() where db_schema_version < 1739; + +INSERT INTO vicidial_settings_containers(container_id,container_notes,container_type,user_group,container_entry) VALUES ('LISTLOADER_AUTO_MAPPING', 'Contains aliases for auto-mapping fields in listloader', 'OTHER', '---ALL---', '; Use this to auto-map fields in the listloader when you attempt to load\r\n; a file. This will populate the \'File data\' dropdown menus \r\n; You may define additional aliases by adding them to the below list.\r\n; They must be of the form \"alias => vicidial_field\". One per line.\r\n; The \"vicidial_field\" value must match the name of a column in the\r\n; vicidial_list table\r\n\r\n\'phone\' => \'phonenumber\'\r\n\'phoneno\' => \'phonenumber\'\r\n\'phone1\' => \'phonenumber\'\r\n\'primaryphone\' => \'phonenumber\'\r\n\'mainphone\' => \'phonenumber\'\r\n\'telephone\' => \'phonenumber\'\r\n\'tel\' => \'phonenumber\'\r\n\'cell\' => \'phonenumber\'\r\n\'cellphone\' => \'phonenumber\'\r\n\'mobile\' => \'phonenumber\'\r\n\'mobilephone\' => \'phonenumber\'\r\n\'workphone\' => \'phonenumber\'\r\n\'homephone\' => \'phonenumber\'\r\n\'fname\' => \'firstname\'\r\n\'first\' => \'firstname\'\r\n\'givenname\' => \'firstname\'\r\n\'lname\' => \'lastname\'\r\n\'last\' => \'lastname\'\r\n\'surname\' => \'lastname\'\r\n\'familyname\' => \'lastname\'\r\n\'mi\' => \'middleinitial\'\r\n\'middle\' => \'middleinitial\'\r\n\'middlename\' => \'middleinitial\'\r\n\'minit\' => \'middleinitial\'\r\n\'addr\' => \'address1\'\r\n\'addr1\' => \'address1\'\r\n\'street\' => \'address1\'\r\n\'streetaddress\' => \'address1\'\r\n\'address\' => \'address1\'\r\n\'addr2\' => \'address2\'\r\n\'street2\' => \'address2\'\r\n\'suite\' => \'address2\'\r\n\'apt\' => \'address2\'\r\n\'apartment\' => \'address2\'\r\n\'unit\' => \'address2\'\r\n\'addr3\' => \'address3\'\r\n\'zip\' => \'postalcode\'\r\n\'zipcode\' => \'postalcode\'\r\n\'postcode\' => \'postalcode\'\r\n\'postalzip\' => \'postalcode\'\r\n\'st\' => \'state\'\r\n\'stateprovince\' => \'state\'\r\n\'region\' => \'state\'\r\n\'prov\' => \'province\'\r\n\'country\' => \'countrycode\'\r\n\'countrycd\' => \'countrycode\'\r\n\'cc\' => \'countrycode\'\r\n\'sex\' => \'gender\'\r\n\'dob\' => \'dateofbirth\'\r\n\'birthday\' => \'dateofbirth\'\r\n\'birthdate\' => \'dateofbirth\'\r\n\'birth\' => \'dateofbirth\'\r\n\'altphone\' => \'altphone\'\r\n\'phone2\' => \'altphone\'\r\n\'secondaryphone\' => \'altphone\'\r\n\'otherphone\' => \'altphone\'\r\n\'alternatephone\' => \'altphone\'\r\n\'emailaddress\' => \'email\'\r\n\'emailaddr\' => \'email\'\r\n\'mail\' => \'email\'\r\n\'note\' => \'comments\'\r\n\'notes\' => \'comments\'\r\n\'comment\' => \'comments\'\r\n\'remark\' => \'comments\'\r\n\'remarks\' => \'comments\'\r\n\'description\' => \'comments\'\r\n\'vendorcode\' => \'vendorleadcode\'\r\n\'vendorid\' => \'vendorleadcode\'\r\n\'vendorleadid\' => \'vendorleadcode\'\r\n\'leadcode\' => \'vendorleadcode\'\r\n\'externalid\' => \'vendorleadcode\'\r\n\'sourcecode\' => \'sourceid\'\r\n\'source\' => \'sourceid\'\r\n\'leadsource\' => \'sourceid\'\r\n\'listid\' => \'listid\'\r\n\'list\' => \'listid\'\r\n\'phonecode\' => \'phonecode\'\r\n\'dialcode\' => \'phonecode\'\r\n\'countrydialing\' => \'phonecode\'\r\n\'prefix\' => \'title\'\r\n\'salutation\' => \'title\'\r\n\'mr\' => \'title\'\r\n\'securityphrase\' => \'securityphrase\'\r\n\'security\' => \'securityphrase\'\r\n\'pin\' => \'securityphrase\'\r\n\'password\' => \'securityphrase\'\r\n\'priority\' => \'rank\'\r\n\'score\' => \'rank\'\r\n\'weight\' => \'rank\'\r\n\'agent\' => \'owner\'\r\n\'assignedto\' => \'owner\'\r\n\'rep\' => \'owner\'\r\n\'town\' => \'city\'\r\n\r\n\r\n; This is the minimum required score that the header field must return\r\n; when processed with the Levenshtein distance algorithm. Default is 70.\r\n; If you wish to raise or lower it, uncomment the below line and change the \r\n; score value to whatever you wish\r\n; minimum_required_score => 70\r\n'); + +UPDATE system_settings SET db_schema_version='1740',db_schema_update_date=NOW() where db_schema_version < 1740; diff --git a/agc_2-X/trunk/www/vicidial/admin_listloader_fifth_gen.php b/agc_2-X/trunk/www/vicidial/admin_listloader_fifth_gen.php index cd45cfc9..fd78ef56 100644 --- a/agc_2-X/trunk/www/vicidial/admin_listloader_fifth_gen.php +++ b/agc_2-X/trunk/www/vicidial/admin_listloader_fifth_gen.php @@ -2,7 +2,7 @@ # admin_listloader_fifth_gen.php - version 2.14 # (based upon - new_listloader_superL.php script) # -# Copyright (C) 2024 Matt Florell,Joe Johnson LICENSE: AGPLv2 +# Copyright (C) 2026 Matt Florell,Joe Johnson LICENSE: AGPLv2 # # ViciDial web-based lead loader from formatted file # @@ -84,14 +84,329 @@ # 231207-1446 - Fix for web_loader_phone_strip duplicate check, issue #1498, also changed format to "Custom layout" default # 240320-1034 - Added misssing input variable filtering # 240801-1132 - Code updates for PHP8 compatibility +# 260203-1600 - Fix for field chooser issue and more code updates for PHP8 compatibility +# 260415-1710 - Added summarized error output, fuzzy field auto-detection for custom layout, Issue #1561 from Acidshock # -$version = '2.14-82'; -$build = '240801-1132'; +$version = '2.14-83'; +$build = '260415-1710'; require("dbconnect_mysqli.php"); require("functions.php"); +$aliases=array(); +$field_match_scores=array(); $min_req_score=70; # default +$field_match_fields=array(); +$alias_stmt="select container_entry from vicidial_settings_containers where container_id='LISTLOADER_AUTO_MAPPING'"; +$alias_rslt=mysql_to_mysqli($alias_stmt, $link); +if (mysqli_num_rows($alias_rslt)>0) + { + $alias_row=mysqli_fetch_row($alias_rslt); + $container_entry=explode("\n", $alias_row[0]); + + for ($q=0; $q\s/', $container_entry[$q])) + { + $alias_entry=explode(" => ", trim($container_entry[$q])); + + if (trim($alias_entry[0])=="minimum_required_score") + { + $VD_field=preg_replace('/[^0-9]/', '', $alias_entry[1]); + $min_req_score=$VD_field; + } + else + { + $alias_field=preg_replace('/[^a-z0-9]/', '', $alias_entry[0]); + $VD_field=preg_replace('/[^a-z0-9]/', '', $alias_entry[1]); + $aliases["$alias_field"]="$VD_field"; + } + } + } + } +if ($min_req_score>100) {$min_req_score=100;} +##### BEGIN summary and fuzzy matching helper functions ##### + +# Fuzzy field matching: maps common CSV header names to vicidial_list field names +function fuzzy_match_field($header_name, $vicidial_field_name) + { + global $aliases; + + # Normalize both strings: lowercase, strip non-alphanumeric + $h = strtolower(trim($header_name)); + $h_clean = preg_replace('/[^a-z0-9]/', '', $h); + $v = strtolower($vicidial_field_name); + $v_clean = preg_replace('/[^a-z0-9]/', '', $v); + + # Exact match after normalization + if ($h_clean == $v_clean) { return 100; } + + # Alias map: common CSV header variations => vicidial field name (cleaned) + /* + $aliases = array( + 'phone' => 'phonenumber', + 'phoneno' => 'phonenumber', + 'phone1' => 'phonenumber', + 'primaryphone' => 'phonenumber', + 'mainphone' => 'phonenumber', + 'telephone' => 'phonenumber', + 'tel' => 'phonenumber', + 'cell' => 'phonenumber', + 'cellphone' => 'phonenumber', + 'mobile' => 'phonenumber', + 'mobilephone' => 'phonenumber', + 'workphone' => 'phonenumber', + 'homephone' => 'phonenumber', + 'fname' => 'firstname', + 'first' => 'firstname', + 'givenname' => 'firstname', + 'lname' => 'lastname', + 'last' => 'lastname', + 'surname' => 'lastname', + 'familyname' => 'lastname', + 'mi' => 'middleinitial', + 'middle' => 'middleinitial', + 'middlename' => 'middleinitial', + 'addr' => 'address1', + 'addr1' => 'address1', + 'street' => 'address1', + 'streetaddress' => 'address1', + 'address' => 'address1', + 'addr2' => 'address2', + 'street2' => 'address2', + 'suite' => 'address2', + 'apt' => 'address2', + 'apartment' => 'address2', + 'unit' => 'address2', + 'addr3' => 'address3', + 'zip' => 'postalcode', + 'zipcode' => 'postalcode', + 'postcode' => 'postalcode', + 'postalzip' => 'postalcode', + 'st' => 'state', + 'stateprovince' => 'state', + 'region' => 'state', + 'prov' => 'province', + 'country' => 'countrycode', + 'countrycd' => 'countrycode', + 'cc' => 'countrycode', + 'sex' => 'gender', + 'dob' => 'dateofbirth', + 'birthday' => 'dateofbirth', + 'birthdate' => 'dateofbirth', + 'birth' => 'dateofbirth', + 'altphone' => 'altphone', + 'phone2' => 'altphone', + 'secondaryphone' => 'altphone', + 'otherphone' => 'altphone', + 'alternatephone' => 'altphone', + 'emailaddress' => 'email', + 'emailaddr' => 'email', + 'mail' => 'email', + 'note' => 'comments', + 'notes' => 'comments', + 'comment' => 'comments', + 'remark' => 'comments', + 'remarks' => 'comments', + 'description' => 'comments', + 'vendorcode' => 'vendorleadcode', + 'vendorid' => 'vendorleadcode', + 'vendorleadid' => 'vendorleadcode', + 'leadcode' => 'vendorleadcode', + 'externalid' => 'vendorleadcode', + 'sourcecode' => 'sourceid', + 'source' => 'sourceid', + 'leadsource' => 'sourceid', + 'listid' => 'listid', + 'list' => 'listid', + 'phonecode' => 'phonecode', + 'dialcode' => 'phonecode', + 'countrydialing' => 'phonecode', + 'prefix' => 'title', + 'salutation' => 'title', + 'mr' => 'title', + 'securityphrase' => 'securityphrase', + 'security' => 'securityphrase', + 'pin' => 'securityphrase', + 'password' => 'securityphrase', + 'priority' => 'rank', + 'score' => 'rank', + 'weight' => 'rank', + 'agent' => 'owner', + 'assignedto' => 'owner', + 'rep' => 'owner', + 'town' => 'city', + ); + */ + + # Check alias match + if (isset($aliases[$h_clean]) && $aliases[$h_clean] == $v_clean) { return 95; } + + # Check if header contains the field name or vice versa + if (strlen($h_clean) > 2 && strlen($v_clean) > 2) + { + if (strpos($h_clean, $v_clean) !== false) { return 90; } + if (strpos($v_clean, $h_clean) !== false) { return 85; } + } + + # Levenshtein distance (for short strings) + if (strlen($h_clean) < 20 && strlen($v_clean) < 20) + { + $lev = levenshtein($h_clean, $v_clean); + $max_len = max(strlen($h_clean), strlen($v_clean)); + if ($max_len > 0) + { + $similarity = (1 - ($lev / $max_len)) * 100; + if ($similarity >= 75) { return intval($similarity); } + } + } + + # similar_text percentage + similar_text($h_clean, $v_clean, $percent); + # if ($percent >= 70) { return intval($percent); } + if ($percent > 0) { return intval($percent); } + return 0; + } + +# Auto-detect best column index for a given vicidial field from header row +function auto_detect_field_index($vicidial_field_name, $header_columns) + { + global $field_match_scores, $field_match_fields; + $best_score = 0; + $best_index = -1; + $pheader_columns=''; + + for ($i = 0; $i < count($header_columns); $i++) + { + $score = fuzzy_match_field($header_columns[$i], $vicidial_field_name); + if ($score > $best_score) + { + $best_score = $score; + $best_index = $i; + $pheader_columns=$header_columns[$i]; + } + } + + # echo "$pheader_columns || $vicidial_field_name || $best_score\n"; + $field_match_fields["$vicidial_field_name"]=$pheader_columns; + $field_match_scores["$vicidial_field_name"]=$best_score; + + # Only return a match if confidence is >= 70% + if ($best_score >= 0) { return array($best_index, $best_score); } + return -1; + } + +# Output a summary table of load results instead of per-line errors +function print_load_summary($good, $bad, $total, $dup, $moved, $inv, $dup_phone_details, $inv_phone_details, $dnc_phone_details, $listid_error_details) + { + print "

\n"; + print "\n"; + print "\n"; + print "\n"; + print "\n"; + if ($dup > 0) + { print "\n"; } + if ($moved > 0) + { print "\n"; } + $inv_count = count($inv_phone_details); + if ($inv_count > 0) + { print "\n"; } + $dnc_count = count($dnc_phone_details); + if ($dnc_count > 0) + { print "\n"; } + $listid_count = count($listid_error_details); + if ($listid_count > 0) + { print "\n"; } + print "
"._QXZ("Load Summary")."
"._QXZ("Good").":$good
"._QXZ("Bad").":$bad
"._QXZ("Total").":$total
"._QXZ("Duplicates").":$dup
"._QXZ("Moved").":$moved
"._QXZ("Invalid Numbers").":$inv_count
"._QXZ("DNC Matches").":$dnc_count
"._QXZ("Invalid List ID").":$listid_count
\n"; + + # Duplicate details section + if (count($dup_phone_details) > 0) + { + print "
\n"; + print "\n"; + print "\n"; + $dup_row_count = 0; + foreach ($dup_phone_details as $dup_phone => $dup_info) + { + if ($dup_row_count < 500) + { + $dup_list_str = implode(', ', array_unique($dup_info['lists'])); + $dup_cnt = $dup_info['count']; + $bg = ($dup_row_count % 2 == 0) ? '#FFF3E0' : '#FFE0B2'; + print "\n"; + } + $dup_row_count++; + } + if ($dup_row_count > 500) + { + $remaining = $dup_row_count - 500; + print "\n"; + } + print "
"._QXZ("Duplicate Details")."
"._QXZ("Phone Number").""._QXZ("Count").""._QXZ("Found In Lists")."
$dup_phone$dup_cnt$dup_list_str
... "._QXZ("and")." $remaining "._QXZ("more")." ...
\n"; + } + + # Invalid number details section + if (count($inv_phone_details) > 0) + { + # Group by reason + $inv_by_reason = array(); + foreach ($inv_phone_details as $inv_info) + { + $reason = $inv_info['reason']; + if (!isset($inv_by_reason[$reason])) { $inv_by_reason[$reason] = array(); } + $inv_by_reason[$reason][] = $inv_info['phone']; + } + print "
\n"; + print "\n"; + foreach ($inv_by_reason as $reason => $phones) + { + $phone_count = count($phones); + $sample = array_slice($phones, 0, 10); + $sample_str = implode(', ', $sample); + if ($phone_count > 10) { $sample_str .= " ... (+".($phone_count - 10)." "._QXZ("more").")"; } + print "\n"; + } + print "
"._QXZ("Invalid Number Details")."
$reason ($phone_count)$sample_str
\n"; + } + + # DNC details section + if (count($dnc_phone_details) > 0) + { + print "
\n"; + print "\n"; + $dnc_sample = array_slice($dnc_phone_details, 0, 20); + foreach ($dnc_sample as $dnc_info) + { + print "\n"; + } + if (count($dnc_phone_details) > 20) + { + $remaining = count($dnc_phone_details) - 20; + print "\n"; + } + print "
"._QXZ("DNC Match Details")."
$dnc_info[phone]$dnc_info[reason]
... "._QXZ("and")." $remaining "._QXZ("more")." ...
\n"; + } + + # Invalid List ID details section + if (count($listid_error_details) > 0) + { + print "
\n"; + print "\n"; + $listid_sample = array_slice($listid_error_details, 0, 20); + foreach ($listid_sample as $lid_info) + { + print "\n"; + } + if (count($listid_error_details) > 20) + { + $remaining = count($listid_error_details) - 20; + print "\n"; + } + print "
"._QXZ("Invalid List ID Details")."
"._QXZ("Record")." $lid_info[record] - "._QXZ("Phone").": $lid_info[phone]"._QXZ("List ID").": $lid_info[list_id]
... "._QXZ("and")." $remaining "._QXZ("more")." ...
\n"; + } + } +##### END summary and fuzzy matching helper functions ##### + $enable_status_mismatch_leadloader_option=0; if (file_exists('options.php')) @@ -102,112 +417,175 @@ if (file_exists('options.php')) $US='_'; $MT[0]=''; -$PHP_AUTH_USER=$_SERVER['PHP_AUTH_USER']; -$PHP_AUTH_PW=$_SERVER['PHP_AUTH_PW']; +$PHP_AUTH_USER=(array_key_exists('PHP_AUTH_USER', $_SERVER) ? $_SERVER['PHP_AUTH_USER'] : ""); +$PHP_AUTH_PW=(array_key_exists('PHP_AUTH_PW', $_SERVER) ? $_SERVER['PHP_AUTH_PW'] : ""); $PHP_SELF=$_SERVER['PHP_SELF']; $PHP_SELF = preg_replace('/\.php.*/i','.php',$PHP_SELF); -$leadfile=$_FILES["leadfile"]; +if (array_key_exists('leadfile', $_FILES)) + { + $leadfile=$_FILES["leadfile"]; $LF_orig = $_FILES['leadfile']['name']; $LF_path = $_FILES['leadfile']['tmp_name']; + } +else + { + $leadfile=""; + $LF_orig = ""; + $LF_path = ""; + } if (isset($_GET["submit_file"])) {$submit_file=$_GET["submit_file"];} elseif (isset($_POST["submit_file"])) {$submit_file=$_POST["submit_file"];} -if (isset($_GET["submit"])) {$submit=$_GET["submit"];} - elseif (isset($_POST["submit"])) {$submit=$_POST["submit"];} -if (isset($_GET["SUBMIT"])) {$SUBMIT=$_GET["SUBMIT"];} - elseif (isset($_POST["SUBMIT"])) {$SUBMIT=$_POST["SUBMIT"];} + else {$submit_file="";} +# if (isset($_GET["submit"])) {$submit=$_GET["submit"];} +# elseif (isset($_POST["submit"])) {$submit=$_POST["submit"];} +# if (isset($_GET["SUBMIT"])) {$SUBMIT=$_GET["SUBMIT"];} +# elseif (isset($_POST["SUBMIT"])) {$SUBMIT=$_POST["SUBMIT"];} if (isset($_GET["leadfile_name"])) {$leadfile_name=$_GET["leadfile_name"];} elseif (isset($_POST["leadfile_name"])) {$leadfile_name=$_POST["leadfile_name"];} + else {$leadfile_name="";} if (isset($_FILES["leadfile"])) {$leadfile_name=$_FILES["leadfile"]['name'];} if (isset($_GET["file_layout"])) {$file_layout=$_GET["file_layout"];} elseif (isset($_POST["file_layout"])) {$file_layout=$_POST["file_layout"];} + else {$file_layout="";} if (isset($_GET["OK_to_process"])) {$OK_to_process=$_GET["OK_to_process"];} elseif (isset($_POST["OK_to_process"])) {$OK_to_process=$_POST["OK_to_process"];} + else {$OK_to_process="";} if (isset($_GET["vendor_lead_code_field"])) {$vendor_lead_code_field=$_GET["vendor_lead_code_field"];} elseif (isset($_POST["vendor_lead_code_field"])) {$vendor_lead_code_field=$_POST["vendor_lead_code_field"];} + else {$vendor_lead_code_field="-1";} if (isset($_GET["source_id_field"])) {$source_id_field=$_GET["source_id_field"];} elseif (isset($_POST["source_id_field"])) {$source_id_field=$_POST["source_id_field"];} + else {$source_id_field="-1";} if (isset($_GET["list_id_field"])) {$list_id_field=$_GET["list_id_field"];} elseif (isset($_POST["list_id_field"])) {$list_id_field=$_POST["list_id_field"];} + else {$list_id_field="-1";} if (isset($_GET["phone_code_field"])) {$phone_code_field=$_GET["phone_code_field"];} elseif (isset($_POST["phone_code_field"])) {$phone_code_field=$_POST["phone_code_field"];} + else {$phone_code_field="-1";} if (isset($_GET["phone_number_field"])) {$phone_number_field=$_GET["phone_number_field"];} elseif (isset($_POST["phone_number_field"])) {$phone_number_field=$_POST["phone_number_field"];} + else {$phone_number_field="-1";} if (isset($_GET["title_field"])) {$title_field=$_GET["title_field"];} elseif (isset($_POST["title_field"])) {$title_field=$_POST["title_field"];} + else {$title_field="-1";} if (isset($_GET["first_name_field"])) {$first_name_field=$_GET["first_name_field"];} elseif (isset($_POST["first_name_field"])) {$first_name_field=$_POST["first_name_field"];} + else {$first_name_field="-1";} if (isset($_GET["middle_initial_field"])) {$middle_initial_field=$_GET["middle_initial_field"];} elseif (isset($_POST["middle_initial_field"])) {$middle_initial_field=$_POST["middle_initial_field"];} + else {$middle_initial_field="-1";} if (isset($_GET["last_name_field"])) {$last_name_field=$_GET["last_name_field"];} elseif (isset($_POST["last_name_field"])) {$last_name_field=$_POST["last_name_field"];} + else {$last_name_field="-1";} if (isset($_GET["address1_field"])) {$address1_field=$_GET["address1_field"];} elseif (isset($_POST["address1_field"])) {$address1_field=$_POST["address1_field"];} + else {$address1_field="-1";} if (isset($_GET["address2_field"])) {$address2_field=$_GET["address2_field"];} elseif (isset($_POST["address2_field"])) {$address2_field=$_POST["address2_field"];} + else {$address2_field="-1";} if (isset($_GET["address3_field"])) {$address3_field=$_GET["address3_field"];} elseif (isset($_POST["address3_field"])) {$address3_field=$_POST["address3_field"];} + else {$address3_field="-1";} if (isset($_GET["city_field"])) {$city_field=$_GET["city_field"];} elseif (isset($_POST["city_field"])) {$city_field=$_POST["city_field"];} + else {$city_field="-1";} if (isset($_GET["state_field"])) {$state_field=$_GET["state_field"];} elseif (isset($_POST["state_field"])) {$state_field=$_POST["state_field"];} + else {$state_field="-1";} if (isset($_GET["province_field"])) {$province_field=$_GET["province_field"];} elseif (isset($_POST["province_field"])) {$province_field=$_POST["province_field"];} + else {$province_field="-1";} if (isset($_GET["postal_code_field"])) {$postal_code_field=$_GET["postal_code_field"];} elseif (isset($_POST["postal_code_field"])) {$postal_code_field=$_POST["postal_code_field"];} + else {$postal_code_field="-1";} if (isset($_GET["country_code_field"])) {$country_code_field=$_GET["country_code_field"];} elseif (isset($_POST["country_code_field"])) {$country_code_field=$_POST["country_code_field"];} + else {$country_code_field="-1";} if (isset($_GET["gender_field"])) {$gender_field=$_GET["gender_field"];} elseif (isset($_POST["gender_field"])) {$gender_field=$_POST["gender_field"];} + else {$gender_field="-1";} if (isset($_GET["date_of_birth_field"])) {$date_of_birth_field=$_GET["date_of_birth_field"];} elseif (isset($_POST["date_of_birth_field"])) {$date_of_birth_field=$_POST["date_of_birth_field"];} + else {$date_of_birth_field="-1";} if (isset($_GET["alt_phone_field"])) {$alt_phone_field=$_GET["alt_phone_field"];} elseif (isset($_POST["alt_phone_field"])) {$alt_phone_field=$_POST["alt_phone_field"];} + else {$alt_phone_field="-1";} if (isset($_GET["email_field"])) {$email_field=$_GET["email_field"];} elseif (isset($_POST["email_field"])) {$email_field=$_POST["email_field"];} + else {$email_field="-1";} if (isset($_GET["security_phrase_field"])) {$security_phrase_field=$_GET["security_phrase_field"];} elseif (isset($_POST["security_phrase_field"])) {$security_phrase_field=$_POST["security_phrase_field"];} + else {$security_phrase_field="-1";} if (isset($_GET["comments_field"])) {$comments_field=$_GET["comments_field"];} elseif (isset($_POST["comments_field"])) {$comments_field=$_POST["comments_field"];} + else {$comments_field="-1";} if (isset($_GET["rank_field"])) {$rank_field=$_GET["rank_field"];} elseif (isset($_POST["rank_field"])) {$rank_field=$_POST["rank_field"];} + else {$rank_field="-1";} if (isset($_GET["owner_field"])) {$owner_field=$_GET["owner_field"];} elseif (isset($_POST["owner_field"])) {$owner_field=$_POST["owner_field"];} + else {$owner_field="-1";} if (isset($_GET["list_id_override"])) {$list_id_override=$_GET["list_id_override"];} elseif (isset($_POST["list_id_override"])) {$list_id_override=$_POST["list_id_override"];} + else {$list_id_override="";} $list_id_override = (preg_replace("/\D/","",$list_id_override)); if (isset($_GET["master_list_override"])) {$master_list_override=$_GET["master_list_override"];} elseif (isset($_POST["master_list_override"])) {$master_list_override=$_POST["master_list_override"];} + else {$master_list_override="";} if (isset($_GET["lead_file"])) {$lead_file=$_GET["lead_file"];} elseif (isset($_POST["lead_file"])) {$lead_file=$_POST["lead_file"];} + else {$lead_file="";} if (isset($_GET["dupcheck"])) {$dupcheck=$_GET["dupcheck"];} elseif (isset($_POST["dupcheck"])) {$dupcheck=$_POST["dupcheck"];} + else {$dupcheck="";} if (isset($_GET["dedupe_statuses"])) {$dedupe_statuses=$_GET["dedupe_statuses"];} elseif (isset($_POST["dedupe_statuses"])) {$dedupe_statuses=$_POST["dedupe_statuses"];} + else {$dedupe_statuses="";} if (isset($_GET["dedupe_statuses_override"])) {$dedupe_statuses_override=$_GET["dedupe_statuses_override"];} elseif (isset($_POST["dedupe_statuses_override"])) {$dedupe_statuses_override=$_POST["dedupe_statuses_override"];} + else {$dedupe_statuses_override="";} if (isset($_GET["status_mismatch_action"])) {$status_mismatch_action=$_GET["status_mismatch_action"];} elseif (isset($_POST["status_mismatch_action"])) {$status_mismatch_action=$_POST["status_mismatch_action"];} + else {$status_mismatch_action="";} if (isset($_GET["postalgmt"])) {$postalgmt=$_GET["postalgmt"];} elseif (isset($_POST["postalgmt"])) {$postalgmt=$_POST["postalgmt"];} + else {$postalgmt="";} if (isset($_GET["phone_code_override"])) {$phone_code_override=$_GET["phone_code_override"];} elseif (isset($_POST["phone_code_override"])) {$phone_code_override=$_POST["phone_code_override"];} + else {$phone_code_override="";} $phone_code_override = (preg_replace("/\D/","",$phone_code_override)); if (isset($_GET["DB"])) {$DB=$_GET["DB"];} elseif (isset($_POST["DB"])) {$DB=$_POST["DB"];} +if (isset($_GET["DBX"])) {$DBX=$_GET["DBX"];} + elseif (isset($_POST["DBX"])) {$DBX=$_POST["DBX"];} if (isset($_GET["template_id"])) {$template_id=$_GET["template_id"];} elseif (isset($_POST["template_id"])) {$template_id=$_POST["template_id"];} + else {$template_id="";} if (isset($_GET["usacan_check"])) {$usacan_check=$_GET["usacan_check"];} elseif (isset($_POST["usacan_check"])) {$usacan_check=$_POST["usacan_check"];} + else {$usacan_check="";} if (isset($_GET["state_conversion"])) {$state_conversion=$_GET["state_conversion"];} elseif (isset($_POST["state_conversion"])) {$state_conversion=$_POST["state_conversion"];} + else {$state_conversion="";} if (isset($_GET["web_loader_phone_length"])) {$web_loader_phone_length=$_GET["web_loader_phone_length"];} elseif (isset($_POST["web_loader_phone_length"])) {$web_loader_phone_length=$_POST["web_loader_phone_length"];} + else {$web_loader_phone_length=0;} if (isset($_GET["international_dnc_scrub"])) {$international_dnc_scrub=$_GET["international_dnc_scrub"];} elseif (isset($_POST["international_dnc_scrub"])) {$international_dnc_scrub=$_POST["international_dnc_scrub"];} + else {$international_dnc_scrub="";} if (isset($_GET["invalid_phone_override"])) {$invalid_phone_override=$_GET["invalid_phone_override"];} elseif (isset($_POST["invalid_phone_override"])) {$invalid_phone_override=$_POST["invalid_phone_override"];} + else {$invalid_phone_override="";} +if (isset($_GET["tz_method"])) {$tz_method=$_GET["tz_method"];} + elseif (isset($_POST["tz_method"])) {$tz_method=$_POST["tz_method"];} + else {$tz_method="";} +if (isset($_GET["server_ip"])) {$server_ip=$_GET["server_ip"];} + elseif (isset($_POST["server_ip"])) {$server_ip=$_POST["server_ip"];} + else {$server_ip="";} +if (isset($_GET["attempt_auto_detect"])) {$attempt_auto_detect=$_GET["attempt_auto_detect"];} + elseif (isset($_POST["attempt_auto_detect"])) {$attempt_auto_detect=$_POST["attempt_auto_detect"];} + else {$attempt_auto_detect="";} -$DB=preg_replace("/[^0-9a-zA-Z]/","",$DB); # if the didnt select an over ride wipe out in_file if ( $list_id_override == "in_file" ) { $list_id_override = ""; } @@ -224,7 +602,6 @@ $vicidial_list_fields = '|lead_id|vendor_lead_code|source_id|list_id|gmt_offset_ ##### START SYSTEM_SETTINGS LOOKUP ##### $stmt = "SELECT use_non_latin,admin_web_directory,custom_fields_enabled,webroot_writable,enable_languages,language_method,active_modules,admin_screen_colors,web_loader_phone_length,enable_international_dncs,web_loader_phone_strip,allow_web_debug FROM system_settings;"; $rslt=mysql_to_mysqli($stmt, $link); -if ($DB) {echo "$stmt\n";} $qm_conf_ct = mysqli_num_rows($rslt); #if ($qm_conf_ct > 0) { @@ -242,11 +619,14 @@ $qm_conf_ct = mysqli_num_rows($rslt); $SSweb_loader_phone_strip = $row[10]; $SSallow_web_debug = $row[11]; } -if ($SSallow_web_debug < 1) {$DB=0;} +if ($SSallow_web_debug < 1 || !isset($DB)) {$DB=0;} +$DB=preg_replace("/[^0-9a-zA-Z]/","",$DB); +$DBX=0; # Always set - used in lookup_gmt, where you will have to override via hard-coding ##### END SETTINGS LOOKUP ##### ########################################### $list_id_override = preg_replace('/[^0-9]/','',$list_id_override); +$attempt_auto_detect = preg_replace('/[^YN]/','',$attempt_auto_detect); $phone_code_override = preg_replace('/[^0-9]/','',$phone_code_override); $web_loader_phone_length = preg_replace('/[^0-9]/','',$web_loader_phone_length); $international_dnc_scrub = preg_replace('/[^-_0-9a-zA-Z]/', '', $international_dnc_scrub); @@ -257,37 +637,39 @@ $status_mismatch_action = preg_replace('/[^- \_0-9a-zA-Z]/', '', $status_mismatc $postalgmt = preg_replace('/[^- \_0-9a-zA-Z]/', '', $postalgmt); $dupcheck = preg_replace('/[^- \_0-9a-zA-Z]/', '', $dupcheck); $lead_file = preg_replace("/\<|\>|\'|\"|\\\\|;/","",$lead_file); -$vendor_lead_code_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$vendor_lead_code_field); -$source_id_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$source_id_field); -$list_id_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$list_id_field); -$phone_code_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$phone_code_field); -$phone_number_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$phone_number_field); -$title_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$title_field); -$first_name_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$first_name_field); -$middle_initial_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$middle_initial_field); -$last_name_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$last_name_field); -$address1_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$address1_field); -$address2_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$address2_field); -$address3_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$address3_field); -$city_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$city_field); -$state_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$state_field); -$province_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$province_field); -$postal_code_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$postal_code_field); -$country_code_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$country_code_field); -$gender_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$gender_field); -$date_of_birth_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$date_of_birth_field); -$alt_phone_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$alt_phone_field); -$email_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$email_field); -$security_phrase_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$security_phrase_field); -$comments_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$comments_field); -$rank_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$rank_field); -$owner_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$owner_field); +$vendor_lead_code_field = preg_replace("/[^-0-9]/",'',$vendor_lead_code_field); +$source_id_field = preg_replace("/[^-0-9]/",'',$source_id_field); +$list_id_field = preg_replace("/[^-0-9]/",'',$list_id_field); +$phone_code_field = preg_replace("/[^-0-9]/",'',$phone_code_field); +$phone_number_field = preg_replace("/[^-0-9]/",'',$phone_number_field); +$title_field = preg_replace("/[^-0-9]/",'',$title_field); +$first_name_field = preg_replace("/[^-0-9]/",'',$first_name_field); +$middle_initial_field = preg_replace("/[^-0-9]/",'',$middle_initial_field); +$last_name_field = preg_replace("/[^-0-9]/",'',$last_name_field); +$address1_field = preg_replace("/[^-0-9]/",'',$address1_field); +$address2_field = preg_replace("/[^-0-9]/",'',$address2_field); +$address3_field = preg_replace("/[^-0-9]/",'',$address3_field); +$city_field = preg_replace("/[^-0-9]/",'',$city_field); +$state_field = preg_replace("/[^-0-9]/",'',$state_field); +$province_field = preg_replace("/[^-0-9]/",'',$province_field); +$postal_code_field = preg_replace("/[^-0-9]/",'',$postal_code_field); +$country_code_field = preg_replace("/[^-0-9]/",'',$country_code_field); +$gender_field = preg_replace("/[^-0-9]/",'',$gender_field); +$date_of_birth_field = preg_replace("/[^-0-9]/",'',$date_of_birth_field); +$alt_phone_field = preg_replace("/[^-0-9]/",'',$alt_phone_field); +$email_field = preg_replace("/[^-0-9]/",'',$email_field); +$security_phrase_field = preg_replace("/[^-0-9]/",'',$security_phrase_field); +$comments_field = preg_replace("/[^-0-9]/",'',$comments_field); +$rank_field = preg_replace("/[^-0-9]/",'',$rank_field); +$owner_field = preg_replace("/[^-0-9]/",'',$owner_field); $submit_file = preg_replace('/[^-_0-9a-zA-Z]/', '', $submit_file); -$submit = preg_replace('/[^-_0-9a-zA-Z]/', '', $submit); -$SUBMIT = preg_replace('/[^-_0-9a-zA-Z]/', '', $SUBMIT); +# $submit = preg_replace('/[^-_0-9a-zA-Z]/', '', $submit); +# $SUBMIT = preg_replace('/[^-_0-9a-zA-Z]/', '', $SUBMIT); $file_layout = preg_replace('/[^-_0-9a-zA-Z]/', '', $file_layout); $OK_to_process = preg_replace('/[^- \_0-9a-zA-Z]/', '', $OK_to_process); $invalid_phone_override = preg_replace('/[^-_0-9a-zA-Z]/', '', $invalid_phone_override); +$tz_method = preg_replace('/[^-\_0-9a-zA-Z]/', '',$tz_method); +$server_ip = preg_replace('/[^-\.\:\_0-9a-zA-Z]/', '', $server_ip); # Variables filter further down in the code # $dedupe_statuses @@ -401,8 +783,8 @@ if (preg_match("/;|:|\/|\^|\[|\]|\"|\'|\*/",$LF_orig)) exit; } -$upload_error = $_FILES['leadfile']['error']; -if ($upload_error != UPLOAD_ERR_OK) +if (isset($_FILES['leadfile']['error'])) {$upload_error = $_FILES['leadfile']['error'];} +if (isset($upload_error) && $upload_error != UPLOAD_ERR_OK) { if ($upload_error == UPLOAD_ERR_INI_SIZE) { @@ -738,7 +1120,7 @@ if ( (!$OK_to_process) or ( ($leadfile) and ($file_layout!="standard" && $file_l > - + @@ -787,7 +1169,11 @@ if ( (!$OK_to_process) or ( ($leadfile) and ($file_layout!="standard" && $file_l - + + + + + \n"; echo "\t\t\n"; @@ -1054,6 +1440,7 @@ if ($OK_to_process) print ""; flush(); $total=0; $good=0; $bad=0; $dup=0; $inv=0; $post=0; $moved=0; $Tline=1; $phone_list=''; + $dup_phone_details=array(); $inv_phone_details=array(); $dnc_phone_details=array(); $listid_error_details=array(); $file=fopen("$lead_file", "r"); if ($webroot_writable > 0) @@ -1073,10 +1460,10 @@ if ($OK_to_process) $file=fopen("$lead_file", "r"); print "
"._QXZ("Processing file")."... (s-1)\n"; + $status_dedupe_str=""; $statuses_clause=""; if (is_array($dedupe_statuses) && count($dedupe_statuses)>0) { $statuses_clause=" and status in ("; - $status_dedupe_str=""; for($ds=0; $ds0) { $row=explode($delimiter, preg_replace('/[\"]/i', '', $buffer)); @@ -1222,34 +1609,34 @@ if ($OK_to_process) $modify_date = ""; $status = "NEW"; $user =""; - $vendor_lead_code = $row[$vendor_lead_code_field]; - $source_code = $row[$source_id_field]; + $vendor_lead_code = ($vendor_lead_code_field>=0 && isset($row[$vendor_lead_code_field]) ? $row[$vendor_lead_code_field] : ""); + $source_code = ($source_id_field>=0 && isset($row[$source_id_field]) ? $row[$source_id_field] : ""); $source_id=$source_code; - $list_id = $row[$list_id_field]; + $list_id = ($list_id_field>=0 && isset($row[$list_id_field]) ? $row[$list_id_field] : ""); $gmt_offset = '0'; $called_since_last_reset='N'; - $phone_code = preg_replace('/[^0-9]/i', '', $row[$phone_code_field]); - $phone_number = preg_replace('/[^0-9]/i', '', $row[$phone_number_field]); - $title = $row[$title_field]; - $first_name = $row[$first_name_field]; - $middle_initial = $row[$middle_initial_field]; - $last_name = $row[$last_name_field]; - $address1 = $row[$address1_field]; - $address2 = $row[$address2_field]; - $address3 = $row[$address3_field]; - $city =$row[$city_field]; - $state = $row[$state_field]; - $province = $row[$province_field]; - $postal_code = $row[$postal_code_field]; - $country_code = $row[$country_code_field]; - $gender = $row[$gender_field]; - $date_of_birth = $row[$date_of_birth_field]; - $alt_phone = preg_replace('/[^0-9]/i', '', $row[$alt_phone_field]); - $email = $row[$email_field]; - $security_phrase = $row[$security_phrase_field]; - $comments = trim($row[$comments_field]); - $rank = $row[$rank_field]; - $owner = $row[$owner_field]; + $phone_code = ($phone_code_field>=0 && isset($row[$phone_code_field]) ? preg_replace('/[^0-9]/i', '', $row[$phone_code_field]) : ""); + $phone_number = ($phone_number_field>=0 && isset($row[$phone_number_field]) ? preg_replace('/[^0-9]/i', '', $row[$phone_number_field]) : ""); + $title = ($title_field>=0 && isset($row[$title_field]) ? $row[$title_field] : ""); + $first_name = ($first_name_field>=0 && isset($row[$first_name_field]) ? $row[$first_name_field] : ""); + $middle_initial = ($middle_initial_field>=0 && isset($row[$middle_initial_field]) ? $row[$middle_initial_field] : ""); + $last_name = ($last_name_field>=0 && isset($row[$last_name_field]) ? $row[$last_name_field] : ""); + $address1 = ($address1_field>=0 && isset($row[$address1_field]) ? $row[$address1_field] : ""); + $address2 = ($address2_field>=0 && isset($row[$address2_field]) ? $row[$address2_field] : ""); + $address3 = ($address3_field>=0 && isset($row[$address3_field]) ? $row[$address3_field] : ""); + $city = ($city_field>=0 && isset($row[$city_field]) ? $row[$city_field] : ""); + $state = ($state_field>=0 && isset($row[$state_field]) ? $row[$state_field] : ""); + $province = ($province_field>=0 && isset($row[$province_field]) ? $row[$province_field] : ""); + $postal_code = ($postal_code_field>=0 && isset($row[$postal_code_field]) ? $row[$postal_code_field] : ""); + $country_code = ($country_code_field>=0 && isset($row[$country_code_field]) ? $row[$country_code_field] : ""); + $gender = ($gender_field>=0 && isset($row[$gender_field]) ? $row[$gender_field] : ""); + $date_of_birth = ($date_of_birth_field>=0 && isset($row[$date_of_birth_field]) ? $row[$date_of_birth_field] : ""); + $alt_phone = ($alt_phone_field>=0 && isset($row[$alt_phone_field]) ? preg_replace('/[^0-9]/i', '', $row[$alt_phone_field]) : ""); + $email = ($email_field>=0 && isset($row[$email_field]) ? $row[$email_field] : ""); + $security_phrase = ($security_phrase_field>=0 && isset($row[$security_phrase_field]) ? $row[$security_phrase_field] : ""); + $comments = ($comments_field>=0 && isset($row[$comments_field]) ? trim($row[$comments_field]) : ""); + $rank = ($rank_field>=0 && isset($row[$rank_field]) ? $row[$rank_field] : ""); + $owner = ($owner_field>=0 && isset($row[$owner_field]) ? $row[$owner_field] : ""); # replace ' " ` \ ; with nothing $vendor_lead_code = preg_replace("/$field_regx/i", "", $vendor_lead_code); @@ -1474,8 +1861,9 @@ if ($OK_to_process) } else { - if ($multi_insert_counter > 8) + if (!isset($multi_insert_counter) || $multi_insert_counter > 8) # will not be set on the first record { + if (!isset($multistmt)) {$multistmt='';} # Will happen on the first record ### insert good record into vicidial_list table ### $stmtZ = "INSERT INTO vicidial_list (lead_id,entry_date,modify_date,status,user,vendor_lead_code,source_id,list_id,gmt_offset_now,called_since_last_reset,phone_code,phone_number,title,first_name,middle_initial,last_name,address1,address2,address3,city,state,province,postal_code,country_code,gender,date_of_birth,alt_phone,email,security_phrase,comments,called_count,last_local_call_time,rank,owner,entry_list_id) values$multistmt('',\"$entry_date\",\"$modify_date\",\"$status\",\"$user\",\"$vendor_lead_code\",\"$source_id\",\"$list_id\",\"$gmt_offset\",\"$called_since_last_reset\",\"$phone_code\",\"$phone_number\",\"$title\",\"$first_name\",\"$middle_initial\",\"$last_name\",\"$address1\",\"$address2\",\"$address3\",\"$city\",\"$state\",\"$province\",\"$postal_code\",\"$country_code\",\"$gender\",\"$date_of_birth\",\"$alt_phone\",\"$email\",\"$security_phrase\",\"$comments\",0,\"2008-01-01 00:00:00\",\"$rank\",\"$owner\",'0');"; $rslt=mysql_to_mysqli($stmtZ, $link); @@ -1495,34 +1883,33 @@ if ($OK_to_process) } else { - if ($bad < 1000000) + if ( $list_id < 100 ) { - if ( $list_id < 100 ) + $listid_error_details[] = array('record' => $Tline, 'phone' => $phone_number, 'list_id' => $list_id); + } + else + { + if ($valid_number < 1) { - print "
"._QXZ("line")." $Tline "._QXZ("BAD- PHONE").": $phone_number "._QXZ("ROW").": |$row[0]| "._QXZ("INVALID LIST ID")."\n"; + $inv_phone_details[] = array('record' => $Tline, 'phone' => $phone_number, 'reason' => $invalid_reason); + } + else if ($dnc_matches > 0) + { + $dnc_phone_details[] = array('record' => $Tline, 'phone' => $phone_number, 'reason' => $invalid_reason); } else { - if ($valid_number < 1) - { - print "
"._QXZ("line")." $Tline "._QXZ("BAD- PHONE").": $phone_number "._QXZ("ROW").": |$row[0]| "._QXZ("INV").": $phone_number\n"; - } - else if ($dnc_matches > 0) - { - print "
line $Tline "._QXZ("BAD- PHONE").": $phone_number "._QXZ("ROW").": |$row[0]| "._QXZ("DNC")."($invalid_reason): $phone_number\n"; - } - else - { - print "
"._QXZ("line")." $Tline "._QXZ("BAD- PHONE").": $phone_number "._QXZ("ROW").": |$row[0]| "._QXZ("DUP").": $dup_lead $dup_lead_list\n"; - } - if ($moved_lead>0) {print "| Moved $moved_lead leads \n";} + $dup++; + if (!isset($dup_phone_details[$phone_number])) { $dup_phone_details[$phone_number] = array('count' => 0, 'lists' => array()); } + $dup_phone_details[$phone_number]['count']++; + if (strlen($dup_lead_list) > 0) { $dup_phone_details[$phone_number]['lists'][] = $dup_lead_list; } } } $bad++; } $total++; $Tline++; - if ($total%100==0) + if ($total%100==0) { print ""; usleep(1000); @@ -1530,7 +1917,7 @@ if ($OK_to_process) } } } - if ($multi_insert_counter!=0) + if (isset($multi_insert_counter) && $multi_insert_counter!=0) { $stmtZ = "INSERT INTO vicidial_list (lead_id,entry_date,modify_date,status,user,vendor_lead_code,source_id,list_id,gmt_offset_now,called_since_last_reset,phone_code,phone_number,title,first_name,middle_initial,last_name,address1,address2,address3,city,state,province,postal_code,country_code,gender,date_of_birth,alt_phone,email,security_phrase,comments,called_count,last_local_call_time,rank,owner,entry_list_id) values".substr($multistmt, 0, -1).";"; mysql_to_mysqli($stmtZ, $link); @@ -1539,15 +1926,15 @@ if ($OK_to_process) } ### LOG INSERTION Admin Log Table ### - $stmt="INSERT INTO vicidial_admin_log set event_date='$NOW_TIME', user='$PHP_AUTH_USER', ip_address='$ip', event_section='LISTS', event_type='LOAD', record_id='$list_id_override', event_code='ADMIN LOAD LIST CUSTOM', event_sql='', event_notes='File Name: $leadfile_name, GOOD: $good, BAD: $bad, MOVED: $moved, TOTAL: $total, DEBUG: dedupe_statuses:$dedupe_statuses[0]| dedupe_statuses_override:$dedupe_statuses_override| dupcheck:$dupcheck| status mismatch action: $status_mismatch_action| lead_file:$lead_file| list_id_override:$list_id_override| phone_code_override:$phone_code_override| postalgmt:$postalgmt| template_id:$template_id| usacan_check:$usacan_check| dnc_country_scrub:$international_dnc_scrub| state_conversion:$state_conversion| web_loader_phone_length:$web_loader_phone_length| web_loader_phone_strip:$SSweb_loader_phone_strip|';"; + $stmt="INSERT INTO vicidial_admin_log set event_date='$NOW_TIME', user='$PHP_AUTH_USER', ip_address='$ip', event_section='LISTS', event_type='LOAD', record_id='$list_id_override', event_code='ADMIN LOAD LIST CUSTOM', event_sql='', event_notes='File Name: $leadfile_name, GOOD: $good, BAD: $bad, MOVED: $moved, TOTAL: $total, DEBUG: dedupe_statuses:".(isset($dedupe_statuses[0]) ? $dedupe_statuses[0] : " NONE")."| dedupe_statuses_override:$dedupe_statuses_override| dupcheck:$dupcheck| status mismatch action: $status_mismatch_action| lead_file:$lead_file| list_id_override:$list_id_override| phone_code_override:$phone_code_override| postalgmt:$postalgmt| template_id:$template_id| usacan_check:$usacan_check| dnc_country_scrub:$international_dnc_scrub| state_conversion:$state_conversion| web_loader_phone_length:$web_loader_phone_length| web_loader_phone_strip:$SSweb_loader_phone_strip|';"; if ($DB) {echo "|$stmt|\n";} $rslt=mysql_to_mysqli($stmt, $link); - if ($moved>0) {$moved_str="       "._QXZ("MOVED").": $moved ";} else {$moved_str="";} + print_load_summary($good, $bad, $total, $dup, $moved, $inv, $dup_phone_details, $inv_phone_details, $dnc_phone_details, $listid_error_details); - print "

"._QXZ("Done")."
"._QXZ("GOOD").": $good       "._QXZ("BAD").": $bad $moved_str       "._QXZ("TOTAL").": $total
"; - } - else + print ""; + } + else { print "
"._QXZ("ERROR").": "._QXZ("The file does not have the required number of fields to process it").".
"; } @@ -1557,9 +1944,10 @@ if ($OK_to_process) if (($leadfile) && ($LF_path)) { $total=0; $good=0; $bad=0; $dup=0; $inv=0; $post=0; $moved=0; $Tline=1; $phone_list=''; + $dup_phone_details=array(); $inv_phone_details=array(); $dnc_phone_details=array(); $listid_error_details=array(); ### LOG INSERTION Admin Log Table ### - $stmt="INSERT INTO vicidial_admin_log set event_date='$NOW_TIME', user='$PHP_AUTH_USER', ip_address='$ip', event_section='LISTS', event_type='LOAD', record_id='$list_id_override', event_code='ADMIN LOAD LIST', event_sql='', event_notes='File Name: $leadfile_name, DEBUG: dedupe_statuses:$dedupe_statuses[0]| dedupe_statuses_override:$dedupe_statuses_override| dupcheck:$dupcheck | status mismatch action: $status_mismatch_action| lead_file:$lead_file| list_id_override:$list_id_override| phone_code_override:$phone_code_override| postalgmt:$postalgmt| template_id:$template_id| usacan_check:$usacan_check| dnc_country_scrub:$international_dnc_scrub| state_conversion:$state_conversion| web_loader_phone_length:$web_loader_phone_length| web_loader_phone_strip:$SSweb_loader_phone_strip|';"; + $stmt="INSERT INTO vicidial_admin_log set event_date='$NOW_TIME', user='$PHP_AUTH_USER', ip_address='$ip', event_section='LISTS', event_type='LOAD', record_id='$list_id_override', event_code='ADMIN LOAD LIST', event_sql='', event_notes='File Name: $leadfile_name, DEBUG: dedupe_statuses:".(isset($dedupe_statuses[0]) ? $dedupe_statuses[0] : " NONE")."| dedupe_statuses_override:$dedupe_statuses_override| dupcheck:$dupcheck | status mismatch action: $status_mismatch_action| lead_file:$lead_file| list_id_override:$list_id_override| phone_code_override:$phone_code_override| postalgmt:$postalgmt| template_id:$template_id| usacan_check:$usacan_check| dnc_country_scrub:$international_dnc_scrub| state_conversion:$state_conversion| web_loader_phone_length:$web_loader_phone_length| web_loader_phone_strip:$SSweb_loader_phone_strip|';"; if ($DB) {echo "|$stmt|\n";} $rslt=mysql_to_mysqli($stmt, $link); @@ -1687,6 +2075,7 @@ if (($leadfile) && ($LF_path)) flush(); $file=fopen("$lead_file", "r"); $total=0; $good=0; $bad=0; $dup=0; $inv=0; $post=0; $moved=0; $Tline=1; $phone_list=''; + $dup_phone_details=array(); $inv_phone_details=array(); $dnc_phone_details=array(); $listid_error_details=array(); print "
"._QXZ("Processing")." $delim_name "._QXZ("file using template")." $template_id... ($tab_count|$pipe_count) (s-2)\n"; if (strlen($list_id_override)>0) { @@ -1752,7 +2141,7 @@ if (($leadfile) && ($LF_path)) $delete_hopper_rslt=mysql_to_mysqli($delete_hopper_stmt, $link); } - + $record=0; while (!feof($file)) { $record++; @@ -1768,38 +2157,38 @@ if (($leadfile) && ($LF_path)) $modify_date = ""; $status = "NEW"; $user =""; - $vendor_lead_code = $row[$vendor_lead_code_field]; - $source_code = $row[$source_id_field]; + $vendor_lead_code = ($vendor_lead_code_field>=0 && isset($row[$vendor_lead_code_field]) ? $row[$vendor_lead_code_field] : ""); + $source_code = ($source_id_field>=0 && isset($row[$source_id_field]) ? $row[$source_id_field] : ""); $source_id=$source_code; - $list_id = $row[$list_id_field]; + $list_id = ($list_id_field>=0 && isset($row[$list_id_field]) ? $row[$list_id_field] : ""); # Added 2/9/2015 to allow dropdown to override template if ($master_list_override) { $list_id=$list_id_override; } $gmt_offset = '0'; $called_since_last_reset='N'; - $phone_code = preg_replace('/[^0-9]/i', '', $row[$phone_code_field]); - $phone_number = preg_replace('/[^0-9]/i', '', $row[$phone_number_field]); - $title = $row[$title_field]; - $first_name = $row[$first_name_field]; - $middle_initial = $row[$middle_initial_field]; - $last_name = $row[$last_name_field]; - $address1 = $row[$address1_field]; - $address2 = $row[$address2_field]; - $address3 = $row[$address3_field]; - $city =$row[$city_field]; - $state = $row[$state_field]; - $province = $row[$province_field]; - $postal_code = $row[$postal_code_field]; - $country_code = $row[$country_code_field]; - $gender = $row[$gender_field]; - $date_of_birth = $row[$date_of_birth_field]; - $alt_phone = preg_replace('/[^0-9]/i', '', $row[$alt_phone_field]); - $email = $row[$email_field]; - $security_phrase = $row[$security_phrase_field]; - $comments = trim($row[$comments_field]); - $rank = $row[$rank_field]; - $owner = $row[$owner_field]; + $phone_code = ($phone_code_field>=0 && isset($row[$phone_code_field]) ? preg_replace('/[^0-9]/i', '', $row[$phone_code_field]) : ""); + $phone_number = ($phone_number_field>=0 && isset($row[$phone_number_field]) ? preg_replace('/[^0-9]/i', '', $row[$phone_number_field]) : ""); + $title = ($title_field>=0 && isset($row[$title_field]) ? $row[$title_field] : ""); + $first_name = ($first_name_field>=0 && isset($row[$first_name_field]) ? $row[$first_name_field] : ""); + $middle_initial = ($middle_initial_field>=0 && isset($row[$middle_initial_field]) ? $row[$middle_initial_field] : ""); + $last_name = ($last_name_field>=0 && isset($row[$last_name_field]) ? $row[$last_name_field] : ""); + $address1 = ($address1_field>=0 && isset($row[$address1_field]) ? $row[$address1_field] : ""); + $address2 = ($address2_field>=0 && isset($row[$address2_field]) ? $row[$address2_field] : ""); + $address3 = ($address3_field>=0 && isset($row[$address3_field]) ? $row[$address3_field] : ""); + $city = ($city_field>=0 && isset($row[$city_field]) ? $row[$city_field] : ""); + $state = ($state_field>=0 && isset($row[$state_field]) ? $row[$state_field] : ""); + $province = ($province_field>=0 && isset($row[$province_field]) ? $row[$province_field] : ""); + $postal_code = ($postal_code_field>=0 && isset($row[$postal_code_field]) ? $row[$postal_code_field] : ""); + $country_code = ($country_code_field>=0 && isset($row[$country_code_field]) ? $row[$country_code_field] : ""); + $gender = ($gender_field>=0 && isset($row[$gender_field]) ? $row[$gender_field] : ""); + $date_of_birth = ($date_of_birth_field>=0 && isset($row[$date_of_birth_field]) ? $row[$date_of_birth_field] : ""); + $alt_phone = ($alt_phone_field>=0 && isset($row[$alt_phone_field]) ? preg_replace('/[^0-9]/i', '', $row[$alt_phone_field]) : ""); + $email = ($email_field>=0 && isset($row[$email_field]) ? $row[$email_field] : ""); + $security_phrase = ($security_phrase_field>=0 && isset($row[$security_phrase_field]) ? $row[$security_phrase_field] : ""); + $comments = ($comments_field>=0 && isset($row[$comments_field]) ? trim($row[$comments_field]) : ""); + $rank = ($rank_field>=0 && isset($row[$rank_field]) ? $row[$rank_field] : ""); + $owner = ($owner_field>=0 && isset($row[$owner_field]) ? $row[$owner_field] : ""); # replace ' " ` \ ; with nothing $vendor_lead_code = preg_replace("/$field_regx/i", "", $vendor_lead_code); @@ -2048,27 +2437,26 @@ if (($leadfile) && ($LF_path)) } else { - if ($bad < 1000000) + if ( $list_id < 100 ) { - if ( $list_id < 100 ) + $listid_error_details[] = array('record' => $Tline, 'phone' => $phone_number, 'list_id' => $list_id); + } + else + { + if ($valid_number < 1) { - print "
"._QXZ("line")." $Tline "._QXZ("BAD- PHONE").": $phone_number "._QXZ("ROW").":|$row[0]| "._QXZ("INVALID LIST ID")."\n"; + $inv_phone_details[] = array('record' => $Tline, 'phone' => $phone_number, 'reason' => $invalid_reason); + } + else if ($dnc_matches > 0) + { + $dnc_phone_details[] = array('record' => $Tline, 'phone' => $phone_number, 'reason' => $invalid_reason); } else { - if ($valid_number < 1) - { - print "
"._QXZ("line")." $Tline "._QXZ("BAD- PHONE").": $phone_number "._QXZ("ROW").":|$row[0]| "._QXZ("INV").": $phone_number\n"; - } - else if ($dnc_matches > 0) - { - print "
line $Tline "._QXZ("BAD- PHONE").": $phone_number "._QXZ("ROW").": |$row[0]| "._QXZ("DNC")."($invalid_reason): $phone_number\n"; - } - else - { - print "
"._QXZ("line")." $Tline "._QXZ("BAD- PHONE").": $phone_number "._QXZ("ROW").":|$row[0] | "._QXZ("DUP").": $dup_lead $dup_lead_list\n"; - } - if ($moved_lead>0) {print "| Moved $moved_lead leads \n";} + $dup++; + if (!isset($dup_phone_details[$phone_number])) { $dup_phone_details[$phone_number] = array('count' => 0, 'lists' => array()); } + $dup_phone_details[$phone_number]['count']++; + if (strlen($dup_lead_list) > 0) { $dup_phone_details[$phone_number]['lists'][] = $dup_lead_list; } } } $bad++; @@ -2083,7 +2471,7 @@ if (($leadfile) && ($LF_path)) } } } - if ($multi_insert_counter!=0) + if (isset($multi_insert_counter) && $multi_insert_counter!=0) { $stmtZ = "INSERT INTO vicidial_list (lead_id,entry_date,modify_date,status,user,vendor_lead_code,source_id,list_id,gmt_offset_now,called_since_last_reset,phone_code,phone_number,title,first_name,middle_initial,last_name,address1,address2,address3,city,state,province,postal_code,country_code,gender,date_of_birth,alt_phone,email,security_phrase,comments,called_count,last_local_call_time,rank,owner,entry_list_id) values".substr($multistmt, 0, -1).";"; mysql_to_mysqli($stmtZ, $link); @@ -2107,19 +2495,19 @@ if (($leadfile) && ($LF_path)) {fwrite($stmt_file, $custom_ins_stmt."\r\n");} } ### LOG INSERTION Admin Log Table ### - $stmt="INSERT INTO vicidial_admin_log set event_date='$NOW_TIME', user='$PHP_AUTH_USER', ip_address='$ip', event_section='LISTS', event_type='LOAD', record_id='$list_id_override', event_code='ADMIN LOAD LIST STANDARD', event_sql='', event_notes='File Name: $leadfile_name, GOOD: $good, BAD: $bad, MOVED: $moved, TOTAL: $total, DEBUG: dedupe_statuses:$dedupe_statuses[0]| dedupe_statuses_override:$dedupe_statuses_override| dupcheck:$dupcheck| status mismatch action: $status_mismatch_action| lead_file:$lead_file| list_id_override:$list_id_override| phone_code_override:$phone_code_override| postalgmt:$postalgmt| template_id:$template_id| usacan_check:$usacan_check| dnc_country_scrub:$international_dnc_scrub| state_conversion:$state_conversion| web_loader_phone_length:$web_loader_phone_length| web_loader_phone_strip:$SSweb_loader_phone_strip|';"; + $stmt="INSERT INTO vicidial_admin_log set event_date='$NOW_TIME', user='$PHP_AUTH_USER', ip_address='$ip', event_section='LISTS', event_type='LOAD', record_id='$list_id_override', event_code='ADMIN LOAD LIST STANDARD', event_sql='', event_notes='File Name: $leadfile_name, GOOD: $good, BAD: $bad, MOVED: $moved, TOTAL: $total, DEBUG: dedupe_statuses:".(isset($dedupe_statuses[0]) ? $dedupe_statuses[0] : " NONE")."| dedupe_statuses_override:$dedupe_statuses_override| dupcheck:$dupcheck| status mismatch action: $status_mismatch_action| lead_file:$lead_file| list_id_override:$list_id_override| phone_code_override:$phone_code_override| postalgmt:$postalgmt| template_id:$template_id| usacan_check:$usacan_check| dnc_country_scrub:$international_dnc_scrub| state_conversion:$state_conversion| web_loader_phone_length:$web_loader_phone_length| web_loader_phone_strip:$SSweb_loader_phone_strip|';"; if ($DB) {echo "|$stmt|\n";} $rslt=mysql_to_mysqli($stmt, $link); - if ($moved>0) {$moved_str="       "._QXZ("MOVED").": $moved ";} else {$moved_str="";} + print_load_summary($good, $bad, $total, $dup, $moved, $inv, $dup_phone_details, $inv_phone_details, $dnc_phone_details, $listid_error_details); - print "

"._QXZ("Done")."
"._QXZ("GOOD").": $good       "._QXZ("BAD").": $bad $moved_str       "._QXZ("TOTAL").": $total
"; + print ""; } - else + else { print "
"._QXZ("ERROR: The file does not have the required number of fields to process it").".
"; } - + } ##### BEGIN process standard file layout ##### @@ -2180,11 +2568,12 @@ if (($leadfile) && ($LF_path)) flush(); $file=fopen("$lead_file", "r"); $total=0; $good=0; $bad=0; $dup=0; $inv=0; $post=0; $moved=0; $Tline=1; $phone_list=''; + $dup_phone_details=array(); $inv_phone_details=array(); $dnc_phone_details=array(); $listid_error_details=array(); print "
"._QXZ("Processing")." $delim_name "._QXZ("file")."... ($tab_count|$pipe_count) (s-3)\n"; + $status_dedupe_str=""; $statuses_clause=""; if (count($dedupe_statuses)>0) { $statuses_clause=" and status in ("; - $status_dedupe_str=""; for($ds=0; $ds $Tline, 'phone' => $phone_number, 'list_id' => $list_id); + } + else + { + if ($valid_number < 1) { - print "
line $Tline "._QXZ("BAD- PHONE").": $phone_number "._QXZ("ROW").": |$row[0]| "._QXZ("INVALID LIST ID")."\n"; + $inv_phone_details[] = array('record' => $Tline, 'phone' => $phone_number, 'reason' => $invalid_reason); + } + else if ($dnc_matches > 0) + { + $dnc_phone_details[] = array('record' => $Tline, 'phone' => $phone_number, 'reason' => $invalid_reason); } else { - if ($valid_number < 1) - { - print "
line $Tline "._QXZ("BAD- PHONE").": $phone_number "._QXZ("ROW").": |$row[0]| "._QXZ("INV")."($invalid_reason): $phone_number\n"; - } - else if ($dnc_matches > 0) - { - print "
line $Tline "._QXZ("BAD- PHONE").": $phone_number "._QXZ("ROW").": |$row[0]| "._QXZ("DNC")."($invalid_reason): $phone_number\n"; - } - else - { - print "
line $Tline "._QXZ("BAD- PHONE").": $phone_number "._QXZ("ROW").": |$row[0]| "._QXZ("DUP").": $dup_lead $dup_lead_list\n"; - } - if ($moved_lead>0) {print "| Moved $moved_lead leads \n";} + $dup++; + if (!isset($dup_phone_details[$phone_number])) { $dup_phone_details[$phone_number] = array('count' => 0, 'lists' => array()); } + $dup_phone_details[$phone_number]['count']++; + if (strlen($dup_lead_list) > 0) { $dup_phone_details[$phone_number]['lists'][] = $dup_lead_list; } } } $bad++; @@ -2516,7 +2905,7 @@ if (($leadfile) && ($LF_path)) } } } - if ($multi_insert_counter!=0) + if (isset($multi_insert_counter) && $multi_insert_counter!=0) { $stmtZ = "INSERT INTO vicidial_list (lead_id,entry_date,modify_date,status,user,vendor_lead_code,source_id,list_id,gmt_offset_now,called_since_last_reset,phone_code,phone_number,title,first_name,middle_initial,last_name,address1,address2,address3,city,state,province,postal_code,country_code,gender,date_of_birth,alt_phone,email,security_phrase,comments,called_count,last_local_call_time,rank,owner,entry_list_id) values".substr($multistmt, 0, -1).";"; mysql_to_mysqli($stmtZ, $link); @@ -2524,13 +2913,13 @@ if (($leadfile) && ($LF_path)) {fwrite($stmt_file, $stmtZ."\r\n");} } ### LOG INSERTION Admin Log Table ### - $stmt="INSERT INTO vicidial_admin_log set event_date='$NOW_TIME', user='$PHP_AUTH_USER', ip_address='$ip', event_section='LISTS', event_type='LOAD', record_id='$list_id_override', event_code='ADMIN LOAD LIST STANDARD', event_sql='', event_notes='File Name: $leadfile_name, GOOD: $good, BAD: $bad, MOVED: $moved, TOTAL: $total, DEBUG: dedupe_statuses:$dedupe_statuses[0]| dedupe_statuses_override:$dedupe_statuses_override| dupcheck:$dupcheck| status mismatch action: $status_mismatch_action| lead_file:$lead_file| list_id_override:$list_id_override| phone_code_override:$phone_code_override| postalgmt:$postalgmt| template_id:$template_id| usacan_check:$usacan_check| dnc_country_scrub:$international_dnc_scrub| state_conversion:$state_conversion| web_loader_phone_length:$web_loader_phone_length| web_loader_phone_strip:$SSweb_loader_phone_strip|';"; + $stmt="INSERT INTO vicidial_admin_log set event_date='$NOW_TIME', user='$PHP_AUTH_USER', ip_address='$ip', event_section='LISTS', event_type='LOAD', record_id='$list_id_override', event_code='ADMIN LOAD LIST STANDARD', event_sql='', event_notes='File Name: $leadfile_name, GOOD: $good, BAD: $bad, MOVED: $moved, TOTAL: $total, DEBUG: dedupe_statuses:".(isset($dedupe_statuses[0]) ? $dedupe_statuses[0] : " NONE")."| dedupe_statuses_override:$dedupe_statuses_override| dupcheck:$dupcheck| status mismatch action: $status_mismatch_action| lead_file:$lead_file| list_id_override:$list_id_override| phone_code_override:$phone_code_override| postalgmt:$postalgmt| template_id:$template_id| usacan_check:$usacan_check| dnc_country_scrub:$international_dnc_scrub| state_conversion:$state_conversion| web_loader_phone_length:$web_loader_phone_length| web_loader_phone_strip:$SSweb_loader_phone_strip|';"; if ($DB) {echo "|$stmt|\n";} $rslt=mysql_to_mysqli($stmt, $link); - if ($moved>0) {$moved_str="       "._QXZ("MOVED").": $moved ";} else {$moved_str="";} + print_load_summary($good, $bad, $total, $dup, $moved, $inv, $dup_phone_details, $inv_phone_details, $dnc_phone_details, $listid_error_details); - print "

"._QXZ("Done")."
"._QXZ("GOOD").": $good       "._QXZ("BAD").": $bad $moved_str       "._QXZ("TOTAL").": $total
"; + print "

"._QXZ("Done")." "._QXZ("GOOD").": $good       "._QXZ("BAD").": $bad       "._QXZ("TOTAL").": $total"; # $moved_str, no longer used } else { @@ -2545,10 +2934,10 @@ if (($leadfile) && ($LF_path)) { print "
"; flush(); - print "
:
:         
: :     
: \n"; if ($available_countries>0) { - echo "\t\t\t\t\n"; + echo "\t\t\t\t\n"; echo $drop_down_dnc_options; } else { - echo "\t\t\t\t\n"; + echo "\t\t\t\t\n"; } echo " $NWB#list_loader-international_dncs$NWE
\r\n"; + print "
\r\n"; print " \r\n"; - print " \r\n"; - print " \r\n"; + print " \r\n"; + print " \r\n"; $fields_stmt = "SELECT vendor_lead_code, source_id, list_id, phone_code, phone_number, title, first_name, middle_initial, last_name, address1, address2, address3, city, state, province, postal_code, country_code, gender, date_of_birth, alt_phone, email, security_phrase, comments, rank, owner from vicidial_list limit 1"; @@ -2569,8 +2958,8 @@ if (($leadfile) && ($LF_path)) $fieldscount_to_print = $row[0]; if ($fieldscount_to_print > 0) { - $rowx=mysqli_fetch_row($rslt); - $custom_records_count = $rowx[0]; + # $rowx=mysqli_fetch_row($rslt); + # $custom_records_count = $rowx[0]; $custom_SQL=''; $stmt="SELECT field_id,field_label,field_name,field_description,field_rank,field_help,field_type,field_options,field_size,field_max,field_default,field_cost,field_required,multi_position,name_position,field_order,field_encrypt from vicidial_lists_fields where list_id='$list_id_override' and field_duplicate!='Y' order by field_rank,field_order,field_label;"; @@ -2723,27 +3112,86 @@ if (($leadfile) && ($LF_path)) $buffer=stripslashes($buffer); $row=explode($delimiter, preg_replace('/[\"]/i', '', $buffer)); + # Pre-scan all fields for auto-detection matches + $auto_detect_map = array(); + $auto_detect_scores = array(); + $temp_rslt_fields = array(); while ($fieldinfo=mysqli_fetch_field($rslt)) { - $rslt_field_name=$fieldinfo->name; + $vicidial_field_name=$fieldinfo->name; + $temp_rslt_fields[] = $vicidial_field_name; + if (!isset($field_match_scores["$vicidial_field_name"])) {$field_match_scores["$vicidial_field_name"]=0;} + } + + if ($attempt_auto_detect=="Y") + { + foreach ($temp_rslt_fields as $tf_name) + { + if ( ($tf_name=="list_id" and $list_id_override!="") or ($tf_name=="phone_code" and $phone_code_override!="") ) + { continue; } + $best_idx_score=auto_detect_field_index($tf_name, $row); + $best_idx = $best_idx_score[0]; $best_ad_score = $best_idx_score[1]; + if ($best_idx >= 0) + { + $best_score = fuzzy_match_field($row[$best_idx], $tf_name); + # Resolve conflicts: if two fields want the same column, higher score wins + if (isset($auto_detect_scores[$best_idx])) + { + if ($best_score > $auto_detect_scores[$best_idx]) + { + # Remove old mapping for this column + foreach ($auto_detect_map as $old_field => $old_idx) + { + if ($old_idx == $best_idx) { unset($auto_detect_map[$old_field]); break; } + } + $auto_detect_map[$tf_name] = $best_idx; + $auto_detect_scores[$best_idx] = $best_score; + } + } + else + { + $auto_detect_map[$tf_name] = $best_idx; + $auto_detect_scores[$best_idx] = $best_score; + } + } + } + } + $auto_count = count($auto_detect_map); + if ($auto_count > 0) + { + print " \r\n"; + } + + foreach ($temp_rslt_fields as $rslt_field_name) + { if ( ($rslt_field_name=="list_id" and $list_id_override!="") or ($rslt_field_name=="phone_code" and $phone_code_override!="") ) { print "\n"; } - else + else { - print " \r\n"; - print " \r\n"; - print " \r\n"; + $auto_indicator = ($is_auto && $field_match_scores["$rslt_field_name"]>=$min_req_score) ? " ✔" : ""; + print " \r\n"; + print " \r\n"; + print " $no_match_text\r\n"; print " \r\n"; } } diff --git a/agc_2-X/trunk/www/vicidial/admin_listloader_fourth_gen.php b/agc_2-X/trunk/www/vicidial/admin_listloader_fourth_gen.php index 602432ae..cad07789 100644 --- a/agc_2-X/trunk/www/vicidial/admin_listloader_fourth_gen.php +++ b/agc_2-X/trunk/www/vicidial/admin_listloader_fourth_gen.php @@ -2,7 +2,7 @@ # admin_listloader_fourth_gen.php - version 2.14 # (based upon - new_listloader_superL.php script) # -# Copyright (C) 2024 Matt Florell,Joe Johnson LICENSE: AGPLv2 +# Copyright (C) 2026 Matt Florell,Joe Johnson LICENSE: AGPLv2 # # ViciDial web-based lead loader from formatted file # @@ -83,10 +83,11 @@ # 231207-1445 - Fix for web_loader_phone_strip duplicate check, issue #1498 # 240320-1033 - Added misssing input variable filtering # 240801-1131 - Code updates for PHP8 compatibility +# 260415-1707 - Small field chooser fix and more code updates for PHP8 compatibility # -$version = '2.14-81'; -$build = '240801-1131'; +$version = '2.14-82'; +$build = '260415-1707'; require("dbconnect_mysqli.php"); require("functions.php"); @@ -101,110 +102,168 @@ if (file_exists('options.php')) $US='_'; $MT[0]=''; -$PHP_AUTH_USER=$_SERVER['PHP_AUTH_USER']; -$PHP_AUTH_PW=$_SERVER['PHP_AUTH_PW']; +$PHP_AUTH_USER=(array_key_exists('PHP_AUTH_USER', $_SERVER) ? $_SERVER['PHP_AUTH_USER'] : ""); +$PHP_AUTH_PW=(array_key_exists('PHP_AUTH_PW', $_SERVER) ? $_SERVER['PHP_AUTH_PW'] : ""); $PHP_SELF=$_SERVER['PHP_SELF']; $PHP_SELF = preg_replace('/\.php.*/i','.php',$PHP_SELF); -$leadfile=$_FILES["leadfile"]; +if (array_key_exists('leadfile', $_FILES)) + { + $leadfile=$_FILES["leadfile"]; $LF_orig = $_FILES['leadfile']['name']; $LF_path = $_FILES['leadfile']['tmp_name']; + } +else + { + $leadfile=""; + $LF_orig = ""; + $LF_path = ""; + } if (isset($_GET["submit_file"])) {$submit_file=$_GET["submit_file"];} elseif (isset($_POST["submit_file"])) {$submit_file=$_POST["submit_file"];} -if (isset($_GET["submit"])) {$submit=$_GET["submit"];} - elseif (isset($_POST["submit"])) {$submit=$_POST["submit"];} -if (isset($_GET["SUBMIT"])) {$SUBMIT=$_GET["SUBMIT"];} - elseif (isset($_POST["SUBMIT"])) {$SUBMIT=$_POST["SUBMIT"];} + else {$submit_file="";} +# if (isset($_GET["submit"])) {$submit=$_GET["submit"];} +# elseif (isset($_POST["submit"])) {$submit=$_POST["submit"];} +# if (isset($_GET["SUBMIT"])) {$SUBMIT=$_GET["SUBMIT"];} +# elseif (isset($_POST["SUBMIT"])) {$SUBMIT=$_POST["SUBMIT"];} if (isset($_GET["leadfile_name"])) {$leadfile_name=$_GET["leadfile_name"];} elseif (isset($_POST["leadfile_name"])) {$leadfile_name=$_POST["leadfile_name"];} + else {$leadfile_name="";} if (isset($_FILES["leadfile"])) {$leadfile_name=$_FILES["leadfile"]['name'];} if (isset($_GET["file_layout"])) {$file_layout=$_GET["file_layout"];} elseif (isset($_POST["file_layout"])) {$file_layout=$_POST["file_layout"];} + else {$file_layout="";} if (isset($_GET["OK_to_process"])) {$OK_to_process=$_GET["OK_to_process"];} elseif (isset($_POST["OK_to_process"])) {$OK_to_process=$_POST["OK_to_process"];} + else {$OK_to_process="";} if (isset($_GET["vendor_lead_code_field"])) {$vendor_lead_code_field=$_GET["vendor_lead_code_field"];} elseif (isset($_POST["vendor_lead_code_field"])) {$vendor_lead_code_field=$_POST["vendor_lead_code_field"];} + else {$vendor_lead_code_field="-1";} if (isset($_GET["source_id_field"])) {$source_id_field=$_GET["source_id_field"];} elseif (isset($_POST["source_id_field"])) {$source_id_field=$_POST["source_id_field"];} + else {$source_id_field="-1";} if (isset($_GET["list_id_field"])) {$list_id_field=$_GET["list_id_field"];} elseif (isset($_POST["list_id_field"])) {$list_id_field=$_POST["list_id_field"];} + else {$list_id_field="-1";} if (isset($_GET["phone_code_field"])) {$phone_code_field=$_GET["phone_code_field"];} elseif (isset($_POST["phone_code_field"])) {$phone_code_field=$_POST["phone_code_field"];} + else {$phone_code_field="-1";} if (isset($_GET["phone_number_field"])) {$phone_number_field=$_GET["phone_number_field"];} elseif (isset($_POST["phone_number_field"])) {$phone_number_field=$_POST["phone_number_field"];} + else {$phone_number_field="-1";} if (isset($_GET["title_field"])) {$title_field=$_GET["title_field"];} elseif (isset($_POST["title_field"])) {$title_field=$_POST["title_field"];} + else {$title_field="-1";} if (isset($_GET["first_name_field"])) {$first_name_field=$_GET["first_name_field"];} elseif (isset($_POST["first_name_field"])) {$first_name_field=$_POST["first_name_field"];} + else {$first_name_field="-1";} if (isset($_GET["middle_initial_field"])) {$middle_initial_field=$_GET["middle_initial_field"];} elseif (isset($_POST["middle_initial_field"])) {$middle_initial_field=$_POST["middle_initial_field"];} + else {$middle_initial_field="-1";} if (isset($_GET["last_name_field"])) {$last_name_field=$_GET["last_name_field"];} elseif (isset($_POST["last_name_field"])) {$last_name_field=$_POST["last_name_field"];} + else {$last_name_field="-1";} if (isset($_GET["address1_field"])) {$address1_field=$_GET["address1_field"];} elseif (isset($_POST["address1_field"])) {$address1_field=$_POST["address1_field"];} + else {$address1_field="-1";} if (isset($_GET["address2_field"])) {$address2_field=$_GET["address2_field"];} elseif (isset($_POST["address2_field"])) {$address2_field=$_POST["address2_field"];} + else {$address2_field="-1";} if (isset($_GET["address3_field"])) {$address3_field=$_GET["address3_field"];} elseif (isset($_POST["address3_field"])) {$address3_field=$_POST["address3_field"];} + else {$address3_field="-1";} if (isset($_GET["city_field"])) {$city_field=$_GET["city_field"];} elseif (isset($_POST["city_field"])) {$city_field=$_POST["city_field"];} + else {$city_field="-1";} if (isset($_GET["state_field"])) {$state_field=$_GET["state_field"];} elseif (isset($_POST["state_field"])) {$state_field=$_POST["state_field"];} + else {$state_field="-1";} if (isset($_GET["province_field"])) {$province_field=$_GET["province_field"];} elseif (isset($_POST["province_field"])) {$province_field=$_POST["province_field"];} + else {$province_field="-1";} if (isset($_GET["postal_code_field"])) {$postal_code_field=$_GET["postal_code_field"];} elseif (isset($_POST["postal_code_field"])) {$postal_code_field=$_POST["postal_code_field"];} + else {$postal_code_field="-1";} if (isset($_GET["country_code_field"])) {$country_code_field=$_GET["country_code_field"];} elseif (isset($_POST["country_code_field"])) {$country_code_field=$_POST["country_code_field"];} + else {$country_code_field="-1";} if (isset($_GET["gender_field"])) {$gender_field=$_GET["gender_field"];} elseif (isset($_POST["gender_field"])) {$gender_field=$_POST["gender_field"];} + else {$gender_field="-1";} if (isset($_GET["date_of_birth_field"])) {$date_of_birth_field=$_GET["date_of_birth_field"];} elseif (isset($_POST["date_of_birth_field"])) {$date_of_birth_field=$_POST["date_of_birth_field"];} + else {$date_of_birth_field="-1";} if (isset($_GET["alt_phone_field"])) {$alt_phone_field=$_GET["alt_phone_field"];} elseif (isset($_POST["alt_phone_field"])) {$alt_phone_field=$_POST["alt_phone_field"];} + else {$alt_phone_field="-1";} if (isset($_GET["email_field"])) {$email_field=$_GET["email_field"];} elseif (isset($_POST["email_field"])) {$email_field=$_POST["email_field"];} + else {$email_field="-1";} if (isset($_GET["security_phrase_field"])) {$security_phrase_field=$_GET["security_phrase_field"];} elseif (isset($_POST["security_phrase_field"])) {$security_phrase_field=$_POST["security_phrase_field"];} + else {$security_phrase_field="-1";} if (isset($_GET["comments_field"])) {$comments_field=$_GET["comments_field"];} elseif (isset($_POST["comments_field"])) {$comments_field=$_POST["comments_field"];} + else {$comments_field="-1";} if (isset($_GET["rank_field"])) {$rank_field=$_GET["rank_field"];} elseif (isset($_POST["rank_field"])) {$rank_field=$_POST["rank_field"];} + else {$rank_field="-1";} if (isset($_GET["owner_field"])) {$owner_field=$_GET["owner_field"];} elseif (isset($_POST["owner_field"])) {$owner_field=$_POST["owner_field"];} + else {$owner_field="-1";} if (isset($_GET["list_id_override"])) {$list_id_override=$_GET["list_id_override"];} elseif (isset($_POST["list_id_override"])) {$list_id_override=$_POST["list_id_override"];} + else {$list_id_override="";} $list_id_override = (preg_replace("/\D/","",$list_id_override)); if (isset($_GET["master_list_override"])) {$master_list_override=$_GET["master_list_override"];} elseif (isset($_POST["master_list_override"])) {$master_list_override=$_POST["master_list_override"];} + else {$master_list_override="";} if (isset($_GET["lead_file"])) {$lead_file=$_GET["lead_file"];} elseif (isset($_POST["lead_file"])) {$lead_file=$_POST["lead_file"];} + else {$lead_file="";} if (isset($_GET["dupcheck"])) {$dupcheck=$_GET["dupcheck"];} elseif (isset($_POST["dupcheck"])) {$dupcheck=$_POST["dupcheck"];} + else {$dupcheck="";} if (isset($_GET["dedupe_statuses"])) {$dedupe_statuses=$_GET["dedupe_statuses"];} elseif (isset($_POST["dedupe_statuses"])) {$dedupe_statuses=$_POST["dedupe_statuses"];} + else {$dedupe_statuses="";} if (isset($_GET["dedupe_statuses_override"])) {$dedupe_statuses_override=$_GET["dedupe_statuses_override"];} elseif (isset($_POST["dedupe_statuses_override"])) {$dedupe_statuses_override=$_POST["dedupe_statuses_override"];} + else {$dedupe_statuses_override="";} if (isset($_GET["status_mismatch_action"])) {$status_mismatch_action=$_GET["status_mismatch_action"];} elseif (isset($_POST["status_mismatch_action"])) {$status_mismatch_action=$_POST["status_mismatch_action"];} + else {$status_mismatch_action="";} if (isset($_GET["postalgmt"])) {$postalgmt=$_GET["postalgmt"];} elseif (isset($_POST["postalgmt"])) {$postalgmt=$_POST["postalgmt"];} + else {$postalgmt="";} if (isset($_GET["phone_code_override"])) {$phone_code_override=$_GET["phone_code_override"];} elseif (isset($_POST["phone_code_override"])) {$phone_code_override=$_POST["phone_code_override"];} + else {$phone_code_override="";} $phone_code_override = (preg_replace("/\D/","",$phone_code_override)); if (isset($_GET["DB"])) {$DB=$_GET["DB"];} elseif (isset($_POST["DB"])) {$DB=$_POST["DB"];} +if (isset($_GET["DBX"])) {$DBX=$_GET["DBX"];} + elseif (isset($_POST["DBX"])) {$DBX=$_POST["DBX"];} if (isset($_GET["template_id"])) {$template_id=$_GET["template_id"];} elseif (isset($_POST["template_id"])) {$template_id=$_POST["template_id"];} + else {$template_id="";} if (isset($_GET["usacan_check"])) {$usacan_check=$_GET["usacan_check"];} elseif (isset($_POST["usacan_check"])) {$usacan_check=$_POST["usacan_check"];} + else {$usacan_check="";} if (isset($_GET["state_conversion"])) {$state_conversion=$_GET["state_conversion"];} elseif (isset($_POST["state_conversion"])) {$state_conversion=$_POST["state_conversion"];} + else {$state_conversion="";} if (isset($_GET["web_loader_phone_length"])) {$web_loader_phone_length=$_GET["web_loader_phone_length"];} elseif (isset($_POST["web_loader_phone_length"])) {$web_loader_phone_length=$_POST["web_loader_phone_length"];} + else {$web_loader_phone_length=0;} if (isset($_GET["international_dnc_scrub"])) {$international_dnc_scrub=$_GET["international_dnc_scrub"];} elseif (isset($_POST["international_dnc_scrub"])) {$international_dnc_scrub=$_POST["international_dnc_scrub"];} - -$DB=preg_replace("/[^0-9a-zA-Z]/","",$DB); + else {$international_dnc_scrub="";} +if (isset($_GET["tz_method"])) {$tz_method=$_GET["tz_method"];} + elseif (isset($_POST["tz_method"])) {$tz_method=$_POST["tz_method"];} + else {$tz_method="";} +if (isset($_GET["server_ip"])) {$server_ip=$_GET["server_ip"];} + elseif (isset($_POST["server_ip"])) {$server_ip=$_POST["server_ip"];} + else {$server_ip="";} # if the didnt select an over ride wipe out in_file if ( $list_id_override == "in_file" ) { $list_id_override = ""; } @@ -221,7 +280,6 @@ $vicidial_list_fields = '|lead_id|vendor_lead_code|source_id|list_id|gmt_offset_ ##### START SYSTEM_SETTINGS LOOKUP ##### $stmt = "SELECT use_non_latin,admin_web_directory,custom_fields_enabled,webroot_writable,enable_languages,language_method,active_modules,admin_screen_colors,web_loader_phone_length,enable_international_dncs,web_loader_phone_strip,allow_web_debug FROM system_settings;"; $rslt=mysql_to_mysqli($stmt, $link); -if ($DB) {echo "$stmt\n";} $qm_conf_ct = mysqli_num_rows($rslt); #if ($qm_conf_ct > 0) { @@ -239,7 +297,9 @@ $qm_conf_ct = mysqli_num_rows($rslt); $SSweb_loader_phone_strip = $row[10]; $SSallow_web_debug = $row[11]; } -if ($SSallow_web_debug < 1) {$DB=0;} +if ($SSallow_web_debug < 1 || !isset($DB)) {$DB=0;} +$DB=preg_replace("/[^0-9a-zA-Z]/","",$DB); +$DBX=0; # Always set - used in lookup_gmt, where you will have to override via hard-coding ##### END SETTINGS LOOKUP ##### ########################################### @@ -254,36 +314,38 @@ $status_mismatch_action = preg_replace('/[^- \_0-9a-zA-Z]/', '', $status_mismatc $postalgmt = preg_replace('/[^- \_0-9a-zA-Z]/', '', $postalgmt); $dupcheck = preg_replace('/[^- \_0-9a-zA-Z]/', '', $dupcheck); $lead_file = preg_replace("/\<|\>|\'|\"|\\\\|;/","",$lead_file); -$vendor_lead_code_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$vendor_lead_code_field); -$source_id_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$source_id_field); -$list_id_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$list_id_field); -$phone_code_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$phone_code_field); -$phone_number_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$phone_number_field); -$title_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$title_field); -$first_name_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$first_name_field); -$middle_initial_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$middle_initial_field); -$last_name_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$last_name_field); -$address1_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$address1_field); -$address2_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$address2_field); -$address3_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$address3_field); -$city_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$city_field); -$state_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$state_field); -$province_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$province_field); -$postal_code_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$postal_code_field); -$country_code_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$country_code_field); -$gender_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$gender_field); -$date_of_birth_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$date_of_birth_field); -$alt_phone_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$alt_phone_field); -$email_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$email_field); -$security_phrase_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$security_phrase_field); -$comments_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$comments_field); -$rank_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$rank_field); -$owner_field = preg_replace("/\<|\>|\'|\"|\\\\|;/",'',$owner_field); +$vendor_lead_code_field = preg_replace("/[^-0-9]/",'',$vendor_lead_code_field); +$source_id_field = preg_replace("/[^-0-9]/",'',$source_id_field); +$list_id_field = preg_replace("/[^-0-9]/",'',$list_id_field); +$phone_code_field = preg_replace("/[^-0-9]/",'',$phone_code_field); +$phone_number_field = preg_replace("/[^-0-9]/",'',$phone_number_field); +$title_field = preg_replace("/[^-0-9]/",'',$title_field); +$first_name_field = preg_replace("/[^-0-9]/",'',$first_name_field); +$middle_initial_field = preg_replace("/[^-0-9]/",'',$middle_initial_field); +$last_name_field = preg_replace("/[^-0-9]/",'',$last_name_field); +$address1_field = preg_replace("/[^-0-9]/",'',$address1_field); +$address2_field = preg_replace("/[^-0-9]/",'',$address2_field); +$address3_field = preg_replace("/[^-0-9]/",'',$address3_field); +$city_field = preg_replace("/[^-0-9]/",'',$city_field); +$state_field = preg_replace("/[^-0-9]/",'',$state_field); +$province_field = preg_replace("/[^-0-9]/",'',$province_field); +$postal_code_field = preg_replace("/[^-0-9]/",'',$postal_code_field); +$country_code_field = preg_replace("/[^-0-9]/",'',$country_code_field); +$gender_field = preg_replace("/[^-0-9]/",'',$gender_field); +$date_of_birth_field = preg_replace("/[^-0-9]/",'',$date_of_birth_field); +$alt_phone_field = preg_replace("/[^-0-9]/",'',$alt_phone_field); +$email_field = preg_replace("/[^-0-9]/",'',$email_field); +$security_phrase_field = preg_replace("/[^-0-9]/",'',$security_phrase_field); +$comments_field = preg_replace("/[^-0-9]/",'',$comments_field); +$rank_field = preg_replace("/[^-0-9]/",'',$rank_field); +$owner_field = preg_replace("/[^-0-9]/",'',$owner_field); $submit_file = preg_replace('/[^-_0-9a-zA-Z]/', '', $submit_file); -$submit = preg_replace('/[^-_0-9a-zA-Z]/', '', $submit); -$SUBMIT = preg_replace('/[^-_0-9a-zA-Z]/', '', $SUBMIT); +# $submit = preg_replace('/[^-_0-9a-zA-Z]/', '', $submit); +# $SUBMIT = preg_replace('/[^-_0-9a-zA-Z]/', '', $SUBMIT); $file_layout = preg_replace('/[^-_0-9a-zA-Z]/', '', $file_layout); $OK_to_process = preg_replace('/[^- \_0-9a-zA-Z]/', '', $OK_to_process); +$tz_method = preg_replace('/[^-\_0-9a-zA-Z]/', '',$tz_method); +$server_ip = preg_replace('/[^-\.\:\_0-9a-zA-Z]/', '', $server_ip); # Variables filter further down in the code # $dedupe_statuses @@ -397,8 +459,8 @@ if (preg_match("/;|:|\/|\^|\[|\]|\"|\'|\*/",$LF_orig)) exit; } -$upload_error = $_FILES['leadfile']['error']; -if ($upload_error != UPLOAD_ERR_OK) +if (isset($_FILES['leadfile']['error'])) {$upload_error = $_FILES['leadfile']['error'];} +if (isset($upload_error) && $upload_error != UPLOAD_ERR_OK) { if ($upload_error == UPLOAD_ERR_INI_SIZE) { @@ -734,7 +796,7 @@ if ( (!$OK_to_process) or ( ($leadfile) and ($file_layout!="standard" && $file_l
"._QXZ("VICIDIAL Column").""._QXZ("File data").""._QXZ("VICIDIAL Column").""._QXZ("File data")."\r\n"; print "
"._QXZ("Auto-detected")." $auto_count "._QXZ("field mappings from file headers")." (min req. score: $min_req_score) $NWB#listloader-autodetect$NWE
".strtoupper(preg_replace('/_/i', ' ', $rslt_field_name)).":
".strtoupper(preg_replace('/_/i', ' ', $rslt_field_name))."$auto_indicator:
> - + @@ -783,7 +845,7 @@ if ( (!$OK_to_process) or ( ($leadfile) and ($file_layout!="standard" && $file_l - + \n"; echo "\t\t\n"; @@ -1025,10 +1087,10 @@ if ($OK_to_process) $file=fopen("$lead_file", "r"); print "
"._QXZ("Processing file")."...\n"; + $status_dedupe_str=""; $statuses_clause=""; if (is_array($dedupe_statuses) && count($dedupe_statuses)>0) { $statuses_clause=" and status in ("; - $status_dedupe_str=""; for($ds=0; $ds=0 && isset($row[$vendor_lead_code_field]) ? $row[$vendor_lead_code_field] : ""); + $source_code = ($source_id_field>=0 && isset($row[$source_id_field]) ? $row[$source_id_field] : ""); $source_id=$source_code; - $list_id = $row[$list_id_field]; + $list_id = ($list_id_field>=0 && isset($row[$list_id_field]) ? $row[$list_id_field] : ""); $gmt_offset = '0'; $called_since_last_reset='N'; - $phone_code = preg_replace('/[^0-9]/i', '', $row[$phone_code_field]); - $phone_number = preg_replace('/[^0-9]/i', '', $row[$phone_number_field]); - $title = $row[$title_field]; - $first_name = $row[$first_name_field]; - $middle_initial = $row[$middle_initial_field]; - $last_name = $row[$last_name_field]; - $address1 = $row[$address1_field]; - $address2 = $row[$address2_field]; - $address3 = $row[$address3_field]; - $city =$row[$city_field]; - $state = $row[$state_field]; - $province = $row[$province_field]; - $postal_code = $row[$postal_code_field]; - $country_code = $row[$country_code_field]; - $gender = $row[$gender_field]; - $date_of_birth = $row[$date_of_birth_field]; - $alt_phone = preg_replace('/[^0-9]/i', '', $row[$alt_phone_field]); - $email = $row[$email_field]; - $security_phrase = $row[$security_phrase_field]; - $comments = trim($row[$comments_field]); - $rank = $row[$rank_field]; - $owner = $row[$owner_field]; + $phone_code = ($phone_code_field>=0 && isset($row[$phone_code_field]) ? preg_replace('/[^0-9]/i', '', $row[$phone_code_field]) : ""); + $phone_number = ($phone_number_field>=0 && isset($row[$phone_number_field]) ? preg_replace('/[^0-9]/i', '', $row[$phone_number_field]) : ""); + $title = ($title_field>=0 && isset($row[$title_field]) ? $row[$title_field] : ""); + $first_name = ($first_name_field>=0 && isset($row[$first_name_field]) ? $row[$first_name_field] : ""); + $middle_initial = ($middle_initial_field>=0 && isset($row[$middle_initial_field]) ? $row[$middle_initial_field] : ""); + $last_name = ($last_name_field>=0 && isset($row[$last_name_field]) ? $row[$last_name_field] : ""); + $address1 = ($address1_field>=0 && isset($row[$address1_field]) ? $row[$address1_field] : ""); + $address2 = ($address2_field>=0 && isset($row[$address2_field]) ? $row[$address2_field] : ""); + $address3 = ($address3_field>=0 && isset($row[$address3_field]) ? $row[$address3_field] : ""); + $city = ($city_field>=0 && isset($row[$city_field]) ? $row[$city_field] : ""); + $state = ($state_field>=0 && isset($row[$state_field]) ? $row[$state_field] : ""); + $province = ($province_field>=0 && isset($row[$province_field]) ? $row[$province_field] : ""); + $postal_code = ($postal_code_field>=0 && isset($row[$postal_code_field]) ? $row[$postal_code_field] : ""); + $country_code = ($country_code_field>=0 && isset($row[$country_code_field]) ? $row[$country_code_field] : ""); + $gender = ($gender_field>=0 && isset($row[$gender_field]) ? $row[$gender_field] : ""); + $date_of_birth = ($date_of_birth_field>=0 && isset($row[$date_of_birth_field]) ? $row[$date_of_birth_field] : ""); + $alt_phone = ($alt_phone_field>=0 && isset($row[$alt_phone_field]) ? preg_replace('/[^0-9]/i', '', $row[$alt_phone_field]) : ""); + $email = ($email_field>=0 && isset($row[$email_field]) ? $row[$email_field] : ""); + $security_phrase = ($security_phrase_field>=0 && isset($row[$security_phrase_field]) ? $row[$security_phrase_field] : ""); + $comments = ($comments_field>=0 && isset($row[$comments_field]) ? trim($row[$comments_field]) : ""); + $rank = ($rank_field>=0 && isset($row[$rank_field]) ? $row[$rank_field] : ""); + $owner = ($owner_field>=0 && isset($row[$owner_field]) ? $row[$owner_field] : ""); # replace ' " ` \ ; with nothing $vendor_lead_code = preg_replace("/$field_regx/i", "", $vendor_lead_code); @@ -1323,10 +1386,10 @@ if ($OK_to_process) $phone_number = preg_replace("/^$SSweb_loader_phone_strip/",'',$phone_number); } + $dup_lead=0; $moved_lead=0; ##### Check for duplicate phone numbers in vicidial_list table for all lists in a campaign ##### if (preg_match("/DUPCAMP/i",$dupcheck)) { - $dup_lead=0; $moved_lead=0; $dup_lists=''; $stmt="SELECT campaign_id from vicidial_lists where list_id='$list_id';"; $rslt=mysql_to_mysqli($stmt, $link); @@ -1399,8 +1462,6 @@ if ($OK_to_process) ##### Check for duplicate phone numbers in vicidial_list table entire database ##### if (preg_match("/DUPSYS/i",$dupcheck)) { - $dup_lead=0; $moved_lead=0; - if ($status_mismatch_action) { if (preg_match('/USING CHECK/', $status_mismatch_action)) @@ -1450,8 +1511,6 @@ if ($OK_to_process) ##### Check for duplicate phone numbers in vicidial_list table for one list_id ##### if (preg_match("/DUPLIST/i",$dupcheck)) { - $dup_lead=0; $moved_lead=0; - if ($status_mismatch_action) { if (preg_match('/USING CHECK/', $status_mismatch_action)) @@ -1499,8 +1558,6 @@ if ($OK_to_process) ##### Check for duplicate title and alt-phone in vicidial_list table for one list_id ##### if (preg_match("/DUPTITLEALTPHONELIST/i",$dupcheck)) { - $dup_lead=0; $moved_lead=0; - if ($status_mismatch_action) { if (preg_match('/USING CHECK/', $status_mismatch_action)) @@ -1548,7 +1605,6 @@ if ($OK_to_process) ##### Check for duplicate phone numbers in vicidial_list table entire database ##### if (preg_match("/DUPTITLEALTPHONESYS/i",$dupcheck)) { - $dup_lead=0; $moved_lead=0; if ($status_mismatch_action) { @@ -1643,6 +1699,7 @@ if ($OK_to_process) $invalid_reason = _QXZ("INVALID PHONE NUMBER NANPA AREACODE PREFIX"); } } + $dnc_matches=0; if ($international_dnc_scrub and $valid_number > 0) { $dnc_table_name="vicidial_dnc_".$international_dnc_scrub; @@ -1684,8 +1741,9 @@ if ($OK_to_process) } else { - if ($multi_insert_counter > 8) + if (!isset($multi_insert_counter) || $multi_insert_counter > 8) # will not be set on the first record { + if (!isset($multistmt)) {$multistmt='';} # Will happen on the first record ### insert good record into vicidial_list table ### $stmtZ = "INSERT INTO vicidial_list (lead_id,entry_date,modify_date,status,user,vendor_lead_code,source_id,list_id,gmt_offset_now,called_since_last_reset,phone_code,phone_number,title,first_name,middle_initial,last_name,address1,address2,address3,city,state,province,postal_code,country_code,gender,date_of_birth,alt_phone,email,security_phrase,comments,called_count,last_local_call_time,rank,owner,entry_list_id) values$multistmt('',\"$entry_date\",\"$modify_date\",\"$status\",\"$user\",\"$vendor_lead_code\",\"$source_id\",\"$list_id\",\"$gmt_offset\",\"$called_since_last_reset\",\"$phone_code\",\"$phone_number\",\"$title\",\"$first_name\",\"$middle_initial\",\"$last_name\",\"$address1\",\"$address2\",\"$address3\",\"$city\",\"$state\",\"$province\",\"$postal_code\",\"$country_code\",\"$gender\",\"$date_of_birth\",\"$alt_phone\",\"$email\",\"$security_phrase\",\"$comments\",0,\"2008-01-01 00:00:00\",\"$rank\",\"$owner\",'0');"; $rslt=mysql_to_mysqli($stmtZ, $link); @@ -1738,7 +1796,7 @@ if ($OK_to_process) } } } - if ($multi_insert_counter!=0) + if (isset($multi_insert_counter) && $multi_insert_counter!=0) { $stmtZ = "INSERT INTO vicidial_list (lead_id,entry_date,modify_date,status,user,vendor_lead_code,source_id,list_id,gmt_offset_now,called_since_last_reset,phone_code,phone_number,title,first_name,middle_initial,last_name,address1,address2,address3,city,state,province,postal_code,country_code,gender,date_of_birth,alt_phone,email,security_phrase,comments,called_count,last_local_call_time,rank,owner,entry_list_id) values".substr($multistmt, 0, -1).";"; mysql_to_mysqli($stmtZ, $link); @@ -1747,7 +1805,7 @@ if ($OK_to_process) } ### LOG INSERTION Admin Log Table ### - $stmt="INSERT INTO vicidial_admin_log set event_date='$NOW_TIME', user='$PHP_AUTH_USER', ip_address='$ip', event_section='LISTS', event_type='LOAD', record_id='$list_id_override', event_code='ADMIN LOAD LIST CUSTOM', event_sql='', event_notes='File Name: $leadfile_name, GOOD: $good, BAD: $bad, MOVED: $moved, TOTAL: $total, DEBUG: dedupe_statuses:$dedupe_statuses[0]| dedupe_statuses_override:$dedupe_statuses_override| dupcheck:$dupcheck| status mismatch action: $status_mismatch_action| lead_file:$lead_file| list_id_override:$list_id_override| phone_code_override:$phone_code_override| postalgmt:$postalgmt| template_id:$template_id| usacan_check:$usacan_check| dnc_country_scrub:$international_dnc_scrub| state_conversion:$state_conversion| web_loader_phone_length:$web_loader_phone_length| web_loader_phone_strip:$SSweb_loader_phone_strip|';"; + $stmt="INSERT INTO vicidial_admin_log set event_date='$NOW_TIME', user='$PHP_AUTH_USER', ip_address='$ip', event_section='LISTS', event_type='LOAD', record_id='$list_id_override', event_code='ADMIN LOAD LIST CUSTOM', event_sql='', event_notes='File Name: $leadfile_name, GOOD: $good, BAD: $bad, MOVED: $moved, TOTAL: $total, DEBUG: dedupe_statuses:".(isset($dedupe_statuses[0]) ? $dedupe_statuses[0] : " NONE")."| dedupe_statuses_override:$dedupe_statuses_override| dupcheck:$dupcheck| status mismatch action: $status_mismatch_action| lead_file:$lead_file| list_id_override:$list_id_override| phone_code_override:$phone_code_override| postalgmt:$postalgmt| template_id:$template_id| usacan_check:$usacan_check| dnc_country_scrub:$international_dnc_scrub| state_conversion:$state_conversion| web_loader_phone_length:$web_loader_phone_length| web_loader_phone_strip:$SSweb_loader_phone_strip|';"; if ($DB) {echo "|$stmt|\n";} $rslt=mysql_to_mysqli($stmt, $link); @@ -1767,7 +1825,7 @@ if (($leadfile) && ($LF_path)) $total=0; $good=0; $bad=0; $dup=0; $inv=0; $post=0; $moved=0; $phone_list=''; ### LOG INSERTION Admin Log Table ### - $stmt="INSERT INTO vicidial_admin_log set event_date='$NOW_TIME', user='$PHP_AUTH_USER', ip_address='$ip', event_section='LISTS', event_type='LOAD', record_id='$list_id_override', event_code='ADMIN LOAD LIST', event_sql='', event_notes='File Name: $leadfile_name, DEBUG: dedupe_statuses:$dedupe_statuses[0]| dedupe_statuses_override:$dedupe_statuses_override| dupcheck:$dupcheck | status mismatch action: $status_mismatch_action| lead_file:$lead_file| list_id_override:$list_id_override| phone_code_override:$phone_code_override| postalgmt:$postalgmt| template_id:$template_id| usacan_check:$usacan_check| dnc_country_scrub:$international_dnc_scrub| state_conversion:$state_conversion| web_loader_phone_length:$web_loader_phone_length| web_loader_phone_strip:$SSweb_loader_phone_strip|';"; + $stmt="INSERT INTO vicidial_admin_log set event_date='$NOW_TIME', user='$PHP_AUTH_USER', ip_address='$ip', event_section='LISTS', event_type='LOAD', record_id='$list_id_override', event_code='ADMIN LOAD LIST', event_sql='', event_notes='File Name: $leadfile_name, DEBUG: dedupe_statuses:".(isset($dedupe_statuses[0]) ? $dedupe_statuses[0] : " NONE")."| dedupe_statuses_override:$dedupe_statuses_override| dupcheck:$dupcheck | status mismatch action: $status_mismatch_action| lead_file:$lead_file| list_id_override:$list_id_override| phone_code_override:$phone_code_override| postalgmt:$postalgmt| template_id:$template_id| usacan_check:$usacan_check| dnc_country_scrub:$international_dnc_scrub| state_conversion:$state_conversion| web_loader_phone_length:$web_loader_phone_length| web_loader_phone_strip:$SSweb_loader_phone_strip|';"; if ($DB) {echo "|$stmt|\n";} $rslt=mysql_to_mysqli($stmt, $link); @@ -1972,38 +2030,38 @@ if (($leadfile) && ($LF_path)) $modify_date = ""; $status = "NEW"; $user =""; - $vendor_lead_code = $row[$vendor_lead_code_field]; - $source_code = $row[$source_id_field]; + $vendor_lead_code = ($vendor_lead_code_field>=0 && isset($row[$vendor_lead_code_field]) ? $row[$vendor_lead_code_field] : ""); + $source_code = ($source_id_field>=0 && isset($row[$source_id_field]) ? $row[$source_id_field] : ""); $source_id=$source_code; - $list_id = $row[$list_id_field]; + $list_id = ($list_id_field>=0 && isset($row[$list_id_field]) ? $row[$list_id_field] : ""); # Added 2/9/2015 to allow dropdown to override template if ($master_list_override) { $list_id=$list_id_override; } $gmt_offset = '0'; $called_since_last_reset='N'; - $phone_code = preg_replace('/[^0-9]/i', '', $row[$phone_code_field]); - $phone_number = preg_replace('/[^0-9]/i', '', $row[$phone_number_field]); - $title = $row[$title_field]; - $first_name = $row[$first_name_field]; - $middle_initial = $row[$middle_initial_field]; - $last_name = $row[$last_name_field]; - $address1 = $row[$address1_field]; - $address2 = $row[$address2_field]; - $address3 = $row[$address3_field]; - $city =$row[$city_field]; - $state = $row[$state_field]; - $province = $row[$province_field]; - $postal_code = $row[$postal_code_field]; - $country_code = $row[$country_code_field]; - $gender = $row[$gender_field]; - $date_of_birth = $row[$date_of_birth_field]; - $alt_phone = preg_replace('/[^0-9]/i', '', $row[$alt_phone_field]); - $email = $row[$email_field]; - $security_phrase = $row[$security_phrase_field]; - $comments = trim($row[$comments_field]); - $rank = $row[$rank_field]; - $owner = $row[$owner_field]; + $phone_code = ($phone_code_field>=0 && isset($row[$phone_code_field]) ? preg_replace('/[^0-9]/i', '', $row[$phone_code_field]) : ""); + $phone_number = ($phone_number_field>=0 && isset($row[$phone_number_field]) ? preg_replace('/[^0-9]/i', '', $row[$phone_number_field]) : ""); + $title = ($title_field>=0 && isset($row[$title_field]) ? $row[$title_field] : ""); + $first_name = ($first_name_field>=0 && isset($row[$first_name_field]) ? $row[$first_name_field] : ""); + $middle_initial = ($middle_initial_field>=0 && isset($row[$middle_initial_field]) ? $row[$middle_initial_field] : ""); + $last_name = ($last_name_field>=0 && isset($row[$last_name_field]) ? $row[$last_name_field] : ""); + $address1 = ($address1_field>=0 && isset($row[$address1_field]) ? $row[$address1_field] : ""); + $address2 = ($address2_field>=0 && isset($row[$address2_field]) ? $row[$address2_field] : ""); + $address3 = ($address3_field>=0 && isset($row[$address3_field]) ? $row[$address3_field] : ""); + $city = ($city_field>=0 && isset($row[$city_field]) ? $row[$city_field] : ""); + $state = ($state_field>=0 && isset($row[$state_field]) ? $row[$state_field] : ""); + $province = ($province_field>=0 && isset($row[$province_field]) ? $row[$province_field] : ""); + $postal_code = ($postal_code_field>=0 && isset($row[$postal_code_field]) ? $row[$postal_code_field] : ""); + $country_code = ($country_code_field>=0 && isset($row[$country_code_field]) ? $row[$country_code_field] : ""); + $gender = ($gender_field>=0 && isset($row[$gender_field]) ? $row[$gender_field] : ""); + $date_of_birth = ($date_of_birth_field>=0 && isset($row[$date_of_birth_field]) ? $row[$date_of_birth_field] : ""); + $alt_phone = ($alt_phone_field>=0 && isset($row[$alt_phone_field]) ? preg_replace('/[^0-9]/i', '', $row[$alt_phone_field]) : ""); + $email = ($email_field>=0 && isset($row[$email_field]) ? $row[$email_field] : ""); + $security_phrase = ($security_phrase_field>=0 && isset($row[$security_phrase_field]) ? $row[$security_phrase_field] : ""); + $comments = ($comments_field>=0 && isset($row[$comments_field]) ? trim($row[$comments_field]) : ""); + $rank = ($rank_field>=0 && isset($row[$rank_field]) ? $row[$rank_field] : ""); + $owner = ($owner_field>=0 && isset($row[$owner_field]) ? $row[$owner_field] : ""); # replace ' " ` \ ; with nothing $vendor_lead_code = preg_replace("/$field_regx/i", "", $vendor_lead_code); @@ -2069,11 +2127,11 @@ if (($leadfile) && ($LF_path)) $phone_number = preg_replace("/^$SSweb_loader_phone_strip/",'',$phone_number); } + $dup_lead=0; $moved_lead=0; ##### Check for duplicate phone numbers in vicidial_list table for all lists in a campaign ##### if (preg_match("/DUPCAMP/i",$dupcheck)) { - $dup_lead=0; $moved_lead=0; - $dup_lists=''; + $dup_lists=''; $stmt="SELECT campaign_id from vicidial_lists where list_id='$list_id';"; $rslt=mysql_to_mysqli($stmt, $link); $ci_recs = mysqli_num_rows($rslt); @@ -2145,8 +2203,6 @@ if (($leadfile) && ($LF_path)) ##### Check for duplicate phone numbers in vicidial_list table entire database ##### if (preg_match("/DUPSYS/i",$dupcheck)) { - $dup_lead=0; $moved_lead=0; - if ($status_mismatch_action) { if (preg_match('/USING CHECK/', $status_mismatch_action)) @@ -2194,8 +2250,6 @@ if (($leadfile) && ($LF_path)) ##### Check for duplicate phone numbers in vicidial_list table for one list_id ##### if (preg_match("/DUPLIST/i",$dupcheck)) { - $dup_lead=0; $moved_lead=0; - if ($status_mismatch_action) { if (preg_match('/USING CHECK/', $status_mismatch_action)) @@ -2242,8 +2296,6 @@ if (($leadfile) && ($LF_path)) ##### Check for duplicate title and alt-phone in vicidial_list table for one list_id ##### if (preg_match("/DUPTITLEALTPHONELIST/i",$dupcheck)) { - $dup_lead=0; $moved_lead=0; - if ($status_mismatch_action) { if (preg_match('/USING CHECK/', $status_mismatch_action)) @@ -2291,8 +2343,6 @@ if (($leadfile) && ($LF_path)) ##### Check for duplicate phone numbers in vicidial_list table entire database ##### if (preg_match("/DUPTITLEALTPHONESYS/i",$dupcheck)) { - $dup_lead=0; $moved_lead=0; - if ($status_mismatch_action) { if (preg_match('/USING CHECK/', $status_mismatch_action)) @@ -2386,6 +2436,7 @@ if (($leadfile) && ($LF_path)) $invalid_reason = _QXZ("INVALID PHONE NUMBER NANPA AREACODE PREFIX"); } } + $dnc_matches=0; if ($international_dnc_scrub and $valid_number > 0) { $dnc_table_name="vicidial_dnc_".$international_dnc_scrub; @@ -2544,7 +2595,7 @@ if (($leadfile) && ($LF_path)) } } } - if ($multi_insert_counter!=0) + if (isset($multi_insert_counter) && $multi_insert_counter!=0) { $stmtZ = "INSERT INTO vicidial_list (lead_id,entry_date,modify_date,status,user,vendor_lead_code,source_id,list_id,gmt_offset_now,called_since_last_reset,phone_code,phone_number,title,first_name,middle_initial,last_name,address1,address2,address3,city,state,province,postal_code,country_code,gender,date_of_birth,alt_phone,email,security_phrase,comments,called_count,last_local_call_time,rank,owner,entry_list_id) values".substr($multistmt, 0, -1).";"; mysql_to_mysqli($stmtZ, $link); @@ -2568,7 +2619,7 @@ if (($leadfile) && ($LF_path)) {fwrite($stmt_file, $custom_ins_stmt."\r\n");} } ### LOG INSERTION Admin Log Table ### - $stmt="INSERT INTO vicidial_admin_log set event_date='$NOW_TIME', user='$PHP_AUTH_USER', ip_address='$ip', event_section='LISTS', event_type='LOAD', record_id='$list_id_override', event_code='ADMIN LOAD LIST STANDARD', event_sql='', event_notes='File Name: $leadfile_name, GOOD: $good, BAD: $bad, MOVED: $moved, TOTAL: $total, DEBUG: dedupe_statuses:$dedupe_statuses[0]| dedupe_statuses_override:$dedupe_statuses_override| dupcheck:$dupcheck| status mismatch action: $status_mismatch_action| lead_file:$lead_file| list_id_override:$list_id_override| phone_code_override:$phone_code_override| postalgmt:$postalgmt| template_id:$template_id| usacan_check:$usacan_check| dnc_country_scrub:$international_dnc_scrub| state_conversion:$state_conversion| web_loader_phone_length:$web_loader_phone_length| web_loader_phone_strip:$SSweb_loader_phone_strip|';"; + $stmt="INSERT INTO vicidial_admin_log set event_date='$NOW_TIME', user='$PHP_AUTH_USER', ip_address='$ip', event_section='LISTS', event_type='LOAD', record_id='$list_id_override', event_code='ADMIN LOAD LIST STANDARD', event_sql='', event_notes='File Name: $leadfile_name, GOOD: $good, BAD: $bad, MOVED: $moved, TOTAL: $total, DEBUG: dedupe_statuses:".(isset($dedupe_statuses[0]) ? $dedupe_statuses[0] : " NONE")."| dedupe_statuses_override:$dedupe_statuses_override| dupcheck:$dupcheck| status mismatch action: $status_mismatch_action| lead_file:$lead_file| list_id_override:$list_id_override| phone_code_override:$phone_code_override| postalgmt:$postalgmt| template_id:$template_id| usacan_check:$usacan_check| dnc_country_scrub:$international_dnc_scrub| state_conversion:$state_conversion| web_loader_phone_length:$web_loader_phone_length| web_loader_phone_strip:$SSweb_loader_phone_strip|';"; if ($DB) {echo "|$stmt|\n";} $rslt=mysql_to_mysqli($stmt, $link); @@ -2643,9 +2694,9 @@ if (($leadfile) && ($LF_path)) $total=0; $good=0; $bad=0; $dup=0; $inv=0; $post=0; $moved=0; $phone_list=''; print "
"._QXZ("Processing")." $delim_name "._QXZ("file")."... ($tab_count|$pipe_count)\n"; + $status_dedupe_str=""; $statuses_clause=""; if (count($dedupe_statuses)>0) { $statuses_clause=" and status in ("; - $status_dedupe_str=""; for($ds=0; $ds 8) + if (!isset($multi_insert_counter) || $multi_insert_counter > 8) { ### insert good deal into pending_transactions table ### $stmtZ = "INSERT INTO vicidial_list (lead_id,entry_date,modify_date,status,user,vendor_lead_code,source_id,list_id,gmt_offset_now,called_since_last_reset,phone_code,phone_number,title,first_name,middle_initial,last_name,address1,address2,address3,city,state,province,postal_code,country_code,gender,date_of_birth,alt_phone,email,security_phrase,comments,called_count,last_local_call_time,rank,owner,entry_list_id) values$multistmt('',\"$entry_date\",\"$modify_date\",\"$status\",\"$user\",\"$vendor_lead_code\",\"$source_id\",\"$list_id\",\"$gmt_offset\",\"$called_since_last_reset\",\"$phone_code\",\"$phone_number\",\"$title\",\"$first_name\",\"$middle_initial\",\"$last_name\",\"$address1\",\"$address2\",\"$address3\",\"$city\",\"$state\",\"$province\",\"$postal_code\",\"$country_code\",\"$gender\",\"$date_of_birth\",\"$alt_phone\",\"$email\",\"$security_phrase\",\"$comments\",0,\"2008-01-01 00:00:00\",\"$rank\",\"$owner\",'0');"; @@ -3231,7 +3275,7 @@ if (($leadfile) && ($LF_path)) } } } - if ($multi_insert_counter!=0) + if (isset($multi_insert_counter) && $multi_insert_counter!=0) { $stmtZ = "INSERT INTO vicidial_list (lead_id,entry_date,modify_date,status,user,vendor_lead_code,source_id,list_id,gmt_offset_now,called_since_last_reset,phone_code,phone_number,title,first_name,middle_initial,last_name,address1,address2,address3,city,state,province,postal_code,country_code,gender,date_of_birth,alt_phone,email,security_phrase,comments,called_count,last_local_call_time,rank,owner,entry_list_id) values".substr($multistmt, 0, -1).";"; mysql_to_mysqli($stmtZ, $link); @@ -3239,7 +3283,7 @@ if (($leadfile) && ($LF_path)) {fwrite($stmt_file, $stmtZ."\r\n");} } ### LOG INSERTION Admin Log Table ### - $stmt="INSERT INTO vicidial_admin_log set event_date='$NOW_TIME', user='$PHP_AUTH_USER', ip_address='$ip', event_section='LISTS', event_type='LOAD', record_id='$list_id_override', event_code='ADMIN LOAD LIST STANDARD', event_sql='', event_notes='File Name: $leadfile_name, GOOD: $good, BAD: $bad, MOVED: $moved, TOTAL: $total, DEBUG: dedupe_statuses:$dedupe_statuses[0]| dedupe_statuses_override:$dedupe_statuses_override| dupcheck:$dupcheck| status mismatch action: $status_mismatch_action| lead_file:$lead_file| list_id_override:$list_id_override| phone_code_override:$phone_code_override| postalgmt:$postalgmt| template_id:$template_id| usacan_check:$usacan_check| dnc_country_scrub:$international_dnc_scrub| state_conversion:$state_conversion| web_loader_phone_length:$web_loader_phone_length| web_loader_phone_strip:$SSweb_loader_phone_strip|';"; + $stmt="INSERT INTO vicidial_admin_log set event_date='$NOW_TIME', user='$PHP_AUTH_USER', ip_address='$ip', event_section='LISTS', event_type='LOAD', record_id='$list_id_override', event_code='ADMIN LOAD LIST STANDARD', event_sql='', event_notes='File Name: $leadfile_name, GOOD: $good, BAD: $bad, MOVED: $moved, TOTAL: $total, DEBUG: dedupe_statuses:".(isset($dedupe_statuses[0]) ? $dedupe_statuses[0] : " NONE")."| dedupe_statuses_override:$dedupe_statuses_override| dupcheck:$dupcheck| status mismatch action: $status_mismatch_action| lead_file:$lead_file| list_id_override:$list_id_override| phone_code_override:$phone_code_override| postalgmt:$postalgmt| template_id:$template_id| usacan_check:$usacan_check| dnc_country_scrub:$international_dnc_scrub| state_conversion:$state_conversion| web_loader_phone_length:$web_loader_phone_length| web_loader_phone_strip:$SSweb_loader_phone_strip|';"; if ($DB) {echo "|$stmt|\n";} $rslt=mysql_to_mysqli($stmt, $link); diff --git a/agc_2-X/trunk/www/vicidial/help_documentation.txt b/agc_2-X/trunk/www/vicidial/help_documentation.txt index 41c4c05c..d1da7c2d 100644 --- a/agc_2-X/trunk/www/vicidial/help_documentation.txt +++ b/agc_2-X/trunk/www/vicidial/help_documentation.txt @@ -1,4 +1,4 @@ -# version: 20260408083901 +# version: 20260413085001 users-user User ID This field is where you put the users ID number, can be up to 20 digits in length, Must be at least 2 characters in length. We strongly recommend not reusing user accounts for different users, for reporting accuracy. To disable a user account, set the Active option to -N-. users-pass Password This field is where you put the users password. Must be at least 2 characters in length, unless the User Password Minimum Length system setting is enabled, which will require a longer password. Only letters and numbers are allowed in user passwords. A medium strength user password will be at least 10 characters in length, and a strong user password will be at least 20 characters in length and have letters as well as at least one number. It is recommended that you use a longer password if possible, stringing together several unrelated words with no spaces, and a number somewhere in the string. The maximum size of a password is 100 characters. users-force_change_password Force Change Password If this option is set to Y then the user will be prompted to change their password the next time they log in to the administration webpage or the agent screen. Default is N. @@ -169,7 +169,7 @@ campaigns-hopper_drop_run_trigger Hopper Drop-Run Trigger This setting, if campaigns-drop_lockout_time Drop Lockout Time This is a number of hours that DROP abandon calls will be prevented from being dialed, to disable set to 0. This setting is very useful in countries like the UK where there are regulations preventing the attempted calling of customers within 72 hours of an Abandon, or DROP. Default is 0. campaigns-force_reset_hopper Force Reset of Hopper This allows you to wipe out the hopper contents upon form submission. It should be filled again when the VDhopper script runs. campaigns-hopper_hold_inserts Hopper Hold Inserts If enabled, this will insert leads into the hopper as a RHOLD status, so they can be activated by an outside process or utility. The AUTONEXT option is also an enabled option, but in the HCI Screen, the user will only have to click once for each call instead of twice. Default is DISABLED. -campaigns-dial_method Dial Method This field is the way to define how dialing is to take place. If MANUAL then the auto_dial_level will be locked at 0 unless Dial Method is changed. If RATIO then the normal dialing a number of lines for Active agents. ADAPT_HARD_LIMIT will dial predictively up to the dropped percentage and then not allow aggressive dialing once the drop limit is reached until the percentage goes down again. ADAPT_TAPERED allows for running over the dropped percentage in the beginning of the shift -as defined by Latest Server Time set for campaign- and gets more strict as the shift goes on, for example, if there are 10 hours or more left in the shift, the TAPERED feature will not affect the adaptive dial level at all, as the number of hours left in the shift drops below 10 hours and gets closer to 0, the dial level will be dropped closer and closer to 1.0 as time goes on. ADAPT_AVERAGE tries to maintain an average or the dropped percentage not imposing hard limits as aggressively as the other two methods. ADAPT_PERCENTMAX will use the Adapt Percent-Max Percentage and the Maximum Adapt Dial Level settings to calculate what it should set the Dial Level to if the dropped percentage limit is reached, and if the calculated value is greater than the current Dial Level, then it won't be changed at that time. You cannot change the Auto Dial Level if you are in any of the ADAPT dial methods. Only the Dialer can change the dial level when in predictive dialing mode. INBOUND_MAN allows the agent to place manual dial calls from a campaign list while being able to take inbound calls between manual dial calls. +campaigns-dial_method Dial Method This field is the way to define how dialing is to take place. If MANUAL then the auto_dial_level will be locked at 0 unless Dial Method is changed. If RATIO then the normal dialing a number of lines for Active agents. ADAPT_HARD_LIMIT will dial predictively up to the dropped percentage and then not allow aggressive dialing once the drop limit is reached until the percentage goes down again. ADAPT_TAPERED allows for running over the dropped percentage in the beginning of the shift -as defined by Latest Server Time set for campaign- and gets more strict as the shift goes on, for example, if there are 10 hours or more left in the shift, the TAPERED feature will not affect the adaptive dial level at all, as the number of hours left in the shift drops below 10 hours and gets closer to 0, the dial level will be dropped closer and closer to 1.0 as time goes on. ADAPT_AVERAGE tries to maintain an average or the dropped percentage not imposing hard limits as aggressively as the other two methods. ADAPT_PERCENTMAX will use the Adapt Percent-Max Percentage and the Maximum Adapt Dial Level settings to calculate what it should set the Dial Level to if the dropped percentage limit is reached, and if the calculated value is greater than the current Dial Level, then it wont be changed at that time. You cannot change the Auto Dial Level if you are in any of the ADAPT dial methods. Only the Dialer can change the dial level when in predictive dialing mode. INBOUND_MAN allows the agent to place manual dial calls from a campaign list while being able to take inbound calls between manual dial calls. campaigns-auto_dial_level Auto Dial Level This is where you set how many lines the system should use per active agent. zero 0 means auto dialing is off and the agents will click to dial each number. Otherwise the system will keep dialing lines equal to active agents multiplied by the dial level to arrive at how many lines this campaign on each server should allow. The ADAPT OVERRIDE checkbox allows you to force a new dial level even though the dial method is in an ADAPT mode. This is useful if there is a dramatic shift in the quality of leads and you want to drastically change the dial_level manually. Note: With the INBOUND_MAN Dial Method, this setting needs to be set to 1.0 so that inbound calls can be received by agents, but even with this set above 0, there will be no auto-dial calls placed from the campaign. campaigns-dial_level_threshold Auto Dial Level Threshold This setting only works with an ADAPT or RATIO Dial Method, and it must be set to something other than DISABLED and the number of agents setting must be above 0. This feature allows you to set a minimum number agents that predictive algorithm will work at. If the number of agents falls below the number that you have set, then the dial level will go to 1.0 until more agents log in or go into the selected state. LOGGED-IN_AGENTS will count all agents logged into the campaign, NON-PAUSED_AGENTS will only count agents that are waiting or talking, and WAITING_AGENTS will only count agents that are waiting for a call. Default is DISABLED. campaigns-available_only_ratio_tally Available Only Tally This field if set to Y will leave out INCALL and QUEUE status agents when calculating the number of calls to dial when not in MANUAL dial mode. Default is N. @@ -337,7 +337,7 @@ campaigns-my_callback_option My Callbacks Checkbox Default This option allo campaigns-show_previous_callback Show Previous Callback This option if enabled will show on the agent screen with a separate yellow panel information about the previously set callback that the agent has up on their screen. Disabling this option will not show that panel. Default is ENABLED. campaigns-callback_useronly_move_minutes Scheduled Callbacks Useronly Move Minutes This option if set to a number greater than 0, will change all USERONLY Scheduled Callbacks that are X minutes after their callback time to ANYONE callbacks. This process runs every minute. Default is 0 for disabled. campaigns-next_dial_my_callbacks Next-Dial My Callbacks This option only works for MANUAL and INBOUND_MAN dial methods, and also only if No Hopper Dialing is enabled. This feature will look for Scheduled Callbacks that have triggered for the agent and dial them next when the agent clicks on the Dial Next Number button on their agent screen. There is a per-user override option for this setting as well. Default is DISABLED. -campaigns-scheduled_callbacks_force_dial Scheduled Callbacks Force Dial This feature will force an agent to a paused state and block out their screen with the next triggered USERONLY scheduled callback to be called. The agent's only option will be to dial this callback, although they are able to look at lead info before they do that. If there are multiple triggered scheduled callbacks for the agent, they all must be called before the agent can move on to handling other items. This feature will not pay attention to the Call Time that is set for the campaign, so these calls may be dialed outside of the set call time. The agent must be able to place manual dial calls for this feature to work. Default is N for disabled. +campaigns-scheduled_callbacks_force_dial Scheduled Callbacks Force Dial This feature will force an agent to a paused state and block out their screen with the next triggered USERONLY scheduled callback to be called. The agents only option will be to dial this callback, although they are able to look at lead info before they do that. If there are multiple triggered scheduled callbacks for the agent, they all must be called before the agent can move on to handling other items. This feature will not pay attention to the Call Time that is set for the campaign, so these calls may be dialed outside of the set call time. The agent must be able to place manual dial calls for this feature to work. Default is N for disabled. campaigns-scheduled_callbacks_timezones_container Scheduled Callbacks Local Timezones This feature allows agents to set scheduled callbacks with a customer local time and timezone. If set to something other than ---DISABLED---, the selected TIMEZONE_LIST type of Settings Container will be used to display a list of time zones in the Scheduled Callback panel of the agent screen that would be used to set the scheduled callback by one of those local times. A TIMEZONE_LIST type of Settings Container would need to be created that will contain one timezone per line with each line containing the 3-letter Country Code, the TimeZone Code, a Y or N for whether Daylight Saving Time is observed in that zone, and a short description of the time zone as you want it to appear to the agents. For example, for the Eastern United States time zone, you could put -USA,EST,Y,Eastern Time Zone-, without the dashes. To see a list of the available time zone combinations on your system, go to the Admin, System Settings page and click on the -Phone Codes- link on that page. Default is DISABLED, and the scheduled callbacks screen will use the agent server time to set callbacks. campaigns-scheduled_callbacks_auto_reschedule Scheduled Callbacks Auto Reschedule This feature only affects ANYONE scheduled callbacks. If DAY_1 is used, it will automatically reschedule lead lead to be called back on the next calling day at the same time they were called if the resulting disposition of the call was not a Human Answer -Y- status. The next calling day is determined by the Call Time that is set for the campaign. In the case of DAY_1, if tomorrow is not an allowed calling day, the system will look at the next day and then the next day until it finds the next allowable calling day to set the ANYONE scheduled callback for. There are up to 6 DAY options, then there are up to 3 WEEK options, then there are up to 6 MONTH options. Default is DISABLED. campaigns-wrapup_seconds Wrap Up Seconds The number of seconds to force an agent to wait before allowing them to receive or dial another call. The timer begins as soon as an agent hangs up on their customer - or in the case of alternate number dialing when the agent finishes the lead - Default is 0 seconds. If the timer runs out before the agent has dispositioned the call, the agent still will NOT move on to the next call until they select a disposition. @@ -412,7 +412,7 @@ campaigns-in_group_dial_select In-Group Manual Dial Select This option is o campaigns-agent_clipboard_copy Agent Screen Clipboard Copy THIS FEATURE IS CURRENTLY ONLY ENABLED FOR INTERNET EXPLORER. This feature allows you to select a field that will be copied to the computer clipboard of the agent computer upon a call being sent to an agent. Common uses for this are to allow for easy pasting of account numbers or phone numbers into legacy client applications on the agent computer. campaigns-qc_enabled QC Enabled Setting this field to Y allows for the agent Quality Control features to work. Default is N. campaigns-qc_statuses QC Statuses This area is where you select which statuses of leads should be gone over by the QC system. Place a check next to the status that you want QC to review. -campaigns-qc_statuses_id QC Statuses ID This area is where you select which "QC_TEMPLATE" settings container will be used to determine the call statuses that are eligible for QC evaluation in this campaign. +campaigns-qc_statuses_id QC Statuses ID This area is where you select which -QC_TEMPLATE- settings container will be used to determine the call statuses that are eligible for QC evaluation in this campaign. campaigns-qc_shift_id QC Shift This is the shift timeframe used to pull QC records for a campaign. The days of the week are ignored for these functions. campaigns-qc_get_record_launch QC Get Record Launch This allows one of the following actions to be triggered upon a QC agent receiving a new record. campaigns-qc_show_recording QC Show Recording This allows for a recording that may be linked with the QC record to be display in the QC agent screen. @@ -462,7 +462,7 @@ lists-campaign_id Campaign This is the campaign that this list belongs to. lists-active Active This defines whether the list is to be dialed on or not. lists-reset_list Reset Lead-Called-Status for this list This resets all leads in this list to N for not called since last reset and means that any lead can now be called if it is the right status as defined in the campaign screen. lists-reset_time Reset Times This field allows you to put times in, separated by a dash-, that this list will be automatically reset by the system. The times must be in 24 hour format with no punctuation, for example 0800-1700 would reset the list at 8AM and 5PM every day. Default is empty. -lists-weekday_resets_container Weekday Resets Container If set to a valid LIST_WEEKDAY_RESETS Settings Container, this option will let you define reset times for this list on a day-of-the-week basis. Within the container, you can set the list reset times for each weekday. Here is an example configuration:
; weekday => reset-times in 24-hour time separated by dashes
monday => 0830-1230-1800
tuesday => 0900-1400-1830
wednesday => 0930-1200-1730-1900
thursday => 1030-1330-1900
friday => 0800-1300-1530
saturday => 0930-1100
sunday => 1000

Note: if you want to leave a day blank, either don't include it or put no numbers after it. This will not override any Reset Times set above for this list, those will still run every day. Default is DISABLED.
+lists-weekday_resets_container Weekday Resets Container If set to a valid LIST_WEEKDAY_RESETS Settings Container, this option will let you define reset times for this list on a day-of-the-week basis. Within the container, you can set the list reset times for each weekday. Here is an example configuration:
; weekday => reset-times in 24-hour time separated by dashes
monday => 0830-1230-1800
tuesday => 0900-1400-1830
wednesday => 0930-1200-1730-1900
thursday => 1030-1330-1900
friday => 0800-1300-1530
saturday => 0930-1100
sunday => 1000

Note: if you want to leave a day blank, either dont include it or put no numbers after it. This will not override any Reset Times set above for this list, those will still run every day. Default is DISABLED.
lists-daily_reset_limit Daily Reset Limit This setting is only editable by a level 9 user. This setting allows an Administrator to limit the number of times that a list can be reset per day. The Resets Today number is counted from the Timeclock End Of Day time that is set in the system. Default is -1 for disabled. lists-expiration_date Expiration Date This option allows you to set the date after which leads in this list will not be allowed to be auto-dialed or manual-list-dialed by the system. Default is 2099-12-31. lists-local_call_time Local Call Time This is a setting for this list only, where you set during which hours you would like to dial leads within this specific list, as determined by the local time in the area in which you are calling. This is controlled by the time zone, as defined by that list setting, and is adjusted for Daylight Savings time if applicable. However, state rules are based on the state field for the lead and not only the time zone that is set. This call time setting is applied after the campaign local call time has been applied to the list and will NOT override the campaign settings. This setting will only narrow down call times in relation to the campaign local call time setting. It will NOT allow calling outside the hours set by the campaign local call time setting. This is useful if you have lists that need different call times within the same campaign. For example calling business numbers between 9am to 5pm and consumer phones between 9am to 9pm within the same campaign. General Guidelines in the USA for Business to Business is 9am to 5pm and Business to Consumer calls is 9am to 9pm. Default is campaign. @@ -470,7 +470,7 @@ lists-audit_comments Audit Comments This option allows comments to be moved lists-agent_script_override Agent Script Override If this field is set, this will be the script that the agent sees on their screen instead of the campaign script when the lead is from this list. Default is not set. lists-qc_scorecard_override QC Scorecard Override This is the scorecard to be shown to the agent when evaluating a QC record. It will override any campaign setting, but ingroup QC settings still take top priority. lists-qc_web_form_address QC WebForm Address This is the website address that a QC agent can go to when clicking on the WEBFORM link in the QC screen. -lists-qc_statuses_id QC Statuses ID This area is where you select which "QC_TEMPLATE" settings container will be used to determine the call statuses that are eligible for QC evaluation in this list. This will override the campaign's "QC Statuses ID" setting if it is set, but not ingroups. +lists-qc_statuses_id QC Statuses ID This area is where you select which -QC_TEMPLATE- settings container will be used to determine the call statuses that are eligible for QC evaluation in this list. This will override the campaigns -QC Statuses ID- setting if it is set, but not ingroups. lists-inbound_list_script_override Inbound Script Override If this field is set, this will be the script that the agent sees on their screen instead of the campaign script when the agent receives an inbound call and the lead is from this list. Default is not set. lists-inbound_drop_voicemail Inbound Drop Voicemail Override If an inbound call associated with this list drops while in an Inbound Group queue, this is the voicemail box the call will be sent to if the Drop Action is set to go to a voicemail box. lists-inbound_after_hours_voicemail Inbound After Hours Voicemail Override If an inbound call associated with this list triggers an after hours action after it has been sent to an Inbound Group queue, this is the voicemail box the call will be sent to if the After Hours Action is set to go to a voicemail box. @@ -681,7 +681,7 @@ inbound_groups-parallel_rec_xx_filename Parallel Rec Filenames If Parallel inbound_groups-recording_dtmf_muting Recording DTMF Muting If enabled, and the Allow Recording DTMF Detection system setting is also enabled, call recordings from this In-Group will be muted for this number of seconds after the first DTMF signal is detected while recording is active. This setting will only effect on calls handled through this In-Group, if you also want DTMF Muting to be active for outbound calls, then each Campaign will also need to have this feature enabled. Default is 0 for disabled. inbound_groups-qc_enabled QC Enabled Setting this field to Y allows for the agent Quality Control features to work. Default is N. inbound_groups-qc_statuses QC Statuses This area is where you select which statuses of leads should be gone over by the QC system. Place a check next to the status that you want QC to review. -inbound_groups-qc_statuses_id QC Statuses ID This area is where you select which "QC_TEMPLATE" settings container will be used to determine the call statuses that are eligible for QC evaluation in this ingroup. This will override both campaign and list "QC Statuses ID" settings. +inbound_groups-qc_statuses_id QC Statuses ID This area is where you select which -QC_TEMPLATE- settings container will be used to determine the call statuses that are eligible for QC evaluation in this ingroup. This will override both campaign and list -QC Statuses ID- settings. inbound_groups-qc_shift_id QC Shift This is the shift timeframe used to pull QC records for an inbound_group. The days of the week are ignored for these functions. inbound_groups-qc_get_record_launch QC Get Record Launch This allows one of the following actions to be triggered upon a QC agent receiving a new record. inbound_groups-qc_show_recording QC Show Recording This allows for a recording that may be linked with the QC record to be display in the QC agent screen. @@ -921,11 +921,11 @@ voicemail-voicemail_timezone Voicemail Zone This setting allows you to set voicemail-voicemail_options Voicemail Options This optional setting allows you to define additional voicemail settings. It is recommended that you leave this blank unless you know what you are doing. users-alter_admin_interface_options Alter Admin Interface Options Changing this setting to 1 will allow this user to alter admin interface options. list_loader Admin lead loader The basic web-based lead loader is designed simply to take a lead file - up to 8MB in size - that is either tab or pipe delimited and load it into the list table. The lead loader allows for field choosing and TXT- Plain Text, CSV- Comma Separated Values and XLS- Excel file formats. The lead loader does not do data validation, but it does allow you to check for duplicates in itself, within the campaign or within the entire system. Also, make sure that you have created the list that these leads are to be under so that you can use them. Here is a list of the fields in their proper order for the lead files:
  1. Vendor Lead Code - shows up in the Vendor ID field of the GUI
  2. Source Code - internal use only for admins and DBAs
  3. List ID - the list number that these leads will show up under
  4. Phone Code - the prefix for the phone number - 1 for US, 44 for UK, 61 for AUS, etc
  5. Phone Number - must be at least 8 digits long
  6. Title - title of the customer - Mr. Ms. Mrs, etc...
  7. First Name
  8. Middle Initial
  9. Last Name
  10. Address Line 1
  11. Address Line 2
  12. Address Line 3
  13. City
  14. State - limited to 2 characters
  15. Province
  16. Postal Code
  17. Country
  18. Gender
  19. Date of Birth
  20. Alternate Phone Number
  21. Email Address
  22. Security Phrase
  23. Comments
  24. Rank
  25. Owner

NOTES: The Excel Lead loader functionality is enabled by a series of perl scripts and needs to have a properly configured /etc/astguiclient.conf file in place on the web server. Also, a couple perl modules must be loaded for it to work as well - OLE-Storage_Lite and Spreadsheet-ParseExcel. You can check for runtime errors in these by looking at your apache error_log file. Also, for duplication checks against campaign lists, the list that has new leads going into it does need to be created in the system before you start to load the leads. -international_dnc_loader International DNC Loader The international DNC loader is used to upload and store DNC lists by country in the dialer database, which can then be used to scrub against in the lead loader. This feature requires that the "Enable International DNC" feature be turned on in the system settings.

A background script constantly runs and checks a user-defined location for files to load. This places them in a queue table, the contents of which are displayed in this interface. From here the user can see what files have been uploaded, are being processed, or are finished/cancelled.

Uploaded files can be processed by assigning them a country code, designating whether or not the uploaded file is meant to purge said country's current DNC list or append to it, and selecting the file format the DNC file follows.

Files are processed automatically when the user presses the "START FILE" button and their progress can be tracked. Or the file can be cancelled and removed from the queue.
-international_dnc_loader-country_code DNC country code This is the list of countries a DNC gleaned from the "vicidial_country_iso_tld" table in the database. In order to process an uploaded file into a DNC suppression table, you must specify what country it is for here. -international_dnc_loader-file_action DNC file action When a user wishes to process a DNC file here, they must specify if the uploaded file is meant to replace the existing data in the country's table (PURGE), or if the uploaded file should insert all new distinct leads in with the records already in the table (APPEND). If this is the first time a file is being loaded for a particular country, it doesn't matter which option is selected. -international_dnc_loader-file_layout DNC file layout This field tells the file processing script what kind of file is being loaded and where to look in the file for the phone numbers. The file formats displayed in the drop-down menu are gotten from the settings container "DNC_IMPORT_FORMATS", and formats should be defined or altered there. -international_dnc_loader-start_cancel Start/cancel file If the user has properly defined a country code, file action, and file layout for an uploaded "READY" file, they can click the "START FILE" button to set the file status to "PENDING", which will cause it to be picked up and processed by the automated processing script. Or, they can click "CANCEL" to set the file status to "CANCELLED", which will cause the file to eventually be purged from the queue table and also erased from the DNC storage folder by the automated processing script. +international_dnc_loader International DNC Loader The international DNC loader is used to upload and store DNC lists by country in the dialer database, which can then be used to scrub against in the lead loader. This feature requires that the -Enable International DNC- feature be turned on in the system settings.

A background script constantly runs and checks a user-defined location for files to load. This places them in a queue table, the contents of which are displayed in this interface. From here the user can see what files have been uploaded, are being processed, or are finished/cancelled.

Uploaded files can be processed by assigning them a country code, designating whether or not the uploaded file is meant to purge said countrys current DNC list or append to it, and selecting the file format the DNC file follows.

Files are processed automatically when the user presses the -START FILE- button and their progress can be tracked. Or the file can be cancelled and removed from the queue.
+international_dnc_loader-country_code DNC country code This is the list of countries a DNC gleaned from the -vicidial_country_iso_tld- table in the database. In order to process an uploaded file into a DNC suppression table, you must specify what country it is for here. +international_dnc_loader-file_action DNC file action When a user wishes to process a DNC file here, they must specify if the uploaded file is meant to replace the existing data in the countrys table (PURGE), or if the uploaded file should insert all new distinct leads in with the records already in the table (APPEND). If this is the first time a file is being loaded for a particular country, it doesnt matter which option is selected. +international_dnc_loader-file_layout DNC file layout This field tells the file processing script what kind of file is being loaded and where to look in the file for the phone numbers. The file formats displayed in the drop-down menu are gotten from the settings container -DNC_IMPORT_FORMATS-, and formats should be defined or altered there. +international_dnc_loader-start_cancel Start/cancel file If the user has properly defined a country code, file action, and file layout for an uploaded -READY- file, they can click the -START FILE- button to set the file status to -PENDING-, which will cause it to be picked up and processed by the automated processing script. Or, they can click -CANCEL- to set the file status to -CANCELLED-, which will cause the file to eventually be purged from the queue table and also erased from the DNC storage folder by the automated processing script. admin_phones_bulk_insert-servers Servers This is a list of the server IP addresses of existing servers in the system that you want the phone entries to be populated across. These must be valid IP addresses, they must be active in the system and you must put one per line in this text area input box. admin_phones_bulk_insert-phones Phones This is a list of the phone extensions that you want to be created on all of the servers listed above. The phone extensions should be letters and numbers only, with no special characters and you must put one per line in this text area box. list_loader-file_layout File layout The layout of the file you are loading. Standard Format uses the pre-defined standard file format. Custom layout allows the user to define the layout of the file themselves. Custom template is a hybrid of the previous two options, which allows the user to use a custom format they have defined previously and saved using the Custom Template Maker. @@ -1411,6 +1411,7 @@ email_accounts-call_handle_method In-Group Call Handle Method This is the a email_accounts-agent_search_method In-Group Agent Search Method The agent search method to be used by the inbound group, LO is Load-Balanced-Overflow and will try to send the call to an agent on the local server before trying to send it to an agent on another server, LB is Load-Balanced and will try to send the call to the next agent no matter what server they are on, SO is Server-Only and will only try to send the calls to agents on the server that the call came in on. Default is LB. NOT USED email_accounts-ingroup_list_id In-Group List ID This is the List ID that will be used to search for a match within. email_accounts-ingroup_campaign_id In-Group Campaign ID This is the Campaign ID that will be used to search for a match within. +listloader-autodetect Listloader auto-detect feature The auto-detect tool utilizes the Levenshtein distance string metric to compare values in the lead files header row against columns in the list database table, and the resulting scores returned by the comparison check can automatically determine if columns in the lead file match to columns in the list table. For this to work, the lead file being loaded must have a header row indicating the data contained in each column, and this check is only done if the -custom layout- File Layout option above is selected.

If there are one or more fields in the list table that score at or higher than the minimum required score -default is 70- for a given named column in the lead file, then the highest scoring field will be automatically selected in the lead processing page. If no list field matches sufficiently to meet the minimum required score, no column will be selected but the page will show the best-matching column on request.

Lead file columns whose names match a column in the list table will receive the highest score. Additionally, users can define their own field aliases in the -LISTLOADER_AUTO_MAPPING- Settings Container to automatically return a high score for a header columns value, regardless of the Levenshtein result. Users can also define a minimum required score other than 70 in the -LISTLOADER_AUTO_MAPPING- Settings Container, if they so choose.
template_maker The custom template maker allows you to define your own file layouts for use with the list loader and also delete them, if necessary. If you frequently upload files that are in a consistent layout other than the standard layout, you may find this tool helpful. The saved layout will work on any uploaded file it matches, regardless of file type or delimiter. The custom template maker allows you to define your own file layouts for use with the list loader and also delete them, if necessary. If you frequently upload files that are in a consistent layout other than the standard layout, you may find this tool helpful. The saved layout will work on any uploaded file it matches, regardless of file type or delimiter. template_maker-create_template Create a new template In order to begin creating your new listloader template, you must first load a lead file that has the layout you wish to create the template for. Click Choose file, and open the file on your computer you wish to use. This will upload a copy to your server and process it to determine the file type and delimiter (for TXT files). vicidial_template_maker Listloader Custom Template Maker Create your own file loading template with this tool. Useful when you load files in a consistent format or layout other than the vicidial standard format, as it allows you to predefine field locations in lead files to bypass the steps to assign them otherwise @@ -1456,7 +1457,7 @@ DIDdetail Inbound DID Detail Report This report displays the details for ev email_log_report Email Log Report This report gives a detailed log report of any emails handled by the dialer, including links to the full text of received emails. It will display the date the email was received, the address and name of the sender, a bit of the beginning of the emails text (with a link to the full text), and the status that the agent dispositioned the email as. inbound_daily_report Inbound Daily Report This report will give a daily or hourly, weekly, monthly, and quarterly count on all calls received by the in-groups selected for the given date range.
TOTAL CALLS OFFERED = Total calls taken by the in-group.
TOTAL CALLS ANSWERED = Total calls answered by the in-group.
TOTAL AGENTS ANSWERED = Total number of distinct agents who fielded calls to this in-group.
TOTAL CALLS ABANDONED = Total calls ended in queue (term reason = "abandon").
TOTAL ABANDON PERCENT = Percentage of calls abandoned (TOTAL CALLS ABANDONED / TOTAL CALLS OFFERED).
AVG ABANDON TIME = Average amount of time a caller waited in queue before abandoning the call.
AVG ANSWER SPEED = Average amount of time a caller waited in queue before an agent answered.
AVG TALK TIME = Average amount of time an agent remained on the line with the caller before the call was hung up - does not include caller queue time.
TOTAL TALK TIME = Total amount of time agents remained on the line with callers before calls ended - does not include caller queue time.
TOTAL WRAP TIME = Total amount of time agents used to -wrap- the call - assumed to be 15 second per answered call.
TOTAL CALL TIME = Total talk time plus total wrap time. IVRstats Inbound IVR Report This report shows a breakdown of IVR paths followed by callers on selected IVRs based on the date range.
IVR CALLS = Total calls taken by or made through the selected IVRs that follow the -CALL PATH-.
QUEUE CALLS = Total inbound calls taken by the selected IVRs that follow the -CALL PATH-.
QUEUE DROP CALLS = Total inbound calls taken by the selected IVRs that follow the -CALL PATH- that were dropped.
QUEUE DROP PERCENT = Percentage of dropped inbound calls taken by the selected IVRs (QUEUE DROP CALLS / QUEUE CALLS).
IVR AVG TIME = Average amount of time spent in-call, taken by dividing IVR CALLS by the total time spent in the selected IVRs.
TOTAL AVG TIME = Total call time spent in the selected IVRs.
CALL PATH = The specific call path followed on the IVR - report will display each distinct path followed by all the selected IVRs for the selected date range. -CMstats Callmenu Survey Report This report shows one of two report types. The first displays all responses to callmenu prompts on calls handled by a given agent, within a list of selected campaigns, for a given time frame. Each call is displayed in chronological order, and for each call, the prompts and responses given are displayed. Each prompt response is treated as its numerical value to create a point total for the call, and total points per prompt and call are given at the bottom of the report. The second report is a multiple agent report, which utilizes the dates given and campaigns selected (the value in the agent field is ignored). The resulting report gives a summary per agent of the prompts met and total value of the responses given. The results for this report are sorted in descending order based on the total points the agent accrued.

SINGLE AGENT REPORT
PHONE = The customer's phone number on the call.
START TIME = The call time from the live_inbound_log table.
TOTAL POINTS = The sum of the numeric values given for all callmenu survey prompts reached on the call.

ALL AGENT REPORT
AGENT = The name of the agent.
TOTAL POINTS = The sum of the numeric values given for all callmenu survey prompts for calls the agent handled within the report parameters. +CMstats Callmenu Survey Report This report shows one of two report types. The first displays all responses to callmenu prompts on calls handled by a given agent, within a list of selected campaigns, for a given time frame. Each call is displayed in chronological order, and for each call, the prompts and responses given are displayed. Each prompt response is treated as its numerical value to create a point total for the call, and total points per prompt and call are given at the bottom of the report. The second report is a multiple agent report, which utilizes the dates given and campaigns selected (the value in the agent field is ignored). The resulting report gives a summary per agent of the prompts met and total value of the responses given. The results for this report are sorted in descending order based on the total points the agent accrued.

SINGLE AGENT REPORT
PHONE = The customers phone number on the call.
START TIME = The call time from the live_inbound_log table.
TOTAL POINTS = The sum of the numeric values given for all callmenu survey prompts reached on the call.

ALL AGENT REPORT
AGENT = The name of the agent.
TOTAL POINTS = The sum of the numeric values given for all callmenu survey prompts for calls the agent handled within the report parameters. LISTS_campaign_stats Lists Campaign Statuses Report LIST ID SUMMARY = Shows each list in the campaign(s) selected by the user, the count of leads in each list, and whether the list is active or inactive.
STATUS FLAGS SUMMARY = Shows a breakdown of the status flags for all the selected lists in all the selected campaigns combined. Status flags are set in the -Statuses- section of a campaign or the -System Statuses-.
CUSTOM STATUS CATEGORY STATS = Shows a breakdown of the custom status categories for all the selected lists in all the selected campaigns combined. Categories can be defined under the -System Statuses- in the admin section.
PER LIST DETAIL STATS = Shows each list in the campaign(s) selected by the user, with a breakdown of each status flag (and percentage of each flag) and status within that list. LISTS_pass_report Lists Pass Report This is a list inventory report, not a calling report. This report will show statistics for all of the lists in the selected campaigns
FIRST LOAD DATE = Date list first had leads loaded.
LIST ID and NAME = List ID number and name of list.
CAMPAIGN = Campaign that the list currently belongs to.
LEAD COUNT = Number of leads in the list.
ACTIVE = Whether or not the lead was active.
CONTACTS 1st-5th,LIFE PASS = Leads that were -human answered- (dispoed a status where HUMAN ANSWER is set to -Y- on the statuses section) on or after the first-fifth call attempt, or LIFE if contacted as such at any point ever.
CNT RATE 1st-5th PASS = Percentage of leads on the list that were -human answered- on or after the first-fifth call attempt, or LIFE if contacted as such at any point ever.
SALE 1st-5th,LIFE PASS = Leads that were sold to (dispoed a status where SALE is set to -Y- on the statuses section) on or after the first-fifth call attempt, or LIFE if contacted as such at any point ever.
CNV RATE 1st-5th PASS = Percentage of leads on the list that were sold to on or after the first-fifth call attempt, or LIFE if contacted as such at any point ever.
DNC 1st-5th,LIFE PASS = Leads that were dispositioned -do not call- (dispoed a status where DNC is set to -Y- on the statuses section) on or after the first-fifth call attempt, or LIFE if contacted as such at any point ever.
DNC RATE 1st-5th,LIFE PASS = Percentage of leads on the list that were -do not call- on or after the first-fifth call attempt, or LIFE if contacted as such at any point ever.
CUST CONTACT 1st-5th,LIFE PASS = Leads that were -customer contacted- (dispoed a status where CUSTOMER CONTACT is set to -Y- on the statuses section) on or after the first-fifth call attempt, or LIFE if contacted as such at any point ever.
CUCT RATE 1st-5th,LIFE PASS = Percentage of leads on the list that were -customer contacted- on or after the first-fifth call attempt, or LIFE if contacted as such at any point ever.
UNWORKABL 1st-5th,LIFE PASS = Leads that were -unworkable- (dispoed a status where UNWORKABLE is set to -Y- on the statuses section) on or after the first-fifth call attempt, or LIFE if contacted as such at any point ever.
UNWK RATE 1st-5th,LIFE PASS = Percentage of leads on the list that were -unworkable- on or after the first-fifth call attempt, or LIFE if contacted as such at any point ever.
SCHEDL CB 1st-5th,LIFE PASS = Leads that were -scheduled callbacks- (dispoed a status where SCHEDULED CALLBACK is set to -Y- on the statuses section) on or after the first-fifth call attempt, or LIFE if contacted as such at any point ever.
SHCB RATE 1st-5th,LIFE PASS = Percentage of leads on the list that were -scheduled callbacks- on or after the first-fifth call attempt, or LIFE if contacted as such at any point ever.
COMPLETED 1st-5th,LIFE PASS = Leads that were -completed- (dispoed a status where COMPLETED is set to -Y- on the statuses section) on or after the first-fifth call attempt, or LIFE if contacted as such at any point ever.
COMP RATE 1st-5th,LIFE PASS = Percentage of leads on the list that were -completed- on or after the first-fifth call attempt, or LIFE if contacted as such at any point ever. LISTS_stats Lists Statuses Report This report gives a detailed breakdown of the contents of a list or lists.
TOTAL LIST ID SUMMARY = Shows each list selected by the user, the count of leads in the list, and whether the list is active or inactive.
TOTAL STATUS FLAGS SUMMARY = Shows a breakdown of the status flags for all the selected lists combined. Status flags are set in the -Statuses- section of a campaign or the -System Statuses-.
LIST ID SUMMARY = Each list selected in the report will be listed separately after the TOTALS summaries. The list summary gives specific information about each particular list.
STATUS FLAGS BREAKDOWN = Same as TOTAL STATUS FLAGS SUMMARY, but only for one list.
STATUS BREAKDOWN = A breakdown of each status in the individual list, along with the status description, number of leads, and percentage relative to the total leads in the list. @@ -1464,8 +1465,8 @@ OUTBOUNDsummary_interval Outbound Summary Interval Report This report gives VDADstats Outbound Calling Report This report gives several reports on outbound calling for campaigns and lists for a specified date range
CALL HANGUP REASON STATS
HANGUP REASON = The reason the call terminated.
CALLS = The number of calls terminated from the aforementioned reason.
CALL STATUS STATS
STATUS = The call disposition.
DESCRIPTION = The description of the status.
CATEGORY = The category of the status.
CALLS = The number of calls resulting the disposition.
CALL TIME - TOTAL TIME = The total time spent on calls resulting in the disposition.
CALL TIME - AVG TIME = The average amount of time spent on calls resulting in the disposition.
CALL TIME - CALLS/HOUR = The number of calls per hour where the call resulted in the disposition - this is relative to the total time of all dispositions, not just this one.
AGENT TIME - CALLS/HOUR = The number of calls per agent hour where the call resulted in the disposition, relative to the total time agents spent in call for all dispositions.
LIST ID STATS
LIST = The list ID number - all lists meeting the selected criteria are displayed here.
CALLS = The number of outbound calls placed from the aforementioned list.
AGENT PRESET DIALS
PRESET NAME = The preset name logged in the user_call_log table (where applicable) for the outbound calls meeting the selected criteria.
CALLS = The number of calls logged with the aforementioned preset.
CUSTOM STATUS CATEGORY STATS
CATEGORY = The category the custom status is currently assigned to.
CALLS = The number of calls logged with the aforementioned category.
DESCRIPTION = The description of the category.
AGENT STATS
AGENT = The user ID and agent involved on outbound calls meeting the selected criteria.
CALLS = The number of outbound calls handled by the aforementioned agent.
TIME H:M:S = The total amount of time the agent spent on the outbound calls.
AVERAGE = The average amount of time the agent spent on the outbound calls. called_counts_multilist_report Called Counts List IDs Report This report will show a called count breakdown by status for a list or group of lists, optionally within a given date range. Lists may also be selected by campaign. fcstats Fronter - Closer Report This report displays fronter and closer information on an in-group for the selected date - useful in local closer campaigns so you can see the activity on internal transfers.
FRONTER STATS
AGENT = The agent making the transfer (fronter).
XFERS = The number of transfers the agent made.
SALE % = Percentage of transfers the agent made that resulted in a sale.
SALE = Number of sales (statuses where sale status flag is set to Y in the -Statuses- section) made on the agents transfers.
DROP = Number of transfers that were dropped (did not make it to a live closer).
OTHER = Number of transfers that were not dropped, but also not sold by the closer.
CLOSER STATS
AGENT = The agent receiving the transfer (closer).
CALLS = Total calls answered by the closer.
SALE = Number of sales (statuses where sale status flag is set to Y in the -Statuses- section) made on the transfers the closer fielded.
DROP = Number of calls the closer received that were dispoed as dropped.
OTHER = Calls the closer fielded that did not result in sales.
CONV % = Percentage of transfers the closer received that resulted in sales. -inbound_forecasting Inbound forecasting This report uses Erlang B formulas to generate call center stats based on inbound call activity for selected campaigns and/or ingroups across a specified date range. From these statistics and also by entering a desired drop call rate, this report can be used to calculate a recommend number of agents to have on the phones to reach the desired drop rate entered.

CALLING HOUR = The hour interval being reported on.
CALLS = Number of calls showing activity in this hour interval. Unlike other reports, this includes calls that start in the preceding hour, if the length of the call causes the call to end in the current hour. Example: an inbound call to the system begins at 9:59am and lasts for three minutes, ending at 10:02am. This call will be counted in both intervals.
TOTAL TIME = The total amount of time calls were active within this call interval. This includes time in queue waiting for an agent, and as stated for the CALLS section above, calls starting in one hour and ending in the other will have the time spent in each interval counted in both. In the above example, 1 minute will be attributed to the 9am hour and 2 minutes to the 10am hour.
AVERAGE TIME = The average call length for the interval, taken by dividing the total time of call activity within this interval divided by the number of calls active within this interval.
DROPPED HOURS = The total amount of time taken by calls that were dropped with time active within this call interval.
BLOCKING = The drop rate, expressed as a decimal in TEXT or a percent in graph form, of an hourly interval. This is taken by dividing the number dropped calls active in the hour by the number of calls active in the hour.
ERLANGS = Number of Erlangs for the hour. Erlangs are calculated by taking the number of calls received in an interval, multiplied by the average duration of a call expressed as a decimal value relative to the interval. For example, if 100 calls came in during an hour, and the average call length is 6 minutes, the Erlang value is 100 calls/hour * .1 hour (6 minutes is 1/10th of an hour), or 10.
GOS = 'Grade of Service'. This is the probability that a call is dropped, which is given by the equation

GoS = (EM/M!)/(Mn=0 En/n!)

where -GoS- is the desired drop rate, -E- is the Erlang value, and -M- is the number of lines/agents needed
REC AGENTS = The recommended number of agents needed to meet the desired drop rate or the desired queue probability. For the Erlang B report it uses the formula

GoS = (EM/M!)/(Mn=0 En/n!)

where -GoS- is the desired drop rate, -E- is the Erlang value, and -M- is the number of lines/agents needed. For the Erlang C report, the equation used is:

Pqueued = (EM/M!)/[EM/M! + (1 - E/M)M-1n=0 En/n!]

where Pqueued is the queue probability, -E- is the Erlang value, and -M- is the number of lines/agents needed
EST AGENTS = The estimated number of agents based on the current drop rate and Erlangs, as entered by the user, for the hours being reported on. This is reached by using the Erlang B formula, which is

GoS = (EM/M!)/(Mn=0 En/n!)

where -GoS- is the current drop rate, -E- is the Erlang value, and -M- is the number of lines/agents
CALLS/AGENT = The average number of calls each agent received for the time interval, gotten by dividing the number of calls by the number of agents (estimated, if an -actual agent- value is not given) -erlang_report Erlang report This report uses Erlang B and C formulas to generate call center stats based on call activity for selected campaigns and/or ingroups across a specified date range. From these statistics and also by entering a desired drop call rate, this report can be used to calculate a recommend number of agents to have on the phones to reach the desired drop rate entered, and depending on whether the report type being run is -B- or -C-, it will display statistics pertaining to call loss (drop) probability, or wait time probability.

COST ANALYSIS STATS
This is an entirely optional set of data that can be entered to calculate the monetary performance of campaigns/call centers.
Actual agents = If you know the actual number of agents and wish to use this in the report caluclations, enter a non-zero value here. If you leave this blank the report will use the number of agents it estimates is in the dialer to make its reports.
Hourly pay per agent = Hourly wages an average employee makes.
Revenue per sale = How much money each sale made in the selected campaigns/ingroups is worth.
Chance of sale = The estimated percentage of calls that result in a sale (the actual percentage is provided after the report is run).
Retry rate = The percentage of callers that attempt to retry after their call is dropped.

CALLING HOUR = The hour interval being reported on.
CALLS = Number of calls showing activity in this hour interval. Unlike other reports, this includes calls that start in the preceding hour, if the length of the call causes the call to end in the current hour. Example: an inbound call to the system begins at 9:59am and lasts for three minutes, ending at 10:02am. This call will be counted in both intervals.
TOTAL TIME = The total amount of time calls were active within this call interval. This includes time in queue waiting for an agent, and as stated for the CALLS section above, calls starting in one hour and ending in the other will have the time spent in each interval counted in both. In the above example, 1 minute will be attributed to the 9am hour and 2 minutes to the 10am hour.
AVERAGE TIME = The average call length for the interval, taken by dividing the total time of call activity within this interval divided by the number of calls active within this interval.
DROPPED HOURS = The total amount of time taken by calls that were dropped with time active within this call interval.
BLOCKING = The drop rate, expressed as a decimal in TEXT or a percent in graph form, of an hourly interval. This is taken by dividing the number dropped calls active in the hour by the number of calls active in the hour.
ERLANGS = Number of Erlangs for the hour. Erlangs are calculated by taking the number of calls received in an interval, multiplied by the average duration of a call expressed as a decimal value relative to the interval. For example, if 100 calls came in during an hour, and the average call length is 6 minutes, the Erlang value is 100 calls/hour * .1 hour (6 minutes is 1/10th of an hour), or 10.
GOS = 'Grade of Service'. A -B- report value - this is the probability that a call is dropped, which is given by the equation

GoS = (EM/M!)/(Mn=0 En/n!)

where -GoS- is the desired drop rate, -E- is the Erlang value, and -M- is the number of lines/agents needed
QUEUE PROB = A -C- report value - the probability that a call is queued, which is given by the equation

Pqueued = (EM/M!)/[EM/M! + (1 - E/M)M-1n=0 En/n!]

where Pqueued is the queue probability, -E- is the Erlang value, and -M- is the number of lines/agents needed
AVERAGE ANSWER = A -C- report value - the average speed of answer, or average call waiting time. This is given by the equation

ASA = (T*Pqueued)/(M-E)

-ASA- is the average speed of answer, -T- is the average duration of the call, Pqueued is the queue probability, -E- is the Erlang value, and -M- is the number of lines/agents needed. Both this and the Pqueued formulas above are only valid if -M- is greater than -E-, that is, the number of trunks in a system is greater than the number of Erlangs.
REC AGENTS = The recommended number of agents needed to meet either the desired drop rate or the desired queue probability. These values are entered by the user and depending on whether the report being run is type -B- or type -C- the report will base their estimate on one of those values. For the Erlang B report it uses the formula

GoS = (EM/M!)/(Mn=0 En/n!)

where -GoS- is the desired drop rate, -E- is the Erlang value, and -M- is the number of lines/agents needed. For the Erlang C report, the equation used is:

Pqueued = (EM/M!)/[EM/M! + (1 - E/M)M-1n=0 En/n!]

where Pqueued is the queue probability, -E- is the Erlang value, and -M- is the number of lines/agents needed
EST AGENTS = The estimated number of agents based on the current drop rate and Erlangs, as entered by the user, for the hours being reported on. This is reached by using the Erlang B formula, for both the B and C report. Since Vicidial does not log what calls were queued in outbound dialing, the -C- report instead uses the drop rate of outbound calls to estimate agents. The formula is

GoS = (EM/M!)/(Mn=0 En/n!)

where -GoS- is the current drop rate, -E- is the Erlang value, and -M- is the number of lines/agents
CALLS/AGENT = The average number of calls each agent received for the time interval, gotten by dividing the number of calls by the number of agents (estimated, if an -actual agent- value is not given)
REV/CALL = Average revenue per call, taken by multiplying the revenue per sale by the number of sales, then dividing by the number of calls
REV/AGENT = Average revenue generated per agent, based on the total revenue (sales * revenue per sale) divided by the number of agents (estimated, if an -actual agent- value is not given)
TOTAL REV = Total revenue, gotten by multiplying the number of sales by the revenue per sale
TOTAL COST = Total cost, gotten by multiplying the agent rate by the number of agents (estimated, if an -actual agent- value is not given)
MARGIN = The difference between the total revenue and the total cost +inbound_forecasting Inbound forecasting This report uses Erlang B formulas to generate call center stats based on inbound call activity for selected campaigns and/or ingroups across a specified date range. From these statistics and also by entering a desired drop call rate, this report can be used to calculate a recommend number of agents to have on the phones to reach the desired drop rate entered.

CALLING HOUR = The hour interval being reported on.
CALLS = Number of calls showing activity in this hour interval. Unlike other reports, this includes calls that start in the preceding hour, if the length of the call causes the call to end in the current hour. Example: an inbound call to the system begins at 9:59am and lasts for three minutes, ending at 10:02am. This call will be counted in both intervals.
TOTAL TIME = The total amount of time calls were active within this call interval. This includes time in queue waiting for an agent, and as stated for the CALLS section above, calls starting in one hour and ending in the other will have the time spent in each interval counted in both. In the above example, 1 minute will be attributed to the 9am hour and 2 minutes to the 10am hour.
AVERAGE TIME = The average call length for the interval, taken by dividing the total time of call activity within this interval divided by the number of calls active within this interval.
DROPPED HOURS = The total amount of time taken by calls that were dropped with time active within this call interval.
BLOCKING = The drop rate, expressed as a decimal in TEXT or a percent in graph form, of an hourly interval. This is taken by dividing the number dropped calls active in the hour by the number of calls active in the hour.
ERLANGS = Number of Erlangs for the hour. Erlangs are calculated by taking the number of calls received in an interval, multiplied by the average duration of a call expressed as a decimal value relative to the interval. For example, if 100 calls came in during an hour, and the average call length is 6 minutes, the Erlang value is 100 calls/hour * .1 hour (6 minutes is 1/10th of an hour), or 10.
GOS = -Grade of Service-. This is the probability that a call is dropped, which is given by the equation

GoS = (EM/M!)/(Mn=0 En/n!)

where -GoS- is the desired drop rate, -E- is the Erlang value, and -M- is the number of lines/agents needed
REC AGENTS = The recommended number of agents needed to meet the desired drop rate or the desired queue probability. For the Erlang B report it uses the formula

GoS = (EM/M!)/(Mn=0 En/n!)

where -GoS- is the desired drop rate, -E- is the Erlang value, and -M- is the number of lines/agents needed. For the Erlang C report, the equation used is:

Pqueued = (EM/M!)/[EM/M! + (1 - E/M)M-1n=0 En/n!]

where Pqueued is the queue probability, -E- is the Erlang value, and -M- is the number of lines/agents needed
EST AGENTS = The estimated number of agents based on the current drop rate and Erlangs, as entered by the user, for the hours being reported on. This is reached by using the Erlang B formula, which is

GoS = (EM/M!)/(Mn=0 En/n!)

where -GoS- is the current drop rate, -E- is the Erlang value, and -M- is the number of lines/agents
CALLS/AGENT = The average number of calls each agent received for the time interval, gotten by dividing the number of calls by the number of agents (estimated, if an -actual agent- value is not given) +erlang_report Erlang report This report uses Erlang B and C formulas to generate call center stats based on call activity for selected campaigns and/or ingroups across a specified date range. From these statistics and also by entering a desired drop call rate, this report can be used to calculate a recommend number of agents to have on the phones to reach the desired drop rate entered, and depending on whether the report type being run is -B- or -C-, it will display statistics pertaining to call loss (drop) probability, or wait time probability.

COST ANALYSIS STATS
This is an entirely optional set of data that can be entered to calculate the monetary performance of campaigns/call centers.
Actual agents = If you know the actual number of agents and wish to use this in the report caluclations, enter a non-zero value here. If you leave this blank the report will use the number of agents it estimates is in the dialer to make its reports.
Hourly pay per agent = Hourly wages an average employee makes.
Revenue per sale = How much money each sale made in the selected campaigns/ingroups is worth.
Chance of sale = The estimated percentage of calls that result in a sale (the actual percentage is provided after the report is run).
Retry rate = The percentage of callers that attempt to retry after their call is dropped.

CALLING HOUR = The hour interval being reported on.
CALLS = Number of calls showing activity in this hour interval. Unlike other reports, this includes calls that start in the preceding hour, if the length of the call causes the call to end in the current hour. Example: an inbound call to the system begins at 9:59am and lasts for three minutes, ending at 10:02am. This call will be counted in both intervals.
TOTAL TIME = The total amount of time calls were active within this call interval. This includes time in queue waiting for an agent, and as stated for the CALLS section above, calls starting in one hour and ending in the other will have the time spent in each interval counted in both. In the above example, 1 minute will be attributed to the 9am hour and 2 minutes to the 10am hour.
AVERAGE TIME = The average call length for the interval, taken by dividing the total time of call activity within this interval divided by the number of calls active within this interval.
DROPPED HOURS = The total amount of time taken by calls that were dropped with time active within this call interval.
BLOCKING = The drop rate, expressed as a decimal in TEXT or a percent in graph form, of an hourly interval. This is taken by dividing the number dropped calls active in the hour by the number of calls active in the hour.
ERLANGS = Number of Erlangs for the hour. Erlangs are calculated by taking the number of calls received in an interval, multiplied by the average duration of a call expressed as a decimal value relative to the interval. For example, if 100 calls came in during an hour, and the average call length is 6 minutes, the Erlang value is 100 calls/hour * .1 hour (6 minutes is 1/10th of an hour), or 10.
GOS = -Grade of Service-. A -B- report value - this is the probability that a call is dropped, which is given by the equation

GoS = (EM/M!)/(Mn=0 En/n!)

where -GoS- is the desired drop rate, -E- is the Erlang value, and -M- is the number of lines/agents needed
QUEUE PROB = A -C- report value - the probability that a call is queued, which is given by the equation

Pqueued = (EM/M!)/[EM/M! + (1 - E/M)M-1n=0 En/n!]

where Pqueued is the queue probability, -E- is the Erlang value, and -M- is the number of lines/agents needed
AVERAGE ANSWER = A -C- report value - the average speed of answer, or average call waiting time. This is given by the equation

ASA = (T*Pqueued)/(M-E)

-ASA- is the average speed of answer, -T- is the average duration of the call, Pqueued is the queue probability, -E- is the Erlang value, and -M- is the number of lines/agents needed. Both this and the Pqueued formulas above are only valid if -M- is greater than -E-, that is, the number of trunks in a system is greater than the number of Erlangs.
REC AGENTS = The recommended number of agents needed to meet either the desired drop rate or the desired queue probability. These values are entered by the user and depending on whether the report being run is type -B- or type -C- the report will base their estimate on one of those values. For the Erlang B report it uses the formula

GoS = (EM/M!)/(Mn=0 En/n!)

where -GoS- is the desired drop rate, -E- is the Erlang value, and -M- is the number of lines/agents needed. For the Erlang C report, the equation used is:

Pqueued = (EM/M!)/[EM/M! + (1 - E/M)M-1n=0 En/n!]

where Pqueued is the queue probability, -E- is the Erlang value, and -M- is the number of lines/agents needed
EST AGENTS = The estimated number of agents based on the current drop rate and Erlangs, as entered by the user, for the hours being reported on. This is reached by using the Erlang B formula, for both the B and C report. Since Vicidial does not log what calls were queued in outbound dialing, the -C- report instead uses the drop rate of outbound calls to estimate agents. The formula is

GoS = (EM/M!)/(Mn=0 En/n!)

where -GoS- is the current drop rate, -E- is the Erlang value, and -M- is the number of lines/agents
CALLS/AGENT = The average number of calls each agent received for the time interval, gotten by dividing the number of calls by the number of agents (estimated, if an -actual agent- value is not given)
REV/CALL = Average revenue per call, taken by multiplying the revenue per sale by the number of sales, then dividing by the number of calls
REV/AGENT = Average revenue generated per agent, based on the total revenue (sales * revenue per sale) divided by the number of agents (estimated, if an -actual agent- value is not given)
TOTAL REV = Total revenue, gotten by multiplying the number of sales by the revenue per sale
TOTAL COST = Total cost, gotten by multiplying the agent rate by the number of agents (estimated, if an -actual agent- value is not given)
MARGIN = The difference between the total revenue and the total cost rt_monitor_log_report Real-time monitoring log report This report enables level 9 users, users with Admin Utilities privileges, to search the logs of Vicidial managers who utilized the monitoring capabilities of the real-time report. Searches can be done for date ranges, campaigns, managers, and agents being monitored, and the results can be sorted by any of the following data returned by the report.

START TIME = The time the manager started monitoring an agent
MANAGER = The manager who initiated the monitoring session
MANAGER SERVER = The IP address of the server the manager was monitoring from
MANAGER PHONE = The phone login the manager used to monitor the agent
MANAGER IP = The IP address of the computer the manager was monitoring from
AGENT MONITORED = The agent ID and name of the agent being monitored
AGENT SERVER = The IP address of the server the agent phone was operating from
AGENT STATUS = The dialer status of the agent at the time the monitoring session was initiated
AGENT SESSION = The session ID of the agent at the time the monitoring session was initiated
LEAD ID = The lead ID the agent was speaking to at the time the monitoring session was initiated. If the agent was not in a call at the time the manager started monitoring them, this value will be -0-
CAMPAIGN = The campaign ID the agent being monitored was placing calls from at the time they started being monitored
END TIME = The time the manager stopped monitoring the agent, ending the monitoring session
LENGTH = The total length in seconds of the monitoring session
TYPE = The type of monitoring session that the manager was running rt_whiteboard_report Real-Time Whiteboard report This report allows the user to display reports in a large graph form with associated statistics printed with the report, and the report will be refreshed at a set interval. This is useful for overhead projections where the user needs to display a set of data in a comprehensive, easy-to-read format. Also, when the user selects a report to display, any report option relevant to that report will be highlighted in red: campaigns, status flags, etc.... rt_whiteboard_report-report_type Report Type The type of report to display.
  • Disposition Totals - A breakdown of disposition totals of calls made.
  • Agent Performance Totals - Shows total calls and sales for agents within a specified date-time range.
  • Agent Performance Rates - Shows conversion rates for agents within a specified date-time range.
  • Team Performance Totals - Shows total calls and sales for teams/user groups within a specified date-time range.
  • Team Performance Rates - Shows converstion rates for teams/user groups within a specified date-time range.
  • Floor Performance Totals (ticker) - Shows cumulative total of sales in a -ticker- format-line graph, with an option to draw a target gross sales.
  • Floor Performance Rates (ticker) - Shows time-elapsed conversion in a -ticker- format-line graph, with an option to draw a target conversion rate.
  • Ingroup Performance Total - Shows total calls and sales for selected ingroups within a specified date-time range.
  • Ingroup Performance Rates - Shows conversion rates for selected ingroups within a specified date-time range.
  • DID Performance Total - Shows total calls and sales for selected DIDs within a specified date-time range.
  • DID Performance Rates - Shows conversion rates for selected DIDs within a specified date-time range.
@@ -1477,7 +1478,7 @@ rt_whiteboard_report-show_results Show results for the past X hours If fill timeclockstatusreport Timeclock Status Report Shows timeclock status of users belonging to a selected user group. user_group_hourly_detail User Group Hourly Report Gives hourly count of distinct agents per user group, with totals. For single days only. usertimeclockreport User Timeclock Report Gives the total hours agents logged in the dialer timeclock, with totals. Can be filtered by user group/user/date range and sorted. -api_log_report API Log report This report shows all records in the API logging table that meet the report criteria. Reports can be run by date range that the API was accessed, the user, agent user, the API function called, and the API result. The report can also be run to include the actual URL of the API that was called and the IP address the request came from.

Additionally, if this extended version of the report is run, the variables used in the API call can be listed separately if the user creates a system container in the System Containers settings by the name of API_LOG_URL_COLUMNS (name must be exact). In this container, variable names are listed individually per line, and each listed variable is given it's own column in the detailed URL report. +api_log_report API Log report This report shows all records in the API logging table that meet the report criteria. Reports can be run by date range that the API was accessed, the user, agent user, the API function called, and the API result. The report can also be run to include the actual URL of the API that was called and the IP address the request came from.

Additionally, if this extended version of the report is run, the variables used in the API call can be listed separately if the user creates a system container in the System Containers settings by the name of API_LOG_URL_COLUMNS (name must be exact). In this container, variable names are listed individually per line, and each listed variable is given its own column in the detailed URL report. sip_event_report SIP Event Report This report is only useful if you have enabled SIP Event Logging on your system(see the SIP Event Logging description in the Campaigns section in this manual for more information). This report will allow you to sort the SIP-messages for calls by several criteria. This report was used during the development of the campaign SIP Actions feature to help determine what calls were False Answer Supervision, by sorting the Ring-Time UP and DOWN. quality_control_report Quality Control Report This report shows quality control call activity within user-selected parameters. If displayed as HTML, it will output each individual call with a header row that shows things like the call date, agent, campaign, call status, QC scorecard and QC result. Underneath that, each checkpoint in the scorecard applied to call will be displayed as individual rows with scores and comments per checkpoint. The report can also be downloaded as a CSV where each call will be a row in the resulting file with the checkpoint data appended toe ach row.

CALL DATE = The date range in which the call was originally made.
FINISH DATE = The date the QC agent who evaluated the call marked it as finished. This will automatically filter out unfinished calls if this is used, regardless of what QC statuses (see below) are selected.
CAMPAIGNS = The campaign the original call was made under.
QC STATUS = The current status of the call in the quality control system - this is NOT the call status from dialing.
USERS = The agent(s) who placed the original calls.
QC AGENTS = The agents who evaluated the call in the quality control system.
SHOW %s = If this box is checked, the scores given by the QC agents will be displayed as percentages instead of points.
SEARCH ARCHIVED DATA = If this is checked, the archived quality control log tables will be searched if they exist. nanpa-running Currently running NANPA scrubs Displays a log of the currently running scrubs, including: Start Time, Leads Count, Filter Count, Status Line, Time to Complete, Field Updated, and Field excluded @@ -1502,8 +1503,8 @@ user_inbound_calls_today User Inbound Calls Today This page will show you t custom_reports_admin-report_name Report Name The report name that the report will be referred to as in the system for purposes of user group access and secondary server use in the system settings. The report name may not be the same as any other custom report, nor may it be the same name as one of the standard system reports. custom_reports_admin-domain Domain The domain that the report is located at. This will be combined with the path name to make a complete URL to use as a link from the reports page. You may leave this blank when the report is located on the same server as the web admin and just use the path name field to make a local URL. custom_reports_admin-path_name Path name The path on the domain where the report is located. When the domain is blank it is assumed that the report is housed on the local web server. -custom_reports_admin-constants Preset constants Here is where a user can define a preset value to pass to the report when it is accessed from the custom report link. This is useful if the user is viewing a report that accepts multiple variables that change the report output and there is a certain set of report parameters the user frequently uses and they wish to save time by coming to the report with those values already set.
Variable name -The enters the variable name here. Names allow alphanumeric characters, underscores, and to a limited extent brackets. Brackets are used to pass an array to the report and should be placed at the end of the variable name, such as 'var_name[]'. The interface will condense brackets by removing any characters within a pair of them, and will also remove unmatched brackets.
Value -Then, the user enters a variable value in the 'Value' field, either by selecting a pre-defined variable value or a custom value. With the exception of 'datetime' and 'filedatetime', all pre-defined variables are dates in yyyy-mm-dd format. The predefined values are: 'today' for today's date, 'yesterday' for yesterday's date, 'datetime' which is a timestamp in the format of 'yyyy-mm-dd hh:ii:ss', 'filedatetime' which is an all-numeric timestamp in the format 'yyyymmddhhiiss', and 6/7/8/13/14/15/30days, all of which are the date 6/7/etc days ago. If the user would like to define their own value for the variable, they can set the value to 'Custom Value', then fill out the custom value in the field to the right. Click 'ADD' to add the variable name/value pair to the presets to include in the report. Values will be URL-encoded prior to being entered in the database. -custom_reports_admin-current_constants Current constants Any report constant the user has entered to add to the report is displayed here. They are not editable, but they can be removed by clicking 'REMOVE' and then re-entered. +custom_reports_admin-constants Preset constants Here is where a user can define a preset value to pass to the report when it is accessed from the custom report link. This is useful if the user is viewing a report that accepts multiple variables that change the report output and there is a certain set of report parameters the user frequently uses and they wish to save time by coming to the report with those values already set.
Variable name -The enters the variable name here. Names allow alphanumeric characters, underscores, and to a limited extent brackets. Brackets are used to pass an array to the report and should be placed at the end of the variable name, such as 'var_name[]'. The interface will condense brackets by removing any characters within a pair of them, and will also remove unmatched brackets.
Value -Then, the user enters a variable value in the -Value- field, either by selecting a pre-defined variable value or a custom value. With the exception of 'datetime' and 'filedatetime', all pre-defined variables are dates in yyyy-mm-dd format. The predefined values are: 'today' for todays date, 'yesterday' for yesterdays date, 'datetime' which is a timestamp in the format of 'yyyy-mm-dd hh:ii:ss', 'filedatetime' which is an all-numeric timestamp in the format 'yyyymmddhhiiss', and 6/7/8/13/14/15/30days, all of which are the date 6/7/etc days ago. If the user would like to define their own value for the variable, they can set the value to -Custom Value-, then fill out the custom value in the field to the right. Click -ADD- to add the variable name/value pair to the presets to include in the report. Values will be URL-encoded prior to being entered in the database. +custom_reports_admin-current_constants Current constants Any report constant the user has entered to add to the report is displayed here. They are not editable, but they can be removed by clicking -REMOVE- and then re-entered. custom_reports_admin-preset_constants Preset constants This textarea field is where presets for the current custom reports are displayed and can be edited. The name/value pairs are displayed per-line and are fully editable. Users can also remove variables simply by deleting the line they are displayed on, or can enter new name/value pairs per line. Variables can also be separated by an ampersand as in the typical URL GET display - the dialer interface will make the necessary adjustments to display them properly in this textarea field. inbound_groups-na_chat_url No Agent Chat URL This web URL address is not seen by the agent, but if it is populated it is called every time a chat that is not handled by an agent is hung up or transferred. Uses the same variables as the web form fields and scripts. --A--dispo--B-- can be used to retrieve the system-defined disposition for the chat. This URL can NOT be a relative path. Default is blank. Custom Fields are not available with this feature. inbound_groups-next_agent_chat Next Agent Chat This determines which agent receives the next chat that is available:
  - random: orders by the random update value in the live_agents table
  - oldest_call_start: orders by the last time an agent was sent a call/chat. Results in agents receiving about the same number of calls/chats overall.
  - oldest_call_finish: orders by the last time an agent finished a call/chat. AKA agent waiting longest receives first call.
  - oldest_inbound_call_start: orders by the last time an agent was sent an inbound call. Results in agents receiving about the same number of calls/chats overall.
  - oldest_inbound_call_finish: orders by the last time an agent finished an inbound call. AKA agent waiting longest receives first call.
  - oldest_inbound_filtered_call_start: orders by the last time an agent was sent an inbound call that was not of a filtered-out status, in-group or length.
  - oldest_inbound_filtered_call_finish: orders by the last time an agent finished an inbound call that was not of a filtered-out status, in-group or length.
  - overall_user_level: orders by the user_level of the agent as defined in the users table a higher user_level will receive more calls/chats.
  - inbound_group_rank: orders by the rank given to the agent for the specific inbound group. Highest to Lowest.
  - campaign_rank: orders by the rank given to the agent for the campaign. Highest to Lowest.
  - ingroup_grade_random: gives a higher probability of getting a call/chat to the higher graded agents by in-group.
  - campaign_grade_random: gives a higher probability of getting a call/chat to the higher graded agents by campaign.
  - fewest_calls: orders by the number of calls/chats received by an agent for that specific inbound group. Least calls/chats first.
  - fewest_calls_campaign: orders by the number of calls/chats received by an agent for the campaign. Least calls/chats first.
  - longest_wait_time: orders by the amount of time agent has been actively waiting for a call/chat.
  - ring_all: rings all available agents until one picks up the phone.
NOTES: For ring_all, the agents that are using phones that have On Hook Agent enabled will have their phones ring and the first one to answer will receive the call and the information on the agent screen. Since ring_all ignores agent wait time and ranking and will call every agent that is available for the queue, we do not recommend using this method for large queues. When using ring_all, agents logged with phones that have the On Hook Agent disabled will have to use the Calls In Queue panel and click on the TAKE CALL link to take calls in queue. The amount of time the agents phone will ring for ring_all is set to the On-Hook Ring Time setting or the shortest ring time of the phones that will be called. We do not recommend using ring_all on high call volume queues, or queues with many agents. The ring_all method is intended to be used with only a few agents and on low call volume in-groups. @@ -1561,7 +1562,7 @@ ACCIDDELETE AC-CID Bulk Delete This will delete the Areacode Caller ID entr call_export_report Call Export Report This report is for the downloading of leads and their vicidial_log and/or vicidial_closer_log information by status, list_id and date range. Report downloads to a flat text file that is tab delimited. call_export_report-user User This option will filter all calls to a specific user - user group permissions for the report user still apply, however. call_export_report-date_field Date Field This option will determine if the data exported will be by call log date or the entry date of when the lead was added to the system. -call_export_report-sort_dir Sort Order This option will determine if the data exported will sorted in ascending or descending order by the "Date Field" option selected. Default is ascending. +call_export_report-sort_dir Sort Order This option will determine if the data exported will sorted in ascending or descending order by the -Date Field- option selected. Default is ascending. call_export_report-header_row Header Row If enabled, the first line in the exported data file will be a list of the headers for the data in the file. call_export_report-rec_fields Recording Fields If enabled, the recordings for the latest phone call for the selected leads will be included in the export. If there is more than one recording, they will be pipe-delimited. call_export_report-custom_fields Custom Fields If Custom List Fields is enabled on your system, and the leads you are exporting have custom fields values stored in the database, they will be included in the export. @@ -1590,9 +1591,9 @@ cb-bulk-cb-dates Scheduled callback dates The date the leads are scheduled qc_scorecards-active_checkpoint Active (checkpoint) Whether or not the checkpoint is active within the scorecard. Inactive checkpoints are not displayed outside the QC scorecard interface. qc_scorecards-admin_notes Checkpoint Admin Notes Any administrative notes - these are not viewable to the QC agent. qc_scorecards-checkpoint_text Checkpoint Text The text instructions for the agent to follow. -qc_scorecards-preset_comments Preset Comments If you want to give the quality control agents the option of adding standardized comments to their QC comments per checkpoint, type them into the corresponding "Preset comments" box, one per line. If a checkpoint has preset comments, they will appear in a drop-down menu to the right of the agent's comment box in their scorecard interface and can be inserted into the comments box by selecting the comment and clicking either the "ADD TO COMMENTS" or "TIMESTAMP & ADD" button. +qc_scorecards-preset_comments Preset Comments If you want to give the quality control agents the option of adding standardized comments to their QC comments per checkpoint, type them into the corresponding -Preset comments- box, one per line. If a checkpoint has preset comments, they will appear in a drop-down menu to the right of the agents comment box in their scorecard interface and can be inserted into the comments box by selecting the comment and clicking either the -ADD TO COMMENTS- or -TIMESTAMP & ADD- button. qc_scorecards-instant_fail Instant Fail Whether or not the checkpoint will have the option to instantly fail the call. -qc_scorecards-modify Modifying checkpoints Any changes made to a checkpoint will be saved automatically so there is no "UPDATE" or "MODIFY" button necessary. +qc_scorecards-modify Modifying checkpoints Any changes made to a checkpoint will be saved automatically so there is no -UPDATE- or -MODIFY- button necessary. qc_scorecards-new_active Active (scorecard) Whether or not the new scorecard is active. Inactive scorecards are not viewable or usable outside the QC scorecard interface. qc_scorecards-new_scorecard_id New Scorecard ID The ID code of the new scorecard, similar to the ID of campaigns, user groups, in-groups, etc. Alphanumeric, 20-character max qc_scorecards-new_scorecard_name New Scorecard Name The full descriptive name of the scorecard. 255-character max @@ -1600,11 +1601,11 @@ qc_scorecards-order Order The order in which the checkpoint will appear whe qc_scorecards-points Checkpoint Points The maximum point value of the checkpoint. rt_state_report Real-Time State report This report compiles statistical information by state or province and displays it graphically on a map of the US, with a subsection for Canadian provinces as well. States and provinces get shaded a color representative of their performance for the type of report selected, meaning the better a state performs the darker it will be shaded on the map. States with no report results will remain in a shade of gray. A comprehensive report is always provided for the entire database, but statistics for individual states and provinces can be brought up simply by clicking on the state on the map (or in the case of small states and Canadian provinces, clicking on the box containing their respective abbreviation). The report is automatically reloaded after a selected interval to reflect the current performance within the selected time frame. It can display a simple inventory breakdown, call volume, contact volume, sales volume, contact rate relative to call volume, and sales rate relative to contact volume. Data can be filtered by campaign, user group, user, in-groups, DIDs, and status types. Additionally, the report can compile data based on either a starting point in time, or a window of time in hours relative to the current time. The report handles both inbound and outbound calls. rt_state_report-parameters Campaigns,Status Flags,User Groups,Users,In-Groups,DIDs Parameters that may or may not be required based on the type of report run. Available options are dependent on the user permissions. Additionally, selecting specific campaigns combined with selecting -ALL- for ingroups will restrict the -ALL- selection to only ingroups for the selected campaigns. Specific campaign selection will also limit the statuses counted if any status flags are selected. -rt_state_report-report_date Report date/time The date and time to report on through to the current date and time when generating statistics. This will be overriden if the "show results for the past XX hours" parameter is used +rt_state_report-report_date Report date/time The date and time to report on through to the current date and time when generating statistics. This will be overriden if the -show results for the past XX hours- parameter is used rt_state_report-report_type Report Type The type of state/province breakdown report to display.
  • Current state counts - covers all the leads in the database
  • Call Volume - covers the number of calls made or received in the database
  • Contact Volume - covers the number of calls dispositioned as customer contacts made or received in the database.
  • Sale Volume - covers the number of calls dispositioned as sales made or received in the database
  • Contact Rate - calculates contact rate percentages for leads dispositioned as customer contacts against calls made/received
  • Sale Rate - calculates sale rate percentages for leads dispositioned as sales against calls made/received that were dispositioned as customer contacts
-rt_state_report-show_results Show results for the past XX hours The number of hours to go back to, relative to the current time, when querying the database for log records to generate the call statistics with. For example, entering "8" in this field means the report will only show statistics for calls handled in the last eight hours. -rt_state_report-target_rate Target rate If this parameter is used and the report type selected is one of the two "rate" reports, any state meeting or exceeding the target volume is automatically shaded the darkest color to signify it has met the target. -rt_state_report-target_volume Target volume If this parameter is used and the report type selected is one of the three "volume" reports, any state meeting or exceeding the target volume is automatically shaded the darkest color to signify it has met the target. +rt_state_report-show_results Show results for the past XX hours The number of hours to go back to, relative to the current time, when querying the database for log records to generate the call statistics with. For example, entering -8- in this field means the report will only show statistics for calls handled in the last eight hours. +rt_state_report-target_rate Target rate If this parameter is used and the report type selected is one of the two -rate- reports, any state meeting or exceeding the target volume is automatically shaded the darkest color to signify it has met the target. +rt_state_report-target_volume Target volume If this parameter is used and the report type selected is one of the three -volume- reports, any state meeting or exceeding the target volume is automatically shaded the darkest color to signify it has met the target. scheduled_callbacks_auto_reschedule Scheduled Callbacks Auto Reschedule This feature only affects ANYONE scheduled callbacks. If DAY_1 is used, it will automatically reschedule lead lead to be called back on the next calling day at thee same time they were called if the resulting disposition of the call was not a Human Answer -Y- status. The next calling day is determined by the Call Time that is set for the campaign. In the case of DAY_1, if tomorrow is not an allowed calling day, the system will look at the next day and then the next day until it finds the next allowable calling day to set the ANYONE scheduled callback for. There are up to 6 DAY options, then there are up to 3 WEEK options, then there are up to 6 MONTH options. Default is DISABLED. scheduled_callbacks_timezones_container Scheduled Callbacks Local Timezones If set to something other than ---DISABLED---, the selected TIMEZONE_LIST type of Settings Container will be used to display a list of time zones in the Scheduled Callback panel of the agent screen that would be used to set the scheduled callback by one of those local times. A TIMEZONE_LIST type of Settings Container would need to be created that will contain one timezone per line with each line containing the 3-letter Country Code, the TimeZone Code, a Y or N for whether Daylight Saving Time is observed in that zone, and a short description of the time zone as you want it to appear to the agents. For example, for the Eastern United States time zone, you could put -USA,EST,Y,Eastern Time Zone-, without the dashes. To see a list of the available time zone combinations on your system, go to the Admin, System Settings page and click on the -Phone Codes- link on that page. Default is DISABLED, and the scheduled callbacks screen will use the agent server time to set callbacks. user_stats-date_field Date Fields These fields are where you define the date range you want to see User Stats for. Default is today. diff --git a/agc_2-X/trunk/www/vicidial/list_merge.php b/agc_2-X/trunk/www/vicidial/list_merge.php index 5cc3c9b0..970557b2 100644 --- a/agc_2-X/trunk/www/vicidial/list_merge.php +++ b/agc_2-X/trunk/www/vicidial/list_merge.php @@ -1,7 +1,7 @@ LICENSE: AGPLv2 +# Copyright (C) 2026 Matt Florell,Joseph Johnson LICENSE: AGPLv2 # # CHANGES # 161004-2240 - Initial Build @@ -12,16 +12,17 @@ # 201117-1350 - Translation bug fixed, Issue #1236 # 220227-2210 - Added allow_web_debug system setting # 240801-1133 - Code updates for PHP8 compatibility +# 260415-1738 - More code updates for PHP8 compatibility # -$version = '2.14-5'; -$build = '240801-1133'; +$version = '2.14-6'; +$build = '260415-1738'; require("dbconnect_mysqli.php"); require("functions.php"); -$PHP_AUTH_USER=$_SERVER['PHP_AUTH_USER']; -$PHP_AUTH_PW=$_SERVER['PHP_AUTH_PW']; +$PHP_AUTH_USER=(array_key_exists('PHP_AUTH_USER', $_SERVER) ? $_SERVER['PHP_AUTH_USER'] : ""); +$PHP_AUTH_PW=(array_key_exists('PHP_AUTH_PW', $_SERVER) ? $_SERVER['PHP_AUTH_PW'] : ""); $PHP_SELF=$_SERVER['PHP_SELF']; $PHP_SELF = preg_replace('/\.php.*/i','.php',$PHP_SELF); $ip = getenv("REMOTE_ADDR"); @@ -48,22 +49,28 @@ if (isset($_GET["num_leads"])) {$num_leads=$_GET["num_leads"];} elseif (isset($_POST["num_leads"])) {$num_leads=$_POST["num_leads"];} if (isset($_GET["destination_list_id"])) {$destination_list_id=$_GET["destination_list_id"];} elseif (isset($_POST["destination_list_id"])) {$destination_list_id=$_POST["destination_list_id"];} + else {$destination_list_id="";} if (isset($_GET["new_list_id"])) {$new_list_id=$_GET["new_list_id"];} elseif (isset($_POST["new_list_id"])) {$new_list_id=$_POST["new_list_id"];} + else {$new_list_id="";} if (isset($_GET["new_list_name"])) {$new_list_name=$_GET["new_list_name"];} elseif (isset($_POST["new_list_name"])) {$new_list_name=$_POST["new_list_name"];} + else {$new_list_name="";} if (isset($_GET["new_list_description"])) {$new_list_description=$_GET["new_list_description"];} elseif (isset($_POST["new_list_description"])) {$new_list_description=$_POST["new_list_description"];} + else {$new_list_description="";} if (isset($_GET["active"])) {$active=$_GET["active"];} elseif (isset($_POST["active"])) {$active=$_POST["active"];} + else {$active="";} if (isset($_GET["campaign_id"])) {$campaign_id=$_GET["campaign_id"];} elseif (isset($_POST["campaign_id"])) {$campaign_id=$_POST["campaign_id"];} + else {$campaign_id="";} if (isset($_GET["retain_original_list"])) {$retain_original_list=$_GET["retain_original_list"];} elseif (isset($_POST["retain_original_list"])) {$retain_original_list=$_POST["retain_original_list"];} + else {$retain_original_list="";} if (isset($_GET["create_new_list"])) {$create_new_list=$_GET["create_new_list"];} elseif (isset($_POST["create_new_list"])) {$create_new_list=$_POST["create_new_list"];} - -$DB = preg_replace('/[^0-9]/','',$DB); + else {$create_new_list="";} ############################################# ##### START SYSTEM_SETTINGS LOOKUP ##### @@ -89,7 +96,8 @@ else # there is something really weird if there are no system settings exit; } -if ($SSallow_web_debug < 1) {$DB=0;} +if ($SSallow_web_debug < 1 || !isset($DB)) {$DB=0;} +$DB=preg_replace("/[^0-9a-zA-Z]/","",$DB); ##### END SETTINGS LOOKUP ##### ########################################### @@ -615,7 +623,7 @@ if (($submit != "submit" ) && ($confirm != "CONFIRM")) echo "
\n"; echo "
:
:         
: : \n"; if ($available_countries>0) { - echo "\t\t\t\t\n"; + echo "\t\t\t\t\n"; echo $drop_down_dnc_options; } else { - echo "\t\t\t\t\n"; + echo "\t\t\t\t\n"; } echo "\t\t
"._QXZ("List Description").": $NWB#lists-list_description$NWE
"._QXZ("Campaign").":