* Reference array contains the id.
*
*
- * @return object
+ * @return CRM_Mailing_DAO_Mailing
*/
public static function add(&$params, $ids = array()) {
$id = CRM_Utils_Array::value('mailing_id', $ids, CRM_Utils_Array::value('id', $params));
}
$mailing = new static();
- $mailing->id = $id;
+ if ($id) {
+ $mailing->id = $id;
+ $mailing->find(TRUE);
+ }
$mailing->domain_id = CRM_Utils_Array::value('domain_id', $params, CRM_Core_Config::domainID());
if (!isset($params['replyto_email']) &&
// check and attach and files as needed
CRM_Core_BAO_File::processAttachment($params, 'civicrm_mailing', $mailing->id);
+ // If we're going to autosend, then check validity before saving.
+ if (!empty($params['scheduled_date']) && $params['scheduled_date'] != 'null') {
+ $errors = static::checkSendable($mailing);
+ if (!empty($errors)) {
+ $fields = implode(',', array_keys($errors));
+ throw new CRM_Core_Exception("Mailing cannot be sent. There are missing fields ($fields).", 'cannot-send', $errors);
+ }
+ }
+
$transaction->commit();
- /**
- * create parent job if not yet created
- * condition on the existence of a scheduled date
- */
+ // Create parent job if not yet created.
+ // Condition on the existence of a scheduled date.
if (!empty($params['scheduled_date']) && $params['scheduled_date'] != 'null') {
$job = new CRM_Mailing_BAO_MailingJob();
$job->mailing_id = $mailing->id;
return $mailing;
}
+ /**
+ * @param CRM_Mailing_DAO_Mailing $mailing
+ * The mailing which may or may not be sendable.
+ * @return array
+ * List of error messages.
+ */
+ public static function checkSendable($mailing) {
+ $errors = array();
+ foreach (array('subject', 'name', 'from_name', 'from_email') as $field) {
+ if (empty($mailing->{$field})) {
+ $errors[$field] = ts('Field "%1" is required.', array(
+ 1 => $field,
+ ));
+ }
+ }
+ if (empty($mailing->body_html) && empty($mailing->body_text)) {
+ $errors['body'] = ts('Field "body_html" or "body_text" is required.');
+ }
+ return $errors;
+ }
+
/**
* Replace the list of recipients on a given mailing
*
* Array or parameters determined by getfields.
*/
function _civicrm_api3_mailing_create_spec(&$params) {
- $params['name']['api.required'] = 1;
- $params['subject']['api.required'] = 1;
$params['created_id']['api.required'] = 1;
$params['created_id']['api.default'] = 'user_contact_id';
$params['api.mailing_job.create']['api.default'] = 1;
create: function create() {
return {
jobs: {}, // {jobId: JobRecord}
- name: "New Mailing",
+ name: "",
campaign_id: null,
from_name: crmFromAddresses.getDefault().author,
from_email: crmFromAddresses.getDefault().email,
replyto_email: "",
- subject: "New Mailing",
+ subject: "",
groups: {include: [], exclude: []},
mailings: {include: [], exclude: []},
body_html: "",
// Save a (draft) mailing
// @param mailing Object (per APIv3)
// @return Promise
- save: function (mailing) {
+ save: function(mailing) {
var params = angular.extend({}, mailing, {
'api.mailing_job.create': 0 // note: exact match to API default
});
+ // Angular ngModel sometimes treats blank fields as undefined.
+ angular.forEach(mailing, function(value, key) {
+ if (value === undefined) {
+ mailing[key] = '';
+ }
+ });
+
// WORKAROUND: Mailing.create (aka CRM_Mailing_BAO_Mailing::create()) interprets scheduled_date
// as an *intent* to schedule and creates tertiary records. Saving a draft with a scheduled_date
// is therefore not allowed. Remove this after fixing Mailing.create's contract.
delete params.jobs;
- return crmApi('Mailing', 'create', params).then(function (result) {
+ return crmApi('Mailing', 'create', params).then(function(result) {
if (result.id && !mailing.id) {
mailing.id = result.id;
} // no rollback, so update mailing.id
{{ts('This mailing has been submitted.')}}
</div>
-<form name="crmMailing" ng-hide="isSubmitted()" crm-autosave="save()" crm-autosave-model="mailing">
+<form name="crmMailing" ng-hide="isSubmitted()" crm-autosave="save()" crm-autosave-model="mailing" crm-autosave-if="true">
<div class="crm-block crm-form-block crmMailing">
<div crm-mailing-block-summary crm-mailing="mailing"/>
{{ts('This mailing has been submitted.')}}
</div>
-<form name="crmMailing" ng-hide="isSubmitted()" crm-autosave="save()" crm-autosave-model="mailing">
+<form name="crmMailing" ng-hide="isSubmitted()" crm-autosave="save()" crm-autosave-model="mailing" crm-autosave-if="true">
<div class="crm-block crm-form-block crmMailing">
<div crm-mailing-block-summary crm-mailing="mailing"/>
{{ts('This mailing has been submitted.')}}
</div>
-<form name="crmMailing" ng-hide="isSubmitted()" crm-autosave="save()" crm-autosave-model="mailing">
+<form name="crmMailing" ng-hide="isSubmitted()" crm-autosave="save()" crm-autosave-model="mailing" crm-autosave-if="true">
<div class="crm-block crm-form-block crmMailing">
<div crm-ui-wizard>
{{ts('This mailing has been submitted.')}}
</div>
-<form name="crmMailing" novalidate ng-hide="isSubmitted()" crm-autosave="save()" crm-autosave-model="mailing">
+<form name="crmMailing" novalidate ng-hide="isSubmitted()" crm-autosave="save()" crm-autosave-model="mailing" crm-autosave-if="true">
<div class="crm-block crm-form-block crmMailing">
<div crm-ui-wizard>
$cases = array(); // $useLogin, $params, $expectedFailure, $expectedJobCount
$cases[] = array(
TRUE, //useLogin
+ array(), // createParams
array('scheduled_date' => '2014-12-13 10:00:00', 'approval_date' => '2014-12-13 00:00:00'),
FALSE, // expectedFailure
1, // expectedJobCount
);
$cases[] = array(
FALSE, //useLogin
+ array(), // createParams
array('scheduled_date' => '2014-12-13 10:00:00', 'approval_date' => '2014-12-13 00:00:00'),
"/Failed to determine current user/", // expectedFailure
0, // expectedJobCount
);
$cases[] = array(
TRUE, //useLogin
+ array(), // createParams
array('scheduled_date' => '2014-12-13 10:00:00'),
FALSE, // expectedFailure
1, // expectedJobCount
);
$cases[] = array(
TRUE, //useLogin
+ array(), // createParams
array(),
"/Missing parameter scheduled_date and.or approval_date/", // expectedFailure
0, // expectedJobCount
);
+ $cases[] = array(
+ TRUE, //useLogin
+ array('name' => ''), // createParams
+ array('scheduled_date' => '2014-12-13 10:00:00', 'approval_date' => '2014-12-13 00:00:00'),
+ "/Mailing cannot be sent. There are missing fields \\(name\\)./", // expectedFailure
+ 0, // expectedJobCount
+ );
return $cases;
}
/**
* @param bool $useLogin
- * @param array $params
+ * @param array $createParams
+ * @param array $submitParams
* @param null|string $expectedFailure
* @param int $expectedJobCount
* @dataProvider submitProvider
*/
- public function testMailerSubmit($useLogin, $params, $expectedFailure, $expectedJobCount) {
+ public function testMailerSubmit($useLogin, $createParams, $submitParams, $expectedFailure, $expectedJobCount) {
if ($useLogin) {
$this->createLoggedInUser();
}
- $id = $this->createDraftMailing();
+ $id = $this->createDraftMailing($createParams);
- $params['id'] = $id;
+ $submitParams['id'] = $id;
if ($expectedFailure) {
- $submitResult = $this->callAPIFailure('mailing', 'submit', $params);
+ $submitResult = $this->callAPIFailure('mailing', 'submit', $submitParams);
$this->assertRegExp($expectedFailure, $submitResult['error_message']);
}
else {
- $submitResult = $this->callAPIAndDocument('mailing', 'submit', $params, __FUNCTION__, __FILE__);
+ $submitResult = $this->callAPIAndDocument('mailing', 'submit', $submitParams, __FUNCTION__, __FILE__);
$this->assertTrue(is_numeric($submitResult['id']));
$this->assertTrue(is_numeric($submitResult['values'][$id]['scheduled_id']));
- $this->assertEquals($params['scheduled_date'], $submitResult['values'][$id]['scheduled_date']);
+ $this->assertEquals($submitParams['scheduled_date'], $submitResult['values'][$id]['scheduled_date']);
}
$this->assertDBQuery($expectedJobCount, 'SELECT count(*) FROM civicrm_mailing_job WHERE mailing_id = %1', array(
1 => array($id, 'Integer'),
}
/**
+ * @param array $params
+ * Extra parameters for the draft mailing.
* @return array|int
*/
- public function createDraftMailing() {
- $createParams = $this->_params;
+ public function createDraftMailing($params = array()) {
+ $createParams = array_merge($this->_params, $params);
$createParams['api.mailing_job.create'] = 0; // note: exact match to API default
$createResult = $this->callAPISuccess('mailing', 'create', $createParams, __FUNCTION__, __FILE__);
$this->assertTrue(is_numeric($createResult['id']));