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();