diff --git a/Civi/API/Provider/MagicFunctionProvider.php b/Civi/API/Provider/MagicFunctionProvider.php index 207b5991cc49..1b44dd931a47 100644 --- a/Civi/API/Provider/MagicFunctionProvider.php +++ b/Civi/API/Provider/MagicFunctionProvider.php @@ -83,7 +83,18 @@ public function invoke($apiRequest) { // Unlike normal API implementations, generic implementations require explicit // knowledge of the entity and action (as well as $params). Bundle up these bits // into a convenient data structure. + if ($apiRequest['action'] === 'getsingle') { + // strip any api nested parts here as otherwise chaining may happen twice + // see https://lab.civicrm.org/dev/core/issues/643 + // testCreateBAODefaults fails without this. + foreach ($apiRequest['params'] as $key => $param) { + if ($key !== 'api.has_parent' && substr($key, 0, 4) === 'api.' || substr($key, 0, 4) === 'api_') { + unset($apiRequest['params'][$key]); + } + } + } $result = $function($apiRequest); + } elseif ($apiRequest['function'] && !$apiRequest['is_generic']) { $result = $function($apiRequest['params']); diff --git a/api/v3/Contribution.php b/api/v3/Contribution.php index a52600f6d820..a5b33bf16fb6 100644 --- a/api/v3/Contribution.php +++ b/api/v3/Contribution.php @@ -231,7 +231,7 @@ function civicrm_api3_contribution_delete($params) { return civicrm_api3_create_success(array($contributionID => 1)); } else { - return civicrm_api3_create_error('Could not delete contribution'); + throw new API_Exception('Could not delete contribution'); } } diff --git a/tests/phpunit/api/v3/ContributionTest.php b/tests/phpunit/api/v3/ContributionTest.php index dd4d79066874..b6df822f75e8 100644 --- a/tests/phpunit/api/v3/ContributionTest.php +++ b/tests/phpunit/api/v3/ContributionTest.php @@ -1117,6 +1117,19 @@ public function testCreateBAODefaults() { )); $this->assertEquals(1, $contribution['contribution_status_id']); $this->assertEquals('Check', $contribution['payment_instrument']); + $this->callAPISuccessGetCount('Contribution', ['id' => $contribution['id']], 0); + } + + /** + * Test that getsingle can be chained with delete. + */ + public function testDeleteChainedGetSingle() { + $contribution = $this->callAPISuccess('contribution', 'create', $this->_params); + $contribution = $this->callAPISuccess('contribution', 'getsingle', array( + 'id' => $contribution['id'], + 'api.contribution.delete' => 1, + )); + $this->callAPISuccessGetCount('Contribution', ['id' => $contribution['id']], 0); } /**