From 6565e243f275bd5f9ceea50bc58c44582d9349e9 Mon Sep 17 00:00:00 2001 From: colemanw Date: Fri, 3 Nov 2023 23:28:55 -0400 Subject: [PATCH] APIv4 - Add is_draft field for mailings, fix test Figuring out if a mailing is a draft or not can be tricky. This encapsulates the tricky-ness in a reusable calculated field. --- .../Spec/Provider/MailingGetSpecProvider.php | 22 ++++++++ ...{MailingEvent.php => MailingEventTest.php} | 55 ++++++++++++++----- 2 files changed, 63 insertions(+), 14 deletions(-) rename tests/phpunit/api/v4/Entity/{MailingEvent.php => MailingEventTest.php} (75%) diff --git a/Civi/Api4/Service/Spec/Provider/MailingGetSpecProvider.php b/Civi/Api4/Service/Spec/Provider/MailingGetSpecProvider.php index c66482debd..9a10292a8c 100644 --- a/Civi/Api4/Service/Spec/Provider/MailingGetSpecProvider.php +++ b/Civi/Api4/Service/Spec/Provider/MailingGetSpecProvider.php @@ -12,6 +12,7 @@ namespace Civi\Api4\Service\Spec\Provider; +use Civi\Api4\Query\Api4SelectQuery; use Civi\Api4\Service\Spec\FieldSpec; use Civi\Api4\Service\Spec\RequestSpec; @@ -27,6 +28,14 @@ class MailingGetSpecProvider extends \Civi\Core\Service\AutoService implements G * @throws \CRM_Core_Exception */ public function modifySpec(RequestSpec $spec): void { + $field = new FieldSpec('is_draft', 'Mailing', 'Boolean'); + $field->setLabel(ts('Is Draft')) + ->setDescription(ts('True if mailing has not been scheduled or sent')) + ->setColumnName('id') + ->setReadonly(TRUE) + ->setSqlRenderer([__CLASS__, 'isDraft']); + $spec->addFieldSpec($field); + $field = new FieldSpec('stats_intended_recipients', 'Mailing', 'Integer'); $field->setLabel(ts('Stats: Intended Recipients')) ->setDescription(ts('Total emails sent')) @@ -134,6 +143,19 @@ class MailingGetSpecProvider extends \Civi\Core\Service\AutoService implements G return $entity === 'Mailing' && $action === 'get'; } + /** + * Check if mailing has not been scheduled by anyone and has no record in MailingJob table. + * + * @param array $idField + * @param \Civi\Api4\Query\Api4SelectQuery $query + * @return string + */ + public static function isDraft(array $idField, Api4SelectQuery $query): string { + $id = $idField['sql_name']; + $scheduled_id = $query->getFieldSibling($idField, 'scheduled_id')['sql_name']; + return "IF($scheduled_id OR EXISTS (SELECT 1 FROM civicrm_mailing_job WHERE is_test = 0 AND mailing_id = $id), 0, 1)"; + } + /** * Generate SQL for counting mailing events * diff --git a/tests/phpunit/api/v4/Entity/MailingEvent.php b/tests/phpunit/api/v4/Entity/MailingEventTest.php similarity index 75% rename from tests/phpunit/api/v4/Entity/MailingEvent.php rename to tests/phpunit/api/v4/Entity/MailingEventTest.php index d0b2db70ee..f626c4a74b 100644 --- a/tests/phpunit/api/v4/Entity/MailingEvent.php +++ b/tests/phpunit/api/v4/Entity/MailingEventTest.php @@ -19,6 +19,7 @@ namespace api\v4\Entity; use api\v4\Api4TestBase; +use Civi\Api4\Mailing; use Civi\Test\TransactionalInterface; /** @@ -33,29 +34,53 @@ class MailingEventTest extends Api4TestBase implements TransactionalInterface { $eid2 = $this->createTestRecord('Email', ['contact_id' => $cid2])['id']; $mid1 = $this->createTestRecord('Mailing')['id']; $mid2 = $this->createTestRecord('Mailing')['id']; - $parentJobIDs = $this->saveTestRecords('MailingJob', - [ - 'records' => [ - ['mailing_id' => $mid1, 'is_test' => 'false'], - ['mailing_id' => $mid2, 'is_test' => 'false'], - ], - ])->column('id'); + $parentJobIDs = $this->saveTestRecords('MailingJob', [ + 'records' => [ + ['mailing_id' => $mid1, 'is_test' => FALSE], + ['mailing_id' => $mid2, 'is_test' => TRUE], + ], + ])->column('id'); + + // Test is_draft field + $mailings = Mailing::get(FALSE) + ->addSelect('id', 'is_draft') + ->addWhere('id', 'IN', [$mid1, $mid2]) + ->execute()->indexBy('id'); + $this->assertFalse($mailings[$mid1]['is_draft']); + $this->assertTrue($mailings[$mid2]['is_draft']); + + Mailing::update(FALSE) + ->addWhere('id', '=', $mid2) + ->addValue('scheduled_id', $cid1) + ->execute(); + + $mailings = Mailing::get(FALSE) + ->addSelect('id', 'is_draft') + ->addWhere('id', 'IN', [$mid1, $mid2]) + ->execute()->indexBy('id'); + $this->assertFalse($mailings[$mid1]['is_draft']); + $this->assertFalse($mailings[$mid2]['is_draft']); + + $parentJobIDs[] = $this->createTestRecord('MailingJob', [ + 'mailing_id' => $mid2, + 'is_test' => FALSE, + ])['id']; $childJobIDs = $this->saveTestRecords('MailingJob', [ 'records' => [ ['mailing_id' => $mid1, 'parent_id' => $parentJobIDs[0], 'job_type' => 'child', 'is_test' => 'false'], - ['mailing_id' => $mid2, 'parent_id' => $parentJobIDs[1], 'job_type' => 'child', 'is_test' => 'false'], + ['mailing_id' => $mid2, 'parent_id' => $parentJobIDs[2], 'job_type' => 'child', 'is_test' => 'false'], ], ])->column('id'); $queueIDs = $this->saveTestRecords('MailingEventQueue', [ 'records' => [ - ['job_id' => $childJobIDs[0], 'contact_id' => $cid1, 'email_id' => $eid1], - ['job_id' => $childJobIDs[0], 'contact_id' => $cid2, 'email_id' => $eid2], - ['job_id' => $childJobIDs[1], 'contact_id' => $cid1, 'email_id' => $eid1], - ['job_id' => $childJobIDs[1], 'contact_id' => $cid2, 'email_id' => $eid2], + ['job_id' => $childJobIDs[0], 'mailing_id' => $mid1, 'contact_id' => $cid1, 'email_id' => $eid1], + ['job_id' => $childJobIDs[0], 'mailing_id' => $mid1, 'contact_id' => $cid2, 'email_id' => $eid2], + ['job_id' => $childJobIDs[1], 'mailing_id' => $mid2, 'contact_id' => $cid1, 'email_id' => $eid1], + ['job_id' => $childJobIDs[1], 'mailing_id' => $mid2, 'contact_id' => $cid2, 'email_id' => $eid2], ], ])->column('id'); @@ -108,10 +133,10 @@ class MailingEventTest extends Api4TestBase implements TransactionalInterface { ], ]); - $mailings = \Civi\Api4\Mailing::get(FALSE) + $mailings = Mailing::get(FALSE) ->addSelect('stats_intended_recipients', 'stats_successful', 'stats_opens_total', 'stats_opens_unique', 'stats_clicks_total', 'stats_clicks_unique', 'stats_bounces', 'stats_unsubscribes', 'stats_optouts', - 'stats_optouts_and_unsubscribes', 'stats_forwards', 'stats_replies') + 'stats_optouts_and_unsubscribes', 'stats_forwards', 'stats_replies', 'is_draft') ->addWhere('id', 'IN', [$mid1, $mid2]) ->addOrderBy('id', 'ASC') ->execute(); @@ -140,6 +165,8 @@ class MailingEventTest extends Api4TestBase implements TransactionalInterface { $this->assertEquals(0, $mailings[1]['stats_optouts']); $this->assertEquals(2, $mailings[0]['stats_optouts_and_unsubscribes']); $this->assertEquals(0, $mailings[1]['stats_optouts_and_unsubscribes']); + $this->assertFalse($mailings[0]['is_draft']); + $this->assertFalse($mailings[1]['is_draft']); } } -- 2.25.1