Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 266
0.00% covered (danger)
0.00%
0 / 23
CRAP
0.00% covered (danger)
0.00%
0 / 1
TriggerRobot
0.00% covered (danger)
0.00%
0 / 266
0.00% covered (danger)
0.00%
0 / 23
9120
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getLoyaltyStores
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
30
 getLoyaltyGroups
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 loopThroughGroups
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 findTriggersByStoreGroup
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
30
 processTrigger
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
30
 processType1
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
30
 processBirthdayTrigger
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
20
 processBuyerTrigger
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
156
 createMessage
0.00% covered (danger)
0.00%
0 / 89
0.00% covered (danger)
0.00%
0 / 1
306
 filterMessage
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 getDateForTrigger
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getTriggerTimeZone
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getMessage
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 getDaysSinceEventArray
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 1
132
 getTimeFrame
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
72
 getStoreArray
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setStoreArray
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getStoreGroupArray
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setStoreGroupArray
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAllTriggersArray
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 setAllTriggersArray
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 createTypeNumArrayString
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3namespace BuyerKiosk\Core\Robot;
4
5use BuyerKiosk\Core\Store;
6use BuyerKiosk\Core\Loyalty\LoyaltyCustomer;
7use BuyerKiosk\Core\Loyalty\LoyaltyCoupon;
8use BuyerKiosk\Core\Loyalty\LoyaltyGroup;
9use BuyerKiosk\Core\Loyalty\LoyaltyOutgoing;
10use BuyerKiosk\Core\Loyalty\LoyaltySMSMessage;
11use BuyerKiosk\Core\Loyalty\LoyaltyTrigger;
12
13class TriggerRobot extends Robot {
14    public $storeArray;
15    public $storeGroupArray;
16    public $allTriggersArray;
17    public $triggerTimeZone;
18    private $log;
19
20    public function __construct() {
21        parent::__construct();
22        $this->log = new \KLogger("/home/kiosk/logs/trigger_log.txt", \KLogger::DEBUG);
23
24    }
25    public function getLoyaltyStores() {
26        try {
27            $stmt = $this->globalDB->query("SELECT typeNum, dbName FROM stores WHERE loyaltySystem = 1");
28            while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
29                $storeArray[$row['typeNum']] = $row['dbName'];
30            }
31            if(isset($storeArray) && count($storeArray) > 1) {
32                return true;
33            }
34        } catch (\PDOException $e) {
35
36        }
37        return false;
38    }
39    public function getLoyaltyGroups() {
40        $storeGroupArray = [];
41        try {
42            $stmt = $this->globalDB->query("SELECT DISTINCT(storeGroup) FROM loyaltyTriggers GROUP BY storeGroup");
43            while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
44                $storeGroupArray[] = $row['storeGroup'];
45            }
46            $this->storeGroupArray = $storeGroupArray;
47        } catch (\PDOException $e) {
48
49        }
50    }
51    public function loopThroughGroups() {
52        foreach ($this->storeGroupArray as $group) {
53            $triggersArray = $this->findTriggersByStoreGroup($group);
54            $this->log->LogDebug($group);
55            foreach($triggersArray as $trigger) {
56                $this->log->LogDebug($trigger->triggerID);
57                $this->allTriggersArray[] = $trigger;
58                $this->processTrigger($trigger);
59            }
60        }
61    }
62    public function findTriggersByStoreGroup($storeGroup) {
63        $triggerArray = [];
64        try {
65            //TODO: Add expiration date
66            $stmt = $this->globalDB->query("SELECT id FROM loyaltyTriggers WHERE storeGroup = ".$storeGroup." AND active = 1 AND deleted = 0");
67            if($stmt) {
68                while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
69                    if($trigger = new LoyaltyTrigger($storeGroup, null, $row['id'])) {
70                        $triggerArray[] = $trigger;
71                    }
72                }
73            }
74            return $triggerArray;
75        } catch (\PDOException $e) {
76
77        }
78        return NULL;
79    }
80    public function processTrigger(LoyaltyTrigger $trigger) {
81        $this->log->LogDebug($trigger->getType());
82        switch ($trigger->getType()) {
83            //Its been X days since X event
84            case 0:
85                $this->processType1($trigger);
86                break;
87            //Birthday
88            case 1:
89                $this->processBirthdayTrigger($trigger);
90                break;
91            case 2:
92                break;
93            //Buyer Visit Trigger
94            case 3:
95                $this->processBuyerTrigger($trigger);
96                break;
97
98
99        }
100    }
101
102    public function processType1(LoyaltyTrigger $trigger) {
103        //$this->log->LogDebug("Process Type 1");
104        $message = $this->getMessage($trigger);
105        //Get all loyaltyIDs that haven't visted this storeGroup in X number of days
106        $triggeredCustomers = $this->getDaysSinceEventArray($trigger);
107        $this->log->LogDebug("Customers: ".count($triggeredCustomers));
108        if(isset($triggeredCustomers) && count($triggeredCustomers) > 0) {
109            foreach($triggeredCustomers as $key => $loyaltyID) {
110                $customer = new LoyaltyCustomer($loyaltyID);
111                if((int)$customer->optValue == 1) {
112                    $this->createMessage($loyaltyID, $message->getMessage(), $trigger);
113                }
114            }
115        }
116    }
117    public function processBirthdayTrigger(LoyaltyTrigger $trigger) {
118        $timeZone = $this->getTriggerTimeZone($trigger);
119        $now = new \DateTime('now', new \DateTimeZone($timeZone));
120        $dateTrigger = $now->add(new \DateInterval("P".$trigger->getDays()."D"));
121        $stmt = $this->globalDB->prepare("SELECT * FROM loyaltyCustomers WHERE MONTH(birthday) = :month AND DAY(birthday) = :day AND optValue = 1 AND storeGroup = :storeGroup");
122        $stmt->bindValue(":month", $dateTrigger->format('n'));
123        error_log("Month". $dateTrigger->format('n'));
124        $stmt->bindValue(":day", $dateTrigger->format('j'));
125        error_log("Day: ".$dateTrigger->format('j'));
126        $stmt->bindValue(":storeGroup", $trigger->getStoreGroup());
127        if($trigger->getSendType() == 0) {
128            $message = new LoyaltySMSMessage($trigger->getGroupID(), null,$trigger->getMessageID());
129        }
130
131        if($stmt->execute()) {
132            while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
133                $this->createMessage($row['id'], $message->getMessage(), $trigger);
134            }
135        }
136    }
137    public function processBuyerTrigger(LoyaltyTrigger $trigger) {
138        $stores = $trigger->getStoresArray();
139        $message = $this->getMessage($trigger);
140        foreach ($stores as $store) {
141            /* @var $store Store */
142            $triggeredCustomers = $this->getDaysSinceEventArray($trigger);
143
144            if(isset($triggeredCustomers) && count($triggeredCustomers) > 0) {
145                foreach($triggeredCustomers as $key => $loyaltyID) {
146                    if($trigger->buyerRating !== 0 && isset($trigger->buyerRating)) {
147                        //We are looking for certain rating criteria for this trigger
148                        $loyaltyCustomer = new LoyaltyCustomer($loyaltyID);
149                        if((int)$loyaltyCustomer->optValue == 1) {
150                            $rating = $loyaltyCustomer->getBuyerRating($store->getTypeNum());
151                            if(!isset($rating) && $trigger->includeNoRatings == 1) {
152                                //There is no rating for this customer BUT we want to include those who do not have ratings
153                                $this->createMessage($loyaltyID, $message->getMessage(), $trigger);
154                            } else if(floatval($rating['AvgRating']) >= floatval($trigger->buyerRating)) {
155                                //Looks like the rating is high enough for the criteria
156                                $this->createMessage($loyaltyID, $message->getMessage(), $trigger);
157                            }
158                        }
159                    } else {
160                        $loyaltyCustomer = new LoyaltyCustomer($loyaltyID);
161                        if((int)$loyaltyCustomer->optValue == 1) {
162                            $this->createMessage($loyaltyID, $message->getMessage(), $trigger);
163                        }
164                    }
165                }
166            }
167        }
168    }
169    public function createMessage($loyaltyID, $text, LoyaltyTrigger $trigger) {
170        $customer = new LoyaltyCustomer($loyaltyID);
171        $this->log->LogDebug("Customer: ".$customer->loyaltyID);
172        //Set the Message Data
173        $message = new LoyaltyOutgoing();
174        $message->setTriggerID($trigger->getTriggerId());
175        $this->log->LogDebug("Trigger ID: ".$message->triggerID);
176        $message->setLoyaltyCustomerID($loyaltyID);
177        $this->log->LogDebug("Loyalty ID: ".$message->loyaltyCustomerID);
178        $message->setCouponID($trigger->getCouponID());
179        $this->log->LogDebug("Coupon ID: ".$message->couponID);
180        $message->setMessageType($trigger->getSendType());
181        $this->log->LogDebug("Send Type: ".$message->messageType);
182        $message->setStoreGroupFrom($trigger->getStoreGroup());
183        $this->log->LogDebug("Store Group ID: ".$message->storeGroupFrom);
184        switch($trigger->sendType) {
185            case 0:
186                $message->setCustPhone($customer->getPhone());
187                break;
188            case 1:
189                $message->setCustPhone($customer->getEmail());
190                break;
191            default:
192                $message->setCustPhone($customer->getPhone());
193                $message->setCustPhone($customer->getEmail());
194                break;
195        }
196        $this->log->LogDebug("Cust Phone: ".$message->custPhone);
197
198
199        //Get The Coupon Data
200        $coupon = new LoyaltyCoupon($trigger->getGroupID(),null, $trigger->getCouponID());
201        $expireDate = $coupon->getExpireDate();
202        //Need to get the Expire Date in a MySQL Format. If ExpireDate is NULL than we need to use ExpireDays
203        if($expireDate !== null) {
204            //Get the expiration date of coupon
205            $expireDate = new \DateTime($coupon->getExpireDate(), new \DateTimeZone('utc'));
206            $expireDate->setTimezone(new \DateTimeZone($this->getTriggerTimeZone($trigger)));
207            $expireDate = $expireDate->format("Y-m-d");
208        } else {
209            $expireDate = new \DateTime('now');
210            $expireDate->add(new \DateInterval("P".$coupon->getExpireDays()."D"));
211            $expireDate = $expireDate->format("Y-m-d");
212        }
213        $uuid = $coupon->createUUID($loyaltyID, $trigger->getStoreGroup(), $expireDate);
214        $couponURL = "http://v2ts.co/c/".$uuid;
215
216        //Bind the Coupon to the Message
217        $message->setCouponUUID($uuid);
218        $this->log->LogDebug("Coupon UUID: ".$message->couponUUID);
219
220        //Setup the timeFrame for this particular message
221        $message->timeFrame = $this->getTimeFrame($trigger);
222        $this->log->LogDebug("TimeFrame: ".$message->timeFrame);
223        $message->timeRandom = $trigger->getTimeRandom();
224        $this->log->LogDebug("TimeRandom: ".$message->timeRandom);
225
226
227
228        //Get the store that is actually going to send out the message
229        $sendFrom = $customer->getOriginStore();
230        //Get the store to send the message from:
231        switch($trigger->getAlertFrom()) {
232            case 0:
233                break;
234            case 1:
235                $sendFrom = $customer->getLastVisitedStore();
236                break;
237            case 2:
238                $sendFrom = $customer->getMostVisitedStore();
239                break;
240            case 3:
241                //$sendFrom = Co-OP phone number
242                break;
243            default:
244                break;
245        }
246        $message->setStoreFrom($sendFrom);
247        $this->log->LogDebug("Store From: ".$message->storeFrom);
248
249        //A Really Quick but not elegant way of grabbing the company name
250        switch (substr($sendFrom, 0, 2)) {
251            case 'cm':
252                $company = "Clothes Mentor";
253                break;
254            case 'pc':
255                $company = "Plato's Closet";
256                break;
257            case 'ou':
258                $company = "Once Upon a Child";
259                break;
260            case 'se':
261                $company = "Style Encore";
262                break;
263            case 'pa':
264                $company = "Play It Again Sports";
265                break;
266            default:
267                $company = "BuyerKiosk";
268                break;
269        }
270
271        $vars = array(
272            "%coupon_url%" => $couponURL,
273            "%coupon_name%" => $coupon->shortName,
274            "%coupon_expire%" => $expireDate,
275            "%company%" => $company,
276            "%customer%" => $customer->getFirstName(),
277            "&nbsp;" => " ",
278            "%new_line%" => "\n"
279        );
280        $message->setMessage($this->filterMessage($text, $sendFrom, $vars));
281        $this->log->LogDebug("Message: ".$message->message);
282        if($message->create()) {
283            $this->log->LogDebug("Outgoing ID: ".$message->id);
284            return $message->id;
285        } else {
286            return null;
287        }
288    }
289    public function filterMessage($message, $origin, $vars = null) {
290        $store = new Store();
291        $store->createStore($origin);
292        foreach ($vars as $key => $value) {
293            $message = str_replace($key, $value, $message);
294        }
295        return $message;
296    }
297    private function getDateForTrigger(LoyaltyTrigger $trigger) {
298        $date = new \DateTime('now', new \DateTimeZone('utc'));
299        $date->sub(new \DateInterval("P" . $trigger->getDays() . "D"));
300        $date = getDateRange($date->format("Y-m-d H:i:s"));
301        return $date;
302    }
303    public function getTriggerTimeZone(LoyaltyTrigger $trigger)
304    {
305        //Get Array of all Stores in this Loyalty Group
306        $storeArray = $trigger->getStoresArray();
307        //Get timeZone for this loyaltyGroup based on the first store in the group (we can assume most, if not all, stores will be in this timezone for now)
308        $timeZone = $storeArray[0]->getTimeZone();
309        $this->triggerTimeZone = $timeZone;
310        return $timeZone;
311    }
312    public function getMessage(LoyaltyTrigger $trigger) {
313        if ($trigger->getSendType() == 0) {
314            //This is an SMS type message
315            return $message = new LoyaltySMSMessage($trigger->getGroupID(), null, $trigger->getMessageID());
316        } else if($trigger->getSendType() == 1) {
317            //This is an email type message
318        }
319        return null;
320    }
321    public function getDaysSinceEventArray(LoyaltyTrigger $trigger) {
322        $date = $this->getDateForTrigger($trigger);
323        $dateStart = $date['dateStart']->format("Y-m-d H:i:s");
324        $dateEnd = $date['dateEnd']->format("Y-m-d H:i:s");
325        $this->log->LogDebug("Date Start: ".$dateStart = $date['dateStart']->format("Y-m-d H:i:s"));
326        $this->log->LogDebug("Date Start: ".$dateEnd = $date['dateEnd']->format("Y-m-d H:i:s"));
327
328        // Setup the Customer Query
329        // Remember:
330        // 0 - New Customers Only
331        // 1 - Return Customers Only
332        // 2 - Both New and Return Customers
333        $customerTypeQuery = "1";
334        if($trigger->customerType == 0) {
335            $customerTypeQuery = "ReturnCustomer = 0";
336        } else if($trigger->customerType == 1) {
337            $customerTypeQuery = "ReturnCustomer = 1";
338        }
339        $storeQuery = "";
340        //Setup the individual Store Query
341
342        if($trigger->getEvent() == 'last_visit_store') {
343            $storeQuery = "typeNum = '".$trigger->getTypeNum()."'";
344        } else {
345            $group = new LoyaltyGroup($trigger->storeGroup);
346            foreach($group->getStoresArray() as $store) {
347                $typeNumArray[] = $store->getTypeNum();
348            }
349            $storeQuery = $this->createTypeNumArrayString($typeNumArray);
350        }
351        $this->log->LogDebug("Store Query: ".$storeQuery);
352
353        $type = "1";
354        if($trigger->getType() == 0) {
355            $type = "1,2";
356        } else if($trigger->getType() == 3) {
357            $type = "3";
358        }
359        $this->log->LogDebug("Type: ".$type);
360        if($trigger->getEvent() !== 'joined') {
361            try {
362                $stmt = $this->globalDB->prepare("SELECT lv.loyaltyID FROM
363(SELECT loyaltyID FROM (SELECT MAX(date) as latestVisit, loyaltyID FROM loyaltyData WHERE typeNum IN(".$storeQuery.") AND type IN(".$type.") GROUP BY loyaltyID) as A WHERE latestVisit BETWEEN :dateStart AND :dateEnd) as lv
364LEFT JOIN
365    (SELECT loyaltyID FROM (SELECT loyaltyID FROM loyaltyData WHERE type IN(".$type.") GROUP BY loyaltyID, date HAVING COUNT(loyaltyID) = 1) as J GROUP BY loyaltyID) as X
366ON lv.loyaltyID = X.loyaltyID");
367                $stmt->bindValue(":dateStart", $dateStart);
368                $stmt->bindValue(":dateEnd", $dateEnd);
369                if($stmt->execute()) {
370                    if($result = $stmt->fetchAll(\PDO::FETCH_COLUMN,0))
371                        return $result;
372                }
373            } catch (\PDOException $e) {
374                error_log($e->getMessage());
375            }
376        } else {
377            // TODO: Write query for 'joined' event type
378        }
379        return null;
380    }
381    public function getTimeFrame(LoyaltyTrigger $trigger) {
382        // 1 = 10am local time
383        // 2 = 12pm local time
384        // 3 = 2pm local time
385        // 4 = 4pm local time
386        // 5 = 6pm local time
387        // 6 = 8pm local time
388        // Time has to be in HH:MM:SS format
389        $timeZone = $this->getTriggerTimeZone($trigger);
390        //If TimeRandom is 1 we need to generate a random number 1-6
391        if($trigger->getTimeRandom() == 1) {
392            $timeFrame = rand(1,6);
393        } else {
394            $timeFrame = $trigger->getTimeframe();
395        }
396        $time = "10:00:00";
397        //Now that we have the timeFrame integer we need to convert that to a local time
398        switch($timeFrame) {
399            case 1:
400                $time = "10:00:00";
401                break;
402            case 2:
403                $time = "12:00:00";
404                break;
405            case 3:
406                $time = "14:00:00";
407                break;
408            case 4:
409                $time = "16:00:00";
410                break;
411            case 5:
412                $time = "18:00:00";
413                break;
414            case 6:
415                $time = "20:00:00";
416                break;
417        }
418        error_log("Time: ".$time);
419        $now = \DateTime::createFromFormat("H:i:s", $time, new \DateTimeZone($timeZone));
420        $timeUTC = $now->setTimezone(new \DateTimeZone('utc'));
421        return $timeUTC->format("Y:m:d H:i:s");
422    }
423
424    /**
425     * @return mixed
426     */
427
428    public function getStoreArray()
429    {
430        return $this->storeArray;
431    }
432
433    /**
434     * @param mixed $storeArray
435     */
436    public function setStoreArray($storeArray)
437    {
438        $this->storeArray = $storeArray;
439    }
440
441    /**
442     * @return mixed
443     */
444    public function getStoreGroupArray()
445    {
446        return $this->storeGroupArray;
447    }
448
449    /**
450     * @param mixed $storeGroupArray
451     */
452    public function setStoreGroupArray($storeGroupArray)
453    {
454        $this->storeGroupArray = $storeGroupArray;
455    }
456
457    /**
458     * @return mixed
459     */
460    public function getAllTriggersArray()
461    {
462        return $this->allTriggersArray;
463    }
464
465    /**
466     * @param mixed $allTriggersArray
467     */
468    public function setAllTriggersArray($allTriggersArray)
469    {
470        $this->allTriggersArray = $allTriggersArray;
471    }
472    private function createTypeNumArrayString($typeNumArray) {
473        $string = ""; $count = 0;
474        foreach($typeNumArray as $typeNum) {
475            if($count < count($typeNumArray)-1) {
476                $string .= "'".$typeNumArray[$count]."',";
477            } else {
478                $string .= "'".$typeNumArray[$count]."'";
479            }
480            $count++;
481        }
482        return $string;
483    }
484
485
486
487}