Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 1275 |
|
0.00% |
0 / 97 |
CRAP | n/a |
0 / 0 |
|
| getStoreFromID | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
12 | |||
| getBuyQueueByName | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
| dbConnectByName | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
56 | |||
| getJSONQueue | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
| getJSONQueueLightCached | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
12 | |||
| getJSONQueueLight | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
| rebuildQueueLightCache | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
| getJSONCompletedCached | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
12 | |||
| rebuildCompletedCache | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
| getJSONCompleted | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
| getJSONItem | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
| getStoreDirectory | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
| getStoreType | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
| getCompletedBuysArray | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
| getLastTenBuysJSON | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
| getBuyerStatsArray | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
| getSorterStatsArray | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
| getPrintLogArray | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
| getBuyersArray | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
30 | |||
| sendBuySMS | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
12 | |||
| getQueueItemArray | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
| getJSONCurrentTime | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
| checkAccessAndReturnStoreObject | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
30 | |||
| getJSONWaitTime | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
| getJSONWaitTimeCached | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getCachedWaitTime | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
12 | |||
| rebuildCachedWaitTime | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
6 | |||
| getJSONShowLoop | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
| getJSONTablets | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
| getJSONStoreTypeNum | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getJSONReferrals | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
| secondsToReadable | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
20 | |||
| secondsToMinHour | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
20 | |||
| titleCase | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
42 | |||
| getCurrentDateRange | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
2 | |||
| getDateRange | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
2 | |||
| isSSL | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
| verifyLoginToken | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
30 | |||
| verifyStoreLogin | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
20 | |||
| createSecurityToken | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
6 | |||
| destroySecurityToken | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
| getAllStoresData | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
30 | |||
| insertStoreStat | |
0.00% |
0 / 35 |
|
0.00% |
0 / 1 |
90 | |||
| insertEmployeeDaily | |
0.00% |
0 / 61 |
|
0.00% |
0 / 1 |
1056 | |||
| getSecondsFromADifference | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getStoresTxtCount | |
0.00% |
0 / 22 |
|
0.00% |
0 / 1 |
6 | |||
| getStoreInfo | |
0.00% |
0 / 27 |
|
0.00% |
0 / 1 |
12 | |||
| getStoreLogo | |
0.00% |
0 / 25 |
|
0.00% |
0 / 1 |
90 | |||
| checkAccessToAPIs | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
30 | |||
| getNumBuyers | |
0.00% |
0 / 27 |
|
0.00% |
0 / 1 |
110 | |||
| base64UrlEncode | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getStoreSlides | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
6 | |||
| getCorpSlides | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
6 | |||
| getHBSlides | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
6 | |||
| getSlideItemArray | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
6 | |||
| getTopCustomers | |
0.00% |
0 / 25 |
|
0.00% |
0 / 1 |
20 | |||
| getAllCustomers | |
0.00% |
0 / 30 |
|
0.00% |
0 / 1 |
30 | |||
| getCustomerAlert | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
12 | |||
| getCustomerData | |
0.00% |
0 / 65 |
|
0.00% |
0 / 1 |
56 | |||
| formatPhoneNumber | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
20 | |||
| getBuyerKioskStats | |
0.00% |
0 / 26 |
|
0.00% |
0 / 1 |
42 | |||
| getDashboardStats | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
2 | |||
| getDashboardBusyTimes | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
| sendDemoEmail | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
6 | |||
| sendDailyEmail | |
0.00% |
0 / 21 |
|
0.00% |
0 / 1 |
6 | |||
| sendRequestEmail | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
6 | |||
| getEmployeeInfo | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
6 | |||
| getEmployeeNameArray | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
| expireSlides | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
| getStoreTypeName | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
| sendMassTwilioTxt | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
12 | |||
| getStoreProcessAverages | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
12 | |||
| getStoreSortAverages | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
6 | |||
| compressLogFiles | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
6 | |||
| getLoyaltyCustomerByPhone | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
30 | |||
| obfuscateCustomerData | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
12 | |||
| obfuscateDigits | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
6 | |||
| obfuscateEmail | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| gen_uuid | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
6 | |||
| filterMessage | |
0.00% |
0 / 30 |
|
0.00% |
0 / 1 |
30 | |||
| similarity | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
42 | |||
| isCurrency | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| generateRemazeKey | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| validateAPIKey | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
30 | |||
| isSecure | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| getAllLoyaltyCustomersByPhone | |
0.00% |
0 / 17 |
|
0.00% |
0 / 1 |
30 | |||
| sendSMStoNumber | |
0.00% |
0 / 28 |
|
0.00% |
0 / 1 |
20 | |||
| convertUTCToLocalTimeStamp | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
| getSurveyMessages | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
2 | |||
| getSurveyLinks | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
| getRandomSurveyLink | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
| getActiveStoreCount | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
| getActiveStores | |
0.00% |
0 / 11 |
|
0.00% |
0 / 1 |
6 | |||
| getInactiveStores | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
2 | |||
| getStoreStatus | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
| getBKStats | |
0.00% |
0 / 26 |
|
0.00% |
0 / 1 |
6 | |||
| sendSurverySMS | |
0.00% |
0 / 51 |
|
0.00% |
0 / 1 |
156 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * BaseModel.php - Core Model Utilities |
| 4 | * |
| 5 | * This file provides core database connection functions and queue helpers. |
| 6 | * |
| 7 | * NOTE: All domain models are now loaded via PSR-4 autoloading. |
| 8 | * The BuyerKiosk namespace maps to userfrosting/src/BuyerKiosk/ |
| 9 | * Legacy class names are aliased in src/BuyerKiosk/Compatibility/LegacyAliases.php |
| 10 | * |
| 11 | * @see composer.json for PSR-4 configuration |
| 12 | * @see src/BuyerKiosk/Compatibility/LegacyAliases.php for backward compatibility |
| 13 | */ |
| 14 | |
| 15 | // PSR-4 autoloading handles all BuyerKiosk\* classes via Composer |
| 16 | // Legacy class names (Store, BuyQueue, Customer, etc.) are aliased automatically |
| 17 | |
| 18 | function getStoreFromID($id) { |
| 19 | global $db_name; |
| 20 | $store = new Store(); |
| 21 | if($db = dbConnectByName($db_name)) { |
| 22 | if(!$store->createStore($id, $db)) { |
| 23 | echo "ERROR STORE DOES NOT EXIST (ERROR CODE: 1005)[".$id."]"; |
| 24 | } |
| 25 | } else { |
| 26 | echo "ERROR COULD NOT CONNECT (ERROR CODE: 1000)"; |
| 27 | } |
| 28 | return $store; |
| 29 | |
| 30 | } |
| 31 | function getBuyQueueByName($dbName) { |
| 32 | $buyQueue = new BuyQueue(); |
| 33 | if($db = dbConnectByName($dbName)) { |
| 34 | $buyQueue->getAllCurrentQueueItems($db); |
| 35 | } else { |
| 36 | echo "ERROR COULD NOT CONNECT (ERROR CODE: 1001)"; |
| 37 | } |
| 38 | return $buyQueue; |
| 39 | } |
| 40 | |
| 41 | // Global array to store database connections |
| 42 | if (!isset($GLOBALS['db_connections'])) { |
| 43 | $GLOBALS['db_connections'] = []; |
| 44 | } |
| 45 | |
| 46 | function dbConnectByName($dbname) { |
| 47 | global $db_user,$db_pass; |
| 48 | if (empty($dbname)) { |
| 49 | error_log("dbConnectByName: Database name is empty"); |
| 50 | return NULL; |
| 51 | } |
| 52 | |
| 53 | // Check if we already have a connection for this database |
| 54 | if (isset($GLOBALS['db_connections'][$dbname]) && $GLOBALS['db_connections'][$dbname] instanceof PDO) { |
| 55 | try { |
| 56 | // Test if connection is still alive |
| 57 | $GLOBALS['db_connections'][$dbname]->query('SELECT 1'); |
| 58 | return $GLOBALS['db_connections'][$dbname]; |
| 59 | } catch (PDOException $e) { |
| 60 | // Connection is dead, remove it |
| 61 | unset($GLOBALS['db_connections'][$dbname]); |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | try { |
| 66 | $db = new PDO('mysql:host='.$_ENV['DB_HOST'].';dbname='.$dbname.';charset=utf8', $_ENV['DB_USER'], $_ENV['DB_PASS']); |
| 67 | $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); |
| 68 | |
| 69 | // Store connection for reuse (limit to 50 connections) |
| 70 | if (count($GLOBALS['db_connections']) < 50) { |
| 71 | $GLOBALS['db_connections'][$dbname] = $db; |
| 72 | } |
| 73 | |
| 74 | return $db; |
| 75 | } catch(PDOException $e) { |
| 76 | error_log("dbConnectByName: Connection failed for database '$dbname': " . $e->getMessage()); |
| 77 | echo "ERROR COULD NOT CONNECT (ERROR CODE: 1002)"; |
| 78 | echo $e->getMessage(); |
| 79 | } |
| 80 | return NULL; |
| 81 | } |
| 82 | function getJSONQueue(Store $store, $app = null) { |
| 83 | $dbName = $store->getDbName(); |
| 84 | $db = dbConnectByName($dbName); |
| 85 | $BuyQueue = new BuyQueue(); |
| 86 | $BuyQueue->createStore($store->getTypeNum()); |
| 87 | $queueItemArray = $BuyQueue->getAllCurrentQueueItems($db, $app); |
| 88 | return json_encode($queueItemArray); |
| 89 | } |
| 90 | function getJSONQueueLightCached(Store $store) |
| 91 | { |
| 92 | //Get Current Queue JSON from predis cache if it is less than 5 minutes old |
| 93 | $client = new Predis\Client($_ENV['REDIS_URL']); |
| 94 | $date = new DateTime('now', new DateTimeZone('UTC')); |
| 95 | if ($client->hexists($store->getTypeNum(), "current_queue_date")) { |
| 96 | $ts = new DateTime($client->hget($store->getTypeNum(), "current_queue_date")); |
| 97 | $to_time = strtotime($date->format("Y-m-d H:i:s")); |
| 98 | $from_time = strtotime($ts->format("Y-m-d H:i:s")); |
| 99 | $minutes = round(abs($to_time - $from_time) / 60, 2); |
| 100 | if ($minutes < 5) { |
| 101 | return $client->hget($store->getTypeNum(), "current_queue"); |
| 102 | } else { |
| 103 | $json = getJSONQueueLight($store); |
| 104 | $client->hset($store->getTypeNum(), "current_queue", $json); |
| 105 | $client->hset($store->getTypeNum(), "current_queue_date", $date->format("Y-m-d H:i:s")); |
| 106 | return $json; |
| 107 | } |
| 108 | } else { |
| 109 | $json = getJSONQueueLight($store); |
| 110 | $client->hset($store->getTypeNum(), "current_queue", $json); |
| 111 | $client->hset($store->getTypeNum(), "current_queue_date", $date->format("Y-m-d H:i:s")); |
| 112 | return $json; |
| 113 | } |
| 114 | } |
| 115 | function getJSONQueueLight($store) { |
| 116 | $dbName = $store->getDbName(); |
| 117 | $db = dbConnectByName($dbName); |
| 118 | $BuyQueue = new BuyQueue(); |
| 119 | $BuyQueue->createStore($store->getTypeNum()); |
| 120 | $queueItemArray = $BuyQueue->getAllCurrentQueueItemsLight($db); |
| 121 | return json_encode($queueItemArray); |
| 122 | } |
| 123 | function rebuildQueueLightCache($store) { |
| 124 | $client = new Predis\Client($_ENV['REDIS_URL']); |
| 125 | $date = new DateTime('now', new DateTimeZone('UTC')); |
| 126 | $json = getJSONQueueLight($store); |
| 127 | $client->hset($store->getTypeNum(), "current_queue", $json); |
| 128 | $client->hset($store->getTypeNum(), "current_queue_date", $date->format("Y-m-d H:i:s")); |
| 129 | } |
| 130 | function getJSONCompletedCached(Store $store) |
| 131 | { |
| 132 | $client = new Predis\Client($_ENV['REDIS_URL']); |
| 133 | $date = new DateTime('now', new DateTimeZone('UTC')); |
| 134 | if ($client->hexists($store->getTypeNum(), "completed_date")) { |
| 135 | $ts = new DateTime($client->hget($store->getTypeNum(), "completed_date")); |
| 136 | $to_time = strtotime($date->format("Y-m-d H:i:s")); |
| 137 | $from_time = strtotime($ts->format("Y-m-d H:i:s")); |
| 138 | $minutes = round(abs($to_time - $from_time) / 60, 2); |
| 139 | if ($minutes < 5) { |
| 140 | return $client->hget($store->getTypeNum(), "completed"); |
| 141 | } else { |
| 142 | $completedBuys = new CompletedBuys(); |
| 143 | $completedBuys->getCompletedBuysLight($store); |
| 144 | $client->hset($store->getTypeNum(), "completed", json_encode($completedBuys->completedBuys)); |
| 145 | $client->hset($store->getTypeNum(), "completed_date", $date->format("Y-m-d H:i:s")); |
| 146 | return json_encode($completedBuys->completedBuys); |
| 147 | } |
| 148 | } else { |
| 149 | $completedBuys = new CompletedBuys(); |
| 150 | $completedBuys->getCompletedBuysLight($store); |
| 151 | $client->hset($store->getTypeNum(), "completed", json_encode($completedBuys->completedBuys)); |
| 152 | $client->hset($store->getTypeNum(), "completed_date", $date->format("Y-m-d H:i:s")); |
| 153 | return json_encode($completedBuys->completedBuys); |
| 154 | } |
| 155 | } |
| 156 | function rebuildCompletedCache(Store $store) { |
| 157 | $client = new Predis\Client($_ENV['REDIS_URL']); |
| 158 | $date = new DateTime('now', new DateTimeZone('UTC')); |
| 159 | $completedBuys = new CompletedBuys(); |
| 160 | $completedBuys->getCompletedBuysLight($store); |
| 161 | $client->hset($store->getTypeNum(), "completed", json_encode($completedBuys->completedBuys)); |
| 162 | $client->hset($store->getTypeNum(), "completed_date", $date->format("Y-m-d H:i:s")); |
| 163 | } |
| 164 | function getJSONCompleted(Store $store) |
| 165 | { |
| 166 | $completedBuys = new CompletedBuys(); |
| 167 | $completedBuys->gatherCompletedBuys($store); |
| 168 | echo json_encode($completedBuys->completedBuys); |
| 169 | } |
| 170 | function getJSONItem(Store $store, $buyID) { |
| 171 | $dbName = $store->getDbName(); |
| 172 | $db = dbConnectByName($dbName); |
| 173 | $BuyQueue = new BuyQueue(); |
| 174 | $BuyQueue->createStore($store->getTypeNum()); |
| 175 | $queueItem = $BuyQueue->getOneQueueItem($db, $buyID); |
| 176 | return json_encode($queueItem); |
| 177 | } |
| 178 | function getStoreDirectory(Store $store) { |
| 179 | global $db_name; |
| 180 | $storeType = $store->getStoreType(); |
| 181 | $db = dbConnectByName($db_name); |
| 182 | $store = $db->query("SELECT * FROM storetypes WHERE type = '".$storeType."'"); |
| 183 | $row = $store->fetch(PDO::FETCH_ASSOC); |
| 184 | return $row['dir']; |
| 185 | } |
| 186 | function getStoreType(Store $store) { |
| 187 | global $db_name; |
| 188 | $storeType = $store->getStoreType(); |
| 189 | $db = dbConnectByName($db_name); |
| 190 | $store = $db->query("SELECT * FROM storetypes WHERE type = '".$storeType."'"); |
| 191 | $row = $store->fetch(PDO::FETCH_ASSOC); |
| 192 | return $row['name']; |
| 193 | } |
| 194 | |
| 195 | function getCompletedBuysArray(Store $store) { |
| 196 | $CompletedBuys = new CompletedBuys(); |
| 197 | $CompletedBuys->gatherCompletedBuys($store); |
| 198 | $completedBuysArray = $CompletedBuys->getCompletedBuys(); |
| 199 | return $completedBuysArray; |
| 200 | } |
| 201 | function getLastTenBuysJSON(Store $store) { |
| 202 | $CompletedBuys = new CompletedBuys(); |
| 203 | $CompletedBuys->gatherLastTen($store); |
| 204 | $completedBuysArray = $CompletedBuys->getCompletedBuys(); |
| 205 | return json_encode($completedBuysArray); |
| 206 | } |
| 207 | function getBuyerStatsArray(Store $store, $date = null) { |
| 208 | $BuyerStats = new BuyerStats(); |
| 209 | $BuyerStats->gatherDailyBuyerStatsArray($store, $date); |
| 210 | $buyerStatsArray = $BuyerStats->getBuyerStatsArray(); |
| 211 | return $buyerStatsArray; |
| 212 | } |
| 213 | function getSorterStatsArray(Store $store, $date = null) { |
| 214 | $BuyerStats = new BuyerStats(); |
| 215 | $BuyerStats->gatherDailySorterStatsArray($store, $date); |
| 216 | $sorterStatsArray = $BuyerStats->SorterStatsArray; |
| 217 | return $sorterStatsArray; |
| 218 | } |
| 219 | function getPrintLogArray(Store $store) { |
| 220 | $PrintLog = new PrintLog(); |
| 221 | $PrintLog->gatherPrintLogArray($store); |
| 222 | $printLogArray = $PrintLog->getPrintLogArray(); |
| 223 | return $printLogArray; |
| 224 | } |
| 225 | function getBuyersArray(Store $store) { |
| 226 | try{ |
| 227 | $db = dbConnectByName($store->getDbName()); |
| 228 | if (!$db) { |
| 229 | error_log("Failed to connect to database: " . $store->getDbName() . " for store: " . $store->getTypeNum()); |
| 230 | return array(); // Return empty array instead of null |
| 231 | } |
| 232 | $query = $db->query("SELECT * FROM employees WHERE active = 1 ORDER BY employeeLastName ASC"); |
| 233 | $buyerArray = array(); |
| 234 | if($query) { |
| 235 | while($row = $query->fetch(PDO::FETCH_ASSOC)) { |
| 236 | $buyerArray[] = $row; |
| 237 | } |
| 238 | } |
| 239 | return $buyerArray; |
| 240 | } catch(PDOException $e) { |
| 241 | error_log("Database error in getBuyersArray for store " . $store->getTypeNum() . ": " . $e->getMessage()); |
| 242 | return array(); // Return empty array instead of null |
| 243 | } |
| 244 | |
| 245 | } |
| 246 | function sendBuySMS($buyID, $typeNum) |
| 247 | { |
| 248 | //@var $store \Store |
| 249 | $storeController = new \BuyerKiosk\StoreController($typeNum); |
| 250 | $store = $storeController->getStore(); |
| 251 | if($store->postBuySMS == 0) { |
| 252 | //Store has buy texts turned off |
| 253 | return null; |
| 254 | } |
| 255 | $db = dbConnectByName($store->getDbName()); |
| 256 | $buyArray = getQueueItemArray($store, $buyID); |
| 257 | $customerController = new \BuyerKiosk\CustomerController(null, $store); |
| 258 | $customer = $customerController->getCustomerById($buyArray['customerID']); |
| 259 | $result = $store->textMessageService->sendBuyText($customer); |
| 260 | if($result['status'] == "success") { |
| 261 | $db->query("INSERT INTO texts (customerID, type, employeeNumber, message) VALUES (".$buyArray['customerID'].", 0, 0, '".$result['id']."')"); |
| 262 | $db->query("UPDATE buyQueue SET twilioSent = 1 WHERE buyID = ".$buyArray['buyID']); |
| 263 | |
| 264 | } |
| 265 | return $result; |
| 266 | } |
| 267 | function getQueueItemArray(Store $store, $buyID) { |
| 268 | $db = dbConnectByName($store->getDbName()); |
| 269 | if(substr($buyID,0,1) == "B") { |
| 270 | $query = $db->query("SELECT * FROM buyQueue, customers WHERE buyQueue.drsBuyID = '".$buyID."' AND customers.customerID = buyQueue.customerID"); |
| 271 | } else { |
| 272 | $query = $db->query("SELECT * FROM buyQueue, customers WHERE buyQueue.buyID = ".$buyID." AND customers.customerID = buyQueue.customerID"); |
| 273 | } |
| 274 | |
| 275 | $row = $query->fetch(PDO::FETCH_ASSOC); |
| 276 | return $row; |
| 277 | } |
| 278 | function getJSONCurrentTime() { |
| 279 | ini_set("date.timezone", "UTC"); |
| 280 | $timeNow = new DateTime("NOW", new DateTimeZone("UTC")); |
| 281 | $time = array( |
| 282 | 'timeNow' => $timeNow->format("Y-m-d H:i:s") |
| 283 | ); |
| 284 | return json_encode($time); |
| 285 | } |
| 286 | function checkAccessAndReturnStoreObject($app, $typeNum, $access) { |
| 287 | if (!$app->user->checkStoreGroup($typeNum) || !getStoreStatus($typeNum)) { |
| 288 | return null; |
| 289 | } |
| 290 | $storeController = new \BuyerKiosk\StoreController($typeNum); |
| 291 | $store = $storeController->getStore(); |
| 292 | if($store instanceof \Store) { |
| 293 | if (!$app->user->checkAccess($access)){ |
| 294 | return null; |
| 295 | } |
| 296 | return $store; |
| 297 | } |
| 298 | return null; |
| 299 | } |
| 300 | function getJSONWaitTime(Store $store) { |
| 301 | $EstimatedWaitTime = new EstimatedWaitTime(); |
| 302 | $EstimatedWaitTime->getEstimatedWaitTime($store); |
| 303 | if($store->getEnableInterval()) { |
| 304 | $temp = $EstimatedWaitTime->waitArray; |
| 305 | } else { |
| 306 | $waitTime = $EstimatedWaitTime->waitMinutes; |
| 307 | $temp = array("waitTime" => $waitTime); |
| 308 | } |
| 309 | return json_encode($temp); |
| 310 | } |
| 311 | function getJSONWaitTimeCached(Store $store) { |
| 312 | return getCachedWaitTime($store); |
| 313 | } |
| 314 | function getCachedWaitTime(Store $store) { |
| 315 | $client = new Predis\Client($_ENV['REDIS_URL']); |
| 316 | $date = new DateTime('now', new DateTimeZone('UTC')); |
| 317 | if($client->hexists($store->getTypeNum(), "waitTime_date")) { |
| 318 | $ts = new DateTime($client->hget($store->getTypeNum(), "waitTime_date")); |
| 319 | $to_time = strtotime($date->format("Y-m-d H:i:s")); |
| 320 | $from_time = strtotime($ts->format("Y-m-d H:i:s")); |
| 321 | $minutes = round(abs($to_time - $from_time) / 60, 2); |
| 322 | if ($minutes < 5) { |
| 323 | return $client->hget($store->getTypeNum(), "waitTime"); |
| 324 | } else { |
| 325 | rebuildCachedWaitTime($store); |
| 326 | return $client->hget($store->getTypeNum(), "waitTime"); |
| 327 | } |
| 328 | } else { |
| 329 | rebuildCachedWaitTime($store); |
| 330 | return $client->hget($store->getTypeNum(), "waitTime"); |
| 331 | } |
| 332 | } |
| 333 | function rebuildCachedWaitTime(Store $store) { |
| 334 | $client = new Predis\Client($_ENV['REDIS_URL']); |
| 335 | $date = new DateTime('now', new DateTimeZone('UTC')); |
| 336 | $EstimatedWaitTime = new EstimatedWaitTime(); |
| 337 | $EstimatedWaitTime->getEstimatedWaitTime($store); |
| 338 | |
| 339 | if($store->getEnableInterval()) { |
| 340 | $temp = $EstimatedWaitTime->waitArray; |
| 341 | } else { |
| 342 | $waitTime = $EstimatedWaitTime->waitMinutes; |
| 343 | $temp = array("waitTime" => $waitTime); |
| 344 | } |
| 345 | $client->hset($store->getTypeNum(), "waitTime", json_encode($temp)); |
| 346 | $client->hset($store->getTypeNum(), "waitTime_date", $date->format("Y-m-d H:i:s")); |
| 347 | } |
| 348 | function getJSONShowLoop(Store $store) { |
| 349 | $DigitalSignLoop = new StoreLoop($store); |
| 350 | $DigitalSignLoop->getCurrentSignLoopForSign(); |
| 351 | $loopArray = $DigitalSignLoop->getLoopArray(); |
| 352 | return json_encode($loopArray); |
| 353 | |
| 354 | } |
| 355 | function getJSONTablets(Store $store) { |
| 356 | $db = dbConnectByName($store->getDbName()); |
| 357 | $query = $db->query("SELECT * FROM tablets"); |
| 358 | $tabletsArray = array(); |
| 359 | while($tablet = $query->fetch(PDO::FETCH_ASSOC)) { |
| 360 | $tabletsArray[] = $tablet; |
| 361 | } |
| 362 | return json_encode($tabletsArray); |
| 363 | } |
| 364 | function getJSONStoreTypeNum(Store $store) { |
| 365 | return json_encode(array("type" => $store->getStoreType(),"num" =>$store->getStoreNum())); |
| 366 | } |
| 367 | function getJSONReferrals(Store $store, $referralCode) { |
| 368 | $referrals = new Referrals(); |
| 369 | $referralsArray = $referrals->getReferralsByCode($store, $referralCode); |
| 370 | if($referralsArray == "none") { |
| 371 | return json_encode($referralsArray); |
| 372 | } else { |
| 373 | return json_encode($referralsArray); |
| 374 | } |
| 375 | |
| 376 | } |
| 377 | function secondsToReadable($seconds) { |
| 378 | if($seconds > 0){ |
| 379 | $hours = floor($seconds/3600); |
| 380 | $seconds -= ($hours * 3600); |
| 381 | $minutes = floor($seconds/60); |
| 382 | $seconds -= ($minutes * 60); |
| 383 | if ($hours > 0) { |
| 384 | $result = new DateInterval("PT{$hours}H{$minutes}M{$seconds}S"); |
| 385 | return $result->format("%hh %Im %Ss"); |
| 386 | } else { |
| 387 | if($minutes > 0) { |
| 388 | $result = new DateInterval("PT{$minutes}M{$seconds}S"); |
| 389 | return $result->format("%im %Ss"); |
| 390 | } else { |
| 391 | $result = new DateInterval("PT{$seconds}S"); |
| 392 | return $result->format("%Ss"); |
| 393 | } |
| 394 | } |
| 395 | } else { |
| 396 | $result = new DateInterval('PT0S'); |
| 397 | return $result->format("%Ss"); |
| 398 | return $result->format("%Ss"); |
| 399 | } |
| 400 | } |
| 401 | function secondsToMinHour($seconds) { |
| 402 | if($seconds > 0){ |
| 403 | $hours = floor($seconds/3600); |
| 404 | $seconds -= ($hours * 3600); |
| 405 | $minutes = floor($seconds/60); |
| 406 | $seconds -= ($minutes * 60); |
| 407 | if ($hours > 0) { |
| 408 | $result = new DateInterval("PT{$hours}H{$minutes}M{$seconds}S"); |
| 409 | return $result->format("%hh %Im"); |
| 410 | } else { |
| 411 | if($minutes > 0) { |
| 412 | $result = new DateInterval("PT{$minutes}M{$seconds}S"); |
| 413 | return $result->format("%im"); |
| 414 | } else { |
| 415 | return "0m"; |
| 416 | } |
| 417 | } |
| 418 | } else { |
| 419 | return "0m"; |
| 420 | } |
| 421 | } |
| 422 | function titleCase($string) |
| 423 | { |
| 424 | $word_splitters = array(' ', '-', "O'", "L'", "D'", 'St.', 'Mc'); |
| 425 | $lowercase_exceptions = array('the', 'den', 'von', 'und', 'der', 'de', 'da', 'of', 'and', "l'", "d'"); |
| 426 | $uppercase_exceptions = array('III', 'IV', 'VI', 'VII', 'VIII', 'IX'); |
| 427 | |
| 428 | $string = strtolower($string); |
| 429 | foreach ($word_splitters as $delimiter) |
| 430 | { |
| 431 | $words = explode($delimiter, $string); |
| 432 | $newwords = array(); |
| 433 | foreach ($words as $word) |
| 434 | { |
| 435 | if (in_array(strtoupper($word), $uppercase_exceptions)) |
| 436 | $word = strtoupper($word); |
| 437 | else |
| 438 | if (!in_array($word, $lowercase_exceptions)) |
| 439 | $word = ucfirst($word); |
| 440 | |
| 441 | $newwords[] = $word; |
| 442 | } |
| 443 | |
| 444 | if (in_array(strtolower($delimiter), $lowercase_exceptions)) |
| 445 | $delimiter = strtolower($delimiter); |
| 446 | |
| 447 | $string = join($delimiter, $newwords); |
| 448 | } |
| 449 | return $string; |
| 450 | } |
| 451 | function getCurrentDateRange() { |
| 452 | $date = new DateTime("now", new DateTimeZone("UTC")); |
| 453 | $date->sub(new DateInterval("PT5H")); |
| 454 | $date = $date->format("Y-m-d"); |
| 455 | |
| 456 | $dateStart = new DateTime($date, new DateTimeZone("UTC")); |
| 457 | $dateStart->add(new DateInterval("PT5H")); |
| 458 | $dateEnd = new DateTime($dateStart->format("Y-m-d H:i:s"),new DateTimeZone("UTC")); |
| 459 | $dateEnd->add(new DateInterval("PT24H")); |
| 460 | |
| 461 | $dateRange = array( |
| 462 | "dateStart" => $dateStart, |
| 463 | "dateEnd" => $dateEnd |
| 464 | ); |
| 465 | return $dateRange; |
| 466 | } |
| 467 | function getDateRange($d) { |
| 468 | $date = new DateTime($d, new DateTimeZone("UTC")); |
| 469 | $date->sub(new DateInterval("PT5H")); |
| 470 | $date = $date->format("Y-m-d"); |
| 471 | |
| 472 | $dateStart = new DateTime($date, new DateTimeZone("UTC")); |
| 473 | $dateStart->add(new DateInterval("PT5H")); |
| 474 | $dateEnd = new DateTime($dateStart->format("Y-m-d H:i:s"), new DateTimeZone("UTC")); |
| 475 | $dateEnd->add(new DateInterval("PT24H")); |
| 476 | |
| 477 | $dateRange = array( |
| 478 | "dateStart" => $dateStart, |
| 479 | "dateEnd" => $dateEnd |
| 480 | ); |
| 481 | return $dateRange; |
| 482 | } |
| 483 | function isSSL() |
| 484 | { |
| 485 | return |
| 486 | (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') |
| 487 | || $_SERVER['SERVER_PORT'] == 443; |
| 488 | } |
| 489 | function verifyLoginToken($store, $token) { |
| 490 | global $db_name; |
| 491 | |
| 492 | $store=htmlspecialchars(strip_tags($store)); |
| 493 | $token = htmlspecialchars(strip_tags($token)); |
| 494 | $db = dbConnectByName($db_name); |
| 495 | try { |
| 496 | $query = $db->prepare("SELECT * FROM tokens WHERE token = ? AND typeNum = ? LIMIT 1"); |
| 497 | $query->execute(array($token,$store)); |
| 498 | $thisToken = $query->fetch(PDO::FETCH_ASSOC); |
| 499 | |
| 500 | $dateRange = getCurrentDateRange(); |
| 501 | |
| 502 | $tokenCreated = new DateTime($thisToken['created']); |
| 503 | |
| 504 | if($tokenCreated > $dateRange['dateStart'] && $tokenCreated < $dateRange['dateEnd'] && $store == $thisToken['typeNum']) { |
| 505 | return true; |
| 506 | } else { |
| 507 | destroySecurityToken($store, $token); |
| 508 | } |
| 509 | } catch(PDOException $e) { |
| 510 | echo $e->getMessage(); |
| 511 | } |
| 512 | return false; |
| 513 | } |
| 514 | function verifyStoreLogin($store, $password) { |
| 515 | global $db_name; |
| 516 | $store = htmlspecialchars(strip_tags($store)); |
| 517 | $password = htmlspecialchars(strip_tags($password)); |
| 518 | |
| 519 | $pwdHasher = new PasswordHash(8, FALSE); |
| 520 | $db = dbConnectByName($db_name); |
| 521 | try { |
| 522 | $storeQuery = $db->prepare("SELECT password FROM stores WHERE typeNum = ?"); |
| 523 | $storeQuery->execute(array($store)); |
| 524 | if($storeQuery->rowCount() > 0) { |
| 525 | $store = $storeQuery->fetch(PDO::FETCH_ASSOC); |
| 526 | $checked = $pwdHasher->CheckPassword($password, $store['password']); |
| 527 | if($checked) { |
| 528 | return true; |
| 529 | } else { |
| 530 | return false; |
| 531 | } |
| 532 | } else { |
| 533 | return false; |
| 534 | } |
| 535 | } catch(PDOException $e) { |
| 536 | |
| 537 | echo $e->getMessage(); |
| 538 | return false; |
| 539 | } |
| 540 | } |
| 541 | function createSecurityToken($typeNum) { |
| 542 | global $db_name; |
| 543 | $storeController = new \BuyerKiosk\StoreController($typeNum); |
| 544 | $store = $storeController->getStore(); |
| 545 | |
| 546 | $RandString = new RandomStringGenerator(); |
| 547 | $token = $RandString->generate(60); |
| 548 | |
| 549 | $db = dbConnectByName($db_name); |
| 550 | try { |
| 551 | $query = $db->prepare("INSERT INTO `tokens` (`id` ,`token` ,`typeNum` ,`created` ,`lastSeen`)VALUES (NULL , ?, ?,CURRENT_TIMESTAMP , CURRENT_TIMESTAMP);"); |
| 552 | $query->execute(array($token,$store->getTypeNum())); |
| 553 | return $token; |
| 554 | } catch (PDOException $e) { |
| 555 | echo $e->getMessage(); |
| 556 | } |
| 557 | return 0; |
| 558 | } |
| 559 | function destroySecurityToken($store, $token) { |
| 560 | global $db_name; |
| 561 | $db = dbConnectByName($db_name); |
| 562 | |
| 563 | $deleteQuery = $db->prepare("DELETE FROM tokens WHERE token = ? AND typeNum = ?"); |
| 564 | $deleteQuery->execute(array($token, $store)); |
| 565 | |
| 566 | session_destroy(); |
| 567 | |
| 568 | } |
| 569 | function getAllStoresData($dev = 0, $active = 1) { |
| 570 | global $db_name; |
| 571 | $stores = array(); |
| 572 | $db = dbConnectByName($db_name); |
| 573 | if($active) { |
| 574 | if($dev) { |
| 575 | $storesQuery = $db->query("SELECT * FROM stores"); |
| 576 | } else { |
| 577 | $storesQuery = $db->query("SELECT * FROM stores WHERE dev = 0 AND active = 1"); |
| 578 | } |
| 579 | } else { |
| 580 | if($dev) { |
| 581 | $storesQuery = $db->query("SELECT * FROM stores"); |
| 582 | } else { |
| 583 | $storesQuery = $db->query("SELECT * FROM stores WHERE dev = 0"); |
| 584 | } |
| 585 | } |
| 586 | |
| 587 | while($row = $storesQuery->fetch(PDO::FETCH_ASSOC)) { |
| 588 | $newStore = new Store(); |
| 589 | $newStore->createStoreFromRowArray($row); |
| 590 | $stores[] = $newStore; |
| 591 | } |
| 592 | return $stores; |
| 593 | } |
| 594 | |
| 595 | function insertStoreStat(StoreStat $storeStat) { |
| 596 | $log = new KLogger($_ENV['LOG_DIR']."dev_log.txt", KLogger::DEBUG); |
| 597 | $date = $storeStat->getDate(); |
| 598 | $store = getStoreFromID($storeStat->typeNum); |
| 599 | $db = dbConnectByName($store->getDbName()); |
| 600 | |
| 601 | $dateRange = getDateRange($date->format("Y-m-d H:i:s")); |
| 602 | $log->LogDebug($date->format("Y-m-d H:i:s")); |
| 603 | |
| 604 | $query = "SELECT id FROM statsStoreDaily WHERE date BETWEEN '".$dateRange['dateStart']->format("Y-m-d H:i:s")."' AND '".$dateRange['dateEnd']->format("Y-m-d H:i:s")."'"; |
| 605 | $dateQuery = $db->query($query); |
| 606 | $log->LogDebug($query); |
| 607 | if($dateQuery->rowCount() > 0) { |
| 608 | try { |
| 609 | $updateQuery = $db->prepare("UPDATE statsStoreDaily SET date=?,avgDelay=?,avgTotal=?,sortDelay=?,sortTime=?,avgPerContainer=?,numBuys=?,numContainers=?,numBuyers=?,firstBuy=?,lastBuy=?,buysStranded=?,uniqueCustomers=? WHERE date BETWEEN '".$dateRange['dateStart']->format("Y-m-d H:i:s")."' AND '".$dateRange['dateEnd']->format("Y-m-d H:i:s")."'"); |
| 610 | $params = array($date->format("Y-m-d H:i:s"),$storeStat->avgDelay,$storeStat->avgTotal,$storeStat->sortDelay,$storeStat->sortTime,$storeStat->avgPerContainer,$storeStat->numBuys,$storeStat->numContainers,$storeStat->numBuyers,$storeStat->firstBuy->format("Y-m-d H:i:s"),$storeStat->lastBuy->format("Y-m-d H:i:s"),$storeStat->buysStranded,$storeStat->uniqueCustomers); |
| 611 | $log->LogDebug($params); |
| 612 | if($updateQuery) { |
| 613 | $result = $updateQuery->execute($params); |
| 614 | } else { |
| 615 | $log->LogError($updateQuery->errorInfo()); |
| 616 | } |
| 617 | |
| 618 | } catch (PDOException $e) { |
| 619 | $log->LogError($e); |
| 620 | return false; |
| 621 | } |
| 622 | if(isset($result) && $result) { |
| 623 | return true; |
| 624 | } else { |
| 625 | $log->LogDebug("Did not add. Update"); |
| 626 | return false; |
| 627 | } |
| 628 | |
| 629 | } else { |
| 630 | try { |
| 631 | $insertQuery = $db->prepare("INSERT INTO statsStoreDaily (`date`, `avgDelay`, `avgTotal`, `sortDelay`, `sortTime`, `avgPerContainer`, `numBuys`, `numContainers`, `numBuyers`, `firstBuy`, `lastBuy`, `buysStranded`, `uniqueCustomers`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)"); |
| 632 | $params = array($date->format("Y-m-d H:i:s"),$storeStat->avgDelay,$storeStat->avgTotal,$storeStat->sortDelay,$storeStat->sortTime,$storeStat->avgPerContainer,$storeStat->numBuys,$storeStat->numContainers,$storeStat->numBuyers,$storeStat->firstBuy->format("Y-m-d H:i:s"),$storeStat->lastBuy->format("Y-m-d H:i:s"),$storeStat->buysStranded,$storeStat->uniqueCustomers); |
| 633 | /*foreach ($params as $param => $value) { |
| 634 | $log->LogDebug($value); |
| 635 | }*/ |
| 636 | if($insertQuery) { |
| 637 | $insertQuery->execute($params); |
| 638 | } else { |
| 639 | $log->LogDebug($insertQuery->errorInfo()); |
| 640 | } |
| 641 | } catch (PDOException $e) { |
| 642 | $log->LogError($e); |
| 643 | return false; |
| 644 | } |
| 645 | if($insertQuery->rowCount() > 0) { |
| 646 | return true; |
| 647 | } else { |
| 648 | $log->LogDebug("Did not add. Insert"); |
| 649 | return false; |
| 650 | } |
| 651 | |
| 652 | } |
| 653 | } |
| 654 | function insertEmployeeDaily(EmployeeDaily $employeeDaily) { |
| 655 | $log = KLoggerFactory::getLogger($_ENV['LOG_DIR']."dev_log.txt", KLogger::DEBUG); |
| 656 | $date = $employeeDaily->getDate(); |
| 657 | $store = getStoreFromID($employeeDaily->getTypeNum()); |
| 658 | $db = dbConnectByName($store->getDbName()); |
| 659 | |
| 660 | $dateRange = getDateRange($date->format("Y-m-d H:i:s")); |
| 661 | |
| 662 | $dateQuery = $db->query("SELECT id FROM statsEmployeeDaily WHERE employeeID = ".$employeeDaily->getEmployeeID()." AND date BETWEEN '".$dateRange['dateStart']->format("Y-m-d H:i:s")."' AND '".$dateRange['dateEnd']->format("Y-m-d H:i:s")."'"); |
| 663 | if($row = $dateQuery->fetch(PDO::FETCH_ASSOC)) { |
| 664 | $firstSort = null;$lastSort = null; |
| 665 | if($employeeDaily->getFirstSort() !== null && $employeeDaily->getLastSort() !== null && |
| 666 | $employeeDaily->getFirstSort() instanceof DateTime && $employeeDaily->getLastSort() instanceof DateTime) { |
| 667 | $firstSort = $employeeDaily->getFirstSort()->format("Y-m-d H:i:s"); |
| 668 | $lastSort = $employeeDaily->getLastSort()->format("Y-m-d H:i:s"); |
| 669 | } |
| 670 | $firstBuy = null;$lastBuy=NULL; |
| 671 | if($employeeDaily->getFirstBuy() !== null && $employeeDaily->getLastBuy() !== null && |
| 672 | $employeeDaily->getFirstBuy() instanceof DateTime && $employeeDaily->getLastBuy() instanceof DateTime) { |
| 673 | $firstBuy = $employeeDaily->getFirstBuy()->format("Y-m-d H:i:s"); |
| 674 | $lastBuy = $employeeDaily->getLastBuy()->format("Y-m-d H:i:s"); |
| 675 | } |
| 676 | //Update Record |
| 677 | try { |
| 678 | $updateQuery = $db->prepare("UPDATE statsEmployeeDaily SET date=?,avgTotal=?,avgPerContainer=?,numBuys=?,numContainers=?,firstBuy=?,lastBuy=?,employeeID=?,sortTime=?,sortDelay=?,firstSort=?,lastSort=?,numSorts=?,sortContainers=?,sortTimePerContainer=? WHERE id = ?"); |
| 679 | if($updateQuery) { |
| 680 | $params = array($date->format("Y-m-d H:i:s"),$employeeDaily->getAvgTotal(),$employeeDaily->getAvgPerContainer(),$employeeDaily->getNumBuys(),$employeeDaily->getNumContainers(),$firstBuy,$lastBuy,$employeeDaily->getEmployeeID(), $employeeDaily->getSortTime(),$employeeDaily->getSortDelay(),$firstSort,$lastSort,$employeeDaily->getNumSorts(), $employeeDaily->getSortContainers(), $employeeDaily->getSortTimePerContainer(), $row['id']); |
| 681 | foreach ($params as $param) { |
| 682 | $log->LogDebug($param); |
| 683 | } |
| 684 | $updateQuery->execute($params); |
| 685 | // Check for out of range error (deleted employee) |
| 686 | $errorInfo = $updateQuery->errorInfo(); |
| 687 | if($errorInfo[0] !== '00000' && $errorInfo[1] == 1264) { |
| 688 | //$log->LogDebug("Skipping stats for deleted employeeID: " . $employeeDaily->getEmployeeID()); |
| 689 | return false; |
| 690 | } |
| 691 | } else { |
| 692 | $log->LogError($updateQuery->errorInfo()); |
| 693 | } |
| 694 | } catch(PDOException $e) { |
| 695 | // Check if it's an out of range error for employeeID (likely deleted employee) |
| 696 | if($e->getCode() == '22003' || strpos($e->getMessage(), 'Out of range') !== false) { |
| 697 | //$log->LogDebug("Skipping stats for deleted employeeID: " . $employeeDaily->getEmployeeID()); |
| 698 | return false; |
| 699 | } |
| 700 | return false; |
| 701 | } |
| 702 | if($updateQuery->rowCount() > 0) { |
| 703 | return true; |
| 704 | } else { |
| 705 | $log->LogDebug("Could not Update Record - ".$row['id']); |
| 706 | return false; |
| 707 | } |
| 708 | } else { |
| 709 | try { |
| 710 | $firstSort = null;$lastSort = null; |
| 711 | if($employeeDaily->getFirstSort() !== null && $employeeDaily->getLastSort() !== null && |
| 712 | $employeeDaily->getFirstSort() instanceof DateTime && $employeeDaily->getLastSort() instanceof DateTime) { |
| 713 | $firstSort = $employeeDaily->getFirstSort()->format("Y-m-d H:i:s"); |
| 714 | $lastSort = $employeeDaily->getLastSort()->format("Y-m-d H:i:s"); |
| 715 | } |
| 716 | $firstBuy = null;$lastBuy=NULL; |
| 717 | if($employeeDaily->getFirstBuy() !== null && $employeeDaily->getLastBuy() !== null && |
| 718 | $employeeDaily->getFirstBuy() instanceof DateTime && $employeeDaily->getLastBuy() instanceof DateTime) { |
| 719 | $firstBuy = $employeeDaily->getFirstBuy()->format("Y-m-d H:i:s"); |
| 720 | $lastBuy = $employeeDaily->getLastBuy()->format("Y-m-d H:i:s"); |
| 721 | } |
| 722 | $insertQuery = $db->prepare("INSERT INTO statsEmployeeDaily (`date`, `avgTotal`, `avgPerContainer`, `numBuys`, `numContainers`, `firstBuy`, `lastBuy`,`employeeID`,`sortTime`,`sortDelay`,`firstSort`,`lastSort`,`numSorts`,`sortContainers`,`sortTimePerContainer`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"); |
| 723 | $params = array($date->format("Y-m-d H:i:s"),$employeeDaily->getAvgTotal(),$employeeDaily->getAvgPerContainer(),$employeeDaily->getNumBuys(),$employeeDaily->getNumContainers(),$firstBuy,$lastBuy, $employeeDaily->getEmployeeID(), $employeeDaily->getSortTime(),$employeeDaily->getSortDelay(),$firstSort,$lastSort,$employeeDaily->getNumSorts(), $employeeDaily->getSortContainers(), $employeeDaily->getSortTimePerContainer()); |
| 724 | if($insertQuery) { |
| 725 | $insertQuery->execute($params); |
| 726 | // Check for out of range error (deleted employee) |
| 727 | $errorInfo = $insertQuery->errorInfo(); |
| 728 | if($errorInfo[0] !== '00000' && $errorInfo[1] == 1264) { |
| 729 | $log->LogDebug("Skipping stats for deleted employeeID: " . $employeeDaily->getEmployeeID()); |
| 730 | return false; |
| 731 | } |
| 732 | } else { |
| 733 | $log->LogDebug($insertQuery->errorInfo()); |
| 734 | } |
| 735 | } catch(PDOException $e) { |
| 736 | // Check if it's an out of range error for employeeID (likely deleted employee) |
| 737 | if($e->getCode() == '22003' || strpos($e->getMessage(), 'Out of range') !== false) { |
| 738 | $log->LogDebug("Skipping stats for deleted employeeID: " . $employeeDaily->getEmployeeID()); |
| 739 | return false; |
| 740 | } |
| 741 | $log->LogDebug($e); |
| 742 | return false; |
| 743 | } |
| 744 | return $insertQuery->rowCount() > 0; |
| 745 | } |
| 746 | } |
| 747 | function getSecondsFromADifference($diff) { |
| 748 | return ((int)$diff->format('%h') * 60 * 60) + ((int)$diff->format('%i') * 60) + ((int)$diff->format('%s')); |
| 749 | } |
| 750 | function getStoresTxtCount(DateTime $end, DateTime $start) { |
| 751 | $log = new KLogger($_ENV['LOG_DIR']."dev_log.txt", KLogger::DEBUG); |
| 752 | $start = getDateRange($start->format("Y-m-d H:i:s")); |
| 753 | $end = getDateRange($end->format("Y-m-d H:i:s")); |
| 754 | |
| 755 | global $db_name; |
| 756 | $textsArray = array(); |
| 757 | |
| 758 | $stores = getAllStoresData(); |
| 759 | |
| 760 | foreach ($stores as $store) { |
| 761 | $db = dbConnectByName($store->getDbName()); |
| 762 | $log->LogDebug($start['dateStart']->format("Y-m-d H:i:s")." - ".$end['dateEnd']->format("Y-m-d H:i:s")); |
| 763 | $txtsQ = $db->query("SELECT count(id) as textCount, SUM(surveyText) as surveyTexts FROM (SELECT CEIL(ROUND((UNIX_TIMESTAMP(timestamp)/customerID)*100000)/100000) as combined, id, timestamp, customerID, IF(type = 5,1,0) as surveyText FROM texts WHERE timestamp BETWEEN '".$start['dateStart']->format("Y-m-d H:i:s")."' AND '".$end['dateEnd']->format("Y-m-d H:i:s")."' GROUP BY combined ORDER BY id DESC) as B"); |
| 764 | $totalTexts = $txtsQ->fetch(PDO::FETCH_ASSOC); |
| 765 | $microBlinkQuery = $db->query("SELECT count(*) as numLicenses FROM tablets WHERE microBlinkAPI IS NOT NULL"); |
| 766 | $totalLicenses = $microBlinkQuery->fetch(PDO::FETCH_ASSOC); |
| 767 | $tempArray = array( |
| 768 | 'storeCity' => $store->getCity(), |
| 769 | 'storeNum' => $store->getTypeNum(), |
| 770 | 'totalTexts' => $totalTexts['textCount'], |
| 771 | 'surveyText' => $totalTexts['surveyTexts'], |
| 772 | 'microBlinkLicenses' => $microBlinkQuery['numLicenses'] |
| 773 | ); |
| 774 | $textsArray[] = $tempArray; |
| 775 | } |
| 776 | return json_encode($textsArray); |
| 777 | } |
| 778 | function getStoreInfo(Store $store) { |
| 779 | $tokenEnabled = 0; |
| 780 | $token = $store->getWiwToken(); |
| 781 | if ($token !== null && strlen($token) > 0) { |
| 782 | $tokenEnabled = 1; |
| 783 | } |
| 784 | $output = array( |
| 785 | 'typeNum' => $store->getTypeNum(), |
| 786 | 'type' => getStoreType($store), |
| 787 | 'city' => $store->getCity(), |
| 788 | 'logo' => getStoreLogo($store, true), |
| 789 | 'timeZone' => $store->getTimeZone(), |
| 790 | 'zipcode' => $store->getZipCode(), |
| 791 | 'dir' => getStoreDirectory($store), |
| 792 | 'state' => $store->getState(), |
| 793 | 'storeGroup' => null, |
| 794 | 'enableWaitTime' => $store->getEnableWaitTime(), |
| 795 | 'api' => $store->getApiKey(), |
| 796 | 'storeNum' => $store->getStoreNum(), |
| 797 | 'postBuySMS' => $store->getPostBuySMS(), |
| 798 | 'active' => $store->getActive(), |
| 799 | 'wiwTokenEnabled' => $tokenEnabled, |
| 800 | 'wiwEnabled' => $store->getWiwEnable(), |
| 801 | 'wiwLocationID' => $store->getWiwLocationID(), |
| 802 | 'yellowTime' => $store->getYellowTime(), |
| 803 | 'redTime' => $store->getRedTime(), |
| 804 | 'dsWeatherBar' => $store->dsWeatherBar |
| 805 | ); |
| 806 | return $output; |
| 807 | } |
| 808 | function getStoreLogo(Store $store, $alt = false) { |
| 809 | $storeType = $store->getStoreType(); |
| 810 | $output = ""; |
| 811 | switch($storeType) { |
| 812 | case 0: |
| 813 | $output = "cm"; |
| 814 | break; |
| 815 | case 1: |
| 816 | if($alt) { |
| 817 | $output = "pc-alt2"; |
| 818 | } else { |
| 819 | $output = "pc"; |
| 820 | } |
| 821 | break; |
| 822 | case 2: |
| 823 | $output = "ouac"; |
| 824 | break; |
| 825 | case 3: |
| 826 | $output = "se"; |
| 827 | break; |
| 828 | case 4: |
| 829 | $output = "pias"; |
| 830 | break; |
| 831 | case 5: |
| 832 | $output = "hom"; |
| 833 | break; |
| 834 | default: |
| 835 | $output = "bk"; |
| 836 | break; |
| 837 | } |
| 838 | return $output; |
| 839 | } |
| 840 | function checkAccessToAPIs($app, $typeNum) { |
| 841 | |
| 842 | $jwt = base64_decode($_COOKIE['pineapple']); |
| 843 | try { |
| 844 | $token = \JWT::decode($jwt, base64_decode(SECRET_KEY)); |
| 845 | if($token->iat + 86400 < time()) { |
| 846 | return false; |
| 847 | } |
| 848 | if($token->iss !== serverName) { |
| 849 | return false; |
| 850 | } |
| 851 | } catch (Exception $e) { |
| 852 | echo $e->getMessage(); |
| 853 | return false; |
| 854 | } |
| 855 | if(!$app->user->checkStoreGroup($typeNum)) { |
| 856 | return false; |
| 857 | } |
| 858 | return true; |
| 859 | } |
| 860 | |
| 861 | function getNumBuyers(Store $store) |
| 862 | { |
| 863 | //$log = new KLogger("../logs/dev_log2.txt", KLogger::DEBUG); |
| 864 | $dbName = $store->getDbName(); |
| 865 | if (empty($dbName)) { |
| 866 | error_log("getNumBuyers: Store database name is empty for store: " . $store->getStoreNum()); |
| 867 | return 0; |
| 868 | } |
| 869 | $db = dbConnectByName($dbName); |
| 870 | if (!$db) { |
| 871 | error_log("getNumBuyers: Failed to connect to database: " . $dbName); |
| 872 | return 0; |
| 873 | } |
| 874 | $query = $db->query("SELECT buyersTimeStamp, numBuyers FROM realTimeData WHERE id = 1"); |
| 875 | if($query) { |
| 876 | $result = $query->fetch(PDO::FETCH_ASSOC); |
| 877 | $dateRange = getCurrentDateRange(); |
| 878 | $numBuyers = 0; |
| 879 | if($result && strtotime($result['buyersTimeStamp']) < strtotime("-2 minutes")) { |
| 880 | $b = $db->query("SELECT DISTINCT buyerID FROM buyQueue WHERE isProcessed = 0 AND buyerID IS NOT NULL AND timeEntered BETWEEN '".$dateRange['dateStart']->format("Y-m-d H:i:s")."' AND '" . $dateRange['dateEnd']->format("Y-m-d H:i:s")."'"); |
| 881 | while ($buyers = $b->fetch(PDO::FETCH_ASSOC)) { |
| 882 | $numBuyers++; |
| 883 | } |
| 884 | if ($store->getAddSortersToEstimate()) { //usually a 0 |
| 885 | $s = $db->query("SELECT DISTINCT sorterID FROM buyQueue WHERE isProcessed = 0 AND sorterID >0 AND sortCompleted = '0000-00-00 00:00:00' AND timeEntered BETWEEN '" . $dateRange['dateStart']->format("Y-m-d H:i:s") . "' AND '" . $dateRange['dateEnd']->format("Y-m-d H:i:s") . "'"); |
| 886 | while ($sorters = $s->fetch(PDO::FETCH_ASSOC)) { |
| 887 | $numBuyers++; |
| 888 | } |
| 889 | } |
| 890 | $stmt = $db->prepare("UPDATE realTimeData SET buyersTimeStamp = CURRENT_TIMESTAMP, numBuyers = :numBuyers WHERE id = 1"); |
| 891 | $stmt->bindValue(":numBuyers", $numBuyers); |
| 892 | $stmt->execute(); |
| 893 | return $numBuyers; |
| 894 | |
| 895 | } else { |
| 896 | return $result ? (int)$result['numBuyers'] : 0; |
| 897 | } |
| 898 | } else { |
| 899 | return 0; |
| 900 | } |
| 901 | |
| 902 | } |
| 903 | function base64UrlEncode($_input) |
| 904 | { |
| 905 | return str_replace(array('=','+','/'),array('_','-',','),base64_encode($_input)); |
| 906 | } |
| 907 | |
| 908 | function getStoreSlides(Store $store) |
| 909 | { |
| 910 | |
| 911 | // Grab Store Specific Slides |
| 912 | $db = dbConnectByName($store->getDbName()); |
| 913 | $selectQuery = $db->query("SELECT * FROM dsSlides WHERE enabled = 1 ORDER BY dateAdded DESC"); |
| 914 | $slidesArray = array(); |
| 915 | while ($slides = $selectQuery->fetch(PDO::FETCH_ASSOC)) { |
| 916 | $dateAdded = new DateTime($slides['dateAdded']); |
| 917 | $dateAdded->setTimezone(new DateTimeZone($store->getTimeZone())); |
| 918 | $slide = array( |
| 919 | 'slideID' => $slides['id'], |
| 920 | 'type' => $slides['type'], |
| 921 | 'slideName' => $slides['slideName'], |
| 922 | 'fileName' => $slides['fileName'], |
| 923 | 'dateAdded' => $dateAdded->format('F j, Y'), |
| 924 | 'plays' => $slides['plays'] |
| 925 | |
| 926 | ); |
| 927 | $slidesArray[] = $slide; |
| 928 | } |
| 929 | return $slidesArray; |
| 930 | } |
| 931 | |
| 932 | function getCorpSlides(Store $store) |
| 933 | { |
| 934 | global $db_name; |
| 935 | //Grab Corporate Slides |
| 936 | $storeType = $store->getStoreType(); |
| 937 | $db = dbConnectByName($db_name); |
| 938 | $selectQuery = $db->query("SELECT * FROM corpSlides WHERE enabled = 1 AND storeType = " . $storeType . " ORDER BY dateAdded DESC"); |
| 939 | $corpSlidesArray = array(); |
| 940 | while ($slides = $selectQuery->fetch(PDO::FETCH_ASSOC)) { |
| 941 | $dateAdded = new DateTime($slides['dateAdded']); |
| 942 | $dateAdded->setTimezone(new DateTimeZone($store->getTimeZone())); |
| 943 | $slide = array( |
| 944 | 'slideID' => $slides['id'], |
| 945 | 'type' => $slides['type'], |
| 946 | 'slideName' => $slides['slideName'], |
| 947 | 'fileName' => $slides['fileName'], |
| 948 | 'dateAdded' => $dateAdded->format('F j, Y'), |
| 949 | 'plays' => $slides['plays'] |
| 950 | ); |
| 951 | $corpSlidesArray[] = $slide; |
| 952 | } |
| 953 | return $corpSlidesArray; |
| 954 | } |
| 955 | function getHBSlides(Store $store) { |
| 956 | global $db_name; |
| 957 | //Grab HipBone Slides |
| 958 | $storeType = $store->getStoreType(); |
| 959 | $db = dbConnectByName($db_name); |
| 960 | $selectQuery = $db->query("SELECT * FROM hbSlides WHERE enabled = 1 AND storeType = " . $storeType . " ORDER BY dateAdded DESC"); |
| 961 | $hbSlidesArray = array(); |
| 962 | while ($slides = $selectQuery->fetch(PDO::FETCH_ASSOC)) { |
| 963 | $dateAdded = new DateTime($slides['dateAdded']); |
| 964 | $dateAdded->setTimezone(new DateTimeZone($store->getTimeZone())); |
| 965 | $slide = array( |
| 966 | 'slideID' => $slides['id'], |
| 967 | 'type' => $slides['type'], |
| 968 | 'slideName' => $slides['slideName'], |
| 969 | 'fileName' => $slides['fileName'], |
| 970 | 'dateAdded' => $dateAdded->format('F j, Y'), |
| 971 | ); |
| 972 | $hbSlidesArray[] = $slide; |
| 973 | } |
| 974 | return $hbSlidesArray; |
| 975 | } |
| 976 | function getSlideItemArray(Store $store) |
| 977 | { |
| 978 | $db = dbConnectByName($store->getDbName()); |
| 979 | $slideItemArray = array(); |
| 980 | $loopQuery = $db->query("SELECT |
| 981 | dsLoop.id, |
| 982 | dsLoop.position, |
| 983 | dsLoop.duration, |
| 984 | dsLoop.slideUploader, |
| 985 | dsLoop.slideID, |
| 986 | IF(slideUploader = 0, dsSlides.fileName, IF(slideUploader = 1, `kiosk_buykiosk`.corpSlides.fileName, `kiosk_buykiosk`.hbSlides.fileName)) as fileName, |
| 987 | IF(slideUploader = 0, dsSlides.slideName, IF(slideUploader = 1, `kiosk_buykiosk`.corpSlides.slideName, `kiosk_buykiosk`.hbSlides.slideName)) as slideName, |
| 988 | IF(slideUploader = 0, dsSlides.type, IF(slideUploader = 1, `kiosk_buykiosk`.corpSlides.type, `kiosk_buykiosk`.hbSlides.type)) as type, |
| 989 | IF(slideUploader = 0, dsSlides.dateAdded, IF(slideUploader = 1, `kiosk_buykiosk`.corpSlides.dateAdded, `kiosk_buykiosk`.hbSlides.dateAdded)) as dateAdded |
| 990 | FROM |
| 991 | dsLoop |
| 992 | LEFT JOIN `kiosk_buykiosk`.hbSlides ON ( `kiosk_buykiosk`.hbSlides.id = dsLoop.slideID AND dsLoop.slideUploader = 2 ) |
| 993 | LEFT JOIN `kiosk_buykiosk`.corpSlides ON ( `kiosk_buykiosk`.corpSlides.id = dsLoop.slideID AND dsLoop.slideUploader = 1 ) |
| 994 | LEFT JOIN dsSlides ON ( dsSlides.id = dsLoop.slideID AND dsLoop.slideUploader = 0 ) ORDER BY position ASC"); |
| 995 | while ($loopItem = $loopQuery->fetch(PDO::FETCH_ASSOC)) { |
| 996 | $tempSlide = array( |
| 997 | 'id' => $loopItem['id'], |
| 998 | 'slideID' => $loopItem['slideID'], |
| 999 | 'position' => $loopItem['position'], |
| 1000 | 'duration' => $loopItem['duration'], |
| 1001 | 'slideUploader' => $loopItem['slideUploader'], |
| 1002 | 'slideName' => $loopItem['slideName'], |
| 1003 | 'fileName' => $loopItem['fileName'], |
| 1004 | 'thumbName' => $loopItem['fileName'], |
| 1005 | 'dateAdded' => $loopItem['dateAdded'], |
| 1006 | 'type' => $loopItem['type'], |
| 1007 | ); |
| 1008 | $slideItemArray[] = $tempSlide; |
| 1009 | } |
| 1010 | return $slideItemArray; |
| 1011 | } |
| 1012 | function getTopCustomers(Store $store, $dateStart = null, $dateEnd = null) { |
| 1013 | $log = new KLogger($_ENV['LOG_DIR']."dev_log.txt", KLogger::DEBUG); |
| 1014 | |
| 1015 | |
| 1016 | $db = dbConnectByName($store->getDbName()); |
| 1017 | if($dateStart == null || $dateEnd == null) { |
| 1018 | $query = $db->query(" |
| 1019 | SELECT buyQueue.customerID, customers.firstName,customers.phone, customers.lastName, COUNT( * ) AS count |
| 1020 | FROM buyQueue |
| 1021 | INNER JOIN customers ON buyQueue.customerID = customers.customerID |
| 1022 | GROUP BY buyQueue.customerID |
| 1023 | ORDER BY count DESC |
| 1024 | LIMIT 0 , 50 |
| 1025 | "); |
| 1026 | } else { |
| 1027 | $dateStart = getDateRange($dateStart); |
| 1028 | $dateEnd = getDateRange($dateEnd); |
| 1029 | $query = $db->query(" |
| 1030 | SELECT buyQueue.customerID, customers.firstName,customers.phone, customers.lastName, COUNT( * ) AS count |
| 1031 | FROM buyQueue timeEntered BETWEEN '".$dateStart['dateStart']->format("Y-m-d H:i:s")."' AND '".$dateEnd['dateEnd']->format("Y-m-d H:i:s")."' |
| 1032 | INNER JOIN customers ON buyQueue.customerID = customers.customerID |
| 1033 | GROUP BY buyQueue.customerID |
| 1034 | ORDER BY count DESC |
| 1035 | LIMIT 0 , 50 |
| 1036 | "); |
| 1037 | } |
| 1038 | $customerArray = array(); |
| 1039 | while($row=$query->fetch(PDO::FETCH_ASSOC)) { |
| 1040 | $tempCustomer = []; |
| 1041 | $tempCustomer['customerID'] = $row['customerID']; |
| 1042 | $tempCustomer['phone'] = $row['phone']; |
| 1043 | $tempCustomer['name'] = $row['firstName']." ".$row['lastName']; |
| 1044 | $tempCustomer['numBuys'] = $row['count']; |
| 1045 | $tempDate = getCurrentDateRange(); |
| 1046 | $tempDate['dateStart']->sub(new DateInterval('P30D')); |
| 1047 | $log->LogDebug("Last 30: ".$tempDate['dateStart']->format("Y-m-d H:i:s")." to ".$tempDate['dateEnd']->format("Y-m-d H:i:s")); |
| 1048 | $query2 = $db->query("SELECT COUNT(*) FROM buyQueue WHERE customerID = ".$row['customerID']." AND timeEntered BETWEEN '".$tempDate['dateStart']->format("Y-m-d H:i:s")."' AND '".$tempDate['dateEnd']->format("Y-m-d H:i:s")."'"); |
| 1049 | $row2 = $query2->fetch(PDO::FETCH_ASSOC); |
| 1050 | $tempCustomer['last30'] = $row2['COUNT(*)']; |
| 1051 | $customerArray[] = $tempCustomer; |
| 1052 | } |
| 1053 | return $customerArray; |
| 1054 | } |
| 1055 | function getAllCustomers(Store $store) { |
| 1056 | $db = dbConnectByName($store->getDbName()); |
| 1057 | |
| 1058 | $query = "SELECT |
| 1059 | customers.customerID, |
| 1060 | MAX(COALESCE(buyQueue.timeEntered, deletedBuys.timeEntered)) as latestVisit, |
| 1061 | customers.firstName, |
| 1062 | customers.phone, |
| 1063 | customers.lastName, |
| 1064 | customers.driversLicense, |
| 1065 | COUNT(CASE WHEN buyQueue.buyID IS NOT NULL OR deletedBuys.buyID IS NOT NULL THEN 1 END) AS count, |
| 1066 | ROUND(AVG(customerRatings.rating), 1) as avg_rating |
| 1067 | FROM customers |
| 1068 | LEFT JOIN buyQueue ON customers.customerID = buyQueue.customerID |
| 1069 | LEFT JOIN deletedBuys ON customers.customerID = deletedBuys.customerID |
| 1070 | LEFT JOIN customerRatings ON customers.customerID = customerRatings.customerID |
| 1071 | GROUP BY |
| 1072 | customers.customerID, |
| 1073 | customers.firstName, |
| 1074 | customers.phone, |
| 1075 | customers.lastName, |
| 1076 | customers.driversLicense |
| 1077 | ORDER BY customers.customerID DESC"; |
| 1078 | |
| 1079 | // Debug: Check if query string is empty before execution |
| 1080 | if (empty(trim($query))) { |
| 1081 | error_log("EMPTY QUERY STRING DETECTED in getAllCustomers() before execution"); |
| 1082 | error_log("Stack trace: " . print_r(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), true)); |
| 1083 | return []; |
| 1084 | } |
| 1085 | $queryResult = $db->query($query); |
| 1086 | $customerArray = []; |
| 1087 | |
| 1088 | while($row = $queryResult->fetch(PDO::FETCH_ASSOC)) { |
| 1089 | $rating = $row['avg_rating'] ?: "NR"; |
| 1090 | $tempArray = $row; |
| 1091 | |
| 1092 | if ($row['latestVisit'] !== null) { |
| 1093 | $lastestVisit = DateTime::createFromFormat('Y-m-d H:i:s', $row['latestVisit'], new DateTimeZone($store->getTimeZone())); |
| 1094 | $latestVisitArray = [ |
| 1095 | 'display' => $lastestVisit->format("M jS, Y g:i a"), |
| 1096 | 'timeStamp' => $lastestVisit->getTimestamp() |
| 1097 | ]; |
| 1098 | } else { |
| 1099 | $latestVisitArray = [ |
| 1100 | 'display' => 'No Buys Recorded', |
| 1101 | 'timeStamp' => 0 |
| 1102 | ]; |
| 1103 | } |
| 1104 | |
| 1105 | $tempArray['driversLicense'] = mb_substr($row['driversLicense'],0,2)."******".mb_substr($row['driversLicense'], -4,4); |
| 1106 | $tempArray['customerID'] = "<a href='/admin/".$store->getTypeNum()."/customers/id/".$row['customerID']."'>".$row['customerID']."</a>"; |
| 1107 | $tempArray['fullName'] = "<a href='/admin/".$store->getTypeNum()."/customers/id/".$row['customerID']."'>".$row['firstName']." ".$row['lastName']."</a>"; |
| 1108 | $tempArray['phone'] = formatPhoneNumber($row['phone']); |
| 1109 | $tempArray['rating'] = $rating; |
| 1110 | $tempArray['latestVisit'] = $latestVisitArray; |
| 1111 | $customerArray[] = $tempArray; |
| 1112 | } |
| 1113 | |
| 1114 | return $customerArray; |
| 1115 | } |
| 1116 | function getCustomerAlert(Store $store, $cust_id = null, $phone = null) { |
| 1117 | $alertArray = []; |
| 1118 | $db = dbConnectByName($store->getDbName()); |
| 1119 | if($cust_id !== null) { |
| 1120 | $stmt = $db->prepare("SELECT customerAlerts.id as id, customerAlerts.customerID as customerID, customerAlerts.type as type, comment, class, customerAlerts.dateAdded as dateAdded, customers.firstName as firstName, customers.lastName as lastName, customers.phone, customers.driversLicense as driversLicense FROM customerAlerts JOIN customers ON customerAlerts.customerID = customers.customerID WHERE customers.customerID = :customerID ORDER BY customerAlerts.dateAdded DESC"); |
| 1121 | $stmt->bindValue(":customerID", $cust_id); |
| 1122 | } else { |
| 1123 | $stmt = $db->prepare("SELECT customerAlerts.id as id, customerAlerts.customerID as customerID, customerAlerts.type as type, comment, class, customerAlerts.dateAdded as dateAdded, customers.firstName as firstName, customers.lastName as lastName, customers.phone, customers.driversLicense as driversLicense FROM customerAlerts JOIN customers ON customerAlerts.customerID = customers.customerID WHERE customers.phone = :phone ORDER BY customerAlerts.dateAdded DESC"); |
| 1124 | $stmt->bindValue(":phone", $phone); |
| 1125 | } |
| 1126 | $stmt->execute(); |
| 1127 | while($row = $stmt->fetch(PDO::FETCH_ASSOC)) { |
| 1128 | $alertArray[] = $row; |
| 1129 | } |
| 1130 | return $alertArray; |
| 1131 | } |
| 1132 | function getCustomerData(Store $store, $cust_id = null, $phone = null) { |
| 1133 | $db = dbConnectByName($store->getDbName()); |
| 1134 | if($cust_id !== null) { |
| 1135 | $query = $db->prepare("SELECT * FROM customers WHERE customerID = :cust_id"); |
| 1136 | $query->bindValue(":cust_id", $cust_id); |
| 1137 | } else { |
| 1138 | $query = $db->prepare("SELECT * FROM customers WHERE phone = :phone"); |
| 1139 | $query->bindValue(":phone", $phone); |
| 1140 | } |
| 1141 | $customerData = array(); |
| 1142 | $employees = getEmployeeNameArray($store); |
| 1143 | |
| 1144 | if($query->execute()) { |
| 1145 | $customerInfo = []; |
| 1146 | $customer = $query->fetch(PDO::FETCH_ASSOC); |
| 1147 | if(!isset($customer['customerID'])) { |
| 1148 | return null; |
| 1149 | } |
| 1150 | $customerInfo['customerID'] = $customer['customerID']; |
| 1151 | $customerInfo['name'] = $customer['firstName']." ".$customer['lastName']; |
| 1152 | $customerInfo['phone'] = formatPhoneNumber($customer['phone']); |
| 1153 | $customerInfo['email'] = $customer['email']; |
| 1154 | $customerInfo['onSMS'] = $customer['onSMS']; |
| 1155 | $customerInfo['onEmail'] = $customer['onEmail']; |
| 1156 | $customerInfo['driversLicense'] = $customer['driversLicense']; |
| 1157 | $customerInfo['address'] = $customer['address']; |
| 1158 | $customerInfo['city'] = $customer['city']; |
| 1159 | $customerInfo['state'] = $customer['state']; |
| 1160 | $customerInfo['zipcode'] = $customer['zipcode']; |
| 1161 | $dateAdded = new DateTime($customer['dateAdded'], new DateTimeZone('UTC')); |
| 1162 | $dateAdded->setTimezone(new DateTimeZone($store->getTimeZone())); |
| 1163 | $customerInfo['dateAdded'] = $dateAdded->format("Y, M jS g:i a"); |
| 1164 | $tempDate = getCurrentDateRange(); |
| 1165 | $tempDate['dateStart']->sub(new DateInterval('P30D')); |
| 1166 | $query2 = $db->query("SELECT COUNT(*) FROM ( |
| 1167 | SELECT timeEntered FROM buyQueue WHERE customerID = ".$customer['customerID']." |
| 1168 | UNION ALL |
| 1169 | SELECT timeEntered FROM deletedBuys WHERE customerID = ".$customer['customerID']." |
| 1170 | ) combined WHERE timeEntered BETWEEN '".$tempDate['dateStart']->format("Y-m-d H:i:s")."' AND '".$tempDate['dateEnd']->format("Y-m-d H:i:s")."'"); |
| 1171 | $row2 = $query2->fetch(PDO::FETCH_ASSOC); |
| 1172 | $customerInfo['last30'] = $row2['COUNT(*)']; |
| 1173 | |
| 1174 | $buyData = array(); |
| 1175 | $first = true; |
| 1176 | $query3 = $db->query("( |
| 1177 | SELECT |
| 1178 | buyID, |
| 1179 | customerID, |
| 1180 | timeEntered, |
| 1181 | dailyNum, |
| 1182 | numContainers, |
| 1183 | twilioSent, |
| 1184 | buyerID, |
| 1185 | 0 as deleted |
| 1186 | FROM buyQueue |
| 1187 | WHERE customerID = ".$customer['customerID']." |
| 1188 | UNION ALL |
| 1189 | SELECT |
| 1190 | buyID, |
| 1191 | customerID, |
| 1192 | timeEntered, |
| 1193 | dailyNum, |
| 1194 | numContainers, |
| 1195 | twilioSent, |
| 1196 | buyerID, |
| 1197 | 1 as deleted |
| 1198 | FROM deletedBuys |
| 1199 | WHERE customerID = ".$customer['customerID']." |
| 1200 | ) ORDER BY timeEntered DESC"); |
| 1201 | while($row = $query3->fetch(PDO::FETCH_ASSOC)) { |
| 1202 | if($first) { |
| 1203 | $lastSeen = new DateTime($row['timeEntered'], new DateTimeZone('UTC')); |
| 1204 | $lastSeen->setTimezone(new DateTimeZone($store->getTimeZone())); |
| 1205 | $customerInfo['lastSeen'] = $lastSeen->format("Y, M jS g:i a"); |
| 1206 | $first = false; |
| 1207 | } |
| 1208 | $empName = isset($employees[$row['buyerID']]) ? $employees[$row['buyerID']] : 'Unknown'; |
| 1209 | $tempBuy = array(); |
| 1210 | $tempBuy['buyID'] = $row['buyID']; |
| 1211 | $time = new DateTime($row['timeEntered'], new DateTimeZone('UTC')); |
| 1212 | $time->setTimezone(new DateTimeZone($store->getTimeZone())); |
| 1213 | $tempBuy['deleted'] = $row['deleted']; |
| 1214 | $tempBuy['date'] = $time->format("Y, M jS"); |
| 1215 | $tempBuy['linkDate'] = $time->format("m_d_y"); |
| 1216 | $tempBuy['time'] = $time->format("g:i A"); |
| 1217 | $tempBuy['dailyNum'] = $row['dailyNum']; |
| 1218 | $tempBuy['containers'] = $row['numContainers']; |
| 1219 | $tempBuy['textSent'] = $row['twilioSent']; |
| 1220 | $tempBuy['buyerName'] = $empName; |
| 1221 | $tempBuy['buyerID'] = $row['buyerID']; |
| 1222 | |
| 1223 | $buyData[] = $tempBuy; |
| 1224 | } |
| 1225 | |
| 1226 | } |
| 1227 | $customerData['customer'] = $customerInfo; |
| 1228 | $customerData['buyData'] = $buyData; |
| 1229 | return $customerData; |
| 1230 | } |
| 1231 | function formatPhoneNumber($phoneNumber) { |
| 1232 | $phoneNumber = preg_replace('/[^0-9]/','',$phoneNumber); |
| 1233 | |
| 1234 | if(strlen($phoneNumber) > 10) { |
| 1235 | $countryCode = substr($phoneNumber, 0, strlen($phoneNumber)-10); |
| 1236 | $areaCode = substr($phoneNumber, -10, 3); |
| 1237 | $nextThree = substr($phoneNumber, -7, 3); |
| 1238 | $lastFour = substr($phoneNumber, -4, 4); |
| 1239 | |
| 1240 | $phoneNumber = '+'.$countryCode.' ('.$areaCode.') '.$nextThree.'-'.$lastFour; |
| 1241 | } |
| 1242 | else if(strlen($phoneNumber) == 10) { |
| 1243 | $areaCode = substr($phoneNumber, 0, 3); |
| 1244 | $nextThree = substr($phoneNumber, 3, 3); |
| 1245 | $lastFour = substr($phoneNumber, 6, 4); |
| 1246 | |
| 1247 | $phoneNumber = '('.$areaCode.') '.$nextThree.'-'.$lastFour; |
| 1248 | } |
| 1249 | else if(strlen($phoneNumber) == 7) { |
| 1250 | $nextThree = substr($phoneNumber, 0, 3); |
| 1251 | $lastFour = substr($phoneNumber, 3, 4); |
| 1252 | |
| 1253 | $phoneNumber = $nextThree.'-'.$lastFour; |
| 1254 | } |
| 1255 | |
| 1256 | return $phoneNumber; |
| 1257 | } |
| 1258 | function getBuyerKioskStats() { |
| 1259 | |
| 1260 | $stores = getAllStoresData(); |
| 1261 | $totalBuys = 0;$totalSMS=0;$totalEmails=0;$totalTexts=0; |
| 1262 | foreach ($stores as $store) { |
| 1263 | $db = dbConnectByName($store->getDbName()); |
| 1264 | $buysQuery = $db->query("SELECT COUNT(*) as buysCount FROM buyQueue"); |
| 1265 | |
| 1266 | if($buysQuery) { |
| 1267 | $result = $buysQuery->fetch(PDO::FETCH_ASSOC); |
| 1268 | $totalBuys += (int)$result['buysCount']; |
| 1269 | } |
| 1270 | $smsQuery = $db->query("SELECT COUNT(*) as smsCount FROM customers WHERE onSMS = 1"); |
| 1271 | |
| 1272 | if($smsQuery) { |
| 1273 | $result = $smsQuery->fetch(PDO::FETCH_ASSOC); |
| 1274 | $totalSMS += (int)$result['smsCount']; |
| 1275 | } |
| 1276 | $textQuery = $db->query("SELECT COUNT(*) as textCount FROM buyQueue WHERE textMe = 1"); |
| 1277 | |
| 1278 | if($textQuery) { |
| 1279 | $result = $textQuery->fetch(PDO::FETCH_ASSOC); |
| 1280 | $totalTexts += (int)$result['textCount']; |
| 1281 | } |
| 1282 | $emailQuery = $db->query("SELECT COUNT(*) as emailCount FROM customers WHERE onEmail = 1"); |
| 1283 | |
| 1284 | if($emailQuery) { |
| 1285 | $result = $emailQuery->fetch(PDO::FETCH_ASSOC); |
| 1286 | $totalEmails += (int)$result['emailCount']; |
| 1287 | } |
| 1288 | } |
| 1289 | |
| 1290 | return array( |
| 1291 | 'totalBuys' => $totalBuys, |
| 1292 | 'totalSMS' => $totalSMS, |
| 1293 | 'totalEmails' => $totalEmails, |
| 1294 | 'totalTexts' => $totalTexts, |
| 1295 | ); |
| 1296 | } |
| 1297 | function getDashboardStats($typeNum) { |
| 1298 | $dS = new DashboardStats($typeNum); |
| 1299 | $dateStart = new DateTime('first day of this month'); |
| 1300 | $dateStart = getDateRange($dateStart->format("Y-m-d H:i:s")); |
| 1301 | $dateEnd = getCurrentDateRange(); |
| 1302 | $log = new KLogger($_ENV['LOG_DIR']."dev_log2.txt",KLogger::DEBUG); |
| 1303 | $log->LogDebug("Model: ".$dateStart['dateStart']->format("Y-m-d H:i:s")." - ".$dateEnd['dateEnd']->format("Y-m-d H:i:s")); |
| 1304 | $dS->setDates($dateStart['dateStart']->format("Y-m-d H:i:s"), $dateEnd['dateEnd']->format("Y-m-d H:i:s")); |
| 1305 | $dS->getTopStats(); |
| 1306 | return $dS; |
| 1307 | } |
| 1308 | function getDashboardBusyTimes($typeNum) |
| 1309 | { |
| 1310 | $dateEnd = getCurrentDateRange(); |
| 1311 | $dateStart = getCurrentDateRange(); |
| 1312 | $dateStart['dateStart']->sub(new DateInterval("P29D")); |
| 1313 | $dS = new DashboardStats($typeNum); |
| 1314 | $dS->setDates($dateStart['dateStart']->format("Y-m-d H:i:s"), $dateEnd['dateEnd']->format("Y-m-d H:i:s")); |
| 1315 | return $dS->getBusyTimesArray(); |
| 1316 | |
| 1317 | } |
| 1318 | function sendDemoEmail($html) { |
| 1319 | $mail = new PHPMailer; |
| 1320 | $log = new KLogger($_ENV['LOG_DIR']."dev_log.txt",KLogger::DEBUG); |
| 1321 | $mail->setFrom('admin@buyerkiosk.com', 'BuyerKiosk'); |
| 1322 | $mail->addAddress('demo@buyerkiosk.com', 'Demo'); |
| 1323 | $mail->isHTML(true); |
| 1324 | $mail->Subject = 'New Demo Request'; |
| 1325 | $mail->Body = $html; |
| 1326 | if($mail->send()) { |
| 1327 | return true; |
| 1328 | } else { |
| 1329 | $log->LogError($mail->ErrorInfo); |
| 1330 | return false; |
| 1331 | } |
| 1332 | } |
| 1333 | function sendDailyEmail($html, $email, Store $store, $fileLocation) { |
| 1334 | $mail = new PHPMailer; |
| 1335 | $mail->isSMTP(); // Set mailer to use SMTP |
| 1336 | $mail->Host = 'smtp.sendgrid.net'; // Specify main and backup SMTP servers |
| 1337 | $mail->SMTPAuth = true; // Enable SMTP authentication |
| 1338 | $mail->Username = 'apikey'; // SMTP username |
| 1339 | $mail->Password = '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'; // SMTP password |
| 1340 | $mail->SMTPSecure = 'ssl'; // Enable TLS encryption, `ssl` also accepted |
| 1341 | $mail->Port = 465; |
| 1342 | $log = new KLogger($_ENV['LOG_DIR']."dev_log.txt",KLogger::DEBUG); |
| 1343 | $mail->setFrom('admin@buyerkiosk.com', 'BuyerKiosk'); |
| 1344 | $mail->addAddress($email); |
| 1345 | $mail->isHTML(true); |
| 1346 | $mail->Subject = 'BuyerKiosk Daily Summary - '.$store->getStoreNum(); |
| 1347 | $mail->Body = $html; |
| 1348 | $mail->addAttachment($fileLocation,"s-file.txt"); |
| 1349 | if($mail->send()) { |
| 1350 | echo "Sent"; |
| 1351 | return true; |
| 1352 | } else { |
| 1353 | echo "Not Sent"; |
| 1354 | $log->LogError($mail->ErrorInfo); |
| 1355 | return false; |
| 1356 | } |
| 1357 | } |
| 1358 | function sendRequestEmail($html, $email, $name) { |
| 1359 | $mail = new PHPMailer; |
| 1360 | $log = new KLogger($_ENV['LOG_DIR']."dev_log.txt",KLogger::DEBUG); |
| 1361 | $mail->setFrom('demo@buyerkiosk.com'); |
| 1362 | $mail->addAddress($email); |
| 1363 | $mail->isHTML(true); |
| 1364 | $mail->Subject = 'Your BuyerKiosk Demo Request Has Been Received'; |
| 1365 | $mail->Body = $html; |
| 1366 | if($mail->send()) { |
| 1367 | return true; |
| 1368 | } else { |
| 1369 | $log->LogError($mail->ErrorInfo); |
| 1370 | return false; |
| 1371 | } |
| 1372 | } |
| 1373 | function getEmployeeInfo(Store $store, $employeeID) { |
| 1374 | $db = dbConnectByName($store->getDbName()); |
| 1375 | $infoQuery = $db->query("SELECT * FROM employees WHERE employeeID = ".$employeeID); |
| 1376 | $employeeArray = []; |
| 1377 | |
| 1378 | if($infoQuery) { |
| 1379 | $row = $infoQuery->fetch(PDO::FETCH_ASSOC); |
| 1380 | $buyq = $db->query("SELECT MIN(date) as firstBuy, MAX(date) as lastBuy FROM statsEmployeeDaily WHERE employeeID = ".$employeeID); |
| 1381 | $buy = $buyq->fetch(PDO::FETCH_ASSOC); |
| 1382 | |
| 1383 | $firstBuy = new DateTime($buy['firstBuy'], new DateTimeZone('UTC')); |
| 1384 | $firstBuy->setTimezone(new DateTimeZone($store->getTimeZone())); |
| 1385 | $lastBuy = new DateTime($buy['lastBuy'], new DateTimeZone('UTC')); |
| 1386 | $lastBuy->setTimezone(new DateTimeZone($store->getTimeZone())); |
| 1387 | $employeeArray['name'] = $row['employeeFirstName']." ".$row['employeeLastName']; |
| 1388 | $employeeArray['firstBuy'] = $firstBuy->format("M jS Y"); |
| 1389 | $employeeArray['lastBuy'] = $lastBuy->format("M jS Y"); |
| 1390 | $employeeArray['id'] = $employeeID; |
| 1391 | } |
| 1392 | return $employeeArray; |
| 1393 | } |
| 1394 | function getEmployeeNameArray(Store $store) { |
| 1395 | $db = dbConnectByName($store->getDbName()); |
| 1396 | $empQuery = $db->query("SELECT employeeID, employeeFirstName as firstName, employeeLastName as lastName FROM employees WHERE 1"); |
| 1397 | $employees = []; |
| 1398 | |
| 1399 | while($row = $empQuery->fetch(PDO::FETCH_ASSOC)) { |
| 1400 | $employees[$row['employeeID']] = $row['firstName']." ".$row['lastName']; |
| 1401 | } |
| 1402 | return $employees; |
| 1403 | } |
| 1404 | function expireSlides() { |
| 1405 | $stores = getAllStoresData(); |
| 1406 | |
| 1407 | foreach ($stores as $store) { |
| 1408 | |
| 1409 | $db = dbConnectByName($store->getDbName()); |
| 1410 | $query = $db->query("SELECT * FROM dsLoop WHERE expireDate <= CURDATE()"); |
| 1411 | $row = $query->fetch(PDO::FETCH_ASSOC); |
| 1412 | $db->query("DELETE FROM dsLoop WHERE id = ".$row['id']); |
| 1413 | } |
| 1414 | |
| 1415 | } |
| 1416 | function getStoreTypeName(Store $store) { |
| 1417 | global $db_name; |
| 1418 | $storeType = $store->getStoreType(); |
| 1419 | $db = dbConnectByName($db_name); |
| 1420 | $query = $db->query("SELECT * FROM storetypes WHERE type = ".$storeType); |
| 1421 | $storeTypeName = $query->fetch(PDO::FETCH_ASSOC); |
| 1422 | |
| 1423 | return $storeTypeName['name']; |
| 1424 | } |
| 1425 | /* |
| 1426 | function checkBuyQueueTextAlerts(Store $store) { |
| 1427 | $n = $db->query("SELECT * FROM textAlerts WHERE buyQueueAlerts = 1"); |
| 1428 | while($row = $n->fetch(PDO::FETCH_ASSOC)) { |
| 1429 | if(strtotime(result['textTimeStamp'])) |
| 1430 | } |
| 1431 | }*/ |
| 1432 | function sendMassTwilioTxt($message) { |
| 1433 | include("/home/ryanvv/userfrosting/lib/twilio/Services/Twilio.php"); |
| 1434 | $log = new KLogger($_ENV['LOG_DIR']."twilio_log.txt", KLogger::DEBUG); |
| 1435 | $AccountSid = "ACa0d8f40468057e6bc520846fba454f4c"; |
| 1436 | $AuthToken = "af23ab5c293dbff72fe9308a701ad92e"; |
| 1437 | |
| 1438 | global $contactDBName; |
| 1439 | $db = dbConnectByName($contactDBName); |
| 1440 | $query = $db->query("SELECT * FROM numbers WHERE 1"); |
| 1441 | $client = new Services_Twilio($AccountSid, $AuthToken); |
| 1442 | |
| 1443 | while($row = $query->fetch(PDO::FETCH_ASSOC)) { |
| 1444 | try { |
| 1445 | $message2 = $client->account->messages->create(array( |
| 1446 | "From" => '+19723474696', |
| 1447 | "To" => "+1".$row['number'], |
| 1448 | "Body" => $message, |
| 1449 | )); |
| 1450 | } catch (Services_Twilio_RestException $e) { |
| 1451 | $log->LogError($e->getMessage()); |
| 1452 | } |
| 1453 | } |
| 1454 | |
| 1455 | |
| 1456 | } |
| 1457 | function getStoreProcessAverages(Store $store, $dateStart, $dateEnd) { |
| 1458 | $db = dbConnectByName($store->getDbName()); |
| 1459 | $statsArray = array(); |
| 1460 | $query = $db->prepare("SELECT (SELECT ROUND(AVG(UNIX_TIMESTAMP(timeCompleted) - UNIX_TIMESTAMP(timeStarted)),1) as processTime FROM buyQueue WHERE timeCompleted > timeStarted AND isProcessed > 0 AND timeEntered BETWEEN :dateStart AND :dateEnd AND (UNIX_TIMESTAMP(timeCompleted) - UNIX_TIMESTAMP(timeStarted) BETWEEN :minSeconds AND :maxSeconds)) as processTime, (SELECT ROUND(AVG((UNIX_TIMESTAMP(timeCompleted) - UNIX_TIMESTAMP(timeStarted))/IF(remainingContainers>0,remainingContainers,numContainers)),1) as ptc FROM buyQueue WHERE timeCompleted > timeStarted AND isProcessed > 0 AND timeEntered BETWEEN :dateStart AND :dateEnd AND (UNIX_TIMESTAMP(timeCompleted) - UNIX_TIMESTAMP(timeStarted) BETWEEN :minSeconds AND :maxSeconds)) as ptc, (SELECT COUNT(d) as totalDays FROM (SELECT DATE(timeEntered) as d FROM buyQueue WHERE timeEntered BETWEEN :dateStart AND :dateEnd AND isProcessed = 1 AND (UNIX_TIMESTAMP(timeCompleted) - UNIX_TIMESTAMP(timeStarted) BETWEEN :minSeconds AND :maxSeconds) GROUP BY d)as H) as totalDays, (SELECT SUM(totalContainers) as sumContainers FROM (SELECT SUM(IF(remainingContainers > 0, remainingContainers, numContainers)) as totalContainers,DATE(timeEntered) as d FROM buyQueue WHERE timeEntered BETWEEN :dateStart AND :dateEnd AND isProcessed = 1 AND (UNIX_TIMESTAMP(timeCompleted) - UNIX_TIMESTAMP(timeStarted) BETWEEN :minSeconds AND :maxSeconds) GROUP BY d)as F) as totalContainers, (SELECT SUM(totalBuys) as sumBuys FROM (SELECT COUNT(buyID) as totalBuys, DATE(timeEntered) as d FROM buyQueue WHERE timeEntered BETWEEN :dateStart AND :dateEnd AND isProcessed = 1 AND (UNIX_TIMESTAMP(timeCompleted) - UNIX_TIMESTAMP(timeStarted) BETWEEN :minSeconds AND :maxSeconds) GROUP BY d)as G) as totalBuys"); |
| 1461 | $result = $query->execute(array(':dateStart' => $dateStart, ':dateEnd'=> $dateEnd, ":minSeconds"=>$store->getStatMinSeconds(),":maxSeconds"=>$store->getStatMaxSeconds())); |
| 1462 | if($result) { |
| 1463 | $row = $query->fetch(PDO::FETCH_ASSOC); |
| 1464 | $statsArray = array( |
| 1465 | 'sortTime' => isset($row['sortTime']) ? $row['sortTime'] : null, |
| 1466 | 'processTime' => $row['processTime'], |
| 1467 | 'ptc' => $row['ptc'], |
| 1468 | 'totalDays' => $row['totalDays'], |
| 1469 | 'totalContainers'=>$row['totalContainers'], |
| 1470 | 'totalBuys'=>$row['totalBuys'] |
| 1471 | ); |
| 1472 | } |
| 1473 | return $statsArray; |
| 1474 | |
| 1475 | } |
| 1476 | function getStoreSortAverages(Store $store, $dateStart, $dateEnd) { |
| 1477 | $db = dbConnectByName($store->getDbName()); |
| 1478 | $statsArray = array(); |
| 1479 | $query = $db->prepare("SELECT (SELECT ROUND(AVG(UNIX_TIMESTAMP(sortCompleted) - UNIX_TIMESTAMP(sortStarted)),1) as sortTime FROM buyQueue WHERE sortCompleted > sortStarted AND isProcessed = 1 AND timeEntered BETWEEN :dateStart AND :dateEnd AND (UNIX_TIMESTAMP(sortCompleted) - UNIX_TIMESTAMP(sortStarted) BETWEEN :minSeconds AND :maxSeconds)) as sortTime, |
| 1480 | |
| 1481 | (SELECT ROUND(AVG((UNIX_TIMESTAMP(sortCompleted) - UNIX_TIMESTAMP(sortStarted))/numContainers),1) FROM buyQueue WHERE sortCompleted > sortStarted AND isProcessed = 1 AND timeEntered BETWEEN :dateStart AND :dateEnd AND (UNIX_TIMESTAMP(sortCompleted) - UNIX_TIMESTAMP(sortStarted) BETWEEN :minSeconds AND :maxSeconds)) as stc, |
| 1482 | |
| 1483 | (SELECT SUM(numContainers) FROM buyQueue WHERE sortCompleted > sortStarted AND isProcessed = 1 AND timeEntered BETWEEN :dateStart AND :dateEnd AND (UNIX_TIMESTAMP(sortCompleted) - UNIX_TIMESTAMP(sortStarted) BETWEEN :minSeconds AND :maxSeconds)) as totalContainers, |
| 1484 | |
| 1485 | (SELECT COUNT(buyID) FROM buyQueue WHERE sortCompleted > sortStarted AND isProcessed = 1 AND timeEntered BETWEEN :dateStart AND :dateEnd AND (UNIX_TIMESTAMP(sortCompleted) - UNIX_TIMESTAMP(sortStarted)BETWEEN :minSeconds AND :maxSeconds)) as totalBuys, |
| 1486 | |
| 1487 | (SELECT COUNT(d) as numDays FROM (SELECT DATE(timeEntered) as d FROM buyQueue WHERE sortCompleted > sortStarted AND isProcessed = 1 AND timeEntered BETWEEN :dateStart AND :dateEnd AND (UNIX_TIMESTAMP(sortCompleted) - UNIX_TIMESTAMP(sortStarted) BETWEEN :minSeconds AND :maxSeconds) GROUP BY d) as H) as numDays"); |
| 1488 | $result = $query->execute(array(':dateStart' => $dateStart, ':dateEnd'=> $dateEnd, ":minSeconds"=>$store->getStatMinSeconds(),":maxSeconds"=>$store->getStatMaxSeconds())); |
| 1489 | if($result) { |
| 1490 | $row = $query->fetch(PDO::FETCH_ASSOC); |
| 1491 | $statsArray = array( |
| 1492 | 'sortTime' => $row['sortTime'], |
| 1493 | 'stc' => $row['stc'], |
| 1494 | 'totalContainers' => $row['totalContainers'], |
| 1495 | 'totalBuys' => $row['totalBuys'], |
| 1496 | 'numDays' => $row['numDays'] |
| 1497 | |
| 1498 | ); |
| 1499 | } |
| 1500 | return $statsArray; |
| 1501 | |
| 1502 | } |
| 1503 | function compressLogFiles() { |
| 1504 | $log = new KLogger($_ENV['LOG_DIR']."dev_log2.txt",KLogger::DEBUG); |
| 1505 | global $home_dir; |
| 1506 | $date = getCurrentDateRange(); |
| 1507 | |
| 1508 | $file = $home_dir."logs/dev_log.txt"; |
| 1509 | $dest = $home_dir."logs/dev_log/".$date['dateStart']->format("Y_m_d").'.gz'; |
| 1510 | $log->LogDebug($file); |
| 1511 | $log->LogDebug($dest); |
| 1512 | |
| 1513 | $result = gzCompressFile($file,$dest); |
| 1514 | if(!$result) { |
| 1515 | $log->LogDebug('Error'); |
| 1516 | } else { |
| 1517 | $log->LogDebug($result); |
| 1518 | } |
| 1519 | |
| 1520 | |
| 1521 | |
| 1522 | } |
| 1523 | function getLoyaltyCustomerByPhone($phone, $storeGroup , $extraDigits = false) { |
| 1524 | //Remove the +1 at the beginning of the number |
| 1525 | if($extraDigits) { |
| 1526 | $phone = substr($phone, 2,11); |
| 1527 | } |
| 1528 | global $db_name; |
| 1529 | $db = dbConnectByName($db_name); |
| 1530 | $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); |
| 1531 | try { |
| 1532 | $stmt = $db->prepare("SELECT * FROM loyaltyCustomers WHERE phone = :phone AND storeGroup = :storeGroup"); |
| 1533 | $stmt->bindParam(":phone", $phone); |
| 1534 | $stmt->bindParam(":storeGroup", $storeGroup); |
| 1535 | if($stmt->execute()) { |
| 1536 | $row = $stmt->fetch(PDO::FETCH_ASSOC); |
| 1537 | if(isset($row['id'])) { |
| 1538 | return $customer = new LoyaltyCustomer($row['id']); |
| 1539 | } else { |
| 1540 | return null; |
| 1541 | } |
| 1542 | } |
| 1543 | } catch (PDOException $e) { |
| 1544 | error_log($e->getMessage()); |
| 1545 | return null; |
| 1546 | } |
| 1547 | return null; |
| 1548 | } |
| 1549 | function obfuscateCustomerData($typeNum) { |
| 1550 | $storeController = new \BuyerKiosk\StoreController($typeNum); |
| 1551 | $store = $storeController->getStore(); |
| 1552 | if($store->getDev()) { |
| 1553 | $db = dbConnectByName($store->getDbName()); |
| 1554 | $stmt = $db->prepare("SELECT * FROM customers"); |
| 1555 | $stmt->execute(); |
| 1556 | while($row = $stmt->fetch(PDO::FETCH_ASSOC)) { |
| 1557 | $update = $db->prepare("UPDATE customers SET email = :email, phone = :phone, driversLicense = :driversLicense, address = :address WHERE customerID = :customerID"); |
| 1558 | $driversLicense = obfuscateDigits($row['driversLicense']); |
| 1559 | $phone = obfuscateDigits($row['phone']); |
| 1560 | $email = obfuscateEmail($row['email']); |
| 1561 | $customerID = $row['customerID']; |
| 1562 | $address = "101 Main Street"; |
| 1563 | $update->bindParam(":phone", $phone); |
| 1564 | $update->bindParam(":driversLicense", $driversLicense); |
| 1565 | $update->bindParam(":address", $address); |
| 1566 | $update->bindParam(":customerID", $customerID); |
| 1567 | $update->bindParam(":email", $email); |
| 1568 | $update->execute(); |
| 1569 | } |
| 1570 | } |
| 1571 | } |
| 1572 | function obfuscateDigits($num) { |
| 1573 | $array = array ( |
| 1574 | "0" => "9", |
| 1575 | "1" => "3", |
| 1576 | "2" => "5", |
| 1577 | "3" => "7", |
| 1578 | "4" => "0", |
| 1579 | "5" => "2", |
| 1580 | "6" => '8', |
| 1581 | "7" => '3', |
| 1582 | "8" => '1', |
| 1583 | "9" => '4' |
| 1584 | ); |
| 1585 | foreach($array as $number => $val) { |
| 1586 | $num = str_replace($number, $val, $num); |
| 1587 | } |
| 1588 | return $num; |
| 1589 | } |
| 1590 | function obfuscateEmail($email) { |
| 1591 | return 'xxx'. substr($email, 4); |
| 1592 | |
| 1593 | } |
| 1594 | function gen_uuid($len=8) { |
| 1595 | |
| 1596 | $hex = md5("C9uGiVUbdaiukeRaZH9E" . uniqid("", true)); |
| 1597 | |
| 1598 | $pack = pack('H*', $hex); |
| 1599 | $tmp = base64_encode($pack); |
| 1600 | |
| 1601 | $uid = preg_replace("#(*UTF8)[^A-Za-z0-9]#", "", $tmp); |
| 1602 | |
| 1603 | $len = max(4, min(128, $len)); |
| 1604 | |
| 1605 | while (strlen($uid) < $len) |
| 1606 | $uid .= gen_uuid(22); |
| 1607 | |
| 1608 | return substr($uid, 0, $len); |
| 1609 | } |
| 1610 | function filterMessage($message, $origin, $vars = null, ?LoyaltyCoupon $coupon = null) { |
| 1611 | $store = new Store(); |
| 1612 | $store->createStore($origin); |
| 1613 | $customer = new LoyaltyCustomer(52); |
| 1614 | |
| 1615 | if(!isset($vars)) { |
| 1616 | $vars = array ( |
| 1617 | "%company%" => $store->getCompanyName(), |
| 1618 | "%store%" => $store->getCity(), |
| 1619 | "%store_number%" => $store->getStoreNum(), |
| 1620 | "%customer%" => $customer->getFirstName(), |
| 1621 | "%first_name%" => $customer->getFirstName(), |
| 1622 | "%last_name%" => $customer->getLastName(), |
| 1623 | "%birthday%" => $customer->getBirthday(), |
| 1624 | "%new_line%" => "\n" |
| 1625 | ); |
| 1626 | } |
| 1627 | if(isset($coupon)) { |
| 1628 | $uuid = $coupon->createUUID($customer->getLoyaltyID()); |
| 1629 | $couponURL = serverName."/c/".$uuid; |
| 1630 | $expireDate = $coupon->getExpireDate(); |
| 1631 | if(isset($expireDate)) { |
| 1632 | //Get the expiration date of coupon |
| 1633 | $expireDate = new DateTime($coupon->getExpireDate(), new DateTimeZone('utc')); |
| 1634 | $expireDate->setTimezone(new DateTimeZone($store->getTimeZone())); |
| 1635 | $expireDate = $expireDate->format("m-d-Y"); |
| 1636 | } else { |
| 1637 | $expireDate = new DateTime('now'); |
| 1638 | $expireDate->add(new DateInterval("P".$coupon->getExpireDays()."D")); |
| 1639 | $expireDate = $expireDate->format("m-d-Y"); |
| 1640 | } |
| 1641 | |
| 1642 | $vars["%coupon_url%"] = $couponURL; |
| 1643 | $vars["%coupon_expire%"] = $expireDate; |
| 1644 | } |
| 1645 | |
| 1646 | foreach ($vars as $key => $value) { |
| 1647 | $message = str_replace($key, $value, $message); |
| 1648 | } |
| 1649 | return $message; |
| 1650 | } |
| 1651 | function similarity($str1, $str2) { |
| 1652 | $len1 = strlen($str1); |
| 1653 | $len2 = strlen($str2); |
| 1654 | |
| 1655 | $max = max($len1, $len2); |
| 1656 | $similarity = $i = $j = 0; |
| 1657 | |
| 1658 | while (($i < $len1) && isset($str2[$j])) { |
| 1659 | if ($str1[$i] == $str2[$j]) { |
| 1660 | $similarity++; |
| 1661 | $i++; |
| 1662 | $j++; |
| 1663 | } elseif ($len1 < $len2) { |
| 1664 | $len1++; |
| 1665 | $j++; |
| 1666 | } elseif ($len1 > $len2) { |
| 1667 | $i++; |
| 1668 | $len1--; |
| 1669 | } else { |
| 1670 | $i++; |
| 1671 | $j++; |
| 1672 | } |
| 1673 | } |
| 1674 | |
| 1675 | return round($similarity / $max, 2); |
| 1676 | } |
| 1677 | function isCurrency($number) |
| 1678 | { |
| 1679 | return preg_match("/\b\d{1,3}(?:,?\d{3})*(?:\.\d{2})?\b/", $number); |
| 1680 | } |
| 1681 | function generateRemazeKey(Store $store) { |
| 1682 | return hash_hmac('sha256', $store->getTypeNum() . ':' . $store->getTypeNum()."@buyerkiosk.com", '237096c8032433965675bc4dc3c3411390221503ec67ab3d332e0dcdebb68676'); |
| 1683 | } |
| 1684 | function validateAPIKey($key, $typeNum) { |
| 1685 | $store = new Store(); |
| 1686 | //Remove any non alpha-numeric characters. This will cause the character count to fail |
| 1687 | $key = preg_replace("/[^A-Za-z0-9]/", "", $key); |
| 1688 | //If we do not have 60 characters we know this is a bad key. |
| 1689 | if(strlen($key) !== 60) { |
| 1690 | return null; |
| 1691 | } |
| 1692 | //Make sure this store exists. |
| 1693 | if(!$store->createStore($typeNum)) { |
| 1694 | return null; |
| 1695 | } |
| 1696 | //Make sire this store is active |
| 1697 | if(!(int)$store->getActive()) { |
| 1698 | return null; |
| 1699 | } |
| 1700 | $storeAPI = $store->getApiKey(); |
| 1701 | //Check if the two strings are the same |
| 1702 | if($key !== $storeAPI) { |
| 1703 | return null; |
| 1704 | } |
| 1705 | return $store; |
| 1706 | } |
| 1707 | function isSecure() { |
| 1708 | return |
| 1709 | (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'); |
| 1710 | } |
| 1711 | function getAllLoyaltyCustomersByPhone($phone, $extraDigits = false) { |
| 1712 | //Remove the +1 at the beginning of the number |
| 1713 | if($extraDigits) { |
| 1714 | $phone = substr($phone, 1,10); |
| 1715 | } |
| 1716 | global $db_name; |
| 1717 | $db = dbConnectByName($db_name); |
| 1718 | $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); |
| 1719 | try { |
| 1720 | $stmt = $db->prepare("SELECT * FROM loyaltyCustomers WHERE phone = :phone ORDER BY lastTextTimestamp DESC"); |
| 1721 | $stmt->bindParam(":phone", $phone); |
| 1722 | if($stmt->execute()) { |
| 1723 | $customerArray = []; |
| 1724 | while($row = $stmt->fetch(PDO::FETCH_ASSOC)) { |
| 1725 | $customerArray[] = new LoyaltyCustomer($row['id']); |
| 1726 | return $customerArray; |
| 1727 | } |
| 1728 | return null; |
| 1729 | } |
| 1730 | } catch (PDOException $e) { |
| 1731 | error_log($e->getMessage()); |
| 1732 | return null; |
| 1733 | } |
| 1734 | return null; |
| 1735 | } |
| 1736 | function sendSMStoNumber($number,$shortName = null,$message=null) { |
| 1737 | $log = new KLogger($_ENV['LOG_DIR']."nexmo.log", KLogger::DEBUG); |
| 1738 | $log->LogDebug("[".$number."] - ".$shortName." - ".$message); |
| 1739 | if($shortName !== null) { |
| 1740 | $message = new LoyaltyMessage(null, $shortName); |
| 1741 | if(strlen($message->getMessage()) > 0) { |
| 1742 | $text = $message->getMessage(); |
| 1743 | } |
| 1744 | } elseif($message !== null) { |
| 1745 | $text = $message; |
| 1746 | } else { |
| 1747 | return null; |
| 1748 | } |
| 1749 | |
| 1750 | $postfields = array( |
| 1751 | 'api_key'=>'67e71b29', |
| 1752 | 'api_secret'=>'47f48c40b1586e71', |
| 1753 | 'from' => '91904', |
| 1754 | 'text' => $text, |
| 1755 | 'to' => "+1".$number, |
| 1756 | ); |
| 1757 | $ch = curl_init(); |
| 1758 | curl_setopt($ch, CURLOPT_URL, 'https://rest.nexmo.com/sms/json'); |
| 1759 | curl_setopt($ch, CURLOPT_POST, 1); |
| 1760 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); |
| 1761 | curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($postfields)); |
| 1762 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1); |
| 1763 | $result = curl_exec($ch); |
| 1764 | $log->LogDebug(print_r($result)); |
| 1765 | $response = json_decode($result); |
| 1766 | $log->LogDebug(print_r($response)); |
| 1767 | curl_close($ch); |
| 1768 | return $response; |
| 1769 | } |
| 1770 | function convertUTCToLocalTimeStamp($timezone, $timeStampString) { |
| 1771 | if($timeStampString == "0000-00-00 00:00:00") { |
| 1772 | return $timeStampString; |
| 1773 | } |
| 1774 | $output = new DateTime($timeStampString, new DateTimeZone("UTC")); |
| 1775 | return $output->setTimezone(new DateTimeZone($timezone))->format("Y-m-d H:i:s"); |
| 1776 | } |
| 1777 | |
| 1778 | function getSurveyMessages(Store $store) { |
| 1779 | global $db_name; |
| 1780 | $db = dbConnectByName($db_name); |
| 1781 | $stmt = $db->query("SELECT surveyThankYou, surveyMinRatingForReview, surveyReviewLink, surveyReviewText, buySurvey, surveyMinRatingForReview, surveySMSText FROM stores WHERE typeNum = '".$store->getTypeNum()."'"); |
| 1782 | $row = $stmt->fetch(PDO::FETCH_ASSOC); |
| 1783 | $result['thankYou'] = $row['surveyThankYou']; |
| 1784 | $result['minRating'] = $row['surveyMinRatingForReview']; |
| 1785 | $result['reviewText'] = $row['surveyReviewText']; |
| 1786 | $result['buySurvey'] = $row['buySurvey']; |
| 1787 | $result['smsText'] = $row['surveySMSText']; |
| 1788 | return $result; |
| 1789 | } |
| 1790 | function getSurveyLinks(Store $store) { |
| 1791 | $storeDB = dbConnectByName($store->getDbName()); |
| 1792 | $stmt = $storeDB->query("SELECT * FROM surveyLinks WHERE active = 1"); |
| 1793 | $row = $stmt->fetch(PDO::FETCH_ASSOC); |
| 1794 | return $row; |
| 1795 | } |
| 1796 | function getRandomSurveyLink(Store $store) { |
| 1797 | $storeDB = dbConnectByName($store->getDbName()); |
| 1798 | try { |
| 1799 | $stmt = $storeDB->query("SELECT * FROM surveyLinks WHERE active = 1 ORDER BY RAND() LIMIT 1"); |
| 1800 | $row = $stmt->fetch(PDO::FETCH_ASSOC); |
| 1801 | return $row; |
| 1802 | } catch (PDOException $e) { |
| 1803 | error_log("surveyLinks table not found in database: " . $store->getDbName()); |
| 1804 | return false; |
| 1805 | } |
| 1806 | } |
| 1807 | |
| 1808 | function getActiveStoreCount() { |
| 1809 | global $db_name; |
| 1810 | $db = dbConnectByName($db_name); |
| 1811 | $stmt = $db->query("SELECT COUNT(DISTINCT sb.origin) as active_count |
| 1812 | FROM kiosk_buys.systemBuys sb |
| 1813 | WHERE sb.timeStamp >= DATE_SUB(CURDATE(), INTERVAL 7 DAY);"); |
| 1814 | $row = $stmt->fetch(PDO::FETCH_ASSOC); |
| 1815 | return (int)$row['active_count']; |
| 1816 | } |
| 1817 | |
| 1818 | function getActiveStores() { |
| 1819 | global $db_name; |
| 1820 | $db = dbConnectByName($db_name); |
| 1821 | $stmt = $db->query("SELECT s.typeNum as origin, |
| 1822 | s.city, |
| 1823 | s.state, |
| 1824 | s.storeType, |
| 1825 | COUNT(*) as buy_count |
| 1826 | FROM kiosk_buys.systemBuys sb |
| 1827 | STRAIGHT_JOIN kiosk_buykiosk.stores s ON sb.origin = s.typeNum |
| 1828 | WHERE sb.timeStamp >= DATE_SUB(CURDATE(), INTERVAL 7 DAY) |
| 1829 | GROUP BY s.typeNum, s.city, s.state, s.storeType |
| 1830 | ORDER BY buy_count DESC;"); |
| 1831 | $activeStores = $stmt->fetchAll(PDO::FETCH_ASSOC); |
| 1832 | |
| 1833 | foreach ($activeStores as &$store) { |
| 1834 | $storeObj = new Store(); |
| 1835 | $storeObj->setStoreType($store['storeType']); |
| 1836 | $store['typeNum'] = $store['origin']; |
| 1837 | $store['storeTypeName'] = getStoreTypeName($storeObj); |
| 1838 | } |
| 1839 | |
| 1840 | return $activeStores; |
| 1841 | } |
| 1842 | |
| 1843 | function getInactiveStores() { |
| 1844 | $allStores = getAllStoresData(1,0); |
| 1845 | $activeStores = getActiveStores(); |
| 1846 | $activeOrigins = array_column($activeStores, 'origin'); |
| 1847 | $inactiveStores = array_filter($allStores, function($store) use ($activeOrigins) { |
| 1848 | return !in_array($store->typeNum, $activeOrigins); |
| 1849 | }); |
| 1850 | |
| 1851 | $inactiveStoresWithNames = array_map(function($store) { |
| 1852 | return [ |
| 1853 | 'typeNum' => $store->typeNum, |
| 1854 | 'city' => $store->city, |
| 1855 | 'state' => $store->state, |
| 1856 | 'storeType' => $store->storeType, |
| 1857 | 'storeTypeName' => getStoreTypeName($store) |
| 1858 | ]; |
| 1859 | }, array_values($inactiveStores)); |
| 1860 | |
| 1861 | return $inactiveStoresWithNames; |
| 1862 | } |
| 1863 | function getStoreStatus($typeNum) { |
| 1864 | $storeController = new \BuyerKiosk\BuyerKiosk\Controllers\StoreController($typeNum); |
| 1865 | $store = $storeController->getStore(); |
| 1866 | if($store->getActive() == 0) { |
| 1867 | $log = new KLogger($_ENV['LOG_DIR']."inactive.log", KLogger::DEBUG); |
| 1868 | $log->LogDebug("Inactive Store Accessed: ".$typeNum); |
| 1869 | } |
| 1870 | return (int)$store->getActive(); |
| 1871 | } |
| 1872 | |
| 1873 | function getBKStats() { |
| 1874 | global $buydb_name; |
| 1875 | $db = dbConnectByName($buydb_name); |
| 1876 | $result['totalBuys'] = 0; |
| 1877 | $result['totalTexts'] = 0; |
| 1878 | $result['totalCustomers'] = 0; |
| 1879 | $result['totalEmails'] = 0; |
| 1880 | $stores = getAllStoresData(0,0); |
| 1881 | foreach($stores as $store) { |
| 1882 | $storeDB = dbConnectByName($store->getDbName()); |
| 1883 | $query1 = "show table status like 'texts'"; |
| 1884 | $stmt = $storeDB->query($query1); |
| 1885 | $row = $stmt->fetch(PDO::FETCH_ASSOC); |
| 1886 | $result['totalTexts'] += $row['Rows']; |
| 1887 | $query2 = "show table status like 'customers'"; |
| 1888 | $stmt = $storeDB->query($query2); |
| 1889 | $row = $stmt->fetch(PDO::FETCH_ASSOC); |
| 1890 | $result['totalCustomers'] += $row['Rows']; |
| 1891 | $query3 = "SELECT count(*) FROM customers WHERE onEmail = 1"; |
| 1892 | $stmt = $storeDB->query($query3); |
| 1893 | $row = $stmt->fetch(PDO::FETCH_ASSOC); |
| 1894 | $result['totalEmails'] += $row['count(*)']; |
| 1895 | $query4 = "show table status like 'buyQueue'"; |
| 1896 | $stmt = $storeDB->query($query4); |
| 1897 | $row = $stmt->fetch(PDO::FETCH_ASSOC); |
| 1898 | $result['totalBuys'] += $row['Rows']; |
| 1899 | } |
| 1900 | return $result; |
| 1901 | } |
| 1902 | function sendSurverySMS($buyID, $typeNum) { |
| 1903 | $log = new KLogger($_ENV['LOG_DIR']."survey.log", KLogger::DEBUG); |
| 1904 | $log->LogDebug("New Survey for ".$typeNum); |
| 1905 | |
| 1906 | global $buydb_name; |
| 1907 | $db = dbConnectByName($buydb_name); |
| 1908 | $stmt = $db->prepare("SELECT customerID, uuid FROM systemBuys WHERE buyID = :buyID AND origin = :typeNum"); |
| 1909 | $stmt->bindValue(":buyID", $buyID); |
| 1910 | $stmt->bindValue(":typeNum", $typeNum); |
| 1911 | |
| 1912 | if($stmt->execute()) { |
| 1913 | $log->LogDebug("BuyID Check Executed"); |
| 1914 | if($row = $stmt->fetch(PDO::FETCH_ASSOC)) { |
| 1915 | $log->LogDebug("BuyID Check Passed"); |
| 1916 | $storeController = new \BuyerKiosk\StoreController($typeNum); |
| 1917 | $store = $storeController->getStore(); |
| 1918 | $storeDB = dbConnectByName($store->getDbName()); |
| 1919 | |
| 1920 | // Check to see if customer consented to text message |
| 1921 | $check = $storeDB->prepare("SELECT textMe FROM buyQueue WHERE buyID = :buyID"); |
| 1922 | $check->bindValue(":buyID", $buyID); |
| 1923 | if($check->execute()) { |
| 1924 | $log->LogDebug("Text Me Check Execute"); |
| 1925 | if($checkRow = $check->fetch(PDO::FETCH_ASSOC)) { |
| 1926 | if((int)$checkRow['textMe'] == 1) { |
| 1927 | $log->LogDebug("Text Me Is a Go"); |
| 1928 | $customerQuery = $storeDB->prepare("SELECT phone FROM customers WHERE customerID = :customerID"); |
| 1929 | $customerQuery->bindValue(":customerID", $row['customerID']); |
| 1930 | |
| 1931 | if($customerQuery->execute()) { |
| 1932 | $customer = $customerQuery->fetch(PDO::FETCH_ASSOC); |
| 1933 | $surveyUrl = "https://v2ts.co/s/".$row['uuid']; |
| 1934 | $log->LogDebug("Survey URL: ".$surveyUrl); |
| 1935 | $log->LogDebug("Phone: ". $customer['phone']); |
| 1936 | |
| 1937 | // Use the textMessageService for all SMS sending (both Nexmo/Vonage and Twilio) |
| 1938 | $log->LogDebug("Sending survey SMS via store's text messaging service"); |
| 1939 | $customerController = new \BuyerKiosk\CustomerController(null, $store); |
| 1940 | $customerObj = $customerController->getCustomerById($row['customerID']); |
| 1941 | $response = null; |
| 1942 | |
| 1943 | if($customerObj) { |
| 1944 | $result = $store->textMessageService->sendSurveyText($customerObj, $surveyUrl); |
| 1945 | if($result['status'] == "success") { |
| 1946 | $response = (object)['status' => 'success', 'id' => $result['id']]; |
| 1947 | } else { |
| 1948 | $log->LogError("Survey SMS failed: " . json_encode($result)); |
| 1949 | } |
| 1950 | } else { |
| 1951 | $log->LogError("Could not load customer object for customerID: " . $row['customerID']); |
| 1952 | } |
| 1953 | |
| 1954 | // Add to texts database if SMS was sent successfully |
| 1955 | if($response && $response->status == 'success') { |
| 1956 | $log->LogDebug("Add Text To Database"); |
| 1957 | $actualMessage = $store->getSurveySMSText() . $surveyUrl; |
| 1958 | // Truncate message if too long for database column (assuming 255 char limit) |
| 1959 | $actualMessage = mb_substr($actualMessage, 0, 255); |
| 1960 | $stmt = $storeDB->prepare("INSERT INTO texts (customerID, type, employeeNumber, message) VALUES (:customerID, 5, 99, :message)"); |
| 1961 | $stmt->bindValue(":customerID", $row['customerID']); |
| 1962 | $stmt->bindValue(":message", $actualMessage); |
| 1963 | if($stmt->execute()) { |
| 1964 | $log->LogDebug("Text was counted"); |
| 1965 | } else { |
| 1966 | $log->LogDebug("Text was not counted"); |
| 1967 | } |
| 1968 | } |
| 1969 | return $response; |
| 1970 | } |
| 1971 | } else { |
| 1972 | $log->LogDebug("Text Me Is a No Go"); |
| 1973 | } |
| 1974 | } |
| 1975 | } |
| 1976 | } |
| 1977 | } |
| 1978 | return null; |
| 1979 | } |
| 1980 | |
| 1981 | |
| 1982 | ?> |