From dd04248c7dae76b97076f319f45ece1f1cbf9804 Mon Sep 17 00:00:00 2001 From: Jon Goldberg Date: Sun, 8 Aug 2021 16:21:09 -0400 Subject: [PATCH] financial#121: Support modifying Soft Credit permissions via hook Re-instate membership filter that got 'lost' --- CRM/Contribute/BAO/Contribution.php | 3 +- CRM/Contribute/BAO/ContributionSoft.php | 206 ++++++++---------- CRM/Core/Permission.php | 1 + CRM/Member/Page/Tab.php | 10 +- Civi/Api4/PCP.php | 22 ++ .../Civi/Financialacls/BaseTestClass.php | 48 +++- .../Financialacls/ContributionSoftTest.php | 177 +++++++++++++++ .../Civi/Financialacls/LineItemTest.php | 9 +- 8 files changed, 350 insertions(+), 126 deletions(-) create mode 100644 Civi/Api4/PCP.php create mode 100644 ext/financialacls/tests/phpunit/Civi/Financialacls/ContributionSoftTest.php diff --git a/CRM/Contribute/BAO/Contribution.php b/CRM/Contribute/BAO/Contribution.php index 28ed2129bb..7d475c5d43 100644 --- a/CRM/Contribute/BAO/Contribution.php +++ b/CRM/Contribute/BAO/Contribution.php @@ -2156,7 +2156,8 @@ LEFT JOIN civicrm_contribution contribution ON ( componentPayment.contribution_ SELECT contribution.id FROM civicrm_contribution contribution INNER JOIN civicrm_contribution_soft softContribution ON ( contribution.id = softContribution.contribution_id ) - WHERE contribution.is_test = 0 AND contribution.is_template != '1' AND softContribution.contact_id = {$contactId} "; + WHERE contribution.is_test = 0 AND contribution.is_template != '1' AND softContribution.contact_id = {$contactId} + $additionalWhere "; $query = "SELECT count( x.id ) count FROM ( "; $query .= $contactContributionsSQL; diff --git a/CRM/Contribute/BAO/ContributionSoft.php b/CRM/Contribute/BAO/ContributionSoft.php index 56f5251550..4c140ca5e2 100644 --- a/CRM/Contribute/BAO/ContributionSoft.php +++ b/CRM/Contribute/BAO/ContributionSoft.php @@ -10,6 +10,7 @@ */ use Civi\Api4\Contribution; +use Civi\Api4\ContributionSoft; /** * @@ -198,45 +199,33 @@ class CRM_Contribute_BAO_ContributionSoft extends CRM_Contribute_DAO_Contributio */ public static function getSoftContributionTotals($contact_id, $isTest = 0) { - $whereClause = "AND cc.cancel_date IS NULL"; + $contributionSofts = ContributionSoft::get() + ->addSelect('currency', 'SUM(amount) AS SUM_amount', 'AVG(amount) AS AVG_amount', 'COUNT(id) AS COUNT_id') + ->setGroupBy([ + 'currency', + ]) + ->addWhere('contact_id', '=', $contact_id) + ->addWhere('contribution_id.is_test', '=', $isTest); - $query = " - SELECT SUM(amount) as amount, AVG(total_amount) as average, cc.currency - FROM civicrm_contribution_soft ccs - LEFT JOIN civicrm_contribution cc ON ccs.contribution_id = cc.id - WHERE cc.is_test = %2 AND ccs.contact_id = %1 {$whereClause} - GROUP BY currency"; - - $params = [ - 1 => [$contact_id, 'Integer'], - 2 => [$isTest, 'Integer'], - ]; - - $cs = CRM_Core_DAO::executeQuery($query, $params); + $contributionSoftsNoCancel = $contributionSofts->addWhere('contribution_id.cancel_date', 'IS NULL')->execute(); + $contributionSoftsYesCancel = $contributionSofts->addWhere('contribution_id.cancel_date', 'IS NOT NULL')->execute(); $count = $countCancelled = 0; $amount = $average = $cancelAmount = []; - while ($cs->fetch()) { - if ($cs->amount > 0) { - $count++; - $amount[] = CRM_Utils_Money::format($cs->amount, $cs->currency); - $average[] = CRM_Utils_Money::format($cs->average, $cs->currency); - } + foreach ($contributionSoftsNoCancel as $csByCurrency) { + $count += $csByCurrency['COUNT_id']; + $amount[] = CRM_Utils_Money::format($csByCurrency['SUM_amount'], $csByCurrency['currency']); + $average[] = CRM_Utils_Money::format($csByCurrency['AVG_amount'], $csByCurrency['currency']); } //to get cancel amount - $cancelAmountWhereClause = "AND cc.cancel_date IS NOT NULL"; - $query = str_replace($whereClause, $cancelAmountWhereClause, $query); - $cancelAmountSQL = CRM_Core_DAO::executeQuery($query, $params); - while ($cancelAmountSQL->fetch()) { - if ($cancelAmountSQL->amount > 0) { - $countCancelled++; - $cancelAmount[] = CRM_Utils_Money::format($cancelAmountSQL->amount, $cancelAmountSQL->currency); - } + foreach ($contributionSoftsYesCancel as $csByCurrency) { + $countCancelled += $csByCurrency['COUNT_id']; + $amount[] = CRM_Utils_Money::format($csByCurrency['SUM_amount'], $csByCurrency['currency']); } - if ($count > 0 || $countCancelled > 0) { + if ($contributionSoftsNoCancel->rowCount || $contributionSoftsYesCancel->rowCount) { return [ $count, $countCancelled, @@ -361,8 +350,11 @@ class CRM_Contribute_BAO_ContributionSoft extends CRM_Contribute_DAO_Contributio * * @return array * Associated array of soft contributions + * + * @throws \API_Exception + * @throws \CRM_Core_Exception */ - public static function getSoftContributionSelector($params) { + public static function getSoftContributionSelector($params): array { $isTest = 0; if (!empty($params['isTest'])) { $isTest = $params['isTest']; @@ -373,12 +365,7 @@ class CRM_Contribute_BAO_ContributionSoft extends CRM_Contribute_DAO_Contributio $params['sort'] = $params['sortBy'] ?? NULL; $contactId = $params['cid']; - $filter = NULL; - if ($params['context'] === 'membership' && !empty($params['entityID']) && $contactId) { - $filter = " AND cc.id IN (SELECT contribution_id FROM civicrm_membership_payment WHERE membership_id = {$params['entityID']})"; - } - - $softCreditList = self::getSoftContributionList($contactId, $filter, $isTest, $params); + $softCreditList = self::getSoftContributionList($contactId, $params['entityID'] ?? NULL, $isTest, $params); $softCreditListDT = []; $softCreditListDT['data'] = array_values($softCreditList); @@ -393,15 +380,26 @@ class CRM_Contribute_BAO_ContributionSoft extends CRM_Contribute_DAO_Contributio * * @param int $contact_id * Contact id. - * @param string $filter + * @param ?int $membershipID * @param int $isTest * Additional filter criteria, later used in where clause. - * @param array $dTParams + * @param null $dTParams * * @return array - * @throws \CRM_Core_Exception + * + * @throws \API_Exception */ - public static function getSoftContributionList($contact_id, $filter = NULL, $isTest = 0, &$dTParams = NULL) { + public static function getSoftContributionList($contact_id, ?int $membershipID = NULL, $isTest = 0, &$dTParams = NULL): array { + // This is necessary for dataTables sorting. + $dataTableMapping = [ + 'sct_label' => 'soft_credit_type_id:label', + 'contributor_name' => 'contact.sort_name', + 'financial_type' => 'contribution_id.financial_type_id:label', + 'contribution_status' => 'contribution_id.contribution_status_id:label', + 'receive_date' => 'contribution.receive_date', + 'pcp_title' => 'pcp_id.title', + 'amount' => 'amount', + ]; $config = CRM_Core_Config::singleton(); $links = [ CRM_Core_Action::VIEW => [ @@ -411,91 +409,64 @@ class CRM_Contribute_BAO_ContributionSoft extends CRM_Contribute_DAO_Contributio 'title' => ts('View related contribution'), ], ]; - $orderBy = 'cc.receive_date DESC'; - if (!empty($dTParams['sort'])) { - $orderBy = $dTParams['sort']; + + $contributionSofts = ContributionSoft::get() + ->addSelect('*', 'contribution_id.receive_date', 'contribution_id.contact_id', 'contribution_id.contact_id.display_name', 'soft_credit_type_id:label', 'contribution_id.contribution_status_id:label', 'contribution_id.financial_type_id:label', 'pcp_id.title') + ->addWhere('contact_id', '=', $contact_id) + ->addWhere('contribution_id.is_test', '=', $isTest); + + if ($membershipID) { + $contributionSofts->addJoin('LineItem', 'INNER', NULL, + ['lineitem.contribution_id', '=', 'contribution_id'], + ['lineitem.entity_id', '=', $membershipID], + ['lineitem.entity_table', '=', '"civicrm_membership"'] + ); } - $limit = ''; + if (!empty($dTParams['rowCount']) && $dTParams['rowCount'] > 0) { - $limit = " LIMIT {$dTParams['offset']}, {$dTParams['rowCount']} "; + $contributionSofts + ->setLimit($dTParams['rowCount']) + ->setOffset($dTParams['offset'] ?? 0); } - $softOgId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'soft_credit_type', 'id', 'name'); - $statusOgId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'contribution_status', 'id', 'name'); - - $query = ' - SELECT SQL_CALC_FOUND_ROWS ccs.id, ccs.amount as amount, - ccs.contribution_id, - ccs.pcp_id, - ccs.pcp_display_in_roll, - ccs.pcp_roll_nickname, - ccs.pcp_personal_note, - ccs.soft_credit_type_id, - sov.label as sct_label, - cc.receive_date, - cc.contact_id as contributor_id, - cc.contribution_status_id as contribution_status_id, - cov.label as contribution_status, - cp.title as pcp_title, - cc.currency, - contact.display_name as contributor_name, - cct.name as financial_type - FROM civicrm_contribution_soft ccs - LEFT JOIN civicrm_contribution cc - ON ccs.contribution_id = cc.id - LEFT JOIN civicrm_pcp cp - ON ccs.pcp_id = cp.id - LEFT JOIN civicrm_contact contact ON - ccs.contribution_id = cc.id AND cc.contact_id = contact.id - LEFT JOIN civicrm_financial_type cct ON cc.financial_type_id = cct.id - LEFT JOIN civicrm_option_value sov ON sov.option_group_id = %3 AND ccs.soft_credit_type_id = sov.value - LEFT JOIN civicrm_option_value cov ON cov.option_group_id = %4 AND cc.contribution_status_id = cov.value - '; - - $where = " - WHERE cc.is_test = %2 AND ccs.contact_id = %1"; - if ($filter) { - $where .= $filter; - } - - $query .= "{$where} ORDER BY {$orderBy} {$limit}"; - $params = [ - 1 => [$contact_id, 'Integer'], - 2 => [$isTest, 'Integer'], - 3 => [$softOgId, 'Integer'], - 4 => [$statusOgId, 'Integer'], - ]; - $cs = CRM_Core_DAO::executeQuery($query, $params); + if (!empty($dTParams['sort'])) { + [$sortField, $direction] = explode(' ', $dTParams['sort']); + $contributionSofts->addOrderBy($dataTableMapping[$sortField] ?: $sortField, strtoupper($direction)); + } + else { + $contributionSofts->addOrderBy('contribution_id.receive_date', 'DESC'); + } + $contributionSofts = $contributionSofts->execute(); - $dTParams['total'] = CRM_Core_DAO::singleValueQuery('SELECT FOUND_ROWS()'); + $dTParams['total'] = $contributionSofts->rowCount; $result = []; - while ($cs->fetch()) { - $result[$cs->id]['amount'] = Civi::format()->money($cs->amount, $cs->currency); - $result[$cs->id]['currency'] = $cs->currency; - $result[$cs->id]['contributor_id'] = $cs->contributor_id; - $result[$cs->id]['contribution_id'] = $cs->contribution_id; - $result[$cs->id]['contributor_name'] = CRM_Utils_System::href( - $cs->contributor_name, + foreach ($contributionSofts as $cs) { + $result[$cs['id']]['amount'] = Civi::format()->money($cs['amount'], $cs['currency']); + $result[$cs['id']]['currency'] = $cs['currency']; + $result[$cs['id']]['contributor_id'] = $cs['contribution_id.contact_id']; + $result[$cs['id']]['contribution_id'] = $cs['contribution_id']; + $result[$cs['id']]['contributor_name'] = CRM_Utils_System::href( + $cs['contribution_id.contact_id.display_name'], 'civicrm/contact/view', - "reset=1&cid={$cs->contributor_id}" + "reset=1&cid={$cs['contribution_id.contact_id']}" ); - $result[$cs->id]['financial_type'] = $cs->financial_type; - $result[$cs->id]['receive_date'] = CRM_Utils_Date::customFormat($cs->receive_date, $config->dateformatDatetime); - $result[$cs->id]['pcp_id'] = $cs->pcp_id; - $result[$cs->id]['pcp_title'] = ($cs->pcp_title) ? $cs->pcp_title : 'n/a'; - $result[$cs->id]['pcp_display_in_roll'] = $cs->pcp_display_in_roll; - $result[$cs->id]['pcp_roll_nickname'] = $cs->pcp_roll_nickname; - $result[$cs->id]['pcp_personal_note'] = $cs->pcp_personal_note; - $result[$cs->id]['contribution_status'] = $cs->contribution_status; - $result[$cs->id]['sct_label'] = $cs->sct_label; + $result[$cs['id']]['financial_type'] = $cs['contribution_id.financial_type_id:label']; + $result[$cs['id']]['receive_date'] = CRM_Utils_Date::customFormat($cs['contribution_id.receive_date'], $config->dateformatDatetime); + $result[$cs['id']]['pcp_id'] = $cs['pcp_id']; + $result[$cs['id']]['pcp_title'] = ($cs['pcp_id.title'] ?? 'n/a'); + $result[$cs['id']]['pcp_display_in_roll'] = $cs['pcp_display_in_roll']; + $result[$cs['id']]['pcp_roll_nickname'] = $cs['pcp_roll_nickname']; + $result[$cs['id']]['pcp_personal_note'] = $cs['pcp_personal_note']; + $result[$cs['id']]['contribution_status'] = $cs['contribution_id.contribution_status_id:label']; + $result[$cs['id']]['sct_label'] = $cs['soft_credit_type_id:label']; $replace = [ - 'contributionid' => $cs->contribution_id, - 'contactId' => $cs->contributor_id, + 'contributionid' => $cs['contribution_id'], + 'contactId' => $cs['contribution_id.contact_id'], ]; - $result[$cs->id]['links'] = CRM_Core_Action::formLink($links, NULL, $replace); + $result[$cs['id']]['links'] = CRM_Core_Action::formLink($links, NULL, $replace); if ($isTest) { - $result[$cs->id]['contribution_status'] = CRM_Core_TestEntity::appendTestText($result[$cs->id]['contribution_status']); + $result[$cs['id']]['contribution_status'] = CRM_Core_TestEntity::appendTestText($result[$cs['id']]['contribution_status']); } } return $result; @@ -678,4 +649,13 @@ class CRM_Contribute_BAO_ContributionSoft extends CRM_Contribute_DAO_Contributio } } + /** + * @inheritDoc + */ + public function addSelectWhereClause(): array { + $clauses['contribution_id'] = CRM_Utils_SQL::mergeSubquery('Contribution'); + CRM_Utils_Hook::selectWhereClause($this, $clauses); + return $clauses; + } + } diff --git a/CRM/Core/Permission.php b/CRM/Core/Permission.php index 0ae7e33163..cc6a600950 100644 --- a/CRM/Core/Permission.php +++ b/CRM/Core/Permission.php @@ -1157,6 +1157,7 @@ class CRM_Core_Permission { $permissions['entity_financial_account']['get'] = $permissions['contribution']['get']; $permissions['financial_account']['get'] = $permissions['contribution']['get']; $permissions['financial_trxn']['get'] = $permissions['contribution']['get']; + $permissions['contribution_soft'] = $permissions['contribution']; // Payment permissions $permissions['payment'] = [ diff --git a/CRM/Member/Page/Tab.php b/CRM/Member/Page/Tab.php index 085212a2e8..a14bbceda2 100644 --- a/CRM/Member/Page/Tab.php +++ b/CRM/Member/Page/Tab.php @@ -297,8 +297,7 @@ class CRM_Member_Page_Tab extends CRM_Core_Page { //show associated soft credit when contribution payment is paid by different person in edit mode if ($this->_id && $this->_contactId) { - $filter = " AND cc.id IN (SELECT contribution_id FROM civicrm_membership_payment WHERE membership_id = {$this->_id})"; - $softCreditList = CRM_Contribute_BAO_ContributionSoft::getSoftContributionList($this->_contactId, $filter); + $softCreditList = CRM_Contribute_BAO_ContributionSoft::getSoftContributionList($this->_contactId, $this->_id); if (!empty($softCreditList)) { $this->assign('softCredit', TRUE); $this->assign('softCreditRows', $softCreditList); @@ -350,9 +349,11 @@ class CRM_Member_Page_Tab extends CRM_Core_Page { } /** - * the main function that is called when the page loads, it decides the which action has to be taken for the page. + * the main function that is called when the page loads, it decides the which + * action has to be taken for the page. * * @return null + * @throws \API_Exception */ public function run() { $this->preProcess(); @@ -372,8 +373,7 @@ class CRM_Member_Page_Tab extends CRM_Core_Page { //show associated soft credit when contribution payment is paid by different person if ($this->_id && $this->_contactId) { - $filter = " AND cc.id IN (SELECT contribution_id FROM civicrm_membership_payment WHERE membership_id = {$this->_id})"; - $softCreditList = CRM_Contribute_BAO_ContributionSoft::getSoftContributionList($this->_contactId, $filter); + $softCreditList = CRM_Contribute_BAO_ContributionSoft::getSoftContributionList($this->_contactId, $this->_id); if (!empty($softCreditList)) { $this->assign('softCredit', TRUE); $this->assign('softCreditRows', $softCreditList); diff --git a/Civi/Api4/PCP.php b/Civi/Api4/PCP.php new file mode 100644 index 0000000000..626a0cde65 --- /dev/null +++ b/Civi/Api4/PCP.php @@ -0,0 +1,22 @@ +installMe(__DIR__) ->apply(); } + /** + * @throws \API_Exception + * @throws \Civi\API\Exception\UnauthorizedException + */ + public function tearDown(): void { + Contribution::delete(FALSE)->addWhere('id', '>', 0)->execute(); + FinancialType::delete(FALSE)->addWhere('name', 'LIKE', '%test%')->execute(); + $this->cleanupPriceSets(); + } + /** * Set ACL permissions, overwriting any existing ones. * * @param array $permissions * Array of permissions e.g ['access CiviCRM','access CiviContribute'], */ - protected function setPermissions(array $permissions) { + protected function setPermissions(array $permissions): void { \CRM_Core_Config::singleton()->userPermissionClass->permissions = $permissions; if (isset(\Civi::$statics['CRM_Financial_BAO_FinancialType'])) { unset(\Civi::$statics['CRM_Financial_BAO_FinancialType']); @@ -63,6 +77,7 @@ class BaseTestClass extends \PHPUnit\Framework\TestCase implements HeadlessInter 'delete contributions of type Donation', 'add contributions of type Donation', 'edit contributions of type Donation', + 'view all contacts', ]); \Civi::settings()->set('acl_financial_type', TRUE); $this->createLoggedInUser(); @@ -103,4 +118,27 @@ class BaseTestClass extends \PHPUnit\Framework\TestCase implements HeadlessInter ->execute()->indexBy('id')); } + /** + * Delete extraneous price sets. + * + * @throws \API_Exception + */ + protected function cleanupPriceSets(): void { + $addedPriceSets = array_keys((array) PriceSet::get(FALSE) + ->addWhere('name', 'NOT IN', [ + 'default_contribution_amount', + 'default_membership_type_amount', + ])->execute()->indexBy('id')); + if (empty($addedPriceSets)) { + return; + } + PriceFieldValue::delete(FALSE) + ->addWhere('price_field_id.price_set_id', 'IN', $addedPriceSets) + ->execute(); + PriceField::delete(FALSE) + ->addWhere('price_set_id', 'IN', $addedPriceSets) + ->execute(); + PriceSet::delete(FALSE)->addWhere('id', 'IN', $addedPriceSets)->execute(); + } + } diff --git a/ext/financialacls/tests/phpunit/Civi/Financialacls/ContributionSoftTest.php b/ext/financialacls/tests/phpunit/Civi/Financialacls/ContributionSoftTest.php new file mode 100644 index 0000000000..03af360df3 --- /dev/null +++ b/ext/financialacls/tests/phpunit/Civi/Financialacls/ContributionSoftTest.php @@ -0,0 +1,177 @@ +createTwoSoftCredits(); + $expectedCredits = [ + 1 => [ + 'amount' => '$100.00', + 'currency' => 'USD', + 'contributor_id' => $this->ids['Contact'][0], + 'contribution_id' => $this->ids['Contribution']['permitted'], + 'contributor_name' => CRM_Utils_System::href( + 'Mr. Anthony Anderson II', + 'civicrm/contact/view', + 'reset=1&cid=' . $this->ids['Contact'][0] + ), + 'financial_type' => 'Donation', + 'pcp_id' => NULL, + 'pcp_title' => 'n/a', + 'pcp_display_in_roll' => FALSE, + 'pcp_roll_nickname' => NULL, + 'pcp_personal_note' => NULL, + 'contribution_status' => 'Completed', + 'sct_label' => NULL, + ], + 2 => [ + 'amount' => '$200.00', + 'currency' => 'USD', + 'contributor_id' => $this->ids['Contact'][1], + 'contribution_id' => $this->ids['Contribution'][1], + 'contributor_name' => CRM_Utils_System::href( + 'Mr. Anthony Anderson II', + 'civicrm/contact/view', + 'reset=1&cid=' . $this->ids['Contact'][1] + ), + 'financial_type' => 'Campaign Contribution', + 'pcp_id' => NULL, + 'pcp_title' => 'n/a', + 'pcp_display_in_roll' => FALSE, + 'pcp_roll_nickname' => NULL, + 'pcp_personal_note' => NULL, + 'contribution_status' => 'Completed', + 'sct_label' => NULL, + ], + ]; + $list = CRM_Contribute_BAO_ContributionSoft::getSoftContributionList($this->ids['Contact']['credited']); + foreach ($expectedCredits[1] as $key => $value) { + $this->assertEquals($value, $list[1][$key], $key); + } + foreach ($expectedCredits[2] as $key => $value) { + $this->assertEquals($value, $list[2][$key], $key); + } + $this->assertEquals($this->ids['Contribution']['permitted'], $list[1]['contribution_id']); + + // And with ACL restrictions. + $this->setupLoggedInUserWithLimitedFinancialTypeAccess(); + $list = CRM_Contribute_BAO_ContributionSoft::getSoftContributionList($this->ids['Contact']['credited']); + $this->assertArrayNotHasKey(2, $list); + CRM_Core_DAO::executeQuery('DROP TABLE IF EXISTS ac'); + CRM_Core_DAO::executeQuery('CREATE TABLE ac SELECT id FROM civicrm_relationship'); + foreach ($expectedCredits[1] as $key => $value) { + $this->assertEquals($value, $list[1][$key], $key); + } + } + + /** + * Test getSoftContributionTotals method. + * + */ + public function testGetSoftContributionTotals(): void { + $this->createTwoSoftCredits(); + $totals = CRM_Contribute_BAO_ContributionSoft::getSoftContributionTotals($this->ids['Contact']['credited']); + $this->assertEquals('$ 300.00', $totals[2], 'test total of completed soft credits'); + $this->assertEquals('$ 150.00', $totals[3], 'test average of completed soft credits'); + $this->assertEquals('', $totals[4], 'test count of cancelled soft credits'); + + // And again, with ACLs enabled. + $this->setupLoggedInUserWithLimitedFinancialTypeAccess(); + + $totals = CRM_Contribute_BAO_ContributionSoft::getSoftContributionTotals($this->ids['Contact']['credited']); + $this->assertEquals('$ 100.00', $totals[2], 'test total of completed soft credits'); + $this->assertEquals('$ 100.00', $totals[3], 'test average of completed soft credits'); + $this->assertEquals('', $totals[4], 'test count of cancelled soft credits'); + } + + /** + * Creates two donor contacts and one soft credited contact. + * + * Creates a contribution for each donor contact, soft crediting the credited. + * The contributions have different financial types ("Donation" and "Campaign Contribution") + * to facilitate testing ACLs. + * + * @return array + */ + protected function createTwoSoftCredits(): array { + try { + $this->ids['Contact'][0] = $this->individualCreate(); + $this->ids['Contact'][1] = $this->individualCreate(); + $this->ids['Contact']['credited'] = $this->individualCreate(); + $this->ids['Contribution']['permitted'] = $this->contributionCreate([ + 'financial_type_id:name' => 'Donation', + 'contact_id' => $this->ids['Contact'][0], + ]); + $this->ids['Contribution'][1] = $this->contributionCreate([ + 'financial_type_id:name' => 'Campaign Contribution', + 'contact_id' => $this->ids['Contact'][1], + 'total_amount' => 100, + ]); + + $params = [ + 'contribution_id' => $this->ids['Contribution']['permitted'], + 'amount' => 100, + 'contact_id' => $this->ids['Contact']['credited'], + ]; + ContributionSoft::create(FALSE)->setValues($params)->execute(); + $params2 = [ + 'contribution_id' => $this->ids['Contribution'][1], + 'amount' => 200, + 'contact_id' => $this->ids['Contact']['credited'], + ]; + ContributionSoft::create(FALSE)->setValues($params2)->execute(); + } + catch (API_Exception $e) { + $this->fail($e->getMessage()); + } + return []; + } + + /** + * Create a contribution with some useful defaults. + * + * @param array $params + * + * @return int + * @throws \API_Exception + */ + private function contributionCreate(array $params): int { + return Contribution::create(FALSE)->setValues(array_merge([ + 'receive_date' => 'now', + 'total_amount' => 150.00, + 'payment_instrument_id' => 1, + 'contribution_status_id' => 1, + ], $params))->execute()->first()['id']; + } + +} diff --git a/ext/financialacls/tests/phpunit/Civi/Financialacls/LineItemTest.php b/ext/financialacls/tests/phpunit/Civi/Financialacls/LineItemTest.php index 60692e2a29..75d57c8a49 100644 --- a/ext/financialacls/tests/phpunit/Civi/Financialacls/LineItemTest.php +++ b/ext/financialacls/tests/phpunit/Civi/Financialacls/LineItemTest.php @@ -3,6 +3,8 @@ namespace Civi\Financialacls; // I fought the Autoloader and the autoloader won. +use Civi\Api4\LineItem; + require_once 'BaseTestClass.php'; /** @@ -29,6 +31,8 @@ class LineItemTest extends BaseTestClass { */ public function testLineItemApiPermissions($version): void { $contact1 = $this->individualCreate(); + $lineItems = $this->callAPISuccess('LineItem', 'get', ['sequential' => TRUE])['values']; + $this->assertCount(0, $lineItems); $this->createPriceSet(); $order = $this->callAPISuccess('Order', 'create', [ 'financial_type_id' => 'Donation', @@ -72,7 +76,7 @@ class LineItemTest extends BaseTestClass { 'price_field_id' => $this->ids['PriceField'][0], 'qty' => 1, 'financial_type_id' => 'Donation', - 'check_permissions' => ($version == 3), + 'check_permissions' => ($version === 3), ]; $line = $this->callAPISuccess('LineItem', 'Create', $lineParams); $lineParams['financial_type_id'] = 'Event Fee'; @@ -80,7 +84,8 @@ class LineItemTest extends BaseTestClass { $this->callAPIFailure('LineItem', 'Create', $lineParams); $this->callAPIFailure('LineItem', 'Create', ['id' => $line['id'], 'check_permissions' => TRUE, 'financial_type_id' => 'Event Fee']); - $this->callAPISuccess('LineItem', 'Create', ['id' => $line['id'], 'check_permissions' => ($version == 3), 'financial_type_id' => 'Donation']); + $invalidLineItem = $this->callAPISuccess('LineItem', 'Create', ['id' => $line['id'], 'check_permissions' => ($version == 3), 'financial_type_id' => 'Donation']); + LineItem::delete(FALSE)->addWhere('id', '=', $invalidLineItem['id'])->execute(); } } -- 2.25.1