Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Helper/TimingHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -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'])) {
Expand All @@ -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();
}

Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand All @@ -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
Expand Down
87 changes: 80 additions & 7 deletions Tests/Helper/TimingHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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.
Expand All @@ -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);
Expand All @@ -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.
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -543,6 +607,7 @@ public function testCheckEventTimingCorrectlyReturnsNullDecisionPathIsNoAndNotAl
$eventData = array();
$eventData['id'] = 1;
$eventData['decisionPath'] = 'no';
$eventData['triggerMode'] = null;

$allowNegative = false;

Expand Down Expand Up @@ -586,6 +651,7 @@ public function testCheckEventTimingReturnsExpectedDateTimeWhenTriggerModeIsInte

$eventData = array();
$eventData['id'] = 1;
$eventData['decisionPath'] = null;
$eventData['triggerMode'] = $triggerMode;
$eventData['triggerInterval'] = $triggerInterval;
$eventData['triggerIntervalUnit'] = $triggerIntervalUnit;
Expand Down Expand Up @@ -636,6 +702,8 @@ public function testCheckEventTimingReturnsExpectedDateTimeWhenTriggerModeIsDate

$eventData = array();
$eventData['id'] = 1;
$eventData['decisionPath'] = null;
$eventData['triggerMode'] = null;
$eventData['triggerMode'] = $triggerMode;
$eventData['triggerDate'] = $triggerDate;

Expand Down Expand Up @@ -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
Expand All @@ -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;
}
}