Commit 6865a89a authored by ErikHommel's avatar ErikHommel
Browse files

issue 7141 - bulk mail from msp

parent 9fcfcb20
<?php
use CRM_Nbrprojectvolunteerlist_ExtensionUtil as E;
/**
* Class to process the invite by bulk mail action
*
* @author Erik Hommel (CiviCooP) <erik.hommel@civicoop.org>
* @date 7 Sep 2020
* @license AGPL-3.0
*/
class CRM_Nbrprojectvolunteerlist_Form_Task_BulkMailing extends CRM_Contact_Form_Task {
private $_countSelected = NULL;
private $_countInvalid = NULL;
private $_selected = [];
private $_invalids = [];
private $_studyId = NULL;
/**
* Method to get the volunteer data for the selected contact IDs
*
*/
private function getVolunteerData() {
$this->_selected = [];
$this->_countInvalid = 0;
$this->_invalids = [];
$this->_countSelected = 0;
$dao = CRM_Nbrprojectvolunteerlist_Utils::getInvitedData($this->_studyId, $this->_contactIds);
while ($dao->fetch()) {
$volunteer = new CRM_Nbrprojectvolunteerlist_NbrVolunteer();
$volunteer->classifyVolunteer("msp", $dao, $this->_invalids, $this->_countInvalid, $this->_selected, $this->_countSelected);
}
}
/**
* Overridden parent method om formulier op te bouwen
*/
public function buildQuickForm() {
if (isset(self::$_searchFormValues['study_id'])) {
$this->_studyId = self::$_searchFormValues['study_id'];
}
$this->assign('selected_txt', E::ts('Volunteers that will be mailed by this bulk mailing:') . $this->_countSelected);
$this->assign('invalid_txt', E::ts('Volunteers that will NOT be mailed with reason:') . $this->_countInvalid);
$this->getVolunteerData();
$this->assign('count_selected_txt', E::ts('Number of volunteers that will be mailed: ') . $this->_countSelected);
$this->assign('count_invalid_txt', E::ts('Number of volunteers that will NOT be mailed: ') . $this->_countInvalid);
$this->assign('volunteers', $this->_selected);
$this->assign('invalids', $this->_invalids);
$this->addDefaultButtons('Create draft mailing');
}
/**
* Overridden parent method
*/
public function postProcess() {
// only if we have a study, selected ids and a template
if (isset($this->_studyId) && !empty($this->_selected)) {
// first create temporary group
try {
$group = civicrm_api3('Group', 'create', CRM_Nbrprojectvolunteerlist_Utils::createBulkGroupParams($this->_studyId));
// next add all volunteers to invite to group
$this->addVolunteersToGroup($group['id']);
$this->createMailing($group['id']);
}
catch (CiviCRM_API3_Exception $ex) {
Civi::log()->error('Could not create a temporary group for bulk mailing in '
. __METHOD__ . ', error message from API Group create: ' . $ex->getMessage());
CRM_Core_Session::setStatus("Could not create a group for bulk mail, please contact IT support.", "Can not execute bulk mail from MSP", "error");
}
}
}
/**
* Method to add volunteer to temporary group for bulk mail
*
* @param $groupId
*/
private function addVolunteersToGroup($groupId) {
foreach ($this->_selected as $selectedContactId => $selectedData) {
try {
civicrm_api3('GroupContact', 'create', [
'group_id' => $groupId,
'contact_id' => $selectedContactId,
]);
}
catch (CiviCRM_API3_Exception $ex) {
Civi::log()->error('Could not add contact with ID ' . $selectedContactId . ' to mailing group for study bulk mail with ID '
. $groupId . ' in ' . __METHOD__ . ', error message from API GroupContact create: ' . $ex->getMessage());
CRM_Core_Session::setStatus("Could not add volunteer with ID ' . $selectedContactId . ', will not be part of the study bulk mailing. Please correct manually.", "Can not add volunteer to study bulk mail", "error");
}
}
}
/**
* Method to create the mailing for the bulk invite
*
* @param $groupId
*/
private function createMailing($groupId) {
$mailingParams = CRM_Nbrprojectvolunteerlist_Utils::createMailingParams( $this->_studyId, $groupId, $this->_submitValues, 'msp');
try {
$mailing = civicrm_api3('Mailing', 'create', $mailingParams);
// insert record to link mailing id and group id
$this->createNbrMailing($groupId, $mailing['id']);
}
catch (CiviCRM_API3_Exception $ex) {
Civi::log()->error('Could not create a mailing for bulk invite in '
. __METHOD__ . ', error message from API Mailing create: ' . $ex->getMessage());
CRM_Core_Session::setStatus("Could not create a mailing for invite by bulk, please contact IT support.", "Can not execute bulk invite", "error");
}
}
/**
* Method to create an NbrMailing to link group and mailing so further processing can be done when
* mailing has been completed
*
* @param $groupId
* @param $mailingId
*/
private function createNbrMailing($groupId, $mailingId) {
try {
civicrm_api3('NbrMailing', 'create', [
'nbr_mailing_type' => "msp",
'mailing_id' => $mailingId,
'group_id' => $groupId,
'study_id' => $this->_studyId,
]);
$studyNumber = CRM_Nihrbackbone_NbrStudy::getStudyNumberWithId($this->_studyId);
CRM_Core_Session::setStatus("Draft study bulk mailing to " . $studyNumber . " successfully created.", "Draft Study Bulk Mailing created", "success");
}
catch (CiviCRM_API3_Exception $ex) {
Civi::log()->error('Could not create a record linking the study bulk mailing with ID ' . $mailingId .
' and group with ID ' . $groupId. '. Mailing has been successfully scheduled but the temporary group will not be deleted nor will add activity to case. Error message from API NbrMailing create: ' . $ex->getMessage());
CRM_Core_Session::setStatus("Mailing scheduled but filing on case not possible, please contact IT support.", "Can not execute post study bulk mail process", "error");
}
}
}
......@@ -9,7 +9,7 @@ use CRM_Nbrprojectvolunteerlist_ExtensionUtil as E;
* @date 7 Sep 2020
* @license AGPL-3.0
*/
class CRM_Nbrprojectvolunteerlist_Form_Task_InviteBulk extends CRM_Contact_Form_Task {
class CRM_Nbrprojectvolunteerlist_Form_Task_BulkMail extends CRM_Contact_Form_Task {
private $_countInvited = NULL;
private $_countInvalid = NULL;
......@@ -18,7 +18,7 @@ class CRM_Nbrprojectvolunteerlist_Form_Task_InviteBulk extends CRM_Contact_Form_
private $_studyId = NULL;
/**
* Method to get the invited data for the selected contact IDs
* Method to get the volunteer data for the selected contact IDs
*
*/
private function getInvitedData() {
......@@ -29,7 +29,7 @@ class CRM_Nbrprojectvolunteerlist_Form_Task_InviteBulk extends CRM_Contact_Form_
$dao = CRM_Nbrprojectvolunteerlist_Utils::getInvitedData($this->_studyId, $this->_contactIds);
while ($dao->fetch()) {
$volunteer = new CRM_Nbrprojectvolunteerlist_NbrVolunteer();
$volunteer->classifyVolunteer("mailing", $dao, $this->_invalids, $this->_countInvalid, $this->_invited, $this->_countInvited);
$volunteer->classifyVolunteer("invite_bulk", $dao, $this->_invalids, $this->_countInvalid, $this->_invited, $this->_countInvited);
}
}
......@@ -120,7 +120,7 @@ class CRM_Nbrprojectvolunteerlist_Form_Task_InviteBulk extends CRM_Contact_Form_
* @param $groupId
*/
private function createMailing($groupId) {
$mailingParams = CRM_Nbrprojectvolunteerlist_Utils::createInviteMailingParams($this->_studyId, $groupId, $this->_submitValues);
$mailingParams = CRM_Nbrprojectvolunteerlist_Utils::createMailingParams($this->_studyId, $groupId, $this->_submitValues, 'invite');
try {
$mailing = civicrm_api3('Mailing', 'create', $mailingParams);
// insert record to link mailing id and group id
......
......@@ -29,7 +29,7 @@ class CRM_Nbrprojectvolunteerlist_Form_Task_InviteByEmail extends CRM_Contact_Fo
$dao = CRM_Nbrprojectvolunteerlist_Utils::getInvitedData($this->_studyId, $this->_contactIds);
while ($dao->fetch()) {
$volunteer = new CRM_Nbrprojectvolunteerlist_NbrVolunteer();
$volunteer->classifyVolunteer("email", $dao, $this->_invalids, $this->_countInvalid, $this->_invited, $this->_countInvited);
$volunteer->classifyVolunteer("invite_mail", $dao, $this->_invalids, $this->_countInvalid, $this->_invited, $this->_countInvited);
}
}
......
......@@ -29,30 +29,33 @@ class CRM_Nbrprojectvolunteerlist_NbrVolunteer {
];
$eligibleStatus = implode(', ', CRM_Nihrbackbone_NbrVolunteerCase::getEligibleDescriptions($dao->eligible_status_id));
$volunteer['eligible_status'] = $eligibleStatus;
// do not allow invite if participation status is excluded
if ($dao->study_participation_status == Civi::service('nbrBackbone')->getExcludedParticipationStatusValue()) {
$countInvalids++;
$volunteer['reason'] = E::ts("Excluded");
$invalids[$dao->contact_id] = $volunteer;
$inviteType = substr($type,0,6);
if ($inviteType == "invite") {
// do not allow invite if participation status is excluded
if ($dao->study_participation_status == Civi::service('nbrBackbone')->getExcludedParticipationStatusValue()) {
$countInvalids++;
$volunteer['reason'] = E::ts("Excluded");
$invalids[$dao->contact_id] = $volunteer;
}
// only allow invite if eligible
elseif (!$this->isEligibleStatus($dao->eligible_status_id)) {
$countInvalids++;
$volunteer['reason'] = E::ts("Not eligible");
$invalids[$dao->contact_id] = $volunteer;
}
}
// only allow invite if eligible
elseif (!$this->isEligibleStatus($dao->eligible_status_id)) {
// do not allow if email is empty
if (empty($dao->email)) {
$countInvalids++;
$volunteer['reason'] = E::ts("Not eligible");
$volunteer['reason'] = E::ts("Does not have an active primary email address");
$invalids[$dao->contact_id] = $volunteer;
}
// do not allow if deceased
elseif (CRM_Nihrbackbone_NihrVolunteer::isDeceased($dao->contact_id)) {
if (CRM_Nihrbackbone_NihrVolunteer::isDeceased($dao->contact_id)) {
$countInvalids++;
$volunteer['reason'] = E::ts("Deceased");
$invalids[$dao->contact_id] = $volunteer;
}
// do not allow if email is empty
elseif (empty($dao->email)) {
$countInvalids++;
$volunteer['reason'] = E::ts("Does not have an active primary email address");
$invalids[$dao->contact_id] = $volunteer;
}
// do not allow if contact has no_email flag
elseif (!CRM_Nihrbackbone_NihrVolunteer::allowsEmail($dao->contact_id)) {
$countInvalids++;
......@@ -65,8 +68,8 @@ class CRM_Nbrprojectvolunteerlist_NbrVolunteer {
$volunteer['reason'] = E::ts("Invalid email address");
$invalids[$dao->contact_id] = $volunteer;
}
// do not allow more than 50 invitations if not bulk
elseif ($type == "email" && $countInvited >= 50) {
// do not allow more than 50 if not bulk
elseif ($type == "invite_email" && $countInvited >= 50) {
$countInvalids++;
$volunteer['reason'] = E::ts("Can not mail more than 50");
$invalids[$dao->contact_id] = $volunteer;
......
......@@ -86,7 +86,7 @@ class CRM_Nbrprojectvolunteerlist_SearchTasks {
}
}
// if one of specific actions, return TRUE
$taskClasses = ['InviteByEmail', 'ChangeStudyStatus', "InviteBulk"];
$taskClasses = ['InviteByEmail', 'ChangeStudyStatus', 'InviteBulk', 'BulkMailing'];
foreach ($taskClasses as $taskClass) {
$checkDisplay = CRM_Utils_Request::retrieveValue('_qf_' . $taskClass . '_display', 'String');
$checkNext = CRM_Utils_Request::retrieveValue('_qf_' . $taskClass . '_next', 'String');
......@@ -113,6 +113,10 @@ class CRM_Nbrprojectvolunteerlist_SearchTasks {
'title' => "Invite Volunteer(s) by Bulk Mail (50+)",
'class' => "CRM_Nbrprojectvolunteerlist_Form_Task_InviteBulk",
],
[
'title' => "Send bulk mailing to Volunteer(s) (50+)",
'class' => "CRM_Nbrprojectvolunteerlist_Form_Task_BulkMailing",
],
[
'title' => "Change Status on Study for Volunteer(s)",
'class' => "CRM_Nbrprojectvolunteerlist_Form_Task_ChangeStudyStatus",
......
......@@ -85,6 +85,27 @@ class CRM_Nbrprojectvolunteerlist_Utils {
return $templates;
}
/**
* Method to create the params for the temporary group used by Invite by Bulk
*
* @param $studyId
* @return array
*/
public static function createBulkGroupParams($studyId) {
$now = new DateTime();
$studyNumber = CRM_Nihrbackbone_NbrStudy::getStudyNumberWithId($studyId);
return [
'name' => "Nbr_BulkMailing_" . $now->format('Ymdhis'),
'title' => "Temp. Study Bulk Mailing " . $studyNumber . " group on " . $now->format('Y-m-d H:i:s'),
'description' => "This group is a temporary one used for bulk mailing study volunteers - do not update or use, will be removed automatically when mailing is completed.",
'is_active' => 1,
'visibility' => "User and User Admin Only",
'group_type' => "Mailing List",
'is_reserved' => 1,
'created_id' => CRM_Core_Session::getLoggedInContactID()
];
}
/**
* Method to create the params for the temporary group used by Invite by Bulk
*
......@@ -112,9 +133,10 @@ class CRM_Nbrprojectvolunteerlist_Utils {
* @param $studyId
* @param $groupId
* @param $formValues
* @param $type (default "")
* @return array|false
*/
public static function createInviteMailingParams($studyId, $groupId, $formValues) {
public static function createMailingParams($studyId, $groupId, $formValues, $type = "") {
if (empty($groupId) || empty($studyId) || empty($formValues)) {
return FALSE;
}
......@@ -132,6 +154,9 @@ class CRM_Nbrprojectvolunteerlist_Utils {
'resubscribe_id' => Civi::service('nbrBackbone')->getResubscribeId(),
'template_options' => '{"nonce":"1"}',
];
if ($type == 'msp') {
$mailingParams['name'] = 'Study Bulk Mailing ' . CRM_Nihrbackbone_NbrStudy::getStudyNumberWithId($studyId) . ' (created ' . date('d-m-Y') . ")";
}
$fromFormParams = ['subject', 'from_name', 'from_email'];
foreach ($fromFormParams as $fromFormParam) {
if (isset($formValues[$fromFormParam]) && !empty($formValues[$fromFormParam])) {
......
......@@ -14,8 +14,8 @@
<url desc="Support">https://civicoop.org</url>
<url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
</urls>
<releaseDate>2020-10-19</releaseDate>
<version>1.23</version>
<releaseDate>2020-11-02</releaseDate>
<version>1.24</version>
<develStage>beta</develStage>
<compatibility>
<ver>4.7</ver>
......
......@@ -16,6 +16,7 @@ function nbrprojectvolunteerlist_civicrm_post($op, $objectName, $objectId, &$obj
}
}
}
/**
* Implements hook_civicrm_buildForm
*
......
{* Confirm contacts and select template for InviteByEmail *}
<h2>{ts}Study Bulk Mailing (50+){/ts}</h2>
<div class="messages status no-popup">
<div class="help-block" id="help">
{ts}You can mail 50+ volunteers in 1 bulk mailing. If you need to mail less you can but you could also use Send Email (max. 50) action.{/ts}
</div>
<h3>{$select_txt}</h3>
{if !empty($volunteers)}
<table>
<tr>
<th>{ts}Name{/ts}</th>
<th>{ts}BioResource ID{/ts}</th>
<th>{ts}Participant ID{/ts}</th>
<th>{ts}Study/Participant ID{/ts}</th>
<th>{ts}Eligibility{/ts}</th>
<th>{ts}Email{/ts}</th>
</tr>
{foreach from=$volunteers key=volunteer_id item=volunteer}
<tr id='volunteerid{$volunteer_id}' class="{cycle values="odd-row,even-row"}">
<td>{$volunteer.display_name}</td>
<td>{$volunteer.bioresource_id}</td>
<td>{$volunteer.participant_id}</td>
<td>{$volunteer.study_participant_id}</td>
<td>{$volunteer.eligible_status}</td>
<td>{$volunteer.email}</td>
</tr>
{/foreach}
</table>
{/if}
<p>{$count_selected_txt}</p>
<h3>{$invalid_txt}</h3>
{if !empty($invalids)}
<table>
<tr>
<th>{ts}Name{/ts}</th>
<th>{ts}BioResource ID{/ts}</th>
<th>{ts}Participant ID{/ts}</th>
<th>{ts}Study/Participant ID{/ts}</th>
<th>{ts}Eligibility{/ts}</th>
<th>{ts}Reason{/ts}</th>
</tr>
{foreach from=$invalids key=contact_id item=invalid}
<tr id='contactid{$contact_id}' class="{cycle values="odd-row,even-row"}">
<td>{$invalid.display_name}</td>
<td>{$invalid.bioresource_id}</td>
<td>{$invalid.participant_id}</td>
<td>{$invalid.study_participant_id}</td>
<td>{$invalid.eligible_status}</td>
<td>{$invalid.reason}</td>
</tr>
{/foreach}
</table>
{/if}
<p>{$count_invalid_txt}</p>
</div>
<p>
<div class="form-item">
{$form.buttons.html}
</div>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment