diff --git a/Helper/TimingHelper.php b/Helper/TimingHelper.php index e8fea7c..6e8ec42 100644 --- a/Helper/TimingHelper.php +++ b/Helper/TimingHelper.php @@ -240,7 +240,8 @@ private function getNextRunDate( //attempt to use the contact's timezone (if directed) if($timing->useContactTimezone()) { - if( ! $lead->getIpAddresses()->isEmpty()) { + $timezone = $lead->getTimezone(); + if(empty($timezone) && ! $lead->getIpAddresses()->isEmpty()) { /** @var $ipDetails array */ $ipDetails = $lead->getIpAddresses()->first()->getIpDetails(); if( ! empty($ipDetails['timezone'])) { @@ -250,12 +251,12 @@ private function getNextRunDate( } //if no timezone is set yet, try to get it from the Timing settings. - if(($timezone == null) && ($timing->getTimezone() != null)) { + if(empty($timezone) && ($timing->getTimezone() != null)) { $timezone = $timing->getTimezone(); } //if no timezone is set yet, use the system's default timezone. - if($timezone == null) { + if(empty($timezone)) { $timezone = date_default_timezone_get(); } diff --git a/README.md b/README.md index dda5dce..143799c 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ For example, you could add a cron expression that only allows sending on weekday Note: newer versions of Mautic just have an "Install/Upgrade Plugins" button (without the dropdown arrow). 5. You should now see the Timing plugin in your list of plugins. -6. Run the following console commands to ensure that the database was updated: +6. Run the following console commands to update the database: ``` php app/console doctrine:schema:update --dump-sql @@ -53,7 +53,11 @@ Example: When this field is enabled, the plugin will evaluate the cron expression off of the Contact's time zone. This allows you to only send emails during the Contact's working hours. -If the Contact's time zone isn't known, the plugin will fall back to the system default time zone or the time zone that you set with the Time Zone field (see below.) +The contact time zone is evaluated in the following order: +1. The timezone field of the contact (e.g. `mautic.lead.field.timezone`), else: +2. The timezone of the last ip address used by the contact, else: +3. The value of the `Time Zone Field` in the action, else: +4. The system default time zone #### Time Zone Field @@ -74,10 +78,10 @@ apk update && apk add ca-certificates && update-ca-certificates && apk add opens #### Running the Tests -Once PHPUnit is installed, you can run the tests by navigating to the root directory of this plugin and running: +Put the plugin dir in mautic plugins dir (`./plugins`) and run in `mautic` root dir: ``` -phpunit +bin/phpunit --bootstrap vendor/autoload.php --configuration app/phpunit.xml.dist 'MauticPlugin\ThirdSetMauticTimingBundle\Tests\Helper\TimingHelperTest' plugins/ThirdSetMauticTimingBundle/Tests/Helper/TimingHelperTest.php ``` ## Credits diff --git a/Tests/Helper/TimingHelperTest.php b/Tests/Helper/TimingHelperTest.php index 3eaef2b..b06843f 100644 --- a/Tests/Helper/TimingHelperTest.php +++ b/Tests/Helper/TimingHelperTest.php @@ -163,6 +163,8 @@ public function testCheckEventTimingCorrectlyReturnsTrueForADueSimpleExpression( $eventData = array(); $eventData['id'] = 1; + $eventData['decisionPath'] = null; + $eventData['triggerMode'] = null; /* @var $timingHelper \MauticPlugin\ThirdSetMauticTimingBundle\Helper\TimingHelper */ $timingHelper = $this->getTimingHelper($timing); @@ -204,6 +206,8 @@ public function testCheckEventTimingCorrectlyReturnsDateTimeWhenScheduled() $eventData = array(); $eventData['id'] = 1; + $eventData['decisionPath'] = null; + $eventData['triggerMode'] = null; /* @var $timingHelper \MauticPlugin\ThirdSetMauticTimingBundle\Helper\TimingHelper */ $timingHelper = $this->getTimingHelper($timing); @@ -224,12 +228,12 @@ public function testCheckEventTimingCorrectlyReturnsDateTimeWhenScheduled() } /** - * @testdox checkEventTiming correctly returns true when a *lead's* time + * @testdox checkEventTiming correctly returns true when a *lead's* ip time * zone makes it due. * * @covers \MauticPlugin\ThirdSetMauticTimingBundle\Helper\TimingHelper::checkEventTiming */ - public function testCheckEventTimingCorrectlyReturnsTrueWhenContactsTimezoneMakesItDue() + public function testCheckEventTimingCorrectlyReturnsTrueWhenContactsIpTimezoneMakesItDue() { //the time and expression would return false, but the offset should //cause them to return true instead. @@ -246,6 +250,8 @@ public function testCheckEventTimingCorrectlyReturnsTrueWhenContactsTimezoneMake $eventData = array(); $eventData['id'] = 1; + $eventData['decisionPath'] = null; + $eventData['triggerMode'] = null; /* @var $timingHelper \MauticPlugin\ThirdSetMauticTimingBundle\Helper\TimingHelper */ $timingHelper = $this->getTimingHelper($timing); @@ -265,6 +271,50 @@ public function testCheckEventTimingCorrectlyReturnsTrueWhenContactsTimezoneMake $this->assertTrue($eventTriggerDate); } + /** + * @testdox checkEventTiming correctly returns true when a *lead's* field time + * zone makes it due. + * + * @covers \MauticPlugin\ThirdSetMauticTimingBundle\Helper\TimingHelper::checkEventTiming + */ + public function testCheckEventTimingCorrectlyReturnsTrueWhenContactsFieldTimezoneMakesItDue() + { + //the time and expression would return false, but the offset should + //cause them to return true instead. + $mockNow = '2016-01-01 10:00:00'; + $expression = '* 01-06 * * *'; + $useContactTimezone = true; + $contactTimezone = 'America/New_York'; // -5 + + /* @var $timing \MauticPlugin\ThirdSetMauticTimingBundle\Entity\Timing */ + $timing = $this->getMockTiming( + $expression, + $useContactTimezone + ); + + $eventData = array(); + $eventData['id'] = 1; + $eventData['decisionPath'] = null; + $eventData['triggerMode'] = null; + + /* @var $timingHelper \MauticPlugin\ThirdSetMauticTimingBundle\Helper\TimingHelper */ + $timingHelper = $this->getTimingHelper($timing); + + /* @var $lead \Mautic\LeadBundle\Entity\Lead */ + $lead = $this->getMockLead(null, $contactTimezone); + + //call the function + $eventTriggerDate = $timingHelper->checkEventTiming( + $eventData, + null, + false, + $lead, + $mockNow + ); + + $this->assertTrue($eventTriggerDate); + } + /** * @testdox checkEventTiming correctly returns a DateTime when a *lead's* * time zone makes it not due. @@ -289,6 +339,8 @@ public function testCheckEventTimingCorrectlyReturnsDateTimeWhenContactsTimezone $eventData = array(); $eventData['id'] = 1; + $eventData['decisionPath'] = null; + $eventData['triggerMode'] = null; /* @var $timingHelper \MauticPlugin\ThirdSetMauticTimingBundle\Helper\TimingHelper */ $timingHelper = $this->getTimingHelper($timing); @@ -330,6 +382,8 @@ public function testCheckEventTimingCorrectlyReturnsDateTimeWhenContactsTimezone $eventData = array(); $eventData['id'] = 1; + $eventData['decisionPath'] = null; + $eventData['triggerMode'] = null; /* @var $timingHelper \MauticPlugin\ThirdSetMauticTimingBundle\Helper\TimingHelper */ $timingHelper = $this->getTimingHelper($timing); @@ -376,6 +430,8 @@ public function testCheckEventTimingCorrectlyReturnsTrueWhenTimingTimezoneMakesI $eventData = array(); $eventData['id'] = 1; + $eventData['decisionPath'] = null; + $eventData['triggerMode'] = null; /* @var $timingHelper \MauticPlugin\ThirdSetMauticTimingBundle\Helper\TimingHelper */ $timingHelper = $this->getTimingHelper($timing); @@ -420,6 +476,8 @@ public function testCheckEventTimingCorrectlyReturnsDateTimeWhenTimingTimezoneMa $eventData = array(); $eventData['id'] = 1; + $eventData['decisionPath'] = null; + $eventData['triggerMode'] = null; /* @var $timingHelper \MauticPlugin\ThirdSetMauticTimingBundle\Helper\TimingHelper */ $timingHelper = $this->getTimingHelper($timing); @@ -465,9 +523,12 @@ public function testCheckEventTimingCorrectlyReturnsNullWhenEventDoesntHaveTimin /** @var $lead \Mautic\LeadBundle\Entity\Lead */ $lead = $this->getMockLead(null); + $eventData = array(); + $eventData['id'] = null; + //call the function $eventTriggerDate = $timingHelper->checkEventTiming( - array(), + $eventData, null, false, $lead, @@ -502,9 +563,12 @@ public function testCheckEventTimingCorrectlyReturnsNullWhenExpressionIsEmpty() /* @var $lead \Mautic\LeadBundle\Entity\Lead */ $lead = $this->getMockLead(null); + $eventData = array(); + $eventData['id'] = null; + //call the function $eventTriggerDate = $timingHelper->checkEventTiming( - array(), + $eventData, null, false, $lead, @@ -543,6 +607,7 @@ public function testCheckEventTimingCorrectlyReturnsNullDecisionPathIsNoAndNotAl $eventData = array(); $eventData['id'] = 1; $eventData['decisionPath'] = 'no'; + $eventData['triggerMode'] = null; $allowNegative = false; @@ -586,6 +651,7 @@ public function testCheckEventTimingReturnsExpectedDateTimeWhenTriggerModeIsInte $eventData = array(); $eventData['id'] = 1; + $eventData['decisionPath'] = null; $eventData['triggerMode'] = $triggerMode; $eventData['triggerInterval'] = $triggerInterval; $eventData['triggerIntervalUnit'] = $triggerIntervalUnit; @@ -636,6 +702,8 @@ public function testCheckEventTimingReturnsExpectedDateTimeWhenTriggerModeIsDate $eventData = array(); $eventData['id'] = 1; + $eventData['decisionPath'] = null; + $eventData['triggerMode'] = null; $eventData['triggerMode'] = $triggerMode; $eventData['triggerDate'] = $triggerDate; @@ -724,21 +792,21 @@ private function getMockTiming( * @param string $timezone A timezone as a string (ex: "America/New_York") * @return Lead Returns a mock Lead. */ - private function getMockLead($timezone = null) + private function getMockLead($ipTimezone = null, $fieldTimezone = null) { //mock the lead $lead = $this->getMockBuilder('\Mautic\LeadBundle\Entity\Lead') ->disableOriginalConstructor() ->getMock(); - if($timezone != null) { + if($ipTimezone != null) { //mock an IpAddress $ipAddress = $this->getMockBuilder('\Mautic\CoreBundle\Entity\IpAddress') ->disableOriginalConstructor() ->getMock(); $ipDetails = array( - 'timezone' => $timezone + 'timezone' => $ipTimezone ); //stub the ipAddress->getIpDetails() function @@ -758,6 +826,11 @@ private function getMockLead($timezone = null) ->method('getIpAddresses') ->will($this->returnValue($ipAddresses)); + //stub the lead->getTimezone() function + $lead->expects($this->any()) + ->method('getTimezone') + ->will($this->returnValue($fieldTimezone)); + return $lead; } }