mirror of
https://codeberg.org/artfulrobot/contactcats.git
synced 2025-06-26 08:48:04 +02:00
update tests, fix stuff, implement bespoke save, create actions for contactcategory
This commit is contained in:
parent
78e5b83c1d
commit
2ae781f6e3
6 changed files with 273 additions and 29 deletions
28
Civi/Api4/Action/ContactCategory/Create.php
Normal file
28
Civi/Api4/Action/ContactCategory/Create.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
namespace Civi\Api4\Action\ContactCategory;
|
||||
|
||||
use Civi\Api4\Generic\Result;
|
||||
use Civi\Api4\ContactCategory;
|
||||
use CRM_Contactcats_ExtensionUtil as E;
|
||||
|
||||
/**
|
||||
* Create ContactCategory action
|
||||
*
|
||||
* This entity's ID is a unique primary key that references
|
||||
* contact_id. Here we overwrite the validateValues which normally
|
||||
*
|
||||
*/
|
||||
class Create extends \Civi\Api4\Generic\DAOCreateAction {
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function _run(Result $result) {
|
||||
// Wrap Save API
|
||||
$saveResults = ContactCategory::save($this->getCheckPermissions())
|
||||
->addRecord($this->values)
|
||||
->execute()->getArrayCopy();
|
||||
$result->exchangeArray($saveResults);
|
||||
}
|
||||
|
||||
}
|
|
@ -72,6 +72,7 @@ class GetFlows extends \Civi\Api4\Generic\AbstractAction {
|
|||
// $result['windowFunctionsSupported'] = $this->windowFunctionsSupported();
|
||||
// if ($result['windowFunctionsSupported']) {
|
||||
if ($this->windowFunctionsSupported()) {
|
||||
// $this->debug1($startDate, $endDate);
|
||||
$this->solveWithWindowFunctions($result, $startDate, $endDate);
|
||||
}
|
||||
else {
|
||||
|
@ -114,19 +115,75 @@ class GetFlows extends \Civi\Api4\Generic\AbstractAction {
|
|||
return $supported;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected function solveWithWindowFunctions(Result $result, string $startDateYmd, ?string $endDateYmd) {
|
||||
protected function debug1(string $startDateYmd, ?string $endDateYmd) {
|
||||
|
||||
$sql = <<<SQL
|
||||
if (!$endDateYmd) {
|
||||
$endDateYmd = date('Ymd', strtotime('tomorrow'));
|
||||
}
|
||||
$params = [1 => [$startDateYmd, 'Int'], 2 => [$endDateYmd, 'Int']];
|
||||
$params1 = [1 => [$startDateYmd, 'Int']];
|
||||
|
||||
$this->dump("all activities", <<<SQL
|
||||
SELECT ac.contact_id, a.activity_date_time, a.id activity_id
|
||||
FROM civicrm_activity a
|
||||
INNER JOIN civicrm_activity_contact ac
|
||||
ON a.id = ac.activity_id AND ac.record_type_id = 3
|
||||
WHERE a.activity_type_id = $this->activityTypeId
|
||||
SQL);
|
||||
|
||||
$this->dump("all start activities", <<<SQL
|
||||
WITH activities AS (
|
||||
SELECT ac.contact_id, a.activity_date_time, a.id activity_id
|
||||
FROM civicrm_activity a
|
||||
INNER JOIN civicrm_activity_contact ac
|
||||
ON a.id = ac.activity_id AND ac.record_type_id = 3
|
||||
WHERE a.activity_type_id = $this->activityTypeId
|
||||
),
|
||||
|
||||
/* startActivity is the latest activity before the window's start date */
|
||||
startActivity AS (
|
||||
SELECT contact_id, activity_id,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY (contact_id)
|
||||
ORDER BY activity_date_time DESC
|
||||
) rn
|
||||
FROM activities a1
|
||||
WHERE a1.activity_date_time < %1
|
||||
)
|
||||
|
||||
select * from startActivity;
|
||||
SQL, $params1);
|
||||
|
||||
$this->dump("all end activities", <<<SQL
|
||||
WITH activities AS (
|
||||
SELECT ac.contact_id, a.activity_date_time, a.id activity_id
|
||||
FROM civicrm_activity a
|
||||
INNER JOIN civicrm_activity_contact ac
|
||||
ON a.id = ac.activity_id AND ac.record_type_id = 3
|
||||
WHERE a.activity_type_id = $this->activityTypeId
|
||||
),
|
||||
|
||||
/* endActivity is the latest activity before the window's end date */
|
||||
endActivity AS (
|
||||
SELECT contact_id, activity_id,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY (contact_id)
|
||||
ORDER BY activity_date_time DESC
|
||||
) rn
|
||||
FROM activities a2
|
||||
WHERE a2.activity_date_time < %2
|
||||
)
|
||||
|
||||
select * from endActivity;
|
||||
SQL, $params);
|
||||
|
||||
$this->dump("all 2", <<<SQL
|
||||
/* Identify the relevant activities for the contacts */
|
||||
WITH activities AS (
|
||||
SELECT ac.contact_id, a.activity_date_time, a.id activity_id
|
||||
FROM civicrm_activity a
|
||||
INNER JOIN civicrm_activity_contact ac
|
||||
ON a.id = ac.activity_id AND ac.record_type_id = 3
|
||||
/*INNER JOIN civicrm_contact_category cc ON cc.id = ac.contact_id */
|
||||
WHERE a.activity_type_id = $this->activityTypeId
|
||||
),
|
||||
|
||||
|
@ -149,7 +206,68 @@ class GetFlows extends \Civi\Api4\Generic\AbstractAction {
|
|||
ORDER BY activity_date_time DESC
|
||||
) rn
|
||||
FROM activities a2
|
||||
WHERE a2.activity_date_time BETWEEN %1 AND %2
|
||||
WHERE a2.activity_date_time < %2
|
||||
)
|
||||
|
||||
SELECT /*startCat.new_category_id from_category_id, endCat.new_category_id to_category_id,*/
|
||||
endActivity.contact_id endCtID, endActivity.activity_id endAcID,
|
||||
startActivity.contact_id startCtID, startActivity.activity_id startAcID
|
||||
FROM endActivity
|
||||
/* INNER JOIN $this->catChangesTableName endCat
|
||||
ON endActivity.activity_id = endCat.entity_id */
|
||||
LEFT JOIN (
|
||||
startActivity
|
||||
/* INNER JOIN $this->catChangesTableName startCat
|
||||
ON startActivity.activity_id = startCat.entity_id */
|
||||
)
|
||||
ON startActivity.contact_id = endActivity.contact_id AND startActivity.rn = 1
|
||||
WHERE endActivity.rn = 1
|
||||
/*ORDER BY from_category_id, to_category_id*/
|
||||
;
|
||||
SQL, $params);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This SQL uses the change activities to determine the flows between two dates.
|
||||
*
|
||||
* It does so by finding the latest activity before the start date and using it's new_category_id
|
||||
* as the category for that contact on that date, and likewise for the end date.
|
||||
*
|
||||
* It is assumed that a change activity is always present.
|
||||
*/
|
||||
protected function solveWithWindowFunctions(Result $result, string $startDateYmd, ?string $endDateYmd) {
|
||||
|
||||
$sql = <<<SQL
|
||||
/* Identify the relevant activities for the contacts */
|
||||
WITH activities AS (
|
||||
SELECT ac.contact_id, a.activity_date_time, a.id activity_id
|
||||
FROM civicrm_activity a
|
||||
INNER JOIN civicrm_activity_contact ac
|
||||
ON a.id = ac.activity_id AND ac.record_type_id = 3
|
||||
WHERE a.activity_type_id = $this->activityTypeId
|
||||
),
|
||||
|
||||
/* startActivity is the latest activity before the window's start date */
|
||||
startActivity AS (
|
||||
SELECT contact_id, activity_id,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY (contact_id)
|
||||
ORDER BY activity_date_time DESC
|
||||
) rn
|
||||
FROM activities a1
|
||||
WHERE a1.activity_date_time < %1
|
||||
),
|
||||
|
||||
/* endActivity is the latest activity before the window's end date */
|
||||
endActivity AS (
|
||||
SELECT contact_id, activity_id,
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY (contact_id)
|
||||
ORDER BY activity_date_time DESC
|
||||
) rn
|
||||
FROM activities a2
|
||||
WHERE a2.activity_date_time < %2
|
||||
)
|
||||
|
||||
/* join startActivity and endActivity to count changes between each shift */
|
||||
|
@ -188,11 +306,21 @@ class GetFlows extends \Civi\Api4\Generic\AbstractAction {
|
|||
}
|
||||
}
|
||||
|
||||
protected function dump(string $msg, string $sql) {
|
||||
print "\n$msg ===============================\n$sql\n";
|
||||
$data = CRM_Core_DAO::executeQuery($sql)->fetchAll();
|
||||
print_r($data);
|
||||
print "\n ===============================\n";
|
||||
/**
|
||||
* useful in debugging phpunit tests only; unused in normal operation.
|
||||
*/
|
||||
protected function dump(string $msg, string $sql, $params = []) {
|
||||
try {
|
||||
$data = CRM_Core_DAO::executeQuery($sql, $params)->fetchAll();
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
print $e->getCause()->userinfo;
|
||||
}
|
||||
print "\n$msg (" . count($data) . ") records ===============================\n";
|
||||
foreach ($data as $row) {
|
||||
print json_encode($row) . "\n";
|
||||
}
|
||||
print "===============================\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
46
Civi/Api4/Action/ContactCategory/Save.php
Normal file
46
Civi/Api4/Action/ContactCategory/Save.php
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
namespace Civi\Api4\Action\ContactCategory;
|
||||
|
||||
use Civi\Api4\Generic\Result;
|
||||
use CRM_Contactcats_ExtensionUtil as E;
|
||||
use CRM_Core_DAO;
|
||||
|
||||
/**
|
||||
* Create ContactCategory action
|
||||
*
|
||||
* This entity's ID is a unique primary key that references
|
||||
* contact_id. Here we overwrite the validateValues which normally
|
||||
*
|
||||
* @see \Civi\Api4\Generic\AbstractAction
|
||||
*
|
||||
*/
|
||||
class Save extends \Civi\Api4\Generic\DAOSaveAction {
|
||||
|
||||
/**
|
||||
* Allow creating records with ids.
|
||||
*
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function _run(Result $result) {
|
||||
$ids = [];
|
||||
foreach (array_column($this->records, 'id') as $id) {
|
||||
if ($id) {
|
||||
$ids[] = (int) $id;
|
||||
}
|
||||
}
|
||||
if ($ids) {
|
||||
$idsList = implode(",", array_filter($ids));
|
||||
$preExisting = array_column(CRM_Core_DAO::executeQuery(
|
||||
"SELECT id FROM civicrm_contact_category WHERE id IN ($idsList)"
|
||||
)->fetchAll(), 'id');
|
||||
// Any where we were given an ID that doesn't exist are important.
|
||||
foreach (array_diff($ids, $preExisting) as $unknownID) {
|
||||
CRM_Core_DAO::executeQuery("INSERT INTO civicrm_contact_category (id) VALUES ($unknownID)");
|
||||
}
|
||||
}
|
||||
|
||||
// Now let it proceed as normal.
|
||||
parent::_run($result);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,8 @@ namespace Civi\Api4;
|
|||
|
||||
use Civi\Api4\Action\ContactCategory\GetFlows;
|
||||
use Civi\Api4\Action\ContactCategory\Sync;
|
||||
use Civi\Api4\Action\ContactCategory\Create;
|
||||
use Civi\Api4\Action\ContactCategory\Save;
|
||||
|
||||
/**
|
||||
* ContactCategory entity.
|
||||
|
@ -13,6 +15,24 @@ use Civi\Api4\Action\ContactCategory\Sync;
|
|||
*/
|
||||
class ContactCategory extends Generic\DAOEntity {
|
||||
|
||||
/**
|
||||
* @param bool $checkPermissions
|
||||
* @return \Civi\Api4\Action\ContactCategory\Create
|
||||
*/
|
||||
public static function create($checkPermissions = TRUE) {
|
||||
return (new Create(static::getEntityName(), __FUNCTION__))
|
||||
->setCheckPermissions($checkPermissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $checkPermissions
|
||||
* @return \Civi\Api4\Action\ContactCategory\Save
|
||||
*/
|
||||
public static function save($checkPermissions = TRUE) {
|
||||
return (new Save(static::getEntityName(), __FUNCTION__))
|
||||
->setCheckPermissions($checkPermissions);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue