Current File : /home/n742ef5/royalanteam.com/mls/AmpreImport.php |
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once(dirname(__FILE__) . '/constant.php');
require_once('helpers/TableHelper.php');
require_once(dirname(__FILE__) .'/../wp-load.php');
global $wpdb;
class ImportProperty
{
private $filters = [];
function __construct()
{
$this->tablesCheck = new TableHelper();
global $apiUrl, $token, $googletoken, $mapboxtoken;
$this->apiUrl = $apiUrl;
$this->googletoken = $googletoken;
$this->mapboxtoken = $mapboxtoken;
$this->token = $token;
}
public function importData()
{
$lockFile = __DIR__ . '/script.lock';
$fp = fopen($lockFile, 'c');
if (!flock($fp, LOCK_EX | LOCK_NB)) {
echo "Script is already running. Exiting...\n";
exit;
}
echo "Script started.\n";
register_shutdown_function(function () use ($fp, $lockFile) {
flock($fp, LOCK_UN);
fclose($fp);
unlink($lockFile);
echo "Lock released.\n";
});
global $wpdb;
$cronStartTime = date("Y-m-d\TH:i:s\Z");
$recordsDownloaded = 0;
$recordsUpdated = 0;
$cronEndTime = NULL;
$propertyDownloadStartTime = NULL;
$propertyDownloadEndTime = NULL;
$success = 0;
$className = 'Ampre';
$cron_table_name = "cron_log";
$query = NULL;
$mls_count = 0;
$this->tablesCheck->cronLogTableCheck();
$this->tablesCheck->propertyTableCheck();
$this->tablesCheck->logerrorCheck();
$this->generateFilters($propertyDownloadStartTime, $propertyDownloadEndTime);
$propertyDownloadStartTime = date('Y-m-d H:i:s', strtotime($propertyDownloadStartTime));
$propertyDownloadEndTime = date('Y-m-d H:i:s', strtotime($propertyDownloadEndTime));
$cron_logId = $this->logCron($cronStartTime, $cronEndTime, $recordsDownloaded, $recordsUpdated, $success, $propertyDownloadStartTime, $propertyDownloadEndTime, $className, $query, $mls_count);
$wpdb->update($cron_table_name, [
'cron_start_time' => $cronStartTime,
'property_download_start_time' => $propertyDownloadStartTime,
'property_download_end_time' => $propertyDownloadEndTime,
'Class_name' => $className,
'success' => 0,
], ['id' => $cron_logId]);
foreach ($this->filters as $filter) {
echo "{$this->apiUrl}?\$filter=" . ($filter) . "&\$orderby=ModificationTimestamp,ListingKey\n";
$url = "{$this->apiUrl}?\$filter=" . rawurlencode($filter) . "&\$orderby=ModificationTimestamp,ListingKey&\$count=true";
$this->fetchAndInsert($url, $recordsDownloaded, $recordsUpdated, $cron_logId);
}
$cronEndTime = date("Y-m-d\TH:i:s\Z");
$wpdb->update($cron_table_name, [
'cron_end_time' => $cronEndTime,
'records_downloaded' => $recordsDownloaded,
'records_updated' => $recordsUpdated,
'success' => 1,
], ['id' => $cron_logId]);
$this->importRoomsData();
echo "Script finished.\n";
}
private function generateFilters(&$propertyDownloadStartTime, &$propertyDownloadEndTime)
{
global $wpdb;
$latestTimestamp = $wpdb->get_var("SELECT property_download_end_time FROM cron_log WHERE success = 1 ORDER BY id DESC LIMIT 1");
$extraCond = "";
if ($latestTimestamp) {
$latestDate = strtotime($latestTimestamp);
$startDateUnix = $latestDate + 1;
$nowUnix = time();
$endDateRaw = date("Y-m-d", $nowUnix);
$endDate2 = $endDateRaw;
$startMonth = (int) date('n', $startDateUnix);
$startYear = (int) date('Y', $startDateUnix);
$nowMonth = (int) date('n', $nowUnix);
$nowYear = (int) date('Y', $nowUnix);
$monthsDiff = ($nowYear - $startYear) * 12 + ($nowMonth - $startMonth);
if ($monthsDiff > 3) {
$endDateUnix = strtotime('+15 days', $startDateUnix);
$endDate = date("Y-m-d\TH:i:s\Z", $endDateUnix);
} else {
$endDate = date("Y-m-d\TH:i:s\Z", $nowUnix);
}
if (date("Y-m-d", $startDateUnix) === $endDate2) {
$startDateUnix = strtotime('-12 hours', $startDateUnix);
}
$startDate = date("Y-m-d\TH:i:s\Z", $startDateUnix);
$extraCond = "ModificationTimestamp ge {$startDate} and ModificationTimestamp le {$endDate}";
} else {
$now = time();
$currentYear = date('Y', $now);
$currentDay = date('d', $now);
$currentMonth = date('m', $now);
$lastYear = $currentYear - 1;
$startDateTimestamp = strtotime("{$lastYear}-{$currentMonth}-01 +".($currentDay - 1)." days");
$endDateTimestamp = strtotime("+1 month", $startDateTimestamp);
$startDate = date("Y-m-d\TH:i:s\Z", $startDateTimestamp);
$endDate = date("Y-m-d\TH:i:s\Z", $endDateTimestamp);
$extraCond = $extraCond = "StandardStatus eq 'Active'";
}
$propertyDownloadStartTime = $startDate;
$propertyDownloadEndTime = $endDate;
$this->filters[] = $extraCond;
}
private function fetchAndInsert($url, &$recordsDownloaded, &$recordsUpdated, $cron_logId)
{
global $wpdb;
$skip = 0;
$limit = 200;
$mls_count = false;
$paginatedUrl = $url . (strpos($url, '?') === false ? '?' : '&') . "\$top=1";
$response = $this->makeCurlRequest($paginatedUrl);
$mls_count = $response['@odata.count'] ?? count($response['value']);
$wpdb->update('cron_log', [
'query_url' => $url,
'mls_count' => $mls_count,
], ['id' => $cron_logId]);
do {
$paginatedUrl = $url . (strpos($url, '?') === false ? '?' : '&') . "\$top=$limit&\$skip=$skip";
$response = $this->makeCurlRequest($paginatedUrl);
if (!isset($response['value']) || empty($response['value'])) {
echo "No data found.\n";
return;
}
foreach ($response['value'] as $record) {
$this->insertRecord($record, $recordsDownloaded, $recordsUpdated);
}
$skip += $limit;
$count = $response['@odata.count'] ?? count($response['value']);
} while ($skip < $count);
}
private function insertRecord($record, &$recordsDownloaded, &$recordsUpdated)
{
global $wpdb;
$properties_table_name = 'properties';
$mappingArray = [
"ListingKey" => "ListingKey",
"ListingPrice" => "ListingPrice",
"PropertyType" => "PropertyType",
"PropertySubType" => "PropertySubType",
"BedroomsTotal" => "BedroomsTotal",
"BathroomsTotalInteger" => "BathroomsTotalInteger",
"City" => "City",
"StateOrProvince" => "StateOrProvince",
"PostalCode" => "PostalCode",
"BuildingAreaTotal" => "BuildingAreaTotal",
"LotSizeArea" => "LotSizeArea",
"LotFeatures" => "LotFeatures",
"PoolFeatures" => "PoolFeatures",
"ParkingTotal" => "ParkingTotal",
"ExteriorFeatures" => "ExteriorFeatures",
"FoundationDetails" => "FoundationDetails",
"Cooling" => "Cooling",
"HeatType" => "HeatType",
"FireplaceFeatures" => "FireplaceFeatures",
"PhotosCount" => "PhotosCount",
"PhotosChangeTimestamp" => "PhotosChangeTimestamp",
"ModificationTimestamp" => 'ModificationTimestamp',
"PublicRemarks" => "PublicRemarks",
"PriceChangeTimestamp" => "PriceChangeTimestamp",
"CloseDate" => "CloseDate",
"ClosePrice" => "ClosePrice",
"ListPrice" => "ListPrice",
"OriginalListPrice" => "OriginalListPrice",
"TaxAnnualAmount" => "TaxAnnualAmount",
"CityRegion" => "SubdivisionName",
"TaxYear" => "TaxYear",
"ListOfficeName" => "ListOfficeName",
"LotSizeSource" => "LotSizeSource",
"InternetEntireListingDisplayYn" => "InternetEntireListingDisplayYn",
"ListingContractDate" => "ListingContractDate",
"Longitude" => "Longitude",
"Latitude" => "Latitude",
"ListAgentFullName" => "ListAgentFullName",
"CountyOrParish" => "CountyOrParish"
];
$listingData = [];
$ListingKey = $record['ListingKey'];
$propertyArea = '';
if (!empty($record['StreetName']) && !empty($record['StreetSuffix'])) {
$propertyArea = $record['StreetName'] . ' ' . $record['StreetSuffix'];
} elseif (!empty($record['StreetName'])) {
$propertyArea = $record['StreetName'];
} elseif (!empty($record['StreetSuffix'])) {
$propertyArea = $record['StreetSuffix'];
}
foreach ($mappingArray as $metaKey => $dbKey) {
if (isset($record[$metaKey])) {
$listingData[$dbKey] = $record[$metaKey];
}
}
$listingData['propertyArea'] = $propertyArea;
foreach ($listingData as $key => $value) {
if (is_array($value)) {
$listingData[$key] = implode(', ', $value);
}
}
$listingData['propertyStatus'] = $record['TransactionType'];
if ($record['StandardStatus'] == NULL && in_array($record['MlsStatus'], ['Active', 'Pending', 'Hold'])) {
$listingData['MlsStatus'] = $record['MlsStatus'];
} elseif ($record['StandardStatus'] != NULL) {
$listingData['MlsStatus'] = $record['StandardStatus'];
} else {
return;
}
$address='';
if (isset($record['UnparsedAddress'])) {
$address = $record['UnparsedAddress'];
} else {
if (!empty($record['UnitNumber'])) {
$unit = '#' . $record['UnitNumber'];
$address = $unit;
}
if (!empty($record['StreetNumber'])) {
$address = $address . ' - ' . $record['StreetNumber'];
}
if (!empty($record['StreetName'])) {
$address = $address . ' ' . $record['StreetName'];
}
if (!empty($record['StreetSuffix'])) {
$address = $address . ' ' . $record['StreetSuffix'];
}
if (!empty($record['CountyOrParish'])) {
$address = $address . ', ' . $record['CountyOrParish'];
}
if (!empty($record['StateOrProvince'])) {
$address = $address . ', ' . $record['StateOrProvince'];
}
if (!empty($record['PostalCode'])) {
$address = $address . ' ' . $record['PostalCode'];
}
}
$listingData['otherjson'] = json_encode($record, JSON_UNESCAPED_UNICODE);
$soldArray = [
"Closed",
"Cancelled",
"Expired",
"Terminated",
"Withdrawn",
"Incomplete",
];
$existingRecord = $wpdb->get_row($wpdb->prepare("SELECT ListingKey, ModificationTimestamp, post_id,flag, PhotosChangeTimestamp, ListPrice, OriginalListPrice FROM $properties_table_name WHERE ListingKey = %s", $ListingKey), ARRAY_A);
$listingData['flag']=0;
$isSold = false;
if (in_array($listingData['MlsStatus'], $soldArray)) {
$isSold = true;
}
if ($isSold == true) {
if ($existingRecord) {
$condition = ['ListingKey' => $ListingKey];
$rows_deleted = $wpdb->delete($properties_table_name, $condition);
if ($rows_deleted) {
$post_id = $existingRecord['post_id'];
self::delete_post_and_attachments($post_id);
echo "$ListingKey Property Deleted \n";
}
$soldDataa = [];
$soldDataa['ModificationTimestamp'] = $record['ModificationTimestamp'];
$soldDataa['MlsStatus'] = $listingData['MlsStatus'];
$soldDataa['ListingKey'] = $listingData['ListingKey'];
$soldDataa['post_id'] = $existingRecord['post_id'];
$soldDataa['City'] = $listingData['City'];
$soldDataa['SubdivisionName'] = $listingData['SubdivisionName'];
$soldDataa['PropertyType'] = $listingData['PropertyType'];
$soldDataa['PropertySubType'] = $record['PropertySubType'];
$soldDataa['deleted_at'] = date("Y-m-d H:i:s");
$wpdb->insert('temp_deleted_listings', $soldDataa);
$post_id = $existingRecord['post_id'];
echo "Property $ListingKey marked as SOLD and fully deleted along with wordpress";
} else {
echo "Skip Closed, Cancled and Expired properties";
echo "\n";
return;
}
} else {
if (empty($existingRecord) || strtotime($record['PhotosChangeTimestamp']) > strtotime($existingRecord['PhotosChangeTimestamp'])) {
$mediaurl = "https://query.ampre.ca/odata/Media?\$top=250&\$filter=ResourceRecordKey%20in%20('$ListingKey')%20and%20ImageSizeDescription%20eq%20'Large'%20and%20MediaStatus%20eq%20'Active'&\$orderby=Order";
$data = $this->makeCurlRequest($mediaurl);
$mediaUrls = [];
if (isset($data['value']) && is_array($data['value'])) {
foreach ($data['value'] as $item) {
if (!empty($item['MediaURL'])) {
$mediaUrls[] = $item['MediaURL'];
}
}
}
$listingData['PhotosCount'] = count($mediaUrls);
$listingData['Media'] = json_encode($mediaUrls);
}
if ($existingRecord) {
echo "Updating property...\n";
if( strtotime($record['ModificationTimestamp']) <= strtotime($existingRecord['ModificationTimestamp'])){
$listingData['flag'] = $existingRecord['flag'];
}
$wpdb->update($properties_table_name, $listingData, ['ListingKey' => $record['ListingKey']]);
$recordsUpdated++;
} else {
$latlng = $this->getLatLngFromAddress($address, $this->googletoken, $this->mapboxtoken);
if (isset($latlng)) {
$listingData['Longitude'] = $latlng['lng'];
$listingData['latitude'] = $latlng['lat'];
}
$listingData['created_at'] = current_time('mysql');
$wpdb->insert($properties_table_name, $listingData);
echo "$ListingKey Property Inserted \n";
$recordsDownloaded++;
}
}
}
private function makeCurlRequest($url)
{
echo $url . "\n";
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 0,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $this->token,
'Content-Type: application/json',
],
]);
$response = curl_exec($curl);
curl_close($curl);
return json_decode($response, true) ?? [];
}
private function getLatLngFromAddress($address, $googletoken = null, $mapboxtoken = null)
{
if ($googletoken) {
// Google Geocoding API
$url = "https://maps.googleapis.com/maps/api/geocode/json?address=" . urlencode($address) . "&key=" . $googletoken;
} elseif ($mapboxtoken) {
// Mapbox Geocoding API
$url = "https://api.mapbox.com/geocoding/v5/mapbox.places/" . urlencode($address) . ".json?access_token=" . $mapboxtoken;
} else {
// No token available
echo 'No token';
return null;
}
echo $url . "\n";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
if ($googletoken && isset($data['results'][0]['geometry']['location'])) {
return [
'lat' => $data['results'][0]['geometry']['location']['lat'],
'lng' => $data['results'][0]['geometry']['location']['lng'],
];
} elseif ($mapboxtoken && isset($data['features'][0]['center'])) {
return [
'lng' => $data['features'][0]['center'][0], // Mapbox gives [lng, lat]
'lat' => $data['features'][0]['center'][1],
];
}
return null; // In case of API error or bad response
}
private function logCron($cronStartTime, $cronEndTime, $recordsDownloaded, $recordsUpdated, $success, $propertyDownloadStartTime, $propertyDownloadEndTime, $className, $query, $mls_count)
{
global $wpdb;
$table_name = 'cron_log';
$data = array(
'cron_start_time' => $cronStartTime,
'cron_end_time' => $cronEndTime,
'records_downloaded' => $recordsDownloaded,
'records_updated' => $recordsUpdated,
'success' => $success,
'property_download_start_time' => $propertyDownloadStartTime,
'property_download_end_time' => $propertyDownloadEndTime,
'Class_name' => $className,
'query_url' => $query,
'mls_count' => $mls_count
);
$wpdb->insert($table_name, $data);
return $wpdb->insert_id;
}
function delete_post_and_attachments($post_id)
{
global $wpdb;
$post = get_post($post_id);
if (!$post) {
return "Post with ID $post_id does not exist.";
}
$attachments = get_attached_media('', $post_id);
foreach ($attachments as $attachment) {
$attachment_id = $attachment->ID;
$file_path = get_attached_file($attachment_id);
if (file_exists($file_path)) {
unlink($file_path);
}
wp_delete_attachment($attachment_id, true);
}
$wpdb->delete($wpdb->postmeta, array('post_id' => $post_id));
wp_delete_post($post_id, true);
return "Post with ID $post_id and all associated data have been deleted.";
}
private function checkAndAddRoomsDataColumn() {
global $wpdb;
$table_name = 'properties';
// Check if column exists
$column_exists = $wpdb->get_results("SHOW COLUMNS FROM {$table_name} LIKE 'rooms_data'");
if (empty($column_exists)) {
// Add rooms_data column if it doesn't exist
$wpdb->query("ALTER TABLE {$table_name} ADD COLUMN rooms_data TEXT NULL");
echo "Added rooms_data column to properties table\n";
}
}
private function importRoomsData() {
global $wpdb;
$table_name = 'properties';
// First ensure the column exists
$this->checkAndAddRoomsDataColumn();
// Get properties where rooms_data is null or empty array
$properties = $wpdb->get_results(
"SELECT ListingKey FROM {$table_name} WHERE flag IN (0,1) and MlsStatus IN ('Active','Pending','Active Under Contract') and City IN ('Markham', 'Toronto', 'Ajax', 'Pickering', 'Oshawa', 'Mississauga', 'Brampton','King') AND ModificationTimestamp IS NOT NULL AND (rooms_data IS NULL OR rooms_data != '[]' OR rooms_data = '') order by ModificationTimestamp desc, id desc LIMIT 5000"
);
if (empty($properties)) {
echo "No properties found needing room data update\n";
return;
}
foreach ($properties as $property) {
$listingKey = $property->ListingKey;
$url = "https://query.ampre.ca/odata/PropertyRooms?\$filter=ListingKey%20eq%20'$listingKey'";
$response = $this->makeCurlRequest($url);
$roomsData = isset($response['value']) ? json_encode($response['value']) : '[]';
print_r($response);
// Update the property with room data
$wpdb->update(
$table_name,
['rooms_data' => $roomsData],
['ListingKey' => $listingKey]
);
echo "Updated room data for property {$listingKey}\n";
}
}
}
$object = new ImportProperty();
$object->importData();