diff --git a/CRM/Member/BAO/Membership.php b/CRM/Member/BAO/Membership.php index 5617e52e965e..7794deef0c9a 100644 --- a/CRM/Member/BAO/Membership.php +++ b/CRM/Member/BAO/Membership.php @@ -364,7 +364,8 @@ public static function create(&$params, &$ids = []) { if (empty($ids['contribution']) && !empty($ids['membership'])) { CRM_Price_BAO_LineItem::deleteLineItems($ids['membership'], 'civicrm_membership'); } - + // @todo - we should ONLY do the below if a contribution is created. Let's + // get some deprecation notices in here & see where it's hit & work to eliminate. // This could happen if there is no contribution or we are in one of many // weird and wonderful flows. This is scary code. Keep adding tests. if (!empty($params['line_item']) && empty($ids['contribution']) && empty($params['contribution_id'])) { diff --git a/api/v3/Order.php b/api/v3/Order.php index 19b4eaefe206..88236aa0113a 100644 --- a/api/v3/Order.php +++ b/api/v3/Order.php @@ -117,6 +117,9 @@ function civicrm_api3_order_create($params) { } } $contributionParams = $params; + // If this is nested we need to set sequential to 0 as sequential handling is done + // in create_success & id will be miscalculated... + $contributionParams['sequential'] = 0; foreach ($contributionParams as $key => $value) { // Unset chained keys so the code does not attempt to do this chaining twice. // e.g if calling 'api.Payment.create' We want to finish creating the order first. diff --git a/tests/phpunit/CRM/Core/Payment/PayPalProIPNTest.php b/tests/phpunit/CRM/Core/Payment/PayPalProIPNTest.php index 19b3e601139d..7e97b7b77f1f 100644 --- a/tests/phpunit/CRM/Core/Payment/PayPalProIPNTest.php +++ b/tests/phpunit/CRM/Core/Payment/PayPalProIPNTest.php @@ -83,6 +83,8 @@ public function testIPNPaymentRecurSuccess() { /** * Test IPN response updates contribution_recur & contribution for first & second contribution. + * + * @throws \CRM_Core_Exception */ public function testIPNPaymentMembershipRecurSuccess() { $durationUnit = 'year'; diff --git a/tests/phpunit/CiviTest/CiviUnitTestCase.php b/tests/phpunit/CiviTest/CiviUnitTestCase.php index 5d7c20e89b3c..59d1f8f51c04 100644 --- a/tests/phpunit/CiviTest/CiviUnitTestCase.php +++ b/tests/phpunit/CiviTest/CiviUnitTestCase.php @@ -2467,10 +2467,10 @@ public function setupRecurringPaymentProcessorTransaction($recurParams = [], $co 'payment_processor_id' => $this->_paymentProcessorID, // processor provided ID - use contact ID as proxy. 'processor_id' => $this->_contactID, - 'api.contribution.create' => $contributionParams, - ], $recurParams)); + 'api.Order.create' => $contributionParams, + ], $recurParams))['values'][0]; $this->_contributionRecurID = $contributionRecur['id']; - $this->_contributionID = $contributionRecur['values']['0']['api.contribution.create']['id']; + $this->_contributionID = $contributionRecur['api.Order.create']['id']; $this->ids['Contribution'][0] = $this->_contributionID; } @@ -2492,7 +2492,7 @@ public function setupMembershipRecurringPaymentProcessorTransaction($params = [] $this->ids['membership_type'] = $this->membershipTypeCreate($membershipParams); //create a contribution so our membership & contribution don't both have id = 1 - if ($this->callAPISuccess('Contribution', 'getcount', []) == 0) { + if ($this->callAPISuccess('Contribution', 'getcount', []) === 0) { $this->contributionCreate([ 'contact_id' => $this->_contactID, 'is_test' => 1, @@ -2502,42 +2502,42 @@ public function setupMembershipRecurringPaymentProcessorTransaction($params = [] 'receive_date' => '2019-07-25 07:34:23', ]); } - $this->setupRecurringPaymentProcessorTransaction($recurParams); - $this->ids['membership'] = $this->callAPISuccess('membership', 'create', [ + $this->ids['membership'] = $this->callAPISuccess('Membership', 'create', [ 'contact_id' => $this->_contactID, 'membership_type_id' => $this->ids['membership_type'], - 'contribution_recur_id' => $this->_contributionRecurID, 'format.only_id' => TRUE, 'source' => 'Payment', + 'skipLineItem' => TRUE, ]); - //CRM-15055 creates line items we don't want so get rid of them so we can set up our own line items - CRM_Core_DAO::executeQuery("TRUNCATE civicrm_line_item"); - - $this->callAPISuccess('line_item', 'create', [ - 'entity_table' => 'civicrm_membership', - 'entity_id' => $this->ids['membership'], - 'contribution_id' => $this->_contributionID, - 'label' => 'General', - 'qty' => 1, - 'unit_price' => 200, - 'line_total' => 200, - 'financial_type_id' => 1, - 'price_field_id' => $this->callAPISuccess('price_field', 'getvalue', [ - 'return' => 'id', - 'label' => 'Membership Amount', - 'options' => ['limit' => 1, 'sort' => 'id DESC'], - ]), - 'price_field_value_id' => $this->callAPISuccess('price_field_value', 'getvalue', [ - 'return' => 'id', - 'label' => 'General', - 'options' => ['limit' => 1, 'sort' => 'id DESC'], - ]), - ]); - $this->callAPISuccess('membership_payment', 'create', [ - 'contribution_id' => $this->_contributionID, - 'membership_id' => $this->ids['membership'], + $this->setupRecurringPaymentProcessorTransaction($recurParams, [ + 'line_items' => [ + [ + 'line_item' => [ + [ + 'entity_table' => 'civicrm_membership', + 'entity_id' => $this->ids['membership'], + 'label' => 'General', + 'qty' => 1, + 'unit_price' => 200, + 'line_total' => 200, + 'financial_type_id' => 1, + 'price_field_id' => $this->callAPISuccess('price_field', 'getvalue', [ + 'return' => 'id', + 'label' => 'Membership Amount', + 'options' => ['limit' => 1, 'sort' => 'id DESC'], + ]), + 'price_field_value_id' => $this->callAPISuccess('price_field_value', 'getvalue', [ + 'return' => 'id', + 'label' => 'General', + 'options' => ['limit' => 1, 'sort' => 'id DESC'], + ]), + ], + ], + ], + ], ]); + $this->callAPISuccess('Membership', 'create', ['id' => $this->ids['membership'], 'contribution_recur_id' => $this->_contributionRecurID]); } /**