diff --git a/CRM/Batch/Form/Entry.php b/CRM/Batch/Form/Entry.php index e39156fdd12a..bb6fd59ffbcd 100644 --- a/CRM/Batch/Form/Entry.php +++ b/CRM/Batch/Form/Entry.php @@ -136,6 +136,13 @@ public function getCurrentRowMembershipID() { return $this->currentRowMembershipID; } + /** + * Get the order (contribution) status for the current row. + */ + protected function getCurrentRowPaymentStatus() { + return CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_Contribution', 'contribution_status_id', $this->currentRow['contribution_status_id']); + } + /** * Get the contact ID for the current row. * @@ -781,7 +788,7 @@ private function processMembership(array $params) { $this->updateContactInfo($value); //check for custom data - $value['custom'] = CRM_Core_BAO_CustomField::postProcess($params['field'][$key], + $value['custom'] = CRM_Core_BAO_CustomField::postProcess($this->currentRow, $key, 'Membership', $value['membership_type_id'] @@ -813,20 +820,13 @@ private function processMembership(array $params) { 'membership_type_id' => $value['membership_type_id'], 'financial_type_id' => $value['financial_type_id'], ], $key); + $order->setEntityParameters($this->getCurrentRowMembershipParams(), $key); if (!empty($order->getLineItems())) { $value['lineItems'] = [$order->getPriceSetID() => $order->getPriceFieldIndexedLineItems()]; $value['processPriceSet'] = TRUE; } // end of contribution related section - - $membershipParams = [ - 'start_date' => $value['membership_start_date'] ?? NULL, - 'end_date' => $value['membership_end_date'] ?? NULL, - 'join_date' => $value['membership_join_date'] ?? NULL, - 'campaign_id' => $value['member_campaign_id'] ?? NULL, - ]; - if ($this->currentRowIsRenew()) { // The following parameter setting may be obsolete. $this->_params = $params; @@ -850,11 +850,37 @@ private function processMembership(array $params) { $this->setCurrentRowMembershipID($membership->id); } else { - // @todo - specify the relevant fields - don't copy all over - $membershipParams = array_merge($value, $membershipParams); - $membership = CRM_Member_BAO_Membership::create($membershipParams); - } + $createdOrder = civicrm_api3('Order', 'create', [ + 'line_items' => $order->getLineItemForV3OrderApi(), + 'receive_date' => $this->currentRow['receive_date'], + 'check_number' => $this->currentRow['check_number'] ?? '', + 'contact_id' => $this->getCurrentRowContactID(), + 'batch_id' => $this->_batchId, + 'financial_type_id' => $this->currentRow['financial_type_id'], + 'payment_instrument_id' => $this->currentRow['payment_instrument_id'], + ]); + $this->currentRowContributionID = $createdOrder['id']; + + $this->setCurrentRowMembershipID($createdOrder['values'][$this->getCurrentRowContributionID()]['line_item'][0]['entity_id']); + if ($this->getCurrentRowPaymentStatus() === 'Completed') { + civicrm_api3('Payment', 'create', [ + 'total_amount' => $order->getTotalAmount() + $order->getTotalTaxAmount(), + 'check_number' => $this->currentRow['check_number'] ?? '', + 'trxn_date' => $this->currentRow['receive_date'], + 'trxn_id' => $this->currentRow['trxn_id'], + 'payment_instrument_id' => $this->currentRow['payment_instrument_id'], + 'contribution_id' => $this->getCurrentRowContributionID(), + 'is_send_contribution_notification' => FALSE, + ]); + } + if (in_array($this->getCurrentRowPaymentStatus(), ['Failed', 'Cancelled'])) { + Contribution::update() + ->addValue('contribution_status_id', $this->currentRow['contribution_status_id']) + ->addWhere('id', '=', $this->getCurrentRowContributionID()) + ->execute(); + } + } //process premiums if (!empty($value['product_name'])) { if ($value['product_name'][0] > 0) { @@ -878,9 +904,9 @@ private function processMembership(array $params) { // end of premium //send receipt mail. - if ($membership->id && !empty($value['send_receipt'])) { - $value['membership_id'] = $membership->id; - $this->emailReceipt($this, $value, $membership); + if ($this->getCurrentRowMembershipID() && !empty($value['send_receipt'])) { + $value['membership_id'] = $this->getCurrentRowMembershipID(); + $this->emailReceipt($this, $value); } } } @@ -893,15 +919,16 @@ private function processMembership(array $params) { * @param CRM_Core_Form $form * Form object. * @param array $formValues - * @param object $membership - * Object. * * @return bool * true if mail was sent successfully * @throws \CRM_Core_Exception|\API_Exception * */ - protected function emailReceipt($form, &$formValues, $membership): bool { + protected function emailReceipt($form, &$formValues): bool { + $membership = new CRM_Member_BAO_Membership(); + $membership->id = $this->getCurrentRowMembershipID(); + $membership->fetch(); // @todo figure out how much of the stuff below is genuinely shared with the batch form & a logical shared place. if (!empty($formValues['payment_instrument_id'])) { $paymentInstrument = CRM_Contribute_PseudoConstant::paymentInstrument(); @@ -1264,10 +1291,44 @@ protected function getCurrentMembership() { $this->currentRowExistingMembership = CRM_Member_BAO_Membership::getContactMembership($this->getCurrentRowContactID(), $this->getCurrentRowMembershipTypeID(), FALSE, NULL, TRUE ); - // Check and fix the membership if it is STALE - CRM_Member_BAO_Membership::fixMembershipStatusBeforeRenew($this->currentRowExistingMembership); + if ($this->currentRowExistingMembership) { + // Check and fix the membership if it is STALE + CRM_Member_BAO_Membership::fixMembershipStatusBeforeRenew($this->currentRowExistingMembership); + } } return $this->currentRowExistingMembership; } + /** + * Get the params as related to the membership entity. + * + * @return array + */ + private function getCurrentRowMembershipParams(): array { + return array_merge($this->getCurrentRowCustomParams(), [ + 'start_date' => $this->currentRow['membership_start_date'] ?? NULL, + 'end_date' => $this->currentRow['membership_end_date'] ?? NULL, + 'join_date' => $this->currentRow['membership_join_date'] ?? NULL, + 'campaign_id' => $this->currentRow['member_campaign_id'] ?? NULL, + 'source' => $this->currentRow['source'] ?? (!$this->currentRowIsRenew() ? ts('Batch entry') : ''), + 'membership_type_id' => $this->currentRow['membership_type_id'], + 'contact_id' => $this->getCurrentRowContactID(), + ]); + } + + /** + * Get the custom value parameters from the current row. + * + * @return array + */ + private function getCurrentRowCustomParams(): array { + $return = []; + foreach ($this->currentRow as $field => $value) { + if (strpos($field, 'custom_') === 0) { + $return[$field] = $value; + } + } + return $return; + } + } diff --git a/CRM/Financial/BAO/Order.php b/CRM/Financial/BAO/Order.php index ad32b31c45a2..29cfc2793855 100644 --- a/CRM/Financial/BAO/Order.php +++ b/CRM/Financial/BAO/Order.php @@ -1058,6 +1058,26 @@ protected function getLinesFromTemplateContribution(): array { return $lines; } + /** + * Get the constructed line items formatted for the v3 Order api. + * + * @return array + * + * @internal core tested code only. + * + * @throws \CiviCRM_API3_Exception + */ + public function getLineItemForV3OrderApi(): array { + $lineItems = []; + foreach ($this->getLineItems() as $key => $line) { + $lineItems[] = [ + 'line_item' => [$line['price_field_value_id'] => $line], + 'params' => $this->entityParameters[$key] ?? [], + ]; + } + return $lineItems; + } + /** * @return array * @throws \API_Exception diff --git a/CRM/Member/BAO/Membership.php b/CRM/Member/BAO/Membership.php index edc63eda522c..ae9a2f160fba 100644 --- a/CRM/Member/BAO/Membership.php +++ b/CRM/Member/BAO/Membership.php @@ -289,9 +289,9 @@ public static function create(&$params, $ids = []) { else { $calcDates = []; } - $params['start_date'] = $params['start_date'] ?? ($calcDates['start_date'] ?? 'null'); - $params['end_date'] = $params['end_date'] ?? ($calcDates['end_date'] ?? 'null'); - $params['join_date'] = $params['join_date'] ?? ($calcDates['join_date'] ?? 'null'); + $params['start_date'] = empty($params['start_date']) ? ($calcDates['start_date'] ?? 'null') : $params['start_date']; + $params['end_date'] = empty($params['end_date']) ? ($calcDates['end_date'] ?? 'null') : $params['end_date']; + $params['join_date'] = empty($params['join_date']) ? ($calcDates['join_date'] ?? 'null') : $params['join_date']; //fix for CRM-3570, during import exclude the statuses those having is_admin = 1 $excludeIsAdmin = $params['exclude_is_admin'] ?? FALSE; diff --git a/tests/phpunit/CRM/Batch/Form/EntryTest.php b/tests/phpunit/CRM/Batch/Form/EntryTest.php index e6c74018b104..7f353c5c1c7d 100644 --- a/tests/phpunit/CRM/Batch/Form/EntryTest.php +++ b/tests/phpunit/CRM/Batch/Form/EntryTest.php @@ -201,6 +201,7 @@ public function testProcessMembership(string $thousandSeparator): void { //check start dates #1 should default to 1 Jan this year, #2 should be as entered $this->assertEquals(date('Y-m-d', strtotime('first day of January 2013')), $memberships[1]['start_date']); $this->assertEquals('2013-02-03', $memberships[2]['start_date']); + $this->assertEquals('2013-12-31', $memberships[2]['end_date']); //check start dates #1 should default to 1 Jan this year, #2 should be as entered $this->assertEquals(date('Y-m-d', strtotime('last day of December 2013')), $memberships[1]['end_date']); @@ -346,8 +347,7 @@ public function getMembershipData(): array { 'financial_type' => 2, 'total_amount' => $this->formatMoneyInput(1500), 'receive_date' => '2013-07-17', - 'receive_date_time' => NULL, - 'payment_instrument' => NULL, + 'payment_instrument' => 1, 'trxn_id' => 'TX102', 'check_number' => NULL, 'contribution_status_id' => 1, @@ -362,8 +362,7 @@ public function getMembershipData(): array { 'financial_type' => 2, 'total_amount' => $this->formatMoneyInput(1500), 'receive_date' => '2013-07-17', - 'receive_date_time' => NULL, - 'payment_instrument' => NULL, + 'payment_instrument' => 1, 'trxn_id' => 'TX103', 'check_number' => NULL, 'contribution_status_id' => 1,