mirror of
https://github.com/salesagility/SuiteCRM.git
synced 2024-12-22 12:28:31 +00:00
1296 lines
56 KiB
PHP
Executable File
1296 lines
56 KiB
PHP
Executable File
<?php
|
|
/**
|
|
*
|
|
* SugarCRM Community Edition is a customer relationship management program developed by
|
|
* SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
|
|
*
|
|
* SuiteCRM is an extension to SugarCRM Community Edition developed by SalesAgility Ltd.
|
|
* Copyright (C) 2011 - 2018 SalesAgility Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU Affero General Public License version 3 as published by the
|
|
* Free Software Foundation with the addition of the following permission added
|
|
* to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
|
|
* IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
|
|
* OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License along with
|
|
* this program; if not, see http://www.gnu.org/licenses or write to the Free
|
|
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
* 02110-1301 USA.
|
|
*
|
|
* You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
|
|
* SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
|
|
*
|
|
* The interactive user interfaces in modified source and object code versions
|
|
* of this program must display Appropriate Legal Notices, as required under
|
|
* Section 5 of the GNU Affero General Public License version 3.
|
|
*
|
|
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
|
|
* these Appropriate Legal Notices must retain the display of the "Powered by
|
|
* SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not
|
|
* reasonably feasible for technical reasons, the Appropriate Legal Notices must
|
|
* display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM".
|
|
*/
|
|
|
|
if (!defined('sugarEntry') || !sugarEntry) {
|
|
die('Not A Valid Entry Point');
|
|
}
|
|
|
|
require_once('modules/jjwg_Maps/jjwg_Maps_sugar.php');
|
|
require_once('modules/Administration/Administration.php');
|
|
|
|
#[\AllowDynamicProperties]
|
|
class jjwg_Maps extends jjwg_Maps_sugar
|
|
{
|
|
|
|
/**
|
|
* @var settings array
|
|
*
|
|
*/
|
|
public $settings = array(
|
|
'google_maps_api_key' => '',
|
|
/**
|
|
* 'valid_geocode_modules' defines the valid module names used with geocoding.
|
|
* @var array
|
|
*/
|
|
'valid_geocode_modules' => array(
|
|
'Accounts', 'Contacts', 'Leads', 'Opportunities', 'Cases', 'Project', 'Meetings', 'Prospects'
|
|
),
|
|
/**
|
|
* 'valid_geocode_tables' defines the valid table names used with geocoding.
|
|
* @var array
|
|
*/
|
|
'valid_geocode_tables' => array(
|
|
'accounts', 'contacts', 'leads', 'opportunities', 'cases', 'project', 'meetings', 'prospects'
|
|
),
|
|
/**
|
|
* 'geocode_modules_to_address_type' defines the modules address types to be used with geocoding.
|
|
* Acceptable Values: 'billing', 'shipping', 'primary', 'alt', 'flex_relate', 'custom', 'address'
|
|
* @var array
|
|
*/
|
|
'geocode_modules_to_address_type' => array(
|
|
'Accounts' => 'billing',
|
|
'Contacts' => 'primary',
|
|
'Leads' => 'primary',
|
|
'Opportunities' => 'billing',
|
|
'Cases' => 'billing',
|
|
'Project' => 'billing',
|
|
'Meetings' => 'flex_relate',
|
|
'Prospects' => 'primary',
|
|
'Users' => 'address'
|
|
),
|
|
/**
|
|
* 'geocoding_api_url' sets the URL used for geocoding (Google or Proxy)
|
|
* @var string
|
|
*/
|
|
'geocoding_api_url' => 'https://maps.googleapis.com/maps/api/geocode/json?sensor=false',
|
|
/**
|
|
* 'geocoding_api_secret' sets a secret phrase to be used by a Proxy for hash comparison
|
|
* @var string
|
|
* 'hash' is added to the URL parameters as a MD5 of the Concatenation of the Address and the Secret
|
|
*/
|
|
'geocoding_api_secret' => '',
|
|
/**
|
|
* 'geocoding_limit' sets the query limit when selecting records to geocode.
|
|
* @var integer
|
|
*/
|
|
'geocoding_limit' => 250,
|
|
/**
|
|
* 'google_geocoding_limit' sets the request limit when geocoding using the Google Maps API.
|
|
* @var integer
|
|
*/
|
|
'google_geocoding_limit' => 100,
|
|
/**
|
|
* 'allow_approximate_location_type' allows a Geocoding 'location_type' of 'APPROXIMATE' to be considered an 'OK' Status
|
|
*/
|
|
'allow_approximate_location_type' => false,
|
|
/**
|
|
* 'map_markers_limit' sets the query limit when selecting records to display on a map.
|
|
* @var integer
|
|
*/
|
|
'map_markers_limit' => 1000,
|
|
/**
|
|
* 'map_default_unit_type' sets the default unit measurement type for distance calculations.
|
|
* @var string
|
|
* Values: 'mi' (miles) or 'km' (kilometers)
|
|
*/
|
|
'map_default_unit_type' => 'mi',
|
|
/**
|
|
* 'map_default_distance' sets the default distance used for distance based maps.
|
|
* @var float
|
|
*/
|
|
'map_default_distance' => 250,
|
|
/**
|
|
* 'map_duplicate_marker_adjustment' sets an offset to be added to
|
|
* longitude and latitude in case of duplicate marker position.
|
|
* @var float
|
|
*/
|
|
'map_duplicate_marker_adjustment' => 0.00002,
|
|
/**
|
|
* 'export_addresses_limit' sets the query limit when selecting records to export.
|
|
* @var integer
|
|
*/
|
|
'export_addresses_limit' => 50000,
|
|
/**
|
|
* 'map_markers_grouping_field' sets the field to be used as the group parameter when display on a map.
|
|
* @var array
|
|
* Examples: assigned_user_name, industry, status, sales_stage, priority
|
|
*/
|
|
'map_markers_grouping_field' => array(
|
|
'Accounts' => 'industry',
|
|
'Contacts' => 'assigned_user_name',
|
|
'Leads' => 'status',
|
|
'Opportunities' => 'sales_stage',
|
|
'Cases' => 'priority',
|
|
'Project' => 'assigned_user_name',
|
|
'Meetings' => 'assigned_user_name',
|
|
'Prospects' => 'assigned_user_name',
|
|
'Users' => 'user_name'
|
|
),
|
|
/**
|
|
* 'map_clusterer_grid_size' is used to set the grid size for calculating map clusterers.
|
|
* @var integer
|
|
*/
|
|
'map_clusterer_grid_size' => 50,
|
|
/**
|
|
* 'map_clusterer_max_zoom' is used to set the maximum zoom level at which clustering will not be applied.
|
|
* @var integer
|
|
*/
|
|
'map_clusterer_max_zoom' => 14,
|
|
/**
|
|
* 'map_default_center_latitude' sets the default center latitude position for maps.
|
|
* @var float
|
|
*/
|
|
'map_default_center_latitude' => 39.5,
|
|
/**
|
|
* 'map_default_center_longitude' sets the default center longitude position for maps.
|
|
* @var float
|
|
*/
|
|
'map_default_center_longitude' => -99.5,
|
|
/**
|
|
* 'address_cache_get_enabled' allows for the getAddressCacheGeocode()
|
|
* method to retrieve data from cache table: jjwg_Address_Cache
|
|
* @var boolean 1/0
|
|
*/
|
|
'address_cache_get_enabled' => true,
|
|
|
|
/**
|
|
* 'address_cache_save_enabled' allows for the saveAddressCacheGeocode()
|
|
* method to save data to cache table: jjwg_Address_Cache
|
|
* @var boolean 1/0
|
|
*/
|
|
'address_cache_save_enabled' => true,
|
|
|
|
/**
|
|
* 'logic_hooks_enabled' allows admins to disable the logic hooks functionality
|
|
* which is very useful during upgrading processes
|
|
*/
|
|
'logic_hooks_enabled' => false
|
|
);
|
|
|
|
/**
|
|
* relate_object - related module's object (flex relate field)
|
|
* @var object
|
|
*/
|
|
public $relate_object;
|
|
|
|
/**
|
|
* jjwg_Address_Cache - Address cache module's object
|
|
* @var object
|
|
*/
|
|
public $jjwg_Address_Cache;
|
|
|
|
|
|
/**
|
|
* geocoded_counts - Geocoding totals
|
|
* @var array
|
|
*/
|
|
public $geocoded_counts = null;
|
|
|
|
/**
|
|
* geocoded_headings - Display headings
|
|
* @var array
|
|
*/
|
|
public $geocoded_headings = null;
|
|
|
|
/**
|
|
* geocoded_module_totals - Geocoded module totals
|
|
* @var array
|
|
*/
|
|
public $geocoded_module_totals = null;
|
|
|
|
/**
|
|
* geocoding_results - Google Geocoding API Results
|
|
* @var array
|
|
*/
|
|
public $geocoding_results = null;
|
|
|
|
/**
|
|
* map_center - Map Center (Related)
|
|
* @var array
|
|
*/
|
|
public $map_center = null;
|
|
|
|
/**
|
|
* map_markers - Map Marker Data (Display)
|
|
* @var array
|
|
*/
|
|
public $map_markers = null;
|
|
|
|
/**
|
|
* map_markers_groups - Sets the array of map groups
|
|
* @var array
|
|
*/
|
|
public $map_markers_groups = array();
|
|
|
|
/**
|
|
* map_markers - Custom Markers Data (jjwg_Markers)
|
|
* @var array
|
|
*/
|
|
public $custom_markers = null;
|
|
|
|
/**
|
|
* custom_areas - Custom Areas Data (jjwg_Areas)
|
|
* @var array
|
|
*/
|
|
public $custom_areas = null;
|
|
|
|
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
public function __construct($init=true)
|
|
{
|
|
parent::__construct();
|
|
// Admin Config Setting
|
|
if ($init) {
|
|
$this->configuration();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load Configuration Settings using Administration Module
|
|
*
|
|
*/
|
|
public function configuration()
|
|
{
|
|
|
|
// Set defaults
|
|
$GLOBALS['jjwg_config_defaults'] = $this->settings;
|
|
|
|
// Adjust Query Limit
|
|
if ($GLOBALS['sugar_config']['resource_management']['default_limit'] < 20000) {
|
|
$GLOBALS['sugar_config']['resource_management']['default_limit'] = 20000;
|
|
}
|
|
|
|
$admin = BeanFactory::newBean('Administration');
|
|
$admin->retrieveSettings('jjwg', true);
|
|
$settings = $admin->settings;
|
|
|
|
$rev = array();
|
|
if (!empty($settings) && (is_countable($settings) ? count($settings) : 0) > 0) {
|
|
foreach ($settings as $category_name => $value) {
|
|
if (substr((string) $category_name, 0, 5) == 'jjwg_') {
|
|
$name = substr((string) $category_name, 5);
|
|
// Set revised settings array
|
|
$rev[$name] = $value;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!empty($rev) && count($rev) > 0) {
|
|
foreach ($rev as $name => $value) {
|
|
|
|
// Set geocode_modules_to_address_type
|
|
if (substr($name, 0, 13) == 'address_type_') {
|
|
$module = substr($name, 13);
|
|
if (in_array($value, array('billing', 'shipping', 'primary', 'alt', 'flex_relate', 'custom', 'address'))) {
|
|
$this->settings['geocode_modules_to_address_type'][$module] = $value;
|
|
}
|
|
}
|
|
|
|
// Set map_markers_grouping_field
|
|
if (substr($name, 0, 15) == 'grouping_field_') {
|
|
$module = substr($name, 15);
|
|
if (!empty($value)) {
|
|
$this->settings['map_markers_grouping_field'][$module] = $value;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!empty($rev['valid_geocode_modules'])) {
|
|
if (!is_array($rev['valid_geocode_modules'])) {
|
|
$this->settings['valid_geocode_modules'] = preg_split('/[\s,]+/', (string) $rev['valid_geocode_modules']);
|
|
}
|
|
}
|
|
if (!empty($rev['valid_geocode_tables'])) {
|
|
if (!is_array($rev['valid_geocode_tables'])) {
|
|
$this->settings['valid_geocode_tables'] = preg_split('/[\s,]+/', (string) $rev['valid_geocode_tables']);
|
|
}
|
|
}
|
|
|
|
// Integer Settings
|
|
$int_settings = array('geocoding_limit', 'google_geocoding_limit',
|
|
'map_markers_limit', 'map_default_distance', 'export_addresses_limit',
|
|
'map_clusterer_grid_size', 'map_clusterer_max_zoom');
|
|
foreach ($int_settings as $setting) {
|
|
if (isset($rev[$setting]) && is_numeric($rev[$setting])) {
|
|
$this->settings[$setting] = (int) $rev[$setting];
|
|
}
|
|
}
|
|
|
|
// Float/Language Settings
|
|
if (isset($rev['map_default_unit_type']) && in_array($rev['map_default_unit_type'], array('mi', 'km'))) {
|
|
$this->settings['map_default_unit_type'] = $rev['map_default_unit_type'];
|
|
}
|
|
if (isset($rev['map_duplicate_marker_adjustment']) && is_numeric($rev['map_duplicate_marker_adjustment'])) {
|
|
$this->settings['map_duplicate_marker_adjustment'] = (float) $rev['map_duplicate_marker_adjustment'];
|
|
}
|
|
if (isset($rev['map_default_center_latitude']) && is_numeric($rev['map_default_center_latitude'])) {
|
|
$this->settings['map_default_center_latitude'] = (float) $rev['map_default_center_latitude'];
|
|
}
|
|
if (isset($rev['map_default_center_longitude']) && is_numeric($rev['map_default_center_longitude'])) {
|
|
$this->settings['map_default_center_longitude'] = (float) $rev['map_default_center_longitude'];
|
|
}
|
|
|
|
// Address Cache Settings: true/false or 1/0
|
|
$this->settings['address_cache_get_enabled'] = (!empty($rev['address_cache_get_enabled'])) ? true : false;
|
|
$this->settings['address_cache_save_enabled'] = (!empty($rev['address_cache_save_enabled'])) ? true : false;
|
|
// Logic Hooks: true/false or 1/0
|
|
$this->settings['logic_hooks_enabled'] = (!empty($rev['logic_hooks_enabled'])) ? true : false;
|
|
// Allow APPROXIMATE 'location_type'
|
|
$this->settings['allow_approximate_location_type'] = (!empty($rev['allow_approximate_location_type'])) ? true : false;
|
|
|
|
// Set Geocoding API URL or Proxy URL
|
|
if (isset($rev['geocoding_api_url'])) {
|
|
$this->settings['geocoding_api_url'] = $rev['geocoding_api_url'];
|
|
}
|
|
// Set Google Maps API Secret
|
|
if (isset($rev['geocoding_api_secret'])) {
|
|
$this->settings['geocoding_api_secret'] = $rev['geocoding_api_secret'];
|
|
}
|
|
// Set Google Maps API Key
|
|
if (!isset($rev['google_maps_api_key'])) {
|
|
$GLOBALS['log']->warn('Undefined index: google_maps_api_key');
|
|
$this->settings['google_maps_api_key'] = null;
|
|
} else {
|
|
$this->settings['google_maps_api_key'] = $rev['google_maps_api_key'];
|
|
}
|
|
}
|
|
|
|
// Set for Global Use
|
|
$GLOBALS['jjwg_config'] = $this->settings;
|
|
}
|
|
|
|
/**
|
|
* Save Configuration Settings using Administration Module
|
|
*
|
|
* @param $data array of post data
|
|
*/
|
|
public function saveConfiguration($data = array())
|
|
{
|
|
$admin = BeanFactory::newBean('Administration');
|
|
//$admin->retrieveSettings('jjwg', true);
|
|
//$settings = $admin->settings;
|
|
$category = 'jjwg';
|
|
|
|
if (!empty($data) && (is_countable($data) ? count($data) : 0) > 0) {
|
|
if (isset($data['google_maps_api_key'])) {
|
|
$admin->saveSetting($category, 'google_maps_api_key', $data['google_maps_api_key']);
|
|
}
|
|
|
|
if (isset($data['valid_geocode_modules'])) {
|
|
if (is_array($data['valid_geocode_modules'])) {
|
|
$data['valid_geocode_modules'] = implode(', ', $data['valid_geocode_modules']);
|
|
}
|
|
$admin->saveSetting($category, 'valid_geocode_modules', $data['valid_geocode_modules']);
|
|
}
|
|
if (isset($data['valid_geocode_tables'])) {
|
|
if (is_array($data['valid_geocode_tables'])) {
|
|
$data['valid_geocode_tables'] = implode(', ', $data['valid_geocode_tables']);
|
|
}
|
|
$admin->saveSetting($category, 'valid_geocode_tables', $data['valid_geocode_tables']);
|
|
}
|
|
|
|
foreach ($data as $name => $value) {
|
|
|
|
// Trim white space on each
|
|
$value = trim($value);
|
|
|
|
// Set geocode_modules_to_address_type
|
|
if (substr((string) $name, 0, 13) == 'address_type_') {
|
|
$module = substr((string) $name, 13);
|
|
if (in_array($module, $this->settings['valid_geocode_modules'])) {
|
|
if (in_array($value, array('billing', 'shipping', 'primary', 'alt', 'flex_relate', 'custom', 'address'))) {
|
|
$admin->saveSetting($category, $name, $value);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set map_markers_grouping_field
|
|
if (substr((string) $name, 0, 15) == 'grouping_field_') {
|
|
$module = substr((string) $name, 15);
|
|
if (in_array($module, $this->settings['valid_geocode_modules'])) {
|
|
if (!empty($value)) {
|
|
$admin->saveSetting($category, $name, $value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Integer Settings
|
|
$int_settings = array('geocoding_limit', 'google_geocoding_limit',
|
|
'map_markers_limit', 'map_default_distance', 'export_addresses_limit',
|
|
'map_clusterer_grid_size', 'map_clusterer_max_zoom',
|
|
'address_cache_get_enabled', 'address_cache_save_enabled',
|
|
'logic_hooks_enabled', 'allow_approximate_location_type');
|
|
foreach ($int_settings as $setting) {
|
|
if (isset($data[$setting]) && is_numeric(trim($data[$setting]))) {
|
|
$admin->saveSetting($category, $setting, (int) trim($data[$setting]));
|
|
}
|
|
}
|
|
|
|
// Float/Language Settings
|
|
if (isset($data['map_default_unit_type']) && in_array(trim($data['map_default_unit_type']), array('mi', 'km'))) {
|
|
$admin->saveSetting($category, 'map_default_unit_type', trim($data['map_default_unit_type']));
|
|
}
|
|
if (empty($data['map_duplicate_marker_adjustment'])) {
|
|
$data['map_duplicate_marker_adjustment'] = 0.00002;
|
|
}
|
|
if (isset($data['map_duplicate_marker_adjustment']) && is_numeric(trim($data['map_duplicate_marker_adjustment']))) {
|
|
$admin->saveSetting($category, 'map_duplicate_marker_adjustment', (float) trim($data['map_duplicate_marker_adjustment']));
|
|
}
|
|
|
|
if (!isset($data['map_default_center_latitude'])) {
|
|
LoggerManager::getLogger()->warn('jjwg_Maps saveConfiguration: Undefined index: map_default_center_latitude');
|
|
$dataMapDefaultCenterLatitude = null;
|
|
} else {
|
|
$dataMapDefaultCenterLatitude = $data['map_default_center_latitude'];
|
|
}
|
|
|
|
if (!$this->is_valid_lat($dataMapDefaultCenterLatitude)) {
|
|
$data['map_default_center_latitude'] = 39.5;
|
|
}
|
|
|
|
if (isset($data['map_default_center_latitude']) && is_numeric(trim($data['map_default_center_latitude']))) {
|
|
$admin->saveSetting($category, 'map_default_center_latitude', (float) trim($data['map_default_center_latitude']));
|
|
}
|
|
|
|
if (!isset($data['map_default_center_longitude'])) {
|
|
LoggerManager::getLogger()->warn('jjwg_Maps saveConfiguration: Undefined index: map_default_center_longitude');
|
|
$dataMapDefaultCenterLongitude = null;
|
|
} else {
|
|
$dataMapDefaultCenterLongitude = $data['map_default_center_longitude'];
|
|
}
|
|
|
|
|
|
if (!$this->is_valid_lng($dataMapDefaultCenterLongitude)) {
|
|
$data['map_default_center_longitude'] = -99.5;
|
|
}
|
|
|
|
if (isset($data['map_default_center_longitude']) && is_numeric(trim($data['map_default_center_longitude']))) {
|
|
$admin->saveSetting($category, 'map_default_center_longitude', (float) trim($data['map_default_center_longitude']));
|
|
}
|
|
|
|
// Set Geocoding API URL or Proxy URL
|
|
|
|
if (!isset($data['geocoding_api_url'])) {
|
|
LoggerManager::getLogger()->warn('jjwg_Maps saveConfiguration: Undefined index: geocoding_api_url ');
|
|
$dataGeocodingApiUrl = null;
|
|
} else {
|
|
$dataGeocodingApiUrl = $data['geocoding_api_url'];
|
|
}
|
|
|
|
if (substr((string) $dataGeocodingApiUrl, 0, 4) != 'http' && substr((string) $dataGeocodingApiUrl, 0, 2) != '//') {
|
|
$data['geocoding_api_url'] = $this->settings['geocoding_api_url'];
|
|
}
|
|
|
|
if (isset($data['geocoding_api_url'])) {
|
|
$admin->saveSetting($category, 'geocoding_api_url', trim($data['geocoding_api_url']));
|
|
}
|
|
// Set Google Maps API Secret
|
|
if (empty($data['geocoding_api_secret'])) {
|
|
$data['geocoding_api_secret'] = '';
|
|
}
|
|
if (isset($data['geocoding_api_secret'])) {
|
|
$admin->saveSetting($category, 'geocoding_api_secret', trim($data['geocoding_api_secret']));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Update Geocode Information for $bean
|
|
*
|
|
* This is method is executed as a before_save logic hook.
|
|
* With before_save, only the values are updated.
|
|
* See before_save logic hooks
|
|
*
|
|
* defineMapsAddress() should find the address by the parent relationship if needed.
|
|
* That is, the parent relationship should define the new maps address.
|
|
*
|
|
* $bean passed by reference
|
|
*
|
|
*/
|
|
public function updateGeocodeInfo(&$bean, $after_save = false)
|
|
{
|
|
$GLOBALS['log']->info(__METHOD__.' START');
|
|
if (empty($bean->id) || empty($bean->object_name) || empty($bean->module_name)) {
|
|
return false;
|
|
}
|
|
$GLOBALS['log']->info(__METHOD__.' $bean->object_name: '.$bean->object_name);
|
|
|
|
// Make sure we have the custom fields in our $bean
|
|
if ($after_save === true) {
|
|
$bean->custom_fields->retrieve();
|
|
}
|
|
$this->logGeocodeInfo($bean);
|
|
|
|
// Define the Address Info based on the new bean data
|
|
// $bean_data is not fetched_row data, but rather the properties of the bean as an array
|
|
$bean_data = get_object_vars($bean);
|
|
$aInfo = $this->defineMapsAddress($bean->object_name, $bean_data);
|
|
$GLOBALS['log']->debug(__METHOD__.' $aInfo: '.print_r($aInfo, true));
|
|
|
|
// If the related Account address has changed then reset the geocode values
|
|
if (isset($aInfo['address']) && $aInfo['address'] != $bean->fetched_row['jjwg_maps_address_c']) {
|
|
|
|
// If needed, check the Address Cache Module for Geocode Info
|
|
if (!is_object($this->jjwg_Address_Cache)) {
|
|
$this->jjwg_Address_Cache = get_module_info('jjwg_Address_Cache');
|
|
}
|
|
// Check Cache, if address is set
|
|
if (!empty($aInfo['address']) && is_object($this->jjwg_Address_Cache)) {
|
|
$aInfoCache = $this->jjwg_Address_Cache->getAddressCacheInfo($aInfo);
|
|
$GLOBALS['log']->debug(__METHOD__.' $aInfoCache: '.print_r($aInfoCache, true));
|
|
if (!empty($aInfoCache['address'])) {
|
|
$aInfo = $aInfoCache;
|
|
}
|
|
}
|
|
// Update/Reset the Geocode fields
|
|
$bean->jjwg_maps_lat_c = (!empty($aInfo['lat'])) ? $aInfo['lat'] : 0;
|
|
$bean->jjwg_maps_lng_c = (!empty($aInfo['lng'])) ? $aInfo['lng'] : 0;
|
|
$bean->jjwg_maps_geocode_status_c = (!empty($aInfo['status'])) ? $aInfo['status'] : '';
|
|
$bean->jjwg_maps_address_c = (!empty($aInfo['address'])) ? $aInfo['address'] : '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update Geocode Information for $bean's Related Meetings
|
|
*
|
|
* This is done typically after the $bean is already saved.
|
|
* See after_save logic hooks
|
|
* Meetings related to: accounts, cases, contacts, leads
|
|
* opportunities, projects and prospects (targets)
|
|
*
|
|
* This method updates the meeting's address info based on
|
|
* the current related bean address info.
|
|
*
|
|
* Note, it was decided to not define the Meeting beans to
|
|
* improve performance and not trigger additional logic hooks.
|
|
*
|
|
* @param $bean
|
|
*/
|
|
public function updateRelatedMeetingsGeocodeInfo(&$bean)
|
|
{
|
|
$GLOBALS['log']->info(__METHOD__.' START');
|
|
if (empty($bean->id) || empty($bean->object_name) || empty($bean->module_name)) {
|
|
return false;
|
|
}
|
|
$GLOBALS['log']->info(__METHOD__.' $bean->object_name: '.$bean->object_name);
|
|
|
|
// Check to see if address info is already set, or redefine
|
|
$bean_data = get_object_vars($bean);
|
|
$aInfo = $this->defineMapsAddress($bean->object_name, $bean_data);
|
|
$GLOBALS['log']->debug(__METHOD__.' $bean_data: '.print_r($bean_data, true));
|
|
$GLOBALS['log']->debug(__METHOD__.' $aInfo: '.$aInfo);
|
|
|
|
// If needed, check the Address Cache Module for Geocode Info
|
|
if (!is_object($this->jjwg_Address_Cache)) {
|
|
$this->jjwg_Address_Cache = get_module_info('jjwg_Address_Cache');
|
|
}
|
|
// Check Cache, if address is set
|
|
if (!empty($aInfo['address']) && is_object($this->jjwg_Address_Cache)) {
|
|
$aInfoCache = $this->jjwg_Address_Cache->getAddressCacheInfo($aInfo);
|
|
$GLOBALS['log']->debug(__METHOD__.' $aInfoCache: '.$aInfoCache);
|
|
if (!empty($aInfoCache['address'])) {
|
|
$aInfo = $aInfoCache;
|
|
}
|
|
}
|
|
|
|
$lngQ = (!empty($aInfo['lng'])) ? $this->db->quote($aInfo['lng']) : 0;
|
|
$latQ = (!empty($aInfo['lat'])) ? $this->db->quote($aInfo['lat']) : 0;
|
|
$statusQ = (!empty($aInfo['status'])) ? $this->db->quote($aInfo['status']) : '';
|
|
$addressQ = (!empty($aInfo['address'])) ? $this->db->quote($aInfo['address']) : '';
|
|
|
|
// Find the Related Meetings by parent_type & parent_id (this relationship is special)
|
|
$query = "SELECT meetings.id, meetings_cstm.id_c FROM meetings " .
|
|
" LEFT JOIN meetings_cstm ON meetings.id = meetings_cstm.id_c " .
|
|
" WHERE meetings.deleted = 0 AND " .
|
|
" meetings.parent_type = '" . $this->db->quote($bean->module_name) . "' AND " .
|
|
" meetings.parent_id = '" . $this->db->quote($bean->id) . "'";
|
|
$result = $this->db->query($query);
|
|
|
|
while ($row = $this->db->fetchByAssoc($result)) {
|
|
$idQ = $this->db->quote($row['id']);
|
|
if (!empty($row['id_c'])) {
|
|
// Update Custom Fields
|
|
$query = "UPDATE meetings_cstm SET" .
|
|
" jjwg_maps_lat_c = '" . $latQ . "'," .
|
|
" jjwg_maps_lng_c = '" . $lngQ . "'," .
|
|
" jjwg_maps_geocode_status_c = '".$statusQ."'," .
|
|
" jjwg_maps_address_c = '" . $addressQ . "'" .
|
|
" WHERE id_c = '" . $idQ . "'";
|
|
$update_result = $this->db->query($query);
|
|
} else {
|
|
// Insert Custom Fields
|
|
$query = "INSERT INTO meetings_cstm" .
|
|
" (id_c, jjwg_maps_lat_c, jjwg_maps_lng_c, jjwg_maps_geocode_status_c, jjwg_maps_address_c)" .
|
|
" VALUES ('" . $idQ . "', '" . $latQ . "', '" . $lngQ . "', '".$statusQ."', '" . $addressQ . "') ";
|
|
$insert_result = $this->db->query($query);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update Geocode Information for Meeting $bean
|
|
*
|
|
* Meeting Only. This method is executed as an after_save logic hook
|
|
* due to the timing that parent_type and parent_id are saved.
|
|
* The values are updated by queries in the updateGeocodeInfoByBeanQuery method.
|
|
*
|
|
* defineMapsAddress() should find the address by the parent relationship if needed.
|
|
* That is, the parent relationship should define the new maps address.
|
|
*
|
|
* $bean passed by reference
|
|
*/
|
|
public function updateMeetingGeocodeInfo(&$bean)
|
|
{
|
|
$GLOBALS['log']->info(__METHOD__.' START');
|
|
if (empty($bean->object_name)) {
|
|
return false;
|
|
}
|
|
$GLOBALS['log']->info(__METHOD__.' $bean->object_name: '.$bean->object_name);
|
|
|
|
// Make sure we have the custom fields in our $bean
|
|
$bean->custom_fields->retrieve();
|
|
$this->logGeocodeInfo($bean);
|
|
|
|
// Define the Address Info based on the new bean data
|
|
// $bean_data is not fetched_row data, but rather the properties of the bean as an array
|
|
$bean_data = get_object_vars($bean);
|
|
$aInfo = $this->defineMapsAddress($bean->object_name, $bean_data);
|
|
$GLOBALS['log']->debug(__METHOD__.' $aInfo: '.print_r($aInfo, true));
|
|
|
|
// If the related Account address has changed then reset the geocode values
|
|
if (isset($aInfo['address']) && $aInfo['address'] != $bean->fetched_row['jjwg_maps_address_c']) {
|
|
|
|
// If needed, check the Address Cache Module for Geocode Info
|
|
if (!is_object($this->jjwg_Address_Cache)) {
|
|
$this->jjwg_Address_Cache = get_module_info('jjwg_Address_Cache');
|
|
}
|
|
// Check Cache, if address is set
|
|
if (!empty($aInfo['address']) && is_object($this->jjwg_Address_Cache)) {
|
|
$aInfoCache = $this->jjwg_Address_Cache->getAddressCacheInfo($aInfo);
|
|
$GLOBALS['log']->debug(__METHOD__.' $aInfoCache: '.print_r($aInfoCache, true));
|
|
if (!empty($aInfoCache['address'])) {
|
|
$aInfo = $aInfoCache;
|
|
}
|
|
}
|
|
// Update/Reset the Geocode fields using Queries (not save() bean method)
|
|
$update_result = $this->updateGeocodeInfoByBeanQuery($bean, $aInfo);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Used to Update or Remove Geocoding Information from Custom Table
|
|
* Simple Query Approach
|
|
*
|
|
* @param type $table_name string
|
|
* @param type $display array (fetched_row)
|
|
* @param type $aInfo array
|
|
*/
|
|
public function updateGeocodeInfoByAssocQuery($table_name, $display, $aInfo = array())
|
|
{
|
|
$GLOBALS['log']->info(__METHOD__.' START');
|
|
if (empty($display['id']) || empty($table_name)) {
|
|
return false;
|
|
}
|
|
$GLOBALS['log']->info(__METHOD__.' $display[\'id\']: '.$display['id']);
|
|
|
|
if (!(in_array($table_name, $this->settings['valid_geocode_tables']))) {
|
|
return false;
|
|
}
|
|
$idQ = $this->db->quote($display['id']);
|
|
$lngQ = (!empty($aInfo['lng'])) ? $this->db->quote($aInfo['lng']) : 0;
|
|
$latQ = (!empty($aInfo['lat'])) ? $this->db->quote($aInfo['lat']) : 0;
|
|
$statusQ = (!empty($aInfo['status'])) ? $this->db->quote($aInfo['status']) : '';
|
|
$addressQ = (!empty($aInfo['address'])) ? $this->db->quote($aInfo['address']) : '';
|
|
|
|
// Find record by id
|
|
$query = "SELECT ".$table_name.".id, ".$table_name."_cstm.id_c FROM ".$table_name." " .
|
|
" LEFT JOIN ".$table_name."_cstm ON ".$table_name.".id = ".$table_name."_cstm.id_c " .
|
|
" WHERE ".$table_name.".deleted = 0 AND ".$table_name.".id = '" . $idQ . "'";
|
|
$result = $this->db->query($query);
|
|
$row = $this->db->fetchByAssoc($result);
|
|
|
|
if (!empty($row['id_c'])) {
|
|
// Update Custom Fields
|
|
$query = "UPDATE " . $table_name . "_cstm SET" .
|
|
" jjwg_maps_lat_c = '" . $latQ . "'," .
|
|
" jjwg_maps_lng_c = '" . $lngQ . "'," .
|
|
" jjwg_maps_geocode_status_c = '".$statusQ."'," .
|
|
" jjwg_maps_address_c = '" . $addressQ . "'" .
|
|
" WHERE id_c = '" . $idQ . "'";
|
|
$update_result = $this->db->query($query);
|
|
} else {
|
|
// Insert Custom Fields
|
|
$query = "INSERT INTO " . $table_name . "_cstm" .
|
|
" (id_c, jjwg_maps_lat_c, jjwg_maps_lng_c, jjwg_maps_geocode_status_c, jjwg_maps_address_c)" .
|
|
" VALUES ('" . $idQ . "', '" . $latQ . "', '" . $lngQ . "', '".$statusQ."', '" . $addressQ . "') ";
|
|
$insert_result = $this->db->query($query);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Used to Update or Remove Geocoding Information from Custom Table
|
|
* Simple Query Approach
|
|
*
|
|
* @param type $bean object
|
|
* @param type $aInfo array
|
|
*/
|
|
public function updateGeocodeInfoByBeanQuery(&$bean, $aInfo = array())
|
|
{
|
|
$GLOBALS['log']->info(__METHOD__.' START');
|
|
if (empty($bean->id) || empty($bean->object_name) || empty($bean->table_name)) {
|
|
return false;
|
|
}
|
|
$GLOBALS['log']->info(__METHOD__.' $bean->object_name: '.$bean->object_name);
|
|
|
|
$table_name = $bean->table_name;
|
|
if (!(in_array($table_name, $this->settings['valid_geocode_tables']))) {
|
|
return false;
|
|
}
|
|
$idQ = $this->db->quote($bean->id);
|
|
$lngQ = (!empty($aInfo['lng'])) ? $this->db->quote($aInfo['lng']) : 0;
|
|
$latQ = (!empty($aInfo['lat'])) ? $this->db->quote($aInfo['lat']) : 0;
|
|
$statusQ = (!empty($aInfo['status'])) ? $this->db->quote($aInfo['status']) : '';
|
|
$addressQ = (!empty($aInfo['address'])) ? $this->db->quote($aInfo['address']) : '';
|
|
|
|
// Find record by id
|
|
$query = "SELECT ".$table_name.".id, ".$table_name."_cstm.id_c FROM ".$table_name." " .
|
|
" LEFT JOIN ".$table_name."_cstm ON ".$table_name.".id = ".$table_name."_cstm.id_c " .
|
|
" WHERE ".$table_name.".deleted = 0 AND ".$table_name.".id = '" . $idQ . "'";
|
|
$result = $this->db->query($query);
|
|
$row = $this->db->fetchByAssoc($result);
|
|
|
|
if (!empty($row['id_c'])) {
|
|
// Update Custom Fields
|
|
$query = "UPDATE " . $table_name . "_cstm SET" .
|
|
" jjwg_maps_lat_c = '" . $latQ . "'," .
|
|
" jjwg_maps_lng_c = '" . $lngQ . "'," .
|
|
" jjwg_maps_geocode_status_c = '".$statusQ."'," .
|
|
" jjwg_maps_address_c = '" . $addressQ . "'" .
|
|
" WHERE id_c = '" . $idQ . "'";
|
|
$update_result = $this->db->query($query);
|
|
} else {
|
|
// Insert Custom Fields
|
|
$query = "INSERT INTO " . $table_name . "_cstm" .
|
|
" (id_c, jjwg_maps_lat_c, jjwg_maps_lng_c, jjwg_maps_geocode_status_c, jjwg_maps_address_c)" .
|
|
" VALUES ('" . $idQ . "', '" . $latQ . "', '" . $lngQ . "', '".$statusQ."', '" . $addressQ . "') ";
|
|
$insert_result = $this->db->query($query);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove All Geocoding Information from Custom Table for Module
|
|
* Simple Query Approach
|
|
*
|
|
* @param type $bean object
|
|
*/
|
|
public function deleteAllGeocodeInfoByBeanQuery(&$bean)
|
|
{
|
|
$GLOBALS['log']->info(__METHOD__.' START');
|
|
if (empty($bean->object_name) || empty($bean->table_name)) {
|
|
return false;
|
|
}
|
|
$GLOBALS['log']->info(__METHOD__.' $bean->object_name: '.$bean->object_name);
|
|
|
|
$table_name = $bean->table_name;
|
|
if (!(in_array($table_name, $this->settings['valid_geocode_tables']))) {
|
|
return false;
|
|
}
|
|
|
|
// Update Fields to NULL
|
|
$query = "UPDATE " . $table_name . "_cstm SET" .
|
|
" jjwg_maps_lat_c = NULL," .
|
|
" jjwg_maps_lng_c = NULL," .
|
|
" jjwg_maps_geocode_status_c = NULL," .
|
|
" jjwg_maps_address_c = NULL" .
|
|
" WHERE 1=1";
|
|
$update_result = $this->db->query($query);
|
|
}
|
|
|
|
/**
|
|
* Get $db result of records (addresses) in need of geocoding
|
|
* @param $table_name string
|
|
* @param $limit integer
|
|
* @param $id string
|
|
*/
|
|
public function getGeocodeAddressesResult($table_name, $limit = 0, $id = '')
|
|
{
|
|
if (!(in_array($table_name, $this->settings['valid_geocode_tables']))) {
|
|
return false;
|
|
}
|
|
if (empty($limit) || !is_int($limit)) {
|
|
$limit = $this->settings['geocoding_limit'];
|
|
}
|
|
// Find the Items to Geocode
|
|
// Assume there is no address at 0,0; it's in the Atlantic Ocean
|
|
$where_conds = "(" .
|
|
"(" . $table_name . "_cstm.jjwg_maps_lat_c = 0 AND " .
|
|
"" . $table_name . "_cstm.jjwg_maps_lng_c = 0)" .
|
|
" OR " .
|
|
"(" . $table_name . "_cstm.jjwg_maps_lat_c IS NULL AND " .
|
|
"" . $table_name . "_cstm.jjwg_maps_lng_c IS NULL)" .
|
|
")" .
|
|
" AND " .
|
|
"(" . $table_name . "_cstm.jjwg_maps_geocode_status_c = '' OR " .
|
|
"" . $table_name . "_cstm.jjwg_maps_geocode_status_c IS NULL)";
|
|
// Limit to only one result
|
|
if (@is_guid($id)) {
|
|
$where_conds .= " AND id = '".$id."'";
|
|
}
|
|
// Create Simple Query
|
|
// Note: Do not use create_new_list_query() or process_list_query()
|
|
// as they will typically exceeded memory allowed.
|
|
$query = "SELECT " . $table_name . ".*, " . $table_name . "_cstm.* FROM " . $table_name .
|
|
" LEFT JOIN " . $table_name . "_cstm " .
|
|
" ON " . $table_name . ".id = " . $table_name . "_cstm.id_c " .
|
|
" WHERE " . $table_name . ".deleted = 0 AND " . $where_conds;
|
|
$display_result = $this->db->limitQuery($query, 0, $limit);
|
|
|
|
return $display_result;
|
|
}
|
|
|
|
/**
|
|
* getGoogleMapsGeocode - Get Lng/Lat using Google Maps V3
|
|
* @var $address
|
|
* @var $return_full_array boolean
|
|
* @var $allow_approximate boolean
|
|
*/
|
|
public function getGoogleMapsGeocode($address, $return_full_array = false, $allow_approximate = true)
|
|
{
|
|
$GLOBALS['log']->debug(__METHOD__.' START');
|
|
$GLOBALS['log']->info(__METHOD__.' $address: '.$address);
|
|
|
|
/* allow_approximate_location_type - overrides only to true */
|
|
if (!empty($this->settings['allow_approximate_location_type'])) {
|
|
$allow_approximate = true;
|
|
}
|
|
|
|
/**
|
|
* Google Maps API v3 - The new v3 Google Maps API no longer requires a Maps API Key!
|
|
* Old Default: https://maps.google.com/maps/api/geocode/json?sensor=false
|
|
* New Default: https://maps.googleapis.com/maps/api/geocode/json?sensor=false
|
|
*/
|
|
$base_url = $this->settings['geocoding_api_url'];
|
|
if (!(strpos((string) $base_url, '?') > 0)) {
|
|
$base_url .= '?';
|
|
}
|
|
// Add Address Parameter
|
|
$request_url = $base_url . "&address=" . urlencode($address);
|
|
$request_url.="&key=".urlencode($this->settings['google_maps_api_key']);
|
|
|
|
$GLOBALS['log']->info(__METHOD__.' cURL Request URL: '.$request_url);
|
|
|
|
$ch = curl_init();
|
|
curl_setopt($ch, CURLOPT_URL, $request_url);
|
|
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1");
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 15);
|
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
|
|
|
// Add proxy option if user enabled proxy
|
|
$admin_config = BeanFactory::newBean('Administration');
|
|
$admin_config->retrieveSettings('proxy');
|
|
if (!empty($admin_config->settings['proxy_on'])) {
|
|
$proxy_host = $admin_config->settings['proxy_host'];
|
|
$proxy_port = $admin_config->settings['proxy_port'];
|
|
|
|
curl_setopt($ch, CURLOPT_PROXY, $proxy_host);
|
|
curl_setopt($ch, CURLOPT_PROXYPORT, $proxy_port);
|
|
|
|
// Check if use proxy auth
|
|
if (!empty($admin_config->settings['proxy_auth'])) {
|
|
$proxy_userpwd = $admin_config->settings['proxy_username'] . ':' . $admin_config->settings['proxy_password'];
|
|
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxy_userpwd);
|
|
}
|
|
}
|
|
// End
|
|
|
|
$json_contents = curl_exec($ch);
|
|
|
|
// Debug: Error Handling
|
|
$ch_errno = curl_errno($ch);
|
|
$ch_error = curl_error($ch);
|
|
if (!empty($ch_errno) || !empty($ch_error)) {
|
|
$GLOBALS['log']->error(__METHOD__.' cURL Error: #'.$ch_errno.' - '.$ch_error);
|
|
}
|
|
|
|
curl_close($ch);
|
|
$GLOBALS['log']->debug(__METHOD__.' $json_contents: '.$json_contents);
|
|
$googlemaps = json_decode($json_contents, true);
|
|
$GLOBALS['log']->debug(__METHOD__.' $googlemaps: '. (is_array($googlemaps) ? '[Array]' : $googlemaps));
|
|
|
|
/**
|
|
* https://developers.google.com/maps/documentation/geocoding/#Results
|
|
* Status: "OK" : geocoding was successful
|
|
* "ZERO_RESULTS" : indicates that the geocode was successful but returned no results
|
|
* "OVER_QUERY_LIMIT" : indicates that you are over your quota
|
|
* "REQUEST_DENIED" : lack of sensor parameter
|
|
* "INVALID_REQUEST" generally indicates that the query (address or lat/lng) is missing.
|
|
* Limit to location_type = 'ROOFTOP', 'RANGE_INTERPOLATED' or 'GEOMETRIC_CENTER' but not 'APPROXIMATE'
|
|
*/
|
|
$aInfo = array('address' => $address);
|
|
if (!empty($googlemaps) && isset($googlemaps['status'])) {
|
|
$resultsGeography = $googlemaps['results'][0]['geometry'] ?? [];
|
|
if ($googlemaps['status'] == 'OVER_QUERY_LIMIT') {
|
|
// Debug: Log Over Limit
|
|
$GLOBALS['log']->warn(__METHOD__.' Google Maps API Status of OVER_QUERY_LIMIT: Over Your Quota');
|
|
} elseif (!$allow_approximate && ($resultsGeography['location_type'] ?? '') == 'APPROXIMATE') {
|
|
// Consider 'APPROXIMATE' to be similar to 'ZERO_RESULTS'
|
|
@$aInfo = array(
|
|
'address' => $address,
|
|
'status' => 'APPROXIMATE',
|
|
'lat' => $resultsGeography['location']['lat'],
|
|
'lng' => $resultsGeography['location']['lng']
|
|
);
|
|
} else {
|
|
// Return address info
|
|
@$aInfo = array(
|
|
'address' => $address,
|
|
'status' => $googlemaps['status'],
|
|
'lat' => $resultsGeography['location']['lat'],
|
|
'lng' => $resultsGeography['location']['lng']
|
|
);
|
|
}
|
|
}
|
|
|
|
if ($return_full_array) {
|
|
$GLOBALS['log']->debug(__METHOD__.' $googlemaps: '.print_r($googlemaps, true));
|
|
return $googlemaps;
|
|
} else {
|
|
$GLOBALS['log']->debug(__METHOD__.' $aInfo: '.print_r($aInfo, true));
|
|
return $aInfo;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Define Maps Address
|
|
*
|
|
* Address Relationship Notes:
|
|
* Account(address)
|
|
* Contact(address)
|
|
* Lead(address)
|
|
* Taget/Prospect(address)
|
|
* Opportunity to Account(address)
|
|
* Case 'account_id' to Account(address)
|
|
* or Case to Account(address)
|
|
* Project to Account(address)
|
|
* or Project to Opportunity to Account(address)
|
|
* Meeting - based on Flex Relate
|
|
*
|
|
* @param $object_name signular object name
|
|
* @param $display fetched row
|
|
*/
|
|
public function defineMapsAddress($object_name, $display)
|
|
{
|
|
$address = false;
|
|
$fields = false;
|
|
$parent = null;
|
|
$parent_type = '';
|
|
$parent_id = '';
|
|
|
|
$GLOBALS['log']->debug(__METHOD__.' START');
|
|
$GLOBALS['log']->debug(__METHOD__.' $object_name: '.$object_name);
|
|
$GLOBALS['log']->debug(__METHOD__.' $display: '.print_r($display, true));
|
|
|
|
// Field naming is different in some modules.
|
|
// Some modules do not have an address, so a related account needs to be found first.
|
|
|
|
if ($object_name == 'Account') {
|
|
$address = $this->defineMapsFormattedAddress($display, $this->settings['geocode_modules_to_address_type']['Accounts']);
|
|
} elseif ($object_name == 'Contact') {
|
|
$address = $this->defineMapsFormattedAddress($display, $this->settings['geocode_modules_to_address_type']['Contacts']);
|
|
} elseif ($object_name == 'Lead') {
|
|
$address = $this->defineMapsFormattedAddress($display, $this->settings['geocode_modules_to_address_type']['Leads']);
|
|
} elseif ($object_name == 'Prospect') {
|
|
$address = $this->defineMapsFormattedAddress($display, $this->settings['geocode_modules_to_address_type']['Prospects']);
|
|
} elseif ($object_name == 'User') {
|
|
$address = $this->defineMapsFormattedAddress($display, $this->settings['geocode_modules_to_address_type']['Users']);
|
|
} elseif ($object_name == 'Opportunity') {
|
|
|
|
// Find Account - Assume only one related Account
|
|
$query = "SELECT accounts.*, accounts_cstm.* FROM accounts LEFT JOIN accounts_cstm ON accounts.id = accounts_cstm.id_c " .
|
|
" LEFT JOIN accounts_opportunities ON accounts.id = accounts_opportunities.account_id AND accounts_opportunities.deleted = 0 " .
|
|
" WHERE accounts.deleted = 0 AND accounts_opportunities.opportunity_id = '" . $display['id'] . "'";
|
|
$GLOBALS['log']->debug(__METHOD__.' Opportunity to Account');
|
|
$result = $this->db->limitQuery($query, 0, 1);
|
|
$fields = $this->db->fetchByAssoc($result);
|
|
|
|
if (!empty($fields)) {
|
|
$address = $this->defineMapsFormattedAddress($fields, $this->settings['geocode_modules_to_address_type']['Opportunities']);
|
|
}
|
|
} elseif (in_array($object_name, array('aCase', 'Case'))) {
|
|
|
|
// Find Account from Case (account_id field)
|
|
|
|
if (!isset($display['account_id'])) {
|
|
LoggerManager::getLogger()->warn('jjwg_Maps defineMapsAddress: Undefined index: account_id ');
|
|
$displayAccountId = null;
|
|
} else {
|
|
$displayAccountId = $display['account_id'];
|
|
}
|
|
|
|
$query = "SELECT accounts.*, accounts_cstm.* FROM accounts LEFT JOIN accounts_cstm ON accounts.id = accounts_cstm.id_c " .
|
|
" WHERE accounts.deleted = 0 AND id = '" . $displayAccountId . "'";
|
|
$GLOBALS['log']->debug(__METHOD__.' Case to Account');
|
|
$result = $this->db->limitQuery($query, 0, 1);
|
|
$fields = $this->db->fetchByAssoc($result);
|
|
|
|
// If Account is not found; Find many to many Account - Assume only one related Account
|
|
if (empty($fields)) {
|
|
$query = "SELECT accounts.*, accounts_cstm.* FROM accounts LEFT JOIN accounts_cstm ON accounts.id = accounts_cstm.id_c " .
|
|
" LEFT JOIN accounts_cases ON accounts.id = accounts_cases.account_id AND accounts_cases.deleted = 0 " .
|
|
" WHERE accounts.deleted = 0 AND accounts_cases.case_id = '" . $display['id'] . "'";
|
|
$GLOBALS['log']->debug(__METHOD__.' Case to Accounts');
|
|
$result = $this->db->limitQuery($query, 0, 1);
|
|
$fields = $this->db->fetchByAssoc($result);
|
|
}
|
|
|
|
if (!empty($fields)) {
|
|
$address = $this->defineMapsFormattedAddress($fields, $this->settings['geocode_modules_to_address_type']['Cases']);
|
|
}
|
|
} elseif ($object_name == 'Project') {
|
|
|
|
// Check relationship from Project to Account - Assume only one related Account
|
|
$query = "SELECT accounts.*, accounts_cstm.* FROM accounts LEFT JOIN accounts_cstm ON accounts.id = accounts_cstm.id_c " .
|
|
" LEFT JOIN projects_accounts ON accounts.id = projects_accounts.account_id AND projects_accounts.deleted = 0 " .
|
|
" WHERE accounts.deleted = 0 AND projects_accounts.project_id = '" . $display['id'] . "'";
|
|
$GLOBALS['log']->debug(__METHOD__.' Project to Account');
|
|
$result = $this->db->limitQuery($query, 0, 1);
|
|
$fields = $this->db->fetchByAssoc($result);
|
|
|
|
if (empty($fields)) {
|
|
// Find Opportunity - Assuming that the Project was created from an Opportunity (Closed Won) Detial View
|
|
$query = "SELECT opportunities.*, opportunities_cstm.* FROM opportunities LEFT JOIN opportunities_cstm ON opportunities.id = opportunities_cstm.id_c " .
|
|
" LEFT JOIN projects_opportunities ON opportunities.id = projects_opportunities.opportunity_id AND projects_opportunities.deleted = 0 " .
|
|
" WHERE opportunities.deleted = 0 AND projects_opportunities.project_id = '" . $display['id'] . "'";
|
|
$GLOBALS['log']->debug(__METHOD__.' Project to Opportunity');
|
|
$result = $this->db->limitQuery($query, 0, 1);
|
|
$opportunity = $this->db->fetchByAssoc($result);
|
|
if ($opportunity === false) {
|
|
$result = null;
|
|
$fields = null;
|
|
} else {
|
|
// Find Account - Assume only one related Account for the Opportunity
|
|
$query = "SELECT accounts.*, accounts_cstm.* FROM accounts LEFT JOIN accounts_cstm ON accounts.id = accounts_cstm.id_c " .
|
|
" LEFT JOIN accounts_opportunities ON accounts.id = accounts_opportunities.account_id AND accounts_opportunities.deleted = 0 " .
|
|
" WHERE accounts.deleted = 0 AND accounts_opportunities.opportunity_id = '" . $opportunity['id'] . "'";
|
|
$GLOBALS['log']->debug(__METHOD__.' Opportunity to Account');
|
|
$result = $this->db->limitQuery($query, 0, 1);
|
|
$fields = $this->db->fetchByAssoc($result);
|
|
}
|
|
}
|
|
|
|
if (!empty($fields)) {
|
|
$address = $this->defineMapsFormattedAddress($fields, $this->settings['geocode_modules_to_address_type']['Project']);
|
|
}
|
|
} elseif ($object_name == 'Meeting') {
|
|
|
|
// Find Meeting - Flex Relate Fields: meetings.parent_type and meetings.parent_id
|
|
$query = "SELECT meetings.*, meetings_cstm.* FROM meetings LEFT JOIN meetings_cstm ON meetings.id = meetings_cstm.id_c " .
|
|
" WHERE meetings.deleted = 0 AND meetings.id = '" . $display['id'] . "'";
|
|
$GLOBALS['log']->debug(__METHOD__.' Meeting');
|
|
$result = $this->db->limitQuery($query, 0, 1);
|
|
$meeting = $this->db->fetchByAssoc($result);
|
|
|
|
if ($meeting === false) {
|
|
$parent_type = null;
|
|
$parent_id = null;
|
|
} else {
|
|
$parent_type = $meeting['parent_type'];
|
|
$parent_id = $meeting['parent_id'];
|
|
}
|
|
$GLOBALS['log']->debug(__METHOD__.' Meeting $parent_type: '.$parent_type);
|
|
$GLOBALS['log']->debug(__METHOD__.' Meeting $parent_id: '.$parent_id);
|
|
|
|
// If the parent_type is valid module to geocode
|
|
if (array_key_exists($parent_type, $this->settings['valid_geocode_modules'])
|
|
&& !empty($parent_id) && $parent_type != 'Meeting') {
|
|
|
|
// Define parent object
|
|
$parent = get_module_info($parent_type);
|
|
$parent->retrieve($parent_id);
|
|
$parent->custom_fields->retrieve();
|
|
$fields = $parent->fetched_row;
|
|
|
|
$GLOBALS['log']->debug(__METHOD__.' Meeting $parent->object_name: '.$parent->object_name);
|
|
$GLOBALS['log']->debug(__METHOD__.' Meeting $parent->fetched_row: '.print_r($parent->fetched_row, true));
|
|
|
|
// Call this defineMapsAddress for parent which will look at other relationships
|
|
$aInfo = $this->defineMapsAddress($parent->object_name, $parent->fetched_row);
|
|
// return $aInfo
|
|
$GLOBALS['log']->debug(__METHOD__.' Meeting $address Found $aInfo: '.print_r($aInfo, true));
|
|
return $aInfo;
|
|
}
|
|
}
|
|
|
|
|
|
// If related account address has already been geocoded
|
|
if (!empty($address) && !is_bool($fields) && $fields['jjwg_maps_geocode_status_c'] == 'OK' &&
|
|
!empty($fields['jjwg_maps_lat_c']) && !empty($fields['jjwg_maps_lng_c'])) {
|
|
$aInfo = array(
|
|
'address' => $address,
|
|
'status' => 'OK',
|
|
'lat' => $fields['jjwg_maps_lat_c'],
|
|
'lng' => $fields['jjwg_maps_lng_c']
|
|
);
|
|
$GLOBALS['log']->debug(__METHOD__.' OK Array Found $aInfo: '.print_r($aInfo, true));
|
|
return $aInfo;
|
|
// elseif return address only - if defined
|
|
} elseif (!empty($address)) {
|
|
$aInfo = array(
|
|
'address' => $address,
|
|
);
|
|
$GLOBALS['log']->debug(__METHOD__.' $address Found $aInfo: '.print_r($aInfo, true));
|
|
return $aInfo;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Define the formatted address line based on address type and field names
|
|
* @param $display bean fields array
|
|
* @param $type type of address: 'billing', 'shipping', 'primary', 'alt', 'custom', 'address'
|
|
*/
|
|
public function defineMapsFormattedAddress($display, $type = 'billing')
|
|
{
|
|
$type = strtolower($type);
|
|
if (!in_array($type, array('billing', 'shipping', 'primary', 'alt', 'custom', 'address'))) {
|
|
$type = 'billing';
|
|
}
|
|
$GLOBALS['log']->debug(__METHOD__.' $type: '.print_r($type, true));
|
|
$address_fields = array('billing_address_street', 'billing_address_city', 'billing_address_state', 'billing_address_postalcode', 'billing_address_country');
|
|
$address_parts = array();
|
|
switch ($type) {
|
|
case 'billing':
|
|
$address_fields = array('billing_address_street', 'billing_address_city', 'billing_address_state', 'billing_address_postalcode', 'billing_address_country');
|
|
break;
|
|
case 'shipping':
|
|
$address_fields = array('shipping_address_street', 'shipping_address_city', 'shipping_address_state', 'shipping_address_postalcode', 'shipping_address_country');
|
|
break;
|
|
case 'primary':
|
|
$address_fields = array('primary_address_street', 'primary_address_city', 'primary_address_state', 'primary_address_postalcode', 'primary_address_country');
|
|
break;
|
|
case 'alt':
|
|
$address_fields = array('alt_address_street', 'alt_address_city', 'alt_address_state', 'alt_address_postalcode', 'alt_address_country');
|
|
break;
|
|
case 'address':
|
|
$address_fields = array('address_street', 'address_city', 'address_state', 'address_postalcode', 'address_country');
|
|
break;
|
|
}
|
|
$GLOBALS['log']->debug(__METHOD__.' $address_fields: '.print_r($address_fields, true));
|
|
foreach ($address_fields as $field) {
|
|
if (!isset($display[$field])) {
|
|
$display[$field] = '';
|
|
}
|
|
if (!empty($display[$field])) {
|
|
$address_parts[] = trim($display[$field]);
|
|
}
|
|
}
|
|
if (strlen(implode('', $address_parts)) > 3) {
|
|
$address = implode(', ', $address_parts);
|
|
$address = preg_replace('/[\n\r]+/', ' ', trim($address));
|
|
$address = preg_replace("/[\t\s]+/", ' ', $address);
|
|
$GLOBALS['log']->debug(__METHOD__.' $address: '.print_r($address, true));
|
|
return trim($address);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check for valid longitude
|
|
* @param $lng float
|
|
*/
|
|
public function is_valid_lng($lng)
|
|
{
|
|
return (is_numeric($lng) && $lng >= -180 && $lng <= 180);
|
|
}
|
|
|
|
/**
|
|
* Check for valid latitude
|
|
* @param $lat float
|
|
*/
|
|
public function is_valid_lat($lat)
|
|
{
|
|
return (is_numeric($lat) && $lat >= -90 && $lat <= 90);
|
|
}
|
|
|
|
/**
|
|
* Bean Log Special
|
|
* This log method filters the $bean into a more readable array
|
|
*/
|
|
public function logGeocodeInfo($bean)
|
|
{
|
|
$log_keys = array(
|
|
'jjwg_maps_lat_c', 'jjwg_maps_lng_c', 'jjwg_maps_address_c', 'jjwg_maps_geocode_status_c',
|
|
'fetched_row', 'parent_id', 'parent_type', 'last_parent_id', 'rel_fields_before_value'
|
|
);
|
|
$log_output = array();
|
|
foreach (get_object_vars($bean) as $key=>$value) {
|
|
if (in_array($key, $log_keys)) {
|
|
$log_output[$key] = $value;
|
|
}
|
|
}
|
|
ksort($log_output);
|
|
$GLOBALS['log']->info(__METHOD__.' $log_output: '.print_r($log_output, true));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
/**
|
|
* Function for Custom Dropdown of Target Lists
|
|
*/
|
|
|
|
function getProspectLists()
|
|
{
|
|
$query = "SELECT id, name, list_type FROM prospect_lists WHERE deleted = 0 ORDER BY name ASC";
|
|
$result = DBManagerFactory::getInstance()->query($query, false);
|
|
|
|
$list = array();
|
|
$list['']='';
|
|
while (($row = DBManagerFactory::getInstance()->fetchByAssoc($result)) != null) {
|
|
$list[$row['id']] = $row['name'];
|
|
}
|
|
|
|
return $list;
|
|
}
|