/** * Create a Contact Membership * * This API is used for creating a Membership for a contact. * Required parameters : membership_type_id and status_id. * * @param array $params an associative array of name/value property values of civicrm_membership * * @return array of newly created membership property values. * @access public */ function civicrm_membership_contact_create(&$params) { _civicrm_initialize(); $error = _civicrm_membership_check_params($params); if (civicrm_error($error)) { return $error; } $values = array(); $error = _civicrm_membership_format_params($params, $values); if (civicrm_error($error)) { return $error; } $params = array_merge($values, $params); require_once 'CRM/Core/Action.php'; $action = CRM_Core_Action::ADD; // we need user id during add mode $ids = array('userId' => $params['contact_id']); //for edit membership id should be present if (CRM_Utils_Array::value('id', $params)) { $ids = array('membership' => $params['id'], 'userId' => $params['contact_id']); $action = CRM_Core_Action::UPDATE; } //need to pass action to handle related memberships. $params['action'] = $action; require_once 'CRM/Member/BAO/Membership.php'; $membershipBAO = CRM_Member_BAO_Membership::create($params, $ids, true); if (array_key_exists('is_error', $membershipBAO)) { // In case of no valid status for given dates, $membershipBAO // is going to contain 'is_error' => "Error Message" return civicrm_create_error(ts('The membership can not be saved, no valid membership status for given dates')); } $membership = array(); _civicrm_object_to_array($membershipBAO, $membership); $values = array(); $values['id'] = $membership['id']; $values['is_error'] = 0; return $values; }
/** * Create a Contact Membership * * This API is used for creating a Membership for a contact. * Required parameters : membership_type_id and status_id. * * @param array $params an associative array of name/value property values of civicrm_membership * * @return array of newly created membership property values. * @access public */ function civicrm_membership_contact_create(&$params) { _civicrm_initialize(); if (!is_array($params)) { return civicrm_create_error('Params is not an array'); } if (!isset($params['membership_type_id']) || !isset($params['contact_id']) || isset($params['is_override']) && !$params['status_id']) { return civicrm_create_error(ts('Required parameter missing')); } $values = array(); $error = _civicrm_membership_format_params($params, $values); if (is_a($error, 'CRM_Core_Error')) { return civicrm_create_error('Membership is not created'); } $params = array_merge($values, $params); require_once 'CRM/Core/Action.php'; $action = CRM_Core_Action::ADD; //for edit membership id should be present if (CRM_Utils_Array::value('id', $params)) { $ids = array('membership' => $params['id'], 'user_id' => $params['contact_id']); $action = CRM_Core_Action::UPDATE; } //need to pass action to handle related memberships. $params['action'] = $action; require_once 'CRM/Member/BAO/Membership.php'; $membershipBAO = CRM_Member_BAO_Membership::create($params, $ids, true); if (array_key_exists('is_error', $membershipBAO)) { // In case of no valid status for given dates, $membershipBAO // is going to contain 'is_error' => "Error Message" return civicrm_create_error(ts('The membership can not be saved, no valid membership status for given dates')); } $membership = array(); _civicrm_object_to_array($membershipBAO, $membership); $values = array(); $values['id'] = $membership['id']; $values['is_error'] = 0; return $values; }
/** * Test resetmodified() */ public function testresetmodifiedId() { $contactId = Contact::createIndividual(); $params = array('contact_id' => $contactId, 'membership_type_id' => $this->_membershipTypeID, 'join_date' => date('Ymd', strtotime('2006-01-21')), 'start_date' => date('Ymd', strtotime('2006-01-21')), 'end_date' => date('Ymd', strtotime('2006-12-21')), 'source' => 'Payment', 'is_override' => 1, 'status_id' => $this->_mebershipStatusID); $ids = array('userId' => $contactId); $membership = CRM_Member_BAO_Membership::create($params, $ids); $resetModifiedId = CRM_Member_BAO_MembershipLog::resetModifiedID($contactId); $this->assertDBNull('CRM_Member_BAO_MembershipLog', $contactId, 'modified_id', 'modified_id', 'Database check for NULL modified id.'); $this->membershipDelete($membership->id); $this->contactDelete($contactId); }
/** * Process membership records. * * @param array $params * Associated array of submitted values. * * * @return bool */ private function processMembership(&$params) { $dateTypes = array('join_date' => 'joinDate', 'membership_start_date' => 'startDate', 'membership_end_date' => 'endDate'); $dates = array('join_date', 'start_date', 'end_date', 'reminder_date'); // get the price set associated with offline membership $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', 'default_membership_type_amount', 'id', 'name'); $this->_priceSet = $priceSets = current(CRM_Price_BAO_PriceSet::getSetDetail($priceSetId)); if (isset($params['field'])) { $customFields = array(); foreach ($params['field'] as $key => $value) { // if contact is not selected we should skip the row if (empty($params['primary_contact_id'][$key])) { continue; } $value['contact_id'] = CRM_Utils_Array::value($key, $params['primary_contact_id']); // update contact information $this->updateContactInfo($value); $membershipTypeId = $value['membership_type_id'] = $value['membership_type'][1]; foreach ($dateTypes as $dateField => $dateVariable) { ${$dateVariable} = CRM_Utils_Date::processDate($value[$dateField]); $fDate[$dateField] = CRM_Utils_Array::value($dateField, $value); } $calcDates = array(); $calcDates[$membershipTypeId] = CRM_Member_BAO_MembershipType::getDatesForMembershipType($membershipTypeId, $joinDate, $startDate, $endDate); foreach ($calcDates as $memType => $calcDate) { foreach ($dates as $d) { //first give priority to form values then calDates. $date = CRM_Utils_Array::value($d, $value); if (!$date) { $date = CRM_Utils_Array::value($d, $calcDate); } $value[$d] = CRM_Utils_Date::processDate($date); } } if (!empty($value['send_receipt'])) { $value['receipt_date'] = date('Y-m-d His'); } if (!empty($value['membership_source'])) { $value['source'] = $value['membership_source']; } unset($value['membership_source']); //Get the membership status if (!empty($value['membership_status'])) { $value['status_id'] = $value['membership_status']; unset($value['membership_status']); } if (empty($customFields)) { // membership type custom data $customFields = CRM_Core_BAO_CustomField::getFields('Membership', FALSE, FALSE, $membershipTypeId); $customFields = CRM_Utils_Array::crmArrayMerge($customFields, CRM_Core_BAO_CustomField::getFields('Membership', FALSE, FALSE, NULL, NULL, TRUE)); } //check for custom data $value['custom'] = CRM_Core_BAO_CustomField::postProcess($params['field'][$key], $key, 'Membership', $membershipTypeId); if (!empty($value['financial_type'])) { $value['financial_type_id'] = $value['financial_type']; } if (!empty($value['payment_instrument'])) { $value['payment_instrument_id'] = $value['payment_instrument']; } // handle soft credit if (!empty($params['soft_credit_contact_id'][$key]) && !empty($params['soft_credit_amount'][$key])) { $value['soft_credit'][$key]['contact_id'] = $params['soft_credit_contact_id'][$key]; $value['soft_credit'][$key]['amount'] = CRM_Utils_Rule::cleanMoney($params['soft_credit_amount'][$key]); //CRM-15350: if soft-credit-type profile field is disabled or removed then //we choose Gift as default value as per Gift Membership rule if (!empty($params['soft_credit_type'][$key])) { $value['soft_credit'][$key]['soft_credit_type_id'] = $params['soft_credit_type'][$key]; } else { $value['soft_credit'][$key]['soft_credit_type_id'] = CRM_Core_OptionGroup::getValue('soft_credit_type', 'Gift', 'name'); } } if (!empty($value['receive_date'])) { $value['receive_date'] = CRM_Utils_Date::processDate($value['receive_date'], $value['receive_date_time'], TRUE); } $params['actualBatchTotal'] += $value['total_amount']; unset($value['financial_type']); unset($value['payment_instrument']); $value['batch_id'] = $this->_batchId; $value['skipRecentView'] = TRUE; // make entry in line item for contribution $editedFieldParams = array('price_set_id' => $priceSetId, 'name' => $value['membership_type'][0]); $editedResults = array(); CRM_Price_BAO_PriceField::retrieve($editedFieldParams, $editedResults); if (!empty($editedResults)) { unset($this->_priceSet['fields']); $this->_priceSet['fields'][$editedResults['id']] = $priceSets['fields'][$editedResults['id']]; unset($this->_priceSet['fields'][$editedResults['id']]['options']); $fid = $editedResults['id']; $editedFieldParams = array('price_field_id' => $editedResults['id'], 'membership_type_id' => $value['membership_type_id']); $editedResults = array(); CRM_Price_BAO_PriceFieldValue::retrieve($editedFieldParams, $editedResults); $this->_priceSet['fields'][$fid]['options'][$editedResults['id']] = $priceSets['fields'][$fid]['options'][$editedResults['id']]; if (!empty($value['total_amount'])) { $this->_priceSet['fields'][$fid]['options'][$editedResults['id']]['amount'] = $value['total_amount']; } $fieldID = key($this->_priceSet['fields']); $value['price_' . $fieldID] = $editedResults['id']; $lineItem = array(); CRM_Price_BAO_PriceSet::processAmount($this->_priceSet['fields'], $value, $lineItem[$priceSetId]); //CRM-11529 for backoffice transactions //when financial_type_id is passed in form, update the //lineitems with the financial type selected in form if (!empty($value['financial_type_id']) && !empty($lineItem[$priceSetId])) { foreach ($lineItem[$priceSetId] as &$values) { $values['financial_type_id'] = $value['financial_type_id']; } } $value['lineItems'] = $lineItem; $value['processPriceSet'] = TRUE; } // end of contribution related section unset($value['membership_type']); unset($value['membership_start_date']); unset($value['membership_end_date']); $value['is_renew'] = FALSE; if (!empty($params['member_option']) && CRM_Utils_Array::value($key, $params['member_option']) == 2) { // The following parameter setting may be obsolete. $this->_params = $params; $value['is_renew'] = TRUE; $isPayLater = CRM_Utils_Array::value('is_pay_later', $params); $campaignId = NULL; if (isset($this->_values) && is_array($this->_values) && !empty($this->_values)) { $campaignId = CRM_Utils_Array::value('campaign_id', $this->_params); if (!array_key_exists('campaign_id', $this->_params)) { $campaignId = CRM_Utils_Array::value('campaign_id', $this->_values); } } foreach (array('join_date', 'start_date', 'end_date') as $dateType) { //CRM-18000 - ignore $dateType if its not explicitly passed if (!empty($fDate[$dateType]) || !empty($fDate['membership_' . $dateType])) { $formDates[$dateType] = CRM_Utils_Array::value($dateType, $value); } } $membershipSource = CRM_Utils_Array::value('source', $value); list($membership) = CRM_Member_BAO_Membership::renewMembership($value['contact_id'], $value['membership_type_id'], FALSE, NULL, NULL, $value['custom'], 1, NULL, FALSE, NULL, $membershipSource, $isPayLater, $campaignId, $formDates); // make contribution entry $contrbutionParams = array_merge($value, array('membership_id' => $membership->id)); // @todo - calling this from here is pretty hacky since it is called from membership.create anyway // This form should set the correct params & not call this fn directly. CRM_Member_BAO_Membership::recordMembershipContribution($contrbutionParams); } else { $membership = CRM_Member_BAO_Membership::create($value, CRM_Core_DAO::$_nullArray); } //process premiums if (!empty($value['product_name'])) { if ($value['product_name'][0] > 0) { list($products, $options) = CRM_Contribute_BAO_Premium::getPremiumProductInfo(); $value['hidden_Premium'] = 1; $value['product_option'] = CRM_Utils_Array::value($value['product_name'][1], $options[$value['product_name'][0]]); $premiumParams = array('product_id' => $value['product_name'][0], 'contribution_id' => CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipPayment', $membership->id, 'contribution_id', 'membership_id'), 'product_option' => $value['product_option'], 'quantity' => 1); CRM_Contribute_BAO_Contribution::addPremium($premiumParams); } } // end of premium //send receipt mail. if ($membership->id && !empty($value['send_receipt'])) { // add the domain email id $domainEmail = CRM_Core_BAO_Domain::getNameAndEmail(); $domainEmail = "{$domainEmail['0']} <{$domainEmail['1']}>"; $value['from_email_address'] = $domainEmail; $value['membership_id'] = $membership->id; $value['contribution_id'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipPayment', $membership->id, 'contribution_id', 'membership_id'); CRM_Member_Form_Membership::emailReceipt($this, $value, $membership); } } } return TRUE; }
/** * Create a Contact Membership * * This API is used for creating a Membership for a contact. * Required parameters : membership_type_id and status_id. * * @param array $params an associative array of name/value property values of civicrm_membership * * @return array of newly created membership property values. * {@getfields membership_create} * @access public */ function civicrm_api3_membership_create($params) { // @todo shouldn't be required - should be handling by api.aliases & api.required in _spec civicrm_api3_verify_one_mandatory($params, NULL, array('membership_type_id', 'membership_type')); // check params for membership id during update if (CRM_Utils_Array::value('id', $params) && !isset($params['skipStatusCal'])) { //don't calculate dates on exisiting membership - expect API use to pass them in // or leave unchanged $params['skipStatusCal'] = 1; } else { // also check for status id if override is set (during add/update) if (isset($params['is_override']) && !CRM_Utils_Array::value('status_id', $params)) { return civicrm_api3_create_error('Status ID required'); } } $values = array(); $error = _civicrm_api3_membership_format_params($params, $values); if (civicrm_error($error)) { return $error; } _civicrm_api3_custom_format_params($params, $values, 'Membership'); $params = array_merge($params, $values); $action = CRM_Core_Action::ADD; // we need user id during add mode $ids = array(); if (CRM_Utils_Array::value('contact_id', $params)) { $ids['userId'] = $params['contact_id']; } //for edit membership id should be present if (CRM_Utils_Array::value('id', $params)) { $ids['membership'] = $params['id']; $action = CRM_Core_Action::UPDATE; } //need to pass action to handle related memberships. $params['action'] = $action; $membershipBAO = CRM_Member_BAO_Membership::create($params, $ids, TRUE); if (array_key_exists('is_error', $membershipBAO)) { // In case of no valid status for given dates, $membershipBAO // is going to contain 'is_error' => "Error Message" return civicrm_api3_create_error(ts('The membership can not be saved, no valid membership status for given dates')); } $membership = array(); _civicrm_api3_object_to_array($membershipBAO, $membership[$membershipBAO->id]); return civicrm_api3_create_success($membership, $params, 'membership', 'create', $membershipBAO); }
/** * process membership records * * @param array $params associated array of submitted values * * @access public * * @return bool */ private function processMembership(&$params) { $dateTypes = array('join_date' => 'joinDate', 'membership_start_date' => 'startDate', 'membership_end_date' => 'endDate'); $dates = array('join_date', 'start_date', 'end_date', 'reminder_date'); // get the price set associated with offline memebership $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', 'default_membership_type_amount', 'id', 'name'); $this->_priceSet = $priceSets = current(CRM_Price_BAO_PriceSet::getSetDetail($priceSetId)); if (isset($params['field'])) { $customFields = array(); foreach ($params['field'] as $key => $value) { // if contact is not selected we should skip the row if (empty($params['primary_contact_id'][$key])) { continue; } $value['contact_id'] = CRM_Utils_Array::value($key, $params['primary_contact_id']); // update contact information $this->updateContactInfo($value); $membershipTypeId = $value['membership_type_id'] = $value['membership_type'][1]; foreach ($dateTypes as $dateField => $dateVariable) { ${$dateVariable} = CRM_Utils_Date::processDate($value[$dateField]); } $calcDates = array(); $calcDates[$membershipTypeId] = CRM_Member_BAO_MembershipType::getDatesForMembershipType($membershipTypeId, $joinDate, $startDate, $endDate); foreach ($calcDates as $memType => $calcDate) { foreach ($dates as $d) { //first give priority to form values then calDates. $date = CRM_Utils_Array::value($d, $value); if (!$date) { $date = CRM_Utils_Array::value($d, $calcDate); } $value[$d] = CRM_Utils_Date::processDate($date); } } if (!empty($value['send_receipt'])) { $value['receipt_date'] = date('Y-m-d His'); } if (!empty($value['membership_source'])) { $value['source'] = $value['membership_source']; } unset($value['membership_source']); //Get the membership status if (!empty($value['membership_status'])) { $value['status_id'] = $value['membership_status']; unset($value['membership_status']); } if (empty($customFields)) { // membership type custom data $customFields = CRM_Core_BAO_CustomField::getFields('Membership', FALSE, FALSE, $membershipTypeId); $customFields = CRM_Utils_Array::crmArrayMerge($customFields, CRM_Core_BAO_CustomField::getFields('Membership', FALSE, FALSE, NULL, NULL, TRUE)); } //check for custom data $value['custom'] = CRM_Core_BAO_CustomField::postProcess($params['field'][$key], $customFields, $key, 'Membership', $membershipTypeId); if (!empty($value['financial_type'])) { $value['financial_type_id'] = $value['financial_type']; } if (!empty($value['payment_instrument'])) { $value['payment_instrument_id'] = $value['payment_instrument']; } // handle soft credit if (is_array(CRM_Utils_Array::value('soft_credit_contact_id', $params)) && !empty($params['soft_credit_contact_id'][$key]) && CRM_Utils_Array::value($key, $params['soft_credit_amount'])) { $value['soft_credit'][$key]['contact_id'] = $params['soft_credit_contact_id'][$key]; $value['soft_credit'][$key]['amount'] = CRM_Utils_Rule::cleanMoney($params['soft_credit_amount'][$key]); } if (!empty($value['receive_date'])) { $value['receive_date'] = CRM_Utils_Date::processDate($value['receive_date'], $value['receive_date_time'], TRUE); } $params['actualBatchTotal'] += $value['total_amount']; unset($value['financial_type']); unset($value['payment_instrument']); $value['batch_id'] = $this->_batchId; $value['skipRecentView'] = TRUE; // make entry in line item for contribution $editedFieldParams = array('price_set_id' => $priceSetId, 'name' => $value['membership_type'][0]); $editedResults = array(); CRM_Price_BAO_PriceField::retrieve($editedFieldParams, $editedResults); if (!empty($editedResults)) { unset($this->_priceSet['fields']); $this->_priceSet['fields'][$editedResults['id']] = $priceSets['fields'][$editedResults['id']]; unset($this->_priceSet['fields'][$editedResults['id']]['options']); $fid = $editedResults['id']; $editedFieldParams = array('price_field_id' => $editedResults['id'], 'membership_type_id' => $value['membership_type_id']); $editedResults = array(); CRM_Price_BAO_PriceFieldValue::retrieve($editedFieldParams, $editedResults); $this->_priceSet['fields'][$fid]['options'][$editedResults['id']] = $priceSets['fields'][$fid]['options'][$editedResults['id']]; if (!empty($value['total_amount'])) { $this->_priceSet['fields'][$fid]['options'][$editedResults['id']]['amount'] = $value['total_amount']; } $fieldID = key($this->_priceSet['fields']); $value['price_' . $fieldID] = $editedResults['id']; $lineItem = array(); CRM_Price_BAO_PriceSet::processAmount($this->_priceSet['fields'], $value, $lineItem[$priceSetId]); //CRM-11529 for backoffice transactions //when financial_type_id is passed in form, update the //lineitems with the financial type selected in form if (!empty($value['financial_type_id']) && !empty($lineItem[$priceSetId])) { foreach ($lineItem[$priceSetId] as &$values) { $values['financial_type_id'] = $value['financial_type_id']; } } $value['lineItems'] = $lineItem; $value['processPriceSet'] = TRUE; } // end of contribution related section unset($value['membership_type']); unset($value['membership_start_date']); unset($value['membership_end_date']); $value['is_renew'] = false; if (!empty($params['member_option']) && CRM_Utils_Array::value($key, $params['member_option']) == 2) { $this->_params = $params; $value['is_renew'] = true; $membership = CRM_Member_BAO_Membership::renewMembershipFormWrapper($value['contact_id'], $value['membership_type_id'], FALSE, $this, NULL, NULL, $value['custom']); // make contribution entry CRM_Member_BAO_Membership::recordMembershipContribution(array_merge($value, array('membership_id' => $membership->id))); } else { $membership = CRM_Member_BAO_Membership::create($value, CRM_Core_DAO::$_nullArray); } //process premiums if (!empty($value['product_name'])) { if ($value['product_name'][0] > 0) { list($products, $options) = CRM_Contribute_BAO_Premium::getPremiumProductInfo(); $value['hidden_Premium'] = 1; $value['product_option'] = CRM_Utils_Array::value($value['product_name'][1], $options[$value['product_name'][0]]); $premiumParams = array('product_id' => $value['product_name'][0], 'contribution_id' => $value['contribution_id'], 'product_option' => $value['product_option'], 'quantity' => 1); CRM_Contribute_BAO_Contribution::addPremium($premiumParams); } } // end of premium //send receipt mail. if ($membership->id && !empty($value['send_receipt'])) { // add the domain email id $domainEmail = CRM_Core_BAO_Domain::getNameAndEmail(); $domainEmail = "{$domainEmail['0']} <{$domainEmail['1']}>"; $value['from_email_address'] = $domainEmail; $value['membership_id'] = $membership->id; CRM_Member_Form_Membership::emailReceipt($this, $value, $membership); } } } return TRUE; }
/** * Process the form submission. * * * @return void */ public function postProcess() { if ($this->_action & CRM_Core_Action::DELETE) { CRM_Member_BAO_Membership::del($this->_id); return; } $allMemberStatus = CRM_Member_PseudoConstant::membershipStatus(); $allContributionStatus = CRM_Contribute_PseudoConstant::contributionStatus(); $isTest = $this->_mode == 'test' ? 1 : 0; $lineItems = NULL; if (!empty($this->_lineItem)) { $lineItems = $this->_lineItem; } $config = CRM_Core_Config::singleton(); // get the submitted form values. $this->_params = $formValues = $this->controller->exportValues($this->_name); $this->convertDateFieldsToMySQL($formValues); $params = $softParams = $ids = array(); $membershipTypeValues = array(); foreach ($this->_memTypeSelected as $memType) { $membershipTypeValues[$memType]['membership_type_id'] = $memType; } //take the required membership recur values. if ($this->_mode && !empty($this->_params['auto_renew'])) { $params['is_recur'] = $this->_params['is_recur'] = $formValues['is_recur'] = TRUE; $mapping = array('frequency_interval' => 'duration_interval', 'frequency_unit' => 'duration_unit'); $count = 0; foreach ($this->_memTypeSelected as $memType) { $recurMembershipTypeValues = CRM_Utils_Array::value($memType, $this->_recurMembershipTypes, array()); foreach ($mapping as $mapVal => $mapParam) { $membershipTypeValues[$memType][$mapVal] = CRM_Utils_Array::value($mapParam, $recurMembershipTypeValues); if (!$count) { $this->_params[$mapVal] = $formValues[$mapVal] = CRM_Utils_Array::value($mapParam, $recurMembershipTypeValues); } } $count++; } } // process price set and get total amount and line items. $lineItem = array(); $priceSetId = NULL; if (!($priceSetId = CRM_Utils_Array::value('price_set_id', $formValues))) { CRM_Member_BAO_Membership::createLineItems($this, $formValues['membership_type_id'], $priceSetId); } $isQuickConfig = 0; if ($this->_priceSetId && CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $this->_priceSetId, 'is_quick_config')) { $isQuickConfig = 1; } $termsByType = array(); if ($priceSetId) { CRM_Price_BAO_PriceSet::processAmount($this->_priceSet['fields'], $this->_params, $lineItem[$priceSetId]); if (CRM_Utils_Array::value('tax_amount', $this->_params)) { $params['tax_amount'] = $this->_params['tax_amount']; } $params['total_amount'] = CRM_Utils_Array::value('amount', $this->_params); $submittedFinancialType = CRM_Utils_Array::value('financial_type_id', $formValues); if (!empty($lineItem[$priceSetId])) { foreach ($lineItem[$priceSetId] as &$li) { if (!empty($li['membership_type_id'])) { if (!empty($li['membership_num_terms'])) { $termsByType[$li['membership_type_id']] = $li['membership_num_terms']; } } ///CRM-11529 for quick config backoffice transactions //when financial_type_id is passed in form, update the //lineitems with the financial type selected in form if ($isQuickConfig && $submittedFinancialType) { $li['financial_type_id'] = $submittedFinancialType; } } } } $this->storeContactFields($formValues); $params['contact_id'] = $this->_contactID; $fields = array('status_id', 'source', 'is_override', 'campaign_id'); foreach ($fields as $f) { $params[$f] = CRM_Utils_Array::value($f, $formValues); } // fix for CRM-3724 // when is_override false ignore is_admin statuses during membership // status calculation. similarly we did fix for import in CRM-3570. if (empty($params['is_override'])) { $params['exclude_is_admin'] = TRUE; } // process date params to mysql date format. $dateTypes = array('join_date' => 'joinDate', 'start_date' => 'startDate', 'end_date' => 'endDate'); foreach ($dateTypes as $dateField => $dateVariable) { ${$dateVariable} = CRM_Utils_Date::processDate($formValues[$dateField]); } $memTypeNumTerms = empty($termsByType) ? CRM_Utils_Array::value('num_terms', $formValues) : NULL; $calcDates = array(); foreach ($this->_memTypeSelected as $memType) { if (empty($memTypeNumTerms)) { $memTypeNumTerms = CRM_Utils_Array::value($memType, $termsByType, 1); } $calcDates[$memType] = CRM_Member_BAO_MembershipType::getDatesForMembershipType($memType, $joinDate, $startDate, $endDate, $memTypeNumTerms); } foreach ($calcDates as $memType => $calcDate) { foreach (array_keys($dateTypes) as $d) { //first give priority to form values then calDates. $date = CRM_Utils_Array::value($d, $formValues); if (!$date) { $date = CRM_Utils_Array::value($d, $calcDate); } $membershipTypeValues[$memType][$d] = CRM_Utils_Date::processDate($date); //$params[$d] = CRM_Utils_Date::processDate( $date ); } } // max related memberships - take from form or inherit from membership type foreach ($this->_memTypeSelected as $memType) { if (array_key_exists('max_related', $formValues)) { $membershipTypeValues[$memType]['max_related'] = CRM_Utils_Array::value('max_related', $formValues); } } if ($this->_id) { $ids['membership'] = $params['id'] = $this->_id; } $session = CRM_Core_Session::singleton(); $ids['userId'] = $session->get('userID'); // membership type custom data foreach ($this->_memTypeSelected as $memType) { $customFields = CRM_Core_BAO_CustomField::getFields('Membership', FALSE, FALSE, $memType); $customFields = CRM_Utils_Array::crmArrayMerge($customFields, CRM_Core_BAO_CustomField::getFields('Membership', FALSE, FALSE, NULL, NULL, TRUE)); $membershipTypeValues[$memType]['custom'] = CRM_Core_BAO_CustomField::postProcess($formValues, $customFields, $this->_id, 'Membership'); } foreach ($this->_memTypeSelected as $memType) { $membershipTypes[$memType] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $memType); } $membershipType = implode(', ', $membershipTypes); // Retrieve the name and email of the current user - this will be the FROM for the receipt email list($userName, $userEmail) = CRM_Contact_BAO_Contact_Location::getEmailDetails($ids['userId']); //CRM-13981, allow different person as a soft-contributor of chosen type if ($this->_contributorContactID != $this->_contactID) { $params['contribution_contact_id'] = $this->_contributorContactID; if (!empty($this->_params['soft_credit_type_id'])) { $softParams['soft_credit_type_id'] = $this->_params['soft_credit_type_id']; $softParams['contact_id'] = $this->_contactID; } } if (!empty($formValues['record_contribution'])) { $recordContribution = array('total_amount', 'financial_type_id', 'payment_instrument_id', 'trxn_id', 'contribution_status_id', 'check_number', 'campaign_id', 'receive_date'); foreach ($recordContribution as $f) { $params[$f] = CRM_Utils_Array::value($f, $formValues); } if (!$this->_onlinePendingContributionId) { if (empty($formValues['source'])) { $params['contribution_source'] = ts('%1 Membership: Offline signup (by %2)', array(1 => $membershipType, 2 => $userName)); } else { $params['contribution_source'] = $formValues['source']; } } if (empty($params['is_override']) && CRM_Utils_Array::value('contribution_status_id', $params) == array_search('Pending', CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'))) { $params['status_id'] = array_search('Pending', $allMemberStatus); $params['skipStatusCal'] = TRUE; $params['is_pay_later'] = 1; $this->assign('is_pay_later', 1); } if (!empty($formValues['send_receipt'])) { $params['receipt_date'] = CRM_Utils_Array::value('receive_date', $formValues); } //insert financial type name in receipt. $formValues['contributionType_name'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', $formValues['financial_type_id']); } // process line items, until no previous line items. if (!empty($lineItem)) { $params['lineItems'] = $lineItem; $params['processPriceSet'] = TRUE; } $createdMemberships = array(); if ($this->_mode) { if (empty($formValues['total_amount']) && !$priceSetId) { // if total amount not provided minimum for membership type is used $params['total_amount'] = $formValues['total_amount'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $formValues['membership_type_id'][1], 'minimum_fee'); } else { $params['total_amount'] = CRM_Utils_Array::value('total_amount', $formValues, 0); } if ($priceSetId && !$isQuickConfig) { $params['financial_type_id'] = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $priceSetId, 'financial_type_id'); } else { $params['financial_type_id'] = CRM_Utils_Array::value('financial_type_id', $formValues); } $this->_paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getPayment($formValues['payment_processor_id'], $this->_mode); //get the payment processor id as per mode. $params['payment_processor_id'] = $this->_params['payment_processor_id'] = $formValues['payment_processor_id'] = $this->_paymentProcessor['id']; $now = date('YmdHis'); $fields = array(); // set email for primary location. $fields['email-Primary'] = 1; $formValues['email-5'] = $formValues['email-Primary'] = $this->_memberEmail; $params['register_date'] = $now; // now set the values for the billing location. foreach ($this->_fields as $name => $dontCare) { $fields[$name] = 1; } // also add location name to the array $formValues["address_name-{$this->_bltID}"] = CRM_Utils_Array::value('billing_first_name', $formValues) . ' ' . CRM_Utils_Array::value('billing_middle_name', $formValues) . ' ' . CRM_Utils_Array::value('billing_last_name', $formValues); $formValues["address_name-{$this->_bltID}"] = trim($formValues["address_name-{$this->_bltID}"]); $fields["address_name-{$this->_bltID}"] = 1; //ensure we don't over-write the payer's email with the member's email if ($this->_contributorContactID == $this->_contactID) { $fields["email-{$this->_bltID}"] = 1; } $ctype = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactID, 'contact_type'); $nameFields = array('first_name', 'middle_name', 'last_name'); foreach ($nameFields as $name) { $fields[$name] = 1; if (array_key_exists("billing_{$name}", $formValues)) { $formValues[$name] = $formValues["billing_{$name}"]; $formValues['preserveDBName'] = TRUE; } } if ($this->_contributorContactID == $this->_contactID) { //see CRM-12869 for discussion of why we don't do this for separate payee payments CRM_Contact_BAO_Contact::createProfileContact($formValues, $fields, $this->_contributorContactID, NULL, NULL, $ctype); } // add all the additional payment params we need $this->_params["state_province-{$this->_bltID}"] = $this->_params["billing_state_province-{$this->_bltID}"] = CRM_Core_PseudoConstant::stateProvinceAbbreviation($this->_params["billing_state_province_id-{$this->_bltID}"]); $this->_params["country-{$this->_bltID}"] = $this->_params["billing_country-{$this->_bltID}"] = CRM_Core_PseudoConstant::countryIsoCode($this->_params["billing_country_id-{$this->_bltID}"]); $this->_params['year'] = CRM_Core_Payment_Form::getCreditCardExpirationYear($this->_params); $this->_params['month'] = CRM_Core_Payment_Form::getCreditCardExpirationMonth($this->_params); $this->_params['ip_address'] = CRM_Utils_System::ipAddress(); $this->_params['amount'] = $params['total_amount']; $this->_params['currencyID'] = $config->defaultCurrency; $this->_params['description'] = ts('Office Credit Card Membership Signup Contribution'); $this->_params['payment_action'] = 'Sale'; $this->_params['invoiceID'] = md5(uniqid(rand(), TRUE)); $this->_params['financial_type_id'] = $params['financial_type_id']; // at this point we've created a contact and stored its address etc // all the payment processors expect the name and address to be in the // so we copy stuff over to first_name etc. $paymentParams = $this->_params; $paymentParams['contactID'] = $this->_contributorContactID; //CRM-10377 if payment is by an alternate contact then we need to set that person // as the contact in the payment params if ($this->_contributorContactID != $this->_contactID) { if (!empty($this->_params['soft_credit_type_id'])) { $softParams['contact_id'] = $params['contact_id']; $softParams['soft_credit_type_id'] = $this->_params['soft_credit_type_id']; } } if (!empty($this->_params['send_receipt'])) { $paymentParams['email'] = $this->_contributorEmail; } CRM_Core_Payment_Form::mapParams($this->_bltID, $this->_params, $paymentParams, TRUE); // CRM-7137 -for recurring membership, // we do need contribution and recuring records. $result = NULL; if (!empty($paymentParams['is_recur'])) { $contributionType = new CRM_Financial_DAO_FinancialType(); $contributionType->id = $params['financial_type_id']; if (!$contributionType->find(TRUE)) { CRM_Core_Error::fatal('Could not find a system table'); } $contribution = CRM_Contribute_Form_Contribution_Confirm::processContribution($this, $paymentParams, $result, $this->_contributorContactID, $contributionType, TRUE, FALSE, $isTest, $lineItems); //create new soft-credit record, CRM-13981 if ($softParams) { $softParams['contribution_id'] = $contribution->id; $softParams['currency'] = $contribution->currency; $softParams['amount'] = $contribution->total_amount; CRM_Contribute_BAO_ContributionSoft::add($softParams); } $paymentParams['contactID'] = $this->_contactID; $paymentParams['contributionID'] = $contribution->id; $paymentParams['contributionTypeID'] = $contribution->financial_type_id; $paymentParams['contributionPageID'] = $contribution->contribution_page_id; $paymentParams['contributionRecurID'] = $contribution->contribution_recur_id; $ids['contribution'] = $contribution->id; $params['contribution_recur_id'] = $paymentParams['contributionRecurID']; } if ($params['total_amount'] > 0.0) { $payment = CRM_Core_Payment::singleton($this->_mode, $this->_paymentProcessor, $this); $result = $payment->doDirectPayment($paymentParams); } if (is_a($result, 'CRM_Core_Error')) { //make sure to cleanup db for recurring case. if (!empty($paymentParams['contributionID'])) { CRM_Contribute_BAO_Contribution::deleteContribution($paymentParams['contributionID']); } if (!empty($paymentParams['contributionRecurID'])) { CRM_Contribute_BAO_ContributionRecur::deleteRecurContribution($paymentParams['contributionRecurID']); } CRM_Core_Error::displaySessionError($result); CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/view/membership', "reset=1&action=add&cid={$this->_contactID}&context=&mode={$this->_mode}")); } if ($result) { $this->_params = array_merge($this->_params, $result); //assign amount to template if payment was successful $this->assign('amount', $params['total_amount']); } // if the payment processor returns a contribution_status_id -> use it! if (isset($result['contribution_status_id'])) { $result['payment_status_id'] = $result['contribution_status_id']; } if (isset($result['payment_status_id'])) { // CRM-16737 $result['contribution_status_id'] is deprecated in favour // of payment_status_id as the payment processor only knows whether the payment is complete // not whether payment completes the contribution $params['contribution_status_id'] = $result['payment_status_id']; } else { $params['contribution_status_id'] = !empty($paymentParams['is_recur']) ? 2 : 1; } if ($params['contribution_status_id'] != array_search('Completed', $allContributionStatus)) { $params['status_id'] = array_search('Pending', $allMemberStatus); $params['skipStatusCal'] = TRUE; // unset send-receipt option, since receipt will be sent when ipn is received. unset($this->_params['send_receipt'], $formValues['send_receipt']); //as membership is pending set dates to null. $memberDates = array('join_date' => 'joinDate', 'start_date' => 'startDate', 'end_date' => 'endDate'); foreach ($memberDates as $dp => $dv) { ${$dv} = NULL; foreach ($this->_memTypeSelected as $memType) { $membershipTypeValues[$memType][$dv] = NULL; } } } $params['receive_date'] = $now; $params['invoice_id'] = $this->_params['invoiceID']; $params['contribution_source'] = ts('%1 Membership Signup: Credit card or direct debit (by %2)', array(1 => $membershipType, 2 => $userName)); $params['source'] = $formValues['source'] ? $formValues['source'] : $params['contribution_source']; $params['trxn_id'] = CRM_Utils_Array::value('trxn_id', $result); $params['payment_instrument_id'] = 1; $params['is_test'] = $this->_mode == 'live' ? 0 : 1; if (!empty($this->_params['send_receipt'])) { $params['receipt_date'] = $now; } else { $params['receipt_date'] = NULL; } $this->set('params', $this->_params); $this->assign('trxn_id', CRM_Utils_Array::value('trxn_id', $result)); $this->assign('receive_date', CRM_Utils_Date::mysqlToIso($params['receive_date'])); // required for creating membership for related contacts $params['action'] = $this->_action; //create membership record. $count = 0; foreach ($this->_memTypeSelected as $memType) { if ($count && ($relateContribution = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id))) { $membershipTypeValues[$memType]['relate_contribution_id'] = $relateContribution; } $membershipParams = array_merge($membershipTypeValues[$memType], $params); //CRM-15366 if (!empty($softParams) && empty($paymentParams['is_recur'])) { $membershipParams['soft_credit'] = $softParams; } if (!empty($paymentParams['is_recur']) && CRM_Utils_Array::value('payment_status_id', $result) == 1) { // CRM-16993 we have a situation where line items have already been created. unset($membershipParams['lineItems']); } $membership = CRM_Member_BAO_Membership::create($membershipParams, $ids); $params['contribution'] = CRM_Utils_Array::value('contribution', $membershipParams); unset($params['lineItems']); $this->_membershipIDs[] = $membership->id; $createdMemberships[$memType] = $membership; $count++; } } else { $params['action'] = $this->_action; if ($this->_onlinePendingContributionId && !empty($formValues['record_contribution'])) { // update membership as well as contribution object, CRM-4395 $params['contribution_id'] = $this->_onlinePendingContributionId; $params['componentId'] = $params['id']; $params['componentName'] = 'contribute'; $result = CRM_Contribute_BAO_Contribution::transitionComponents($params, TRUE); if (!empty($result) && !empty($params['contribution_id'])) { $lineItem = array(); $lineItems = CRM_Price_BAO_LineItem::getLineItems($params['contribution_id'], 'contribution', NULL, TRUE, TRUE); $itemId = key($lineItems); $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', $lineItems[$itemId]['price_field_id'], 'price_set_id'); $fieldType = NULL; if ($itemId && !empty($lineItems[$itemId]['price_field_id'])) { $fieldType = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', $lineItems[$itemId]['price_field_id'], 'html_type'); } $lineItems[$itemId]['unit_price'] = $params['total_amount']; $lineItems[$itemId]['line_total'] = $params['total_amount']; $lineItems[$itemId]['id'] = $itemId; $lineItem[$priceSetId] = $lineItems; $contributionBAO = new CRM_Contribute_BAO_Contribution(); $contributionBAO->id = $params['contribution_id']; $contributionBAO->contact_id = $params['contact_id']; $contributionBAO->find(); CRM_Price_BAO_LineItem::processPriceSet($params['contribution_id'], $lineItem, $contributionBAO, 'civicrm_membership'); //create new soft-credit record, CRM-13981 if ($softParams) { $softParams['contribution_id'] = $params['contribution_id']; while ($contributionBAO->fetch()) { $softParams['currency'] = $contributionBAO->currency; $softParams['amount'] = $contributionBAO->total_amount; } CRM_Contribute_BAO_ContributionSoft::add($softParams); } } //carry updated membership object. $membership = new CRM_Member_DAO_Membership(); $membership->id = $this->_id; $membership->find(TRUE); $cancelled = TRUE; if ($membership->end_date) { //display end date w/ status message. $endDate = $membership->end_date; if (!in_array($membership->status_id, array(array_search('Cancelled', CRM_Member_PseudoConstant::membershipStatus(NULL, " name = 'Cancelled' ", 'name', FALSE, TRUE)), array_search('Expired', CRM_Member_PseudoConstant::membershipStatus())))) { $cancelled = FALSE; } } // suppress form values in template. $this->assign('cancelled', $cancelled); // FIX ME: need to recheck this // here we might updated dates, so get from object. foreach ($calcDates[$membership->membership_type_id] as $date => &$val) { if ($membership->{$date}) { $val = $membership->{$date}; } } $createdMemberships[] = $membership; } else { $count = 0; foreach ($this->_memTypeSelected as $memType) { if ($count && !empty($formValues['record_contribution']) && ($relateContribution = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id))) { $membershipTypeValues[$memType]['relate_contribution_id'] = $relateContribution; } $membershipParams = array_merge($params, $membershipTypeValues[$memType]); if (!empty($formValues['int_amount'])) { $init_amount = array(); foreach ($formValues as $key => $value) { if (strstr($key, 'txt-price')) { $init_amount[$key] = $value; } } $membershipParams['init_amount'] = $init_amount; } if (!empty($softParams)) { $membershipParams['soft_credit'] = $softParams; } $membership = CRM_Member_BAO_Membership::create($membershipParams, $ids); $params['contribution'] = CRM_Utils_Array::value('contribution', $membershipParams); unset($params['lineItems']); $this->_membershipIDs[] = $membership->id; $createdMemberships[$memType] = $membership; $count++; } } } if (!empty($lineItem[$priceSetId])) { $invoiceSettings = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME, 'contribution_invoice_settings'); $invoicing = CRM_Utils_Array::value('invoicing', $invoiceSettings); $taxAmount = FALSE; $totalTaxAmount = 0; foreach ($lineItem[$priceSetId] as &$priceFieldOp) { if (!empty($priceFieldOp['membership_type_id'])) { $priceFieldOp['start_date'] = $membershipTypeValues[$priceFieldOp['membership_type_id']]['start_date'] ? CRM_Utils_Date::customFormat($membershipTypeValues[$priceFieldOp['membership_type_id']]['start_date'], '%B %E%f, %Y') : '-'; $priceFieldOp['end_date'] = $membershipTypeValues[$priceFieldOp['membership_type_id']]['end_date'] ? CRM_Utils_Date::customFormat($membershipTypeValues[$priceFieldOp['membership_type_id']]['end_date'], '%B %E%f, %Y') : '-'; } else { $priceFieldOp['start_date'] = $priceFieldOp['end_date'] = 'N/A'; } if ($invoicing && isset($priceFieldOp['tax_amount'])) { $taxAmount = TRUE; $totalTaxAmount += $priceFieldOp['tax_amount']; } } if ($invoicing) { $dataArray = array(); foreach ($lineItem[$priceSetId] as $key => $value) { if (isset($value['tax_amount']) && isset($value['tax_rate'])) { if (isset($dataArray[$value['tax_rate']])) { $dataArray[$value['tax_rate']] = $dataArray[$value['tax_rate']] + CRM_Utils_Array::value('tax_amount', $value); } else { $dataArray[$value['tax_rate']] = CRM_Utils_Array::value('tax_amount', $value); } } } if ($taxAmount) { $this->assign('totalTaxAmount', $totalTaxAmount); $this->assign('taxTerm', CRM_Utils_Array::value('tax_term', $invoiceSettings)); } $this->assign('dataArray', $dataArray); } } $this->assign('lineItem', !empty($lineItem) && !$isQuickConfig ? $lineItem : FALSE); $receiptSend = FALSE; $contributionId = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id); $membershipIds = $this->_membershipIDs; if ($contributionId && !empty($membershipIds)) { $contributionDetails = CRM_Contribute_BAO_Contribution::getContributionDetails(CRM_Export_Form_Select::MEMBER_EXPORT, $this->_membershipIDs); if ($contributionDetails[$membership->id]['contribution_status'] == 'Completed') { $receiptSend = TRUE; } } if (!empty($formValues['send_receipt']) && $receiptSend) { $formValues['contact_id'] = $this->_contactID; $formValues['contribution_id'] = $contributionId; // send email receipt $mailSend = self::emailReceipt($this, $formValues, $membership); } if ($this->_action & CRM_Core_Action::UPDATE) { //end date can be modified by hooks, so if end date is set then use it. $endDate = $membership->end_date ? $membership->end_date : $endDate; $statusMsg = ts('Membership for %1 has been updated.', array(1 => $this->_memberDisplayName)); if ($endDate && $endDate !== 'null') { $endDate = CRM_Utils_Date::customFormat($endDate); $statusMsg .= ' ' . ts('The membership End Date is %1.', array(1 => $endDate)); } if ($receiptSend) { $statusMsg .= ' ' . ts('A confirmation and receipt has been sent to %1.', array(1 => $this->_contributorEmail)); } } elseif ($this->_action & CRM_Core_Action::ADD) { // FIX ME: fix status messages $statusMsg = array(); foreach ($membershipTypes as $memType => $membershipType) { $statusMsg[$memType] = ts('%1 membership for %2 has been added.', array(1 => $membershipType, 2 => $this->_memberDisplayName)); $membership = $createdMemberships[$memType]; $memEndDate = $membership->end_date ? $membership->end_date : $endDate; //get the end date from calculated dates. if (!$memEndDate && empty($params['is_recur'])) { $memEndDate = CRM_Utils_Array::value('end_date', $calcDates[$memType]); } if ($memEndDate && $memEndDate !== 'null') { $memEndDate = CRM_Utils_Date::customFormat($memEndDate); $statusMsg[$memType] .= ' ' . ts('The new membership End Date is %1.', array(1 => $memEndDate)); } } $statusMsg = implode('<br/>', $statusMsg); if ($receiptSend && !empty($mailSend)) { $statusMsg .= ' ' . ts('A membership confirmation and receipt has been sent to %1.', array(1 => $this->_contributorEmail)); } } // finally set membership id if already not set if (!$this->_id) { $this->_id = $membership->id; } CRM_Core_Session::setStatus($statusMsg, ts('Complete'), 'success'); $buttonName = $this->controller->getButtonName(); if ($this->_context == 'standalone') { if ($buttonName == $this->getButtonName('upload', 'new')) { $session->replaceUserContext(CRM_Utils_System::url('civicrm/member/add', 'reset=1&action=add&context=standalone')); } else { $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$this->_contactID}&selectedChild=member")); } } elseif ($buttonName == $this->getButtonName('upload', 'new')) { $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/membership', "reset=1&action=add&context=membership&cid={$this->_contactID}")); } }
/** * Perform create or delete action on related memberships. * * @param string $action * Create or delete. * @param array $owner * Primary membership info (membership_id, contact_id, membership_type ...). */ public function relAction($action, $owner) { switch ($action) { case 'delete': $id = CRM_Utils_Request::retrieve('mid', 'Positive', $this); $relatedContactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this); $relatedDisplayName = CRM_Contact_BAO_Contact::displayName($relatedContactId); CRM_Member_BAO_Membership::del($id); CRM_Core_Session::setStatus(ts('Related membership for %1 has been deleted.', array(1 => $relatedDisplayName)), ts('Membership Deleted'), 'success'); break; case 'create': $ids = array(); $params = array('contact_id' => CRM_Utils_Request::retrieve('rid', 'Positive', $this), 'membership_type_id' => $owner['membership_type_id'], 'owner_membership_id' => $owner['id'], 'join_date' => CRM_Utils_Date::processDate($owner['join_date'], NULL, TRUE, 'Ymd'), 'start_date' => CRM_Utils_Date::processDate($owner['start_date'], NULL, TRUE, 'Ymd'), 'end_date' => CRM_Utils_Date::processDate($owner['end_date'], NULL, TRUE, 'Ymd'), 'source' => ts('Manual Assignment of Related Membership'), 'is_test' => $owner['is_test'], 'campaign_id' => CRM_Utils_Array::value('campaign_id', $owner), 'status_id' => $owner['status_id'], 'skipStatusCal' => TRUE, 'createActivity' => TRUE); CRM_Member_BAO_Membership::create($params, $ids); $relatedDisplayName = CRM_Contact_BAO_Contact::displayName($params['contact_id']); CRM_Core_Session::setStatus(ts('Related membership for %1 has been created.', array(1 => $relatedDisplayName)), ts('Membership Added'), 'success'); break; default: CRM_Core_Error::fatal(ts("Invalid action specified in URL")); } // Redirect back to membership view page for the owner, without the relAction parameters CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/view/membership', "action=view&reset=1&id={$owner['membership_id']}&cid={$owner['contact_id']}" . $this->addContext())); }
/** * function to create memberships for related contacts * * @param array $params array of key - value pairs * @param object $membership membership object * * @return null|relatedMembership array of memberships if created * @static * @access public */ static function createRelatedMemberships(&$params, &$membership) { static $relatedContactIds = array(); // required since create method doesn't return all the // parameters in the returned membership object if (!$membership->find(true)) { return; } require_once 'CRM/Member/PseudoConstant.php'; $deceasedStatusId = array_search('Deceased', CRM_Member_PseudoConstant::membershipStatus()); $allRelatedContacts = array(); $relatedContacts = array(); if (!is_a($membership, 'CRM_Core_Error')) { $allRelatedContacts = CRM_Member_BAO_Membership::checkMembershipRelationship($membership->id, $membership->contact_id, CRM_Utils_Array::value('action', $params)); } // check for loops. CRM-4213 // remove repeated related contacts, which already inherited membership. $relatedContactIds[$membership->contact_id] = true; foreach ($allRelatedContacts as $cid => $status) { if (!CRM_Utils_Array::value($cid, $relatedContactIds)) { $relatedContactIds[$cid] = true; //don't create membership again for owner contact. $nestedRelationship = false; if ($membership->owner_membership_id) { $nestedRelMembership = new CRM_Member_DAO_Membership(); $nestedRelMembership->id = $membership->owner_membership_id; $nestedRelMembership->contact_id = $cid; $nestedRelationship = $nestedRelMembership->find(true); $nestedRelMembership->free(); } if (!$nestedRelationship) { $relatedContacts[$cid] = $status; } } } //lets cleanup related membership if any. if (empty($relatedContacts)) { require_once 'CRM/Member/BAO/Membership.php'; CRM_Member_BAO_Membership::deleteRelatedMemberships($membership->id); } else { // Edit the params array unset($params['id']); // Reminder should be sent only to the direct membership unset($params['reminder_date']); // unset the custom value ids if (is_array(CRM_Utils_Array::value('custom', $params))) { foreach ($params['custom'] as $k => $v) { unset($params['custom'][$k]['id']); } } if (!isset($params['membership_type_id'])) { $params['membership_type_id'] = $membership->membership_type_id; } foreach ($relatedContacts as $contactId => $relationshipStatus) { //use existing membership record. $relMembership = new CRM_Member_DAO_Membership(); $relMembership->contact_id = $contactId; $relMembership->owner_membership_id = $membership->id; $relMemIds = array(); if ($relMembership->find(true)) { $params['id'] = $relMemIds['membership'] = $relMembership->id; } $params['contact_id'] = $contactId; $params['owner_membership_id'] = $membership->id; // set status_id as it might have been changed for // past relationship $params['status_id'] = $membership->status_id; if ($deceasedStatusId && CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $contactId, 'is_deceased')) { $params['status_id'] = $deceasedStatusId; } else { if (CRM_Utils_Array::value('action', $params) & CRM_Core_Action::UPDATE && $relationshipStatus == CRM_Contact_BAO_Relationship::PAST) { // FIXME : While updating/ renewing the // membership, if the relationship is PAST then // the membership of the related contact must be // expired. // For that, getting Membership Status for which // is_current_member is 0. It works for the // generated data as there is only one membership // status having is_current_member = 0. // But this wont work exactly if there will be // more than one status having is_current_member = 0. require_once 'CRM/Member/DAO/MembershipStatus.php'; $membershipStatus = new CRM_Member_DAO_MembershipStatus(); $membershipStatus->is_current_member = 0; if ($membershipStatus->find(true)) { $params['status_id'] = $membershipStatus->id; } } } //don't calculate status again in create( ); $params['skipStatusCal'] = true; //do create activity if we changed status. if ($params['status_id'] != $relMembership->status_id) { $params['createActivity'] = true; } // we should not created contribution record for related contacts, CRM-3371 unset($params['contribution_status_id']); CRM_Member_BAO_Membership::create($params, $relMemIds); } } }
/** * Update an existing contact membership * * This api is used for updating an existing contact membership. * Required parrmeters : id of a membership * * @param Array $params an associative array of name/value property values of civicrm_membership * * @return array of updated membership property values * @access public */ function crm_update_contact_membership($params) { _crm_initialize(); if (!is_array($params)) { return _crm_error('Params is not an array'); } if (!isset($params['id'])) { return _crm_error('Required parameter missing'); } $changeFields = array('membership_start_date' => 'start_date', 'membership_end_date' => 'end_date', 'membership_source' => 'source'); foreach ($changeFields as $field => $requiredField) { if (array_key_exists($field, $params)) { $params[$requiredField] = $params[$field]; unset($params[$field]); } } require_once 'CRM/Member/BAO/Membership.php'; $membershipBAO =& new CRM_Member_BAO_Membership(); $membershipBAO->id = $params['id']; $membershipBAO->find(true); $oldStatusID = $membershipBAO->status_id; $membershipBAO->copyValues($params); $datefields = array('start_date', 'end_date', 'join_date', 'reminder_date'); //fix the dates foreach ($datefields as $value) { $membershipBAO->{$value} = CRM_Utils_Date::customFormat($membershipBAO->{$value}, '%Y%m%d'); // Handle resetting date to 'null' (which is converted to 00000 by customFormat) if ($membershipBAO->{$value} == '00000') { $membershipBAO->{$value} = 'null'; } $params[$value] = $membershipBAO->{$value}; } $membershipBAO->save(); require_once "CRM/Core/Action.php"; // Check and add membership for related contacts $relatedContacts = CRM_Member_BAO_Membership::checkMembershipRelationship($membershipBAO->id, (int) $membershipBAO->contact_id, CRM_Core_Action::UPDATE); //delete all the related membership records before creating CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipBAO->id); $params['membership_type_id'] = $membershipBAO->membership_type_id; foreach ($relatedContacts as $contactId => $relationshipStatus) { if ($relationshipStatus & CRM_Contact_BAO_Relationship::CURRENT) { $params['contact_id'] = $contactId; $params['owner_membership_id'] = $membershipBAO->id; unset($params['id']); CRM_Member_BAO_Membership::create($params, CRM_Core_DAO::$_nullArray); } } // Create activity history record. require_once "CRM/Member/PseudoConstant.php"; $membershipType = CRM_Member_PseudoConstant::membershipType($membershipBAO->membership_type_id); if (!$membershipType) { $membershipType = ts('Membership'); } $activitySummary = $membershipType; if ($membershipBAO->source != 'null') { $activitySummary .= " - {$membershipBAO->source}"; } if ($membershipBAO->owner_membership_id) { $cid = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $membershipBAO->owner_membership_id, 'contact_id'); $displayName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $cid, 'display_name'); $activitySummary .= " (by {$displayName})"; } // create activity record only if there is change in the statusID (CRM-2521). if ($oldStatusID != $membershipBAO->status_id) { $activityParams = array('source_contact_id' => $membershipBAO->contact_id, 'source_record_id' => $membershipBAO->id, 'activity_type_id' => array_search('Membership Signup', CRM_Core_PseudoConstant::activityType()), 'subject' => $activitySummary, 'activity_date_time' => $params['join_date'], 'is_test' => $membershipBAO->is_test, 'status_id' => 2); require_once 'api/v2/Activity.php'; if (is_a(civicrm_activity_create($activityParams), 'CRM_Core_Error')) { return false; } } $membership = array(); _crm_object_to_array($membershipBAO, $membership); $membershipBAO->free(); return $membership; }
/** * Function to create / update / delete membership for related contacts. * * This function will create/update/delete membership for related * contact based on 1) contact have active membership 2) that * membership is is extedned by the same relationship type to that * of the existing relationship. * * @param $contactId Int contact id * @param $params array array of values submitted by POST * @param $ids array array of ids * @param $action which action called this function * * @static * */ static function relatedMemberships($contactId, &$params, $ids, $action = CRM_Core_Action::ADD, $active = true) { // Check the end date and set the status of the relationship // accrodingly. $status = self::CURRENT; if (!empty($params['end_date'])) { $endDate = CRM_Utils_Date::setDateDefaults($params['end_date'], null, 'Ymd'); $today = date('Ymd'); if ($today > $endDate) { $status = self::PAST; } } if ($action & CRM_Core_Action::ADD && $status & self::PAST) { // if relationship is PAST and action is ADD, no qustion // of creating RELATED membership and return back to // calling method return; } $rel = explode("_", $params['relationship_type_id']); $relTypeId = $rel[0]; $relDirection = "_{$rel[1]}_{$rel[2]}"; $targetContact = array(); if ($action & CRM_Core_Action::ADD || $action & CRM_Core_Action::DELETE) { $contact = $contactId; $targetContact = CRM_Utils_Array::value('contact_check', $params); } else { if ($action & CRM_Core_Action::UPDATE) { $contact = $ids['contact']; $targetContact = array($ids['contactTarget'] => 1); } } // Build the 'values' array for // 1. ContactA // 2. ContactB // This will allow us to check if either of the contacts in // relationship have active memberships. $values = array(); // 1. ContactA $values[$contact] = array('relatedContacts' => $targetContact, 'relationshipTypeId' => $relTypeId, 'relationshipTypeDirection' => $relDirection); // 2. ContactB if (!empty($targetContact)) { foreach ($targetContact as $cid => $donCare) { $values[$cid] = array('relatedContacts' => array($contact => 1), 'relationshipTypeId' => $relTypeId); $relTypeParams = array('id' => $relTypeId); $relTypeValues = array(); require_once 'CRM/Contact/BAO/RelationshipType.php'; CRM_Contact_BAO_RelationshipType::retrieve($relTypeParams, $relTypeValues); if (CRM_Utils_Array::value('name_a_b', $relTypeValues) == CRM_Utils_Array::value('name_b_a', $relTypeValues)) { $values[$cid]['relationshipTypeDirection'] = '_a_b'; } else { $values[$cid]['relationshipTypeDirection'] = $relDirection == '_a_b' ? '_b_a' : '_a_b'; } } } // Now get the active memberships for all the contacts. // If contact have any valid membership(s), then add it to // 'values' array. foreach ($values as $cid => $subValues) { $memParams = array('contact_id' => $cid); $memberships = array(); require_once 'CRM/Member/BAO/Membership.php'; CRM_Member_BAO_Membership::getValues($memParams, $memberships, $active); if (empty($memberships)) { continue; } $values[$cid]['memberships'] = $memberships; } // done with 'values' array. // Finally add / edit / delete memberships for the related contacts foreach ($values as $cid => $details) { if (!array_key_exists('memberships', $details)) { continue; } require_once 'CRM/Member/BAO/MembershipType.php'; foreach ($details['memberships'] as $membershipId => $membershipValues) { if ($action & CRM_Core_Action::DELETE) { // delete memberships of the related contacts. CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipId); continue; } if ($action & CRM_Core_Action::UPDATE && $status & self::PAST && $membershipValues['owner_membership_id']) { // If relationship is PAST and action is UPDATE // then delete the RELATED membership CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipValues['owner_membership_id'], $membershipValues['membership_contact_id']); continue; } // add / edit the memberships for related // contacts. // Get the Membership Type Details. $membershipType = CRM_Member_BAO_MembershipType::getMembershipTypeDetails($membershipValues['membership_type_id']); if ("{$details['relationshipTypeId']}{$details['relationshipTypeDirection']}" == CRM_Utils_Array::value('relationship_type_id', $membershipType) . "_" . CRM_Utils_Array::value('relationship_direction', $membershipType)) { // Check if relationship being created/updated is // similar to that of membership type's // relationship. $membershipValues['owner_membership_id'] = $membershipId; unset($membershipValues['id']); unset($membershipValues['membership_contact_id']); unset($membershipValues['contact_id']); unset($membershipValues['membership_id']); foreach ($details['relatedContacts'] as $relatedContactId => $donCare) { $membershipValues['contact_id'] = $relatedContactId; if ($action & CRM_Core_Action::UPDATE) { //delete the membership record for related //contact before creating new membership record. CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipId, $relatedContactId); } CRM_Member_BAO_Membership::create($membershipValues, CRM_Core_DAO::$_nullArray); } } else { if ($action & CRM_Core_Action::UPDATE) { // if action is update and updated relationship do // not match with the existing // membership=>relationship then we need to // delete the membership record created for // previous relationship. CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipId, $ids['contactTarget']); } } } } }
/** * Function to process the form * * @access public * @return None */ public function postProcess() { require_once 'CRM/Member/BAO/Membership.php'; require_once 'CRM/Member/BAO/MembershipType.php'; require_once 'CRM/Member/BAO/MembershipStatus.php'; if ($this->_action & CRM_Core_Action::DELETE) { CRM_Member_BAO_Membership::deleteRelatedMemberships($this->_id); CRM_Member_BAO_Membership::deleteMembership($this->_id); return; } $config =& CRM_Core_Config::singleton(); // get the submitted form values. $this->_params = $formValues = $this->controller->exportValues($this->_name); $params = array(); $ids = array(); // set the contact, when contact is selected if (CRM_Utils_Array::value('contact_select_id', $formValues)) { $this->_contactID = CRM_Utils_Array::value('contact_select_id', $formValues); } $params['contact_id'] = $this->_contactID; // we need to retrieve email address if ($this->_context == 'standalone' && CRM_Utils_Array::value('send_receipt', $formValues)) { require_once 'CRM/Contact/BAO/Contact/Location.php'; list($this->_contributorDisplayName, $this->_contributorEmail) = CRM_Contact_BAO_Contact_Location::getEmailDetails($this->_contactID); } $fields = array('status_id', 'source', 'is_override'); foreach ($fields as $f) { $params[$f] = CRM_Utils_Array::value($f, $formValues); } // fix for CRM-3724 // when is_override false ignore is_admin statuses during membership // status calculation. similarly we did fix for import in CRM-3570. if (!CRM_Utils_Array::value('is_override', $params)) { $params['exclude_is_admin'] = true; } $params['membership_type_id'] = $formValues['membership_type_id'][1]; $joinDate = CRM_Utils_Date::processDate($formValues['join_date']); $startDate = CRM_Utils_Date::processDate($formValues['start_date']); $endDate = CRM_Utils_Date::processDate($formValues['end_date']); $calcDates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($params['membership_type_id'], $joinDate, $startDate, $endDate); $dates = array('join_date', 'start_date', 'end_date', 'reminder_date', 'receive_date'); $currentTime = getDate(); foreach ($dates as $d) { if (isset($formValues[$d]) && !CRM_Utils_System::isNull($formValues[$d])) { $params[$d] = CRM_Utils_Date::processDate($formValues[$d]); } else { if (isset($calcDates[$d])) { $params[$d] = CRM_Utils_Date::processDate($calcDates[$d]); } } } if ($this->_id) { $ids['membership'] = $params['id'] = $this->_id; } $session = CRM_Core_Session::singleton(); $ids['userId'] = $session->get('userID'); // membership type custom data $customFields = CRM_Core_BAO_CustomField::getFields('Membership', false, false, CRM_Utils_Array::value('membership_type_id', $params)); $customFields = CRM_Utils_Array::crmArrayMerge($customFields, CRM_Core_BAO_CustomField::getFields('Membership', false, false, null, null, true)); $params['custom'] = CRM_Core_BAO_CustomField::postProcess($formValues, $customFields, $this->_id, 'Membership'); // Retrieve the name and email of the current user - this will be the FROM for the receipt email require_once 'CRM/Contact/BAO/Contact/Location.php'; list($userName, $userEmail) = CRM_Contact_BAO_Contact_Location::getEmailDetails($ids['userId']); if (CRM_Utils_Array::value('record_contribution', $formValues)) { $recordContribution = array('total_amount', 'contribution_type_id', 'payment_instrument_id', 'trxn_id', 'contribution_status_id', 'check_number'); foreach ($recordContribution as $f) { $params[$f] = CRM_Utils_Array::value($f, $formValues); } $membershipType = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $formValues['membership_type_id'][1]); if (!$this->_onlinePendingContributionId) { $params['contribution_source'] = "{$membershipType} Membership: Offline membership signup (by {$userName})"; } if ($formValues['send_receipt']) { $params['receipt_date'] = $params['receive_date']; } //insert contribution type name in receipt. $formValues['contributionType_name'] = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_ContributionType', $formValues['contribution_type_id']); } if ($this->_mode) { $params['total_amount'] = $formValues['total_amount'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $params['membership_type_id'], 'minimum_fee'); $params['contribution_type_id'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $params['membership_type_id'], 'contribution_type_id'); require_once 'CRM/Core/BAO/PaymentProcessor.php'; $this->_paymentProcessor = CRM_Core_BAO_PaymentProcessor::getPayment($formValues['payment_processor_id'], $this->_mode); require_once "CRM/Contact/BAO/Contact.php"; $now = date('YmdHis'); $fields = array(); // set email for primary location. $fields["email-Primary"] = 1; $formValues["email-5"] = $formValues["email-Primary"] = $this->_contributorEmail; $params['register_date'] = $now; // now set the values for the billing location. foreach ($this->_fields as $name => $dontCare) { $fields[$name] = 1; } // also add location name to the array $formValues["address_name-{$this->_bltID}"] = CRM_Utils_Array::value('billing_first_name', $formValues) . ' ' . CRM_Utils_Array::value('billing_middle_name', $formValues) . ' ' . CRM_Utils_Array::value('billing_last_name', $formValues); $formValues["address_name-{$this->_bltID}"] = trim($formValues["address_name-{$this->_bltID}"]); $fields["address_name-{$this->_bltID}"] = 1; $fields["email-{$this->_bltID}"] = 1; $ctype = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactID, 'contact_type'); $nameFields = array('first_name', 'middle_name', 'last_name'); foreach ($nameFields as $name) { $fields[$name] = 1; if (array_key_exists("billing_{$name}", $formValues)) { $formValues[$name] = $formValues["billing_{$name}"]; $formValues['preserveDBName'] = true; } } $contactID = CRM_Contact_BAO_Contact::createProfileContact($formValues, $fields, $this->_contactID, null, null, $ctype); // add all the additioanl payment params we need $this->_params["state_province-{$this->_bltID}"] = $this->_params["billing_state_province-{$this->_bltID}"] = CRM_Core_PseudoConstant::stateProvinceAbbreviation($this->_params["billing_state_province_id-{$this->_bltID}"]); $this->_params["country-{$this->_bltID}"] = $this->_params["billing_country-{$this->_bltID}"] = CRM_Core_PseudoConstant::countryIsoCode($this->_params["billing_country_id-{$this->_bltID}"]); $this->_params['year'] = $this->_params['credit_card_exp_date']['Y']; $this->_params['month'] = $this->_params['credit_card_exp_date']['M']; $this->_params['ip_address'] = CRM_Utils_System::ipAddress(); $this->_params['amount'] = $params['total_amount']; $this->_params['currencyID'] = $config->defaultCurrency; $this->_params['payment_action'] = 'Sale'; $this->_params['invoiceID'] = md5(uniqid(rand(), true)); // at this point we've created a contact and stored its address etc // all the payment processors expect the name and address to be in the // so we copy stuff over to first_name etc. $paymentParams = $this->_params; if (CRM_Utils_Array::value('send_receipt', $this->_params)) { $paymentParams['email'] = $this->_contributorEmail; } require_once 'CRM/Core/Payment/Form.php'; CRM_Core_Payment_Form::mapParams($this->_bltID, $this->_params, $paymentParams, true); $payment =& CRM_Core_Payment::singleton($this->_mode, 'Contribute', $this->_paymentProcessor, $this); $result =& $payment->doDirectPayment($paymentParams); if (is_a($result, 'CRM_Core_Error')) { CRM_Core_Error::displaySessionError($result); CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/view/membership', "reset=1&action=add&cid={$this->_contactID}&context=&mode={$this->_mode}")); } if ($result) { $this->_params = array_merge($this->_params, $result); } $params['contribution_status_id'] = 1; $params['receive_date'] = $now; $params['invoice_id'] = $this->_params['invoiceID']; $params['contribution_source'] = ts('Online Membership: Admin Interface'); $params['source'] = $formValues['source'] ? $formValues['source'] : $params['contribution_source']; $params['trxn_id'] = $result['trxn_id']; $params['payment_instrument_id'] = 1; $params['is_test'] = $this->_mode == 'live' ? 0 : 1; if (CRM_Utils_Array::value('send_receipt', $this->_params)) { $params['receipt_date'] = $now; } else { $params['receipt_date'] = null; } $this->set('params', $this->_params); $this->assign('trxn_id', $result['trxn_id']); $this->assign('receive_date', CRM_Utils_Date::mysqlToIso($params['receive_date'])); // required for creating membership for related contacts $params['action'] = $this->_action; $membership =& CRM_Member_BAO_Membership::create($params, $ids); $contribution = new CRM_Contribute_BAO_Contribution(); $contribution->trxn_id = $result['trxn_id']; if ($contribution->find(true)) { // next create the transaction record $trxnParams = array('contribution_id' => $contribution->id, 'trxn_date' => $now, 'trxn_type' => 'Debit', 'total_amount' => $params['total_amount'], 'fee_amount' => CRM_Utils_Array::value('fee_amount', $result), 'net_amount' => CRM_Utils_Array::value('net_amount', $result, $params['total_amount']), 'currency' => $config->defaultCurrency, 'payment_processor' => $this->_paymentProcessor['payment_processor_type'], 'trxn_id' => $result['trxn_id']); require_once 'CRM/Contribute/BAO/FinancialTrxn.php'; $trxn =& CRM_Contribute_BAO_FinancialTrxn::create($trxnParams); } } else { $params['action'] = $this->_action; if ($this->_onlinePendingContributionId && CRM_Utils_Array::value('record_contribution', $formValues)) { // update membership as well as contribution object, CRM-4395 require_once 'CRM/Contribute/Form/Contribution.php'; $params['contribution_id'] = $this->_onlinePendingContributionId; $params['componentId'] = $params['id']; $params['componentName'] = 'contribute'; $result = CRM_Contribute_BAO_Contribution::transitionComponents($params, true); //carry updated membership object. $membership =& new CRM_Member_DAO_Membership(); $membership->id = $this->_id; $membership->find(true); $cancelled = true; if ($membership->end_date) { //display end date w/ status message. $endDate = $membership->end_date; require_once 'CRM/Member/PseudoConstant.php'; $membershipStatues = CRM_Member_PseudoConstant::membershipStatus(); if (!in_array($membership->status_id, array(array_search('Cancelled', $membershipStatues), array_search('Expired', $membershipStatues)))) { $cancelled = false; } } // suppress form values in template. $this->assign('cancelled', $cancelled); } else { $membership =& CRM_Member_BAO_Membership::create($params, $ids); } } if (CRM_Utils_Array::value('send_receipt', $formValues)) { require_once 'CRM/Core/DAO.php'; CRM_Core_DAO::setFieldValue('CRM_Member_DAO_MembershipType', $params['membership_type_id'], 'receipt_text_signup', $formValues['receipt_text_signup']); } $receiptSend = false; if (CRM_Utils_Array::value('send_receipt', $formValues)) { $receiptSend = true; $receiptFrom = "{$userName} <{$userEmail}>"; if (CRM_Utils_Array::value('payment_instrument_id', $formValues)) { $paymentInstrument = CRM_Contribute_PseudoConstant::paymentInstrument(); $formValues['paidBy'] = $paymentInstrument[$formValues['payment_instrument_id']]; } // retrieve custom data require_once "CRM/Core/BAO/UFGroup.php"; $customFields = $customValues = array(); foreach ($this->_groupTree as $groupID => $group) { if ($groupID == 'info') { continue; } foreach ($group['fields'] as $k => $field) { $field['title'] = $field['label']; $customFields["custom_{$k}"] = $field; } } $members = array(array('member_id', '=', $membership->id, 0, 0)); // check whether its a test drive if ($this->_mode) { $members[] = array('member_test', '=', 1, 0, 0); } CRM_Core_BAO_UFGroup::getValues($this->_contactID, $customFields, $customValues, false, $members); if ($this->_mode) { if (CRM_Utils_Array::value('billing_first_name', $this->_params)) { $name = $this->_params['billing_first_name']; } if (CRM_Utils_Array::value('billing_middle_name', $this->_params)) { $name .= " {$this->_params['billing_middle_name']}"; } if (CRM_Utils_Array::value('billing_last_name', $this->_params)) { $name .= " {$this->_params['billing_last_name']}"; } $this->assign('billingName', $name); // assign the address formatted up for display $addressParts = array("street_address-{$this->_bltID}", "city-{$this->_bltID}", "postal_code-{$this->_bltID}", "state_province-{$this->_bltID}", "country-{$this->_bltID}"); $addressFields = array(); foreach ($addressParts as $part) { list($n, $id) = explode('-', $part); if (isset($this->_params['billing_' . $part])) { $addressFields[$n] = $this->_params['billing_' . $part]; } } require_once 'CRM/Utils/Address.php'; $this->assign('address', CRM_Utils_Address::format($addressFields)); $date = CRM_Utils_Date::format($this->_params['credit_card_exp_date']); $date = CRM_Utils_Date::mysqlToIso($date); $this->assign('credit_card_exp_date', $date); $this->assign('credit_card_number', CRM_Utils_System::mungeCreditCard($this->_params['credit_card_number'])); $this->assign('credit_card_type', $this->_params['credit_card_type']); $this->assign('contributeMode', 'direct'); $this->assign('isAmountzero', 0); $this->assign('is_pay_later', 0); $this->assign('isPrimary', 1); } $this->assign('module', 'Membership'); $this->assign('contactID', $this->_contactID); $this->assign('membershipID', $params['membership_id']); $this->assign('receiptType', 'membership signup'); $this->assign('receive_date', $params['receive_date']); $this->assign('formValues', $formValues); $this->assign('mem_start_date', CRM_Utils_Date::customFormat($calcDates['start_date'])); $this->assign('mem_end_date', CRM_Utils_Date::customFormat($calcDates['end_date'])); $this->assign('membership_name', CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $formValues['membership_type_id'][1])); $this->assign('customValues', $customValues); require_once 'CRM/Core/BAO/MessageTemplates.php'; list($mailSend, $subject, $message, $html) = CRM_Core_BAO_MessageTemplates::sendTemplate(array('groupName' => 'msg_tpl_workflow_contribution', 'valueName' => 'contribution_offline_receipt', 'contactId' => $this->_contactID, 'from' => $receiptFrom, 'toName' => $this->_contributorDisplayName, 'toEmail' => $this->_contributorEmail, 'isTest' => (bool) ($this->_action & CRM_Core_Action::PREVIEW))); } if ($this->_action & CRM_Core_Action::UPDATE) { $statusMsg = ts('Membership for %1 has been updated.', array(1 => $this->_contributorDisplayName)); if ($endDate) { $endDate = CRM_Utils_Date::customFormat($endDate); $statusMsg .= ' ' . ts('The membership End Date is %1.', array(1 => $endDate)); } if ($receiptSend) { $statusMsg .= ' ' . ts('A confirmation and receipt has been sent to %1.', array(1 => $this->_contributorEmail)); } } elseif ($this->_action & CRM_Core_Action::ADD) { require_once 'CRM/Core/DAO.php'; $memType = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $params['membership_type_id']); $statusMsg = ts('%1 membership for %2 has been added.', array(1 => $memType, 2 => $this->_contributorDisplayName)); //get the end date from calculated dates. $endDate = $endDate ? $endDate : CRM_Utils_Array::value('end_date', $calcDates); if ($endDate) { $endDate = CRM_Utils_Date::customFormat($endDate); $statusMsg .= ' ' . ts('The new membership End Date is %1.', array(1 => $endDate)); } if ($receiptSend && $mailSend) { $statusMsg .= ' ' . ts('A membership confirmation and receipt has been sent to %1.', array(1 => $this->_contributorEmail)); } } CRM_Core_Session::setStatus($statusMsg); $buttonName = $this->controller->getButtonName(); if ($this->_context == 'standalone') { if ($buttonName == $this->getButtonName('upload', 'new')) { $session->replaceUserContext(CRM_Utils_System::url('civicrm/member/add', 'reset=1&action=add&context=standalone')); } else { $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$this->_contactID}&selectedChild=member")); } } else { if ($buttonName == $this->getButtonName('upload', 'new')) { $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/membership', "reset=1&action=add&context=membership&cid={$this->_contactID}")); } } }
function testGetRenewalDatesForMembershipType() { require_once 'CRM/Member/BAO/Membership.php'; $ids = array('memberOfContact' => $this->_orgContactID); $params = array('name' => 'General', 'description' => null, 'minimum_fee' => 100, 'duration_unit' => 'year', 'period_type' => 'rolling', 'duration_interval' => 1, 'contribution_type_id' => $this->_contributionTypeId, 'relationship_type_id' => $this->_relationshipTypeId, 'visibility' => 'Public', 'is_active' => 1); $membershipType = CRM_Member_BAO_MembershipType::add($params, $ids); $params = array('contact_id' => $this->_indiviContactID, 'membership_type_id' => $membershipType->id, 'join_date' => '2006-01-21', 'start_date' => '2006-01-21', 'end_date' => '2006-12-21', 'source' => 'Payment', 'is_override' => 1, 'status_id' => $this->_membershipStatusID); $ids = array(); $membership = CRM_Member_BAO_Membership::create($params, $ids); $membershipRenewDates = CRM_Member_BAO_MembershipType::getRenewalDatesForMembershipType($membership->id); $this->assertEquals($membershipRenewDates['start_date'], '20060121', 'Verify membership renewal start date.'); $this->assertEquals($membershipRenewDates['end_date'], '20071221', 'Verify membership renewal end date.'); }
/** * Test civicrm_membershipcontributionlink_get - success expected. */ public function testGet() { $contactId = Contact::createIndividual(); $params = array('contact_id' => $contactId, 'currency' => 'USD', 'contribution_type_id' => $this->_contributionTypeID, 'contribution_status_id' => 1, 'contribution_page_id' => null, 'payment_instrument_id' => 1, 'id' => null, 'total_amount' => 200.0); require_once 'CRM/Contribute/BAO/Contribution.php'; $contribution = CRM_Contribute_BAO_Contribution::create($params, $ids); $params = array('contact_id' => $contactId, 'membership_type_id' => $this->_membershipTypeID, 'source' => 'Payment', 'is_override' => 1, 'status_id' => $this->_membershipStatusID); $ids = array(); $membership = CRM_Member_BAO_Membership::create($params, $ids); $params = array('contribution_id' => $contribution->id, 'membership_id' => $membership->id); $Create = civicrm_membershipcontributionlink_create($params); $GetParams = civicrm_membershipcontributionlink_get(&$params); $this->assertEquals($GetParams[$Create['id']]['membership_id'], $membership->id, 'Check Membership Id'); $this->assertEquals($GetParams[$Create['id']]['contribution_id'], $contribution->id, 'Check Contribution Id'); }
/** * Test resetmodified() */ function testresetmodifiedId() { $contactId = Contact::createIndividual(); $params = array('contact_id' => $contactId, 'membership_type_id' => $this->_membershipTypeID, 'join_date' => '2009-01-21', 'start_date' => '2009-01-21', 'end_date' => '2009-12-21', 'source' => 'Payment', 'is_override' => 1, 'status_id' => $this->_mebershipStatusID); $ids = array(); $membership = CRM_Member_BAO_Membership::create($params, $ids); $contactId2 = Contact::createIndividual(); $this->assertDBNull('CRM_Member_BAO_MembershipLog', $contactId2, 'modified_id', 'modified_id', 'Database check for NULL modified id.'); }
/** * Create a Contact Membership * * This API is used for creating a Membership for a contact. * Required parameters : membership_type_id and status_id. * * @param array $params an associative array of name/value property values of civicrm_membership * * @return array of newly created membership property values. * {@getfields membership_create} * @access public */ function civicrm_api3_membership_create($params) { // check params for membership id during update if (!empty($params['id']) && !isset($params['skipStatusCal'])) { //don't calculate status on exisiting membership - expect API use to pass them in // or leave unchanged $params['skipStatusCal'] = 1; } else { // also check for status id if override is set (during add/update) if (!empty($params['is_override']) && empty($params['status_id'])) { return civicrm_api3_create_error('Status ID required'); } } $values = array(); _civicrm_api3_custom_format_params($params, $values, 'Membership'); $params = array_merge($params, $values); // Fixme: This code belongs in the BAO if (empty($params['id']) || !empty($params['num_terms'])) { if (empty($params['id'])) { $calcDates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($params['membership_type_id'], CRM_Utils_Array::value('join_date', $params), CRM_Utils_Array::value('start_date', $params), CRM_Utils_Array::value('end_date', $params), CRM_Utils_Array::value('num_terms', $params, 1)); } else { $calcDates = CRM_Member_BAO_MembershipType::getRenewalDatesForMembershipType($params['id'], NULL, CRM_Utils_Array::value('membership_type_id', $params), $params['num_terms']); } foreach (array('join_date', 'start_date', 'end_date') as $date) { if (empty($params[$date]) && isset($calcDates[$date])) { $params[$date] = $calcDates[$date]; } } } // Fixme: This code belongs in the BAO $action = CRM_Core_Action::ADD; // we need user id during add mode $ids = array(); if (!empty($params['contact_id'])) { $ids['userId'] = $params['contact_id']; } //for edit membership id should be present if (!empty($params['id'])) { $ids['membership'] = $params['id']; $action = CRM_Core_Action::UPDATE; } //need to pass action to handle related memberships. $params['action'] = $action; $membershipBAO = CRM_Member_BAO_Membership::create($params, $ids, TRUE); if (array_key_exists('is_error', $membershipBAO)) { // In case of no valid status for given dates, $membershipBAO // is going to contain 'is_error' => "Error Message" return civicrm_api3_create_error(ts('The membership can not be saved, no valid membership status for given dates')); } $membership = array(); _civicrm_api3_object_to_array($membershipBAO, $membership[$membershipBAO->id]); return civicrm_api3_create_success($membership, $params, 'membership', 'create', $membershipBAO); }
/** * check function getRenewalDatesForMembershipType( ) * */ public function testGetRenewalDatesForMembershipType() { $ids = array(); $params = array('name' => 'General', 'domain_id' => 1, 'description' => NULL, 'minimum_fee' => 100, 'duration_unit' => 'year', 'member_of_contact_id' => $this->_orgContactID, 'period_type' => 'rolling', 'duration_interval' => 1, 'financial_type_id' => $this->_financialTypeId, 'relationship_type_id' => $this->_relationshipTypeId, 'visibility' => 'Public', 'is_active' => 1); $membershipType = CRM_Member_BAO_MembershipType::add($params, $ids); $params = array('contact_id' => $this->_indiviContactID, 'membership_type_id' => $membershipType->id, 'join_date' => '20060121000000', 'start_date' => '20060121000000', 'end_date' => '20070120000000', 'source' => 'Payment', 'is_override' => 1, 'status_id' => $this->_membershipStatusID); $ids = array(); $membership = CRM_Member_BAO_Membership::create($params, $ids); $membershipRenewDates = CRM_Member_BAO_MembershipType::getRenewalDatesForMembershipType($membership->id); $this->assertEquals($membershipRenewDates['start_date'], '20060121', 'Verify membership renewal start date.'); $this->assertEquals($membershipRenewDates['end_date'], '20080120', 'Verify membership renewal end date.'); $this->membershipDelete($membership->id); $this->membershipTypeDelete(array('id' => $membershipType->id)); }
/** * function to create memberships for related contacts * * @param array $params array of key - value pairs * @param object $membership membership object * * @return null|relatedMembership array of memberships if created * @static * @access public */ static function createRelatedMemberships(&$params, &$membership) { static $relatedContactIds = array(); // required since create method doesn't return all the // parameters in the returned membership object if (!$membership->find(true)) { return; } $allRelatedContacts = array(); $relatedContacts = array(); if (!is_a($membership, 'CRM_Core_Error')) { $allRelatedContacts = CRM_Member_BAO_Membership::checkMembershipRelationship($membership->id, $membership->contact_id, CRM_Utils_Array::value('action', $params)); } // check for loops. CRM-4213 // remove repeated related contacts, which already inherited membership. $relatedContactIds[$membership->contact_id] = true; foreach ($allRelatedContacts as $cid => $status) { if (!CRM_Utils_Array::value($cid, $relatedContactIds)) { $relatedContacts[$cid] = $status; $relatedContactIds[$cid] = true; } } if (!empty($relatedContacts)) { // delete all the related membership records before creating CRM_Member_BAO_Membership::deleteRelatedMemberships($membership->id); // Edit the params array unset($params['id']); // Reminder should be sent only to the direct membership unset($params['reminder_date']); // unset the custom value ids if (is_array(CRM_Utils_Array::value('custom', $params))) { foreach ($params['custom'] as $k => $v) { unset($params['custom'][$k]['id']); } } if (!isset($params['membership_type_id'])) { $params['membership_type_id'] = $membership->membership_type_id; } foreach ($relatedContacts as $contactId => $relationshipStatus) { $params['contact_id'] = $contactId; $params['owner_membership_id'] = $membership->id; // set status_id as it might have been changed for // past relationship $params['status_id'] = $membership->status_id; if (CRM_Utils_Array::value('action', $params) & CRM_Core_Action::UPDATE && $relationshipStatus == CRM_Contact_BAO_Relationship::PAST) { // FIXME : While updating/ renewing the // membership, if the relationship is PAST then // the membership of the related contact must be // expired. // For that, getting Membership Status for which // is_current_member is 0. It works for the // generated data as there is only one membership // status having is_current_member = 0. // But this wont work exactly if there will be // more than one status having is_current_member = 0. require_once 'CRM/Member/DAO/MembershipStatus.php'; $membership = new CRM_Member_DAO_MembershipStatus(); $membership->is_current_member = 0; if ($membership->find(true)) { $params['status_id'] = $membership->id; } } // we should not created contribution record for related contacts, CRM-3371 unset($params['contribution_status_id']); CRM_Member_BAO_Membership::create($params, CRM_Core_DAO::$_nullArray); } } }
/** * handle the values in import mode * * @param int $onDuplicate the code for what action to take on duplicates * @param array $values the array of values belonging to this line * * @return boolean the result of this processing * @access public */ function import($onDuplicate, &$values) { // first make sure this is a valid line $response = $this->summary($values); if ($response != CRM_Member_Import_Parser::VALID) { return $response; } $params =& $this->getActiveFieldParams(); //assign join date equal to start date if join date is not provided if (!$params['join_date'] && $params['membership_start_date']) { $params['join_date'] = $params['membership_start_date']; } $session =& CRM_Core_Session::singleton(); $dateType = $session->get("dateTypes"); $formatted = array(); $customFields = CRM_Core_BAO_CustomField::getFields(CRM_Utils_Array::value('contact_type', $params)); // don't add to recent items, CRM-4399 $formatted['skipRecentView'] = true; foreach ($params as $key => $val) { if ($val) { switch ($key) { case 'join_date': if (CRM_Utils_Date::convertToDefaultDate($params, $dateType, $key)) { if (!CRM_Utils_Rule::date($params[$key])) { CRM_Import_Parser_Contact::addToErrorMsg('Join Date', $errorMessage); } } else { CRM_Import_Parser_Contact::addToErrorMsg('Join Date', $errorMessage); } break; case 'membership_start_date': if (CRM_Utils_Date::convertToDefaultDate($params, $dateType, $key)) { if (!CRM_Utils_Rule::date($params[$key])) { CRM_Import_Parser_Contact::addToErrorMsg('Start Date', $errorMessage); } } else { CRM_Import_Parser_Contact::addToErrorMsg('Start Date', $errorMessage); } break; case 'membership_end_date': if (CRM_Utils_Date::convertToDefaultDate($params, $dateType, $key)) { if (!CRM_Utils_Rule::date($params[$key])) { CRM_Import_Parser_Contact::addToErrorMsg('End Date', $errorMessage); } } else { CRM_Import_Parser_Contact::addToErrorMsg('End Date', $errorMessage); } break; case 'is_override': $params[$key] = CRM_Utils_String::strtobool($val); break; } if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) { if ($customFields[$customFieldID][2] == 'Date') { CRM_Import_Parser_Contact::formatCustomDate($params, $formatted, $dateType, $key); unset($params[$key]); } else { if ($customFields[$customFieldID][2] == 'Boolean') { $params[$key] = CRM_Utils_String::strtoboolstr($val); } } } } } //date-Format part ends static $indieFields = null; if ($indieFields == null) { require_once 'CRM/Member/DAO/Membership.php'; $tempIndieFields =& CRM_Member_DAO_Membership::import(); $indieFields = $tempIndieFields; } $formatValues = array(); foreach ($params as $key => $field) { if ($field == null || $field === '') { continue; } $formatValues[$key] = $field; } $formatError = _civicrm_membership_formatted_param($formatValues, $formatted, true); if ($formatError) { array_unshift($values, $formatError['error_message']); return CRM_Member_Import_Parser::ERROR; } if ($onDuplicate != CRM_Member_Import_Parser::DUPLICATE_UPDATE) { $formatted['custom'] = CRM_Core_BAO_CustomField::postProcess($formatted, CRM_Core_DAO::$_nullObject, null, 'Membership'); } else { //fix for CRM-2219 Update Membership // onDuplicate == CRM_Member_Import_Parser::DUPLICATE_UPDATE if (CRM_Utils_Array::value('is_override', $formatted) && !CRM_Utils_Array::value('status_id', $formatted)) { array_unshift($values, "Required parameter missing: Status"); return CRM_Member_Import_Parser::ERROR; } if ($formatValues['membership_id']) { require_once 'CRM/Member/BAO/Membership.php'; $dao = new CRM_Member_BAO_Membership(); $dao->id = $formatValues['membership_id']; $dates = array('join_date', 'start_date', 'end_date'); foreach ($dates as $v) { if (!$formatted[$v]) { $formatted[$v] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $formatValues['membership_id'], $v); } } $formatted['custom'] = CRM_Core_BAO_CustomField::postProcess($formatted, CRM_Core_DAO::$_nullObject, $formatValues['membership_id'], 'Membership'); if ($dao->find(true)) { $ids = array('membership' => $formatValues['membership_id'], 'userId' => $session->get('userID')); $newMembership =& CRM_Member_BAO_Membership::create($formatted, $ids, true); if (civicrm_error($newMembership)) { array_unshift($values, $newMembership['is_error'] . " for Membership ID " . $formatValues['membership_id'] . ". Row was skipped."); return CRM_Member_Import_Parser::ERROR; } else { $this->_newMemberships[] = $newMembership->id; return CRM_Member_Import_Parser::VALID; } } else { array_unshift($values, "Matching Membership record not found for Membership ID " . $formatValues['membership_id'] . ". Row was skipped."); return CRM_Member_Import_Parser::ERROR; } } } //Format dates $startDate = CRM_Utils_Date::customFormat($formatted['start_date'], '%Y-%m-%d'); $endDate = CRM_Utils_Date::customFormat($formatted['end_date'], '%Y-%m-%d'); $joinDate = CRM_Utils_Date::customFormat($formatted['join_date'], '%Y-%m-%d'); if ($this->_contactIdIndex < 0) { //retrieve contact id using contact dedupe rule $formatValues['contact_type'] = $this->_contactType; $error = civicrm_check_contact_dedupe($formatValues); if (civicrm_duplicate($error)) { $matchedIDs = explode(',', $error['error_message']['params'][0]); if (count($matchedIDs) > 1) { array_unshift($values, "Multiple matching contact records detected for this row. The membership was not imported"); return CRM_Member_Import_Parser::ERROR; } else { $cid = $matchedIDs[0]; $formatted['contact_id'] = $cid; //fix for CRM-1924 require_once 'CRM/Member/BAO/MembershipStatus.php'; require_once 'CRM/Member/BAO/MembershipType.php'; require_once 'CRM/Member/PseudoConstant.php'; $calcDates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($formatted['membership_type_id'], $joinDate, $startDate, $endDate); self::formattedDates($calcDates, $formatted); //fix for CRM-3570, exclude the statuses those having is_admin = 1 //now user can import is_admin if is override is true. $excludeIsAdmin = false; if (!CRM_Utils_Array::value('is_override', $formatted)) { $formatted['exclude_is_admin'] = $excludeIsAdmin = true; } $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($startDate, $endDate, $joinDate, 'today', $excludeIsAdmin); if (!$formatted['status_id']) { $formatted['status_id'] = $calcStatus['id']; } elseif (!CRM_Utils_Array::value('is_override', $formatted)) { if (empty($calcStatus)) { array_unshift($values, "Status in import row (" . $formatValues['status_id'] . ") does not match calculated status based on your configured Membership Status Rules. Record was not imported."); return CRM_Member_Import_Parser::ERROR; } else { if ($formatted['status_id'] != $calcStatus['id']) { //Status Hold" is either NOT mapped or is FALSE array_unshift($values, "Status in import row (" . $formatValues['status_id'] . ") does not match calculated status based on your configured Membership Status Rules (" . $calcStatus['name'] . "). Record was not imported."); return CRM_Member_Import_Parser::ERROR; } } } $newMembership = civicrm_contact_membership_create($formatted); if (civicrm_error($newMembership)) { array_unshift($values, $newMembership['error_message']); return CRM_Member_Import_Parser::ERROR; } $this->_newMemberships[] = $newMembership['id']; return CRM_Member_Import_Parser::VALID; } } else { // Using new Dedupe rule. $ruleParams = array('contact_type' => $this->_contactType, 'level' => 'Strict'); require_once 'CRM/Dedupe/BAO/Rule.php'; $fieldsArray = CRM_Dedupe_BAO_Rule::dedupeRuleFields($ruleParams); foreach ($fieldsArray as $value) { if (array_key_exists(trim($value), $params)) { $paramValue = $params[trim($value)]; if (is_array($paramValue)) { $disp .= $params[trim($value)][0][trim($value)] . " "; } else { $disp .= $params[trim($value)] . " "; } } } if (CRM_Utils_Array::value('external_identifier', $params)) { if ($disp) { $disp .= "AND {$params['external_identifier']}"; } else { $disp = $params['external_identifier']; } } array_unshift($values, "No matching Contact found for (" . $disp . ")"); return CRM_Member_Import_Parser::ERROR; } } else { if ($formatValues['external_identifier']) { $checkCid = new CRM_Contact_DAO_Contact(); $checkCid->external_identifier = $formatValues['external_identifier']; $checkCid->find(true); if ($checkCid->id != $formatted['contact_id']) { array_unshift($values, "Mismatch of External identifier :" . $formatValues['external_identifier'] . " and Contact Id:" . $formatted['contact_id']); return CRM_Member_Import_Parser::ERROR; } } //to calculate dates require_once 'CRM/Member/BAO/MembershipType.php'; $calcDates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($formatted['membership_type_id'], $joinDate, $startDate, $endDate); self::formattedDates($calcDates, $formatted); //end of date calculation part //fix for CRM-3570, exclude the statuses those having is_admin = 1 //now user can import is_admin if is override is true. $excludeIsAdmin = false; if (!CRM_Utils_Array::value('is_override', $formatted)) { $formatted['exclude_is_admin'] = $excludeIsAdmin = true; } require_once 'CRM/Member/BAO/MembershipStatus.php'; $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($startDate, $endDate, $joinDate, 'today', $excludeIsAdmin); if (!$formatted['status_id']) { $formatted['status_id'] = $calcStatus['id']; } else { if (!CRM_Utils_Array::value('is_override', $formatted)) { if (empty($calcStatus)) { array_unshift($values, "Status in import row (" . $formatValues['status_id'] . ") does not match calculated status based on your configured Membership Status Rules. Record was not imported."); return CRM_Member_Import_Parser::ERROR; } else { if ($formatted['status_id'] != $calcStatus['id']) { //Status Hold" is either NOT mapped or is FALSE array_unshift($values, "Status in import row (" . $formatValues['status_id'] . ") does not match calculated status based on your configured Membership Status Rules (" . $calcStatus['name'] . "). Record was not imported."); return CRM_Member_Import_Parser::ERROR; } } } } $newMembership = civicrm_contact_membership_create($formatted); if (civicrm_error($newMembership)) { array_unshift($values, $newMembership['error_message']); return CRM_Member_Import_Parser::ERROR; } $this->_newMemberships[] = $newMembership['id']; return CRM_Member_Import_Parser::VALID; } }
/** * Renew stale membership. */ public function testStaleMembership() { $statusId = 3; $contactId = Contact::createIndividual(); $joinDate = $startDate = date("Ymd", strtotime(date("Ymd") . " -1 year -15 days")); $endDate = date("Ymd", strtotime($joinDate . " +1 year -1 day")); $params = array('contact_id' => $contactId, 'membership_type_id' => $this->_membershipTypeID, 'join_date' => $joinDate, 'start_date' => $startDate, 'end_date' => $endDate, 'source' => 'Payment', 'status_id' => $statusId); $ids = array(); $membership = CRM_Member_BAO_Membership::create($params, $ids); $membershipId = $this->assertDBNotNull('CRM_Member_BAO_Membership', $contactId, 'id', 'contact_id', 'Database check for created membership.'); $this->assertEquals($membership->status_id, $statusId, 'Verify correct status id is calculated.'); $this->assertEquals($membership->membership_type_id, $this->_membershipTypeID, 'Verify correct membership type id.'); //verify all dates. $dates = array('startDate' => 'start_date', 'joinDate' => 'join_date', 'endDate' => 'end_date'); foreach ($dates as $date => $dbDate) { $this->assertEquals($membership->{$dbDate}, ${$date}, "Verify correct {$date} is present."); } $this->assertDBNotNull('CRM_Member_BAO_MembershipLog', $membership->id, 'id', 'membership_id', 'Database checked on membershiplog record.'); // this is a test and we dont want qfKey generation / validation // easier to suppress it, than change core code $config = CRM_Core_Config::singleton(); $config->keyDisable = TRUE; $membershipRenewal = new CRM_Core_Form(); $membershipRenewal->controller = new CRM_Core_Controller(); list($MembershipRenew) = CRM_Member_BAO_Membership::renewMembership($contactId, $this->_membershipTypeID, FALSE, $membershipRenewal, NULL, NULL, NULL, 1, NULL, NULL, NULL, FALSE, NULL); $this->assertDBNotNull('CRM_Member_BAO_MembershipLog', $MembershipRenew->id, 'id', 'membership_id', 'Database checked on membershiplog record.'); $this->membershipDelete($membershipId); Contact::delete($contactId); }
/** * Create / update / delete membership for related contacts. * * This function will create/update/delete membership for related * contact based on 1) contact have active membership 2) that * membership is is extedned by the same relationship type to that * of the existing relationship. * * @param int $contactId * contact id. * @param array $params * array of values submitted by POST. * @param array $ids * array of ids. * @param \const|int $action which action called this function * * @param bool $active * * @throws \CRM_Core_Exception */ public static function relatedMemberships($contactId, &$params, $ids, $action = CRM_Core_Action::ADD, $active = TRUE) { // Check the end date and set the status of the relationship // accordingly. $status = self::CURRENT; $targetContact = $targetContact = CRM_Utils_Array::value('contact_check', $params, array()); $today = date('Ymd'); // If a relationship hasn't yet started, just return for now // TODO: handle edge-case of updating start_date of an existing relationship if (!empty($params['start_date'])) { $startDate = substr(CRM_Utils_Date::format($params['start_date']), 0, 8); if ($today < $startDate) { return; } } if (!empty($params['end_date'])) { $endDate = substr(CRM_Utils_Date::format($params['end_date']), 0, 8); if ($today > $endDate) { $status = self::PAST; } } if ($action & CRM_Core_Action::ADD && $status & self::PAST) { // If relationship is PAST and action is ADD, do nothing. return; } $rel = explode('_', $params['relationship_type_id']); $relTypeId = $rel[0]; if (!empty($rel[1])) { $relDirection = "_{$rel[1]}_{$rel[2]}"; } else { // this call is coming from somewhere where the direction was resolved early on (e.g an api call) // so we can assume _a_b $relDirection = "_a_b"; $targetContact = array($params['contact_id_b'] => 1); } if ($action & CRM_Core_Action::ADD || $action & CRM_Core_Action::DELETE) { $contact = $contactId; } elseif ($action & CRM_Core_Action::UPDATE) { $contact = $ids['contact']; $targetContact = array($ids['contactTarget'] => 1); } // Build the 'values' array for // 1. ContactA // 2. ContactB // This will allow us to check if either of the contacts in // relationship have active memberships. $values = array(); // 1. ContactA $values[$contact] = array('relatedContacts' => $targetContact, 'relationshipTypeId' => $relTypeId, 'relationshipTypeDirection' => $relDirection); // 2. ContactB if (!empty($targetContact)) { foreach ($targetContact as $cid => $donCare) { $values[$cid] = array('relatedContacts' => array($contact => 1), 'relationshipTypeId' => $relTypeId); $relTypeParams = array('id' => $relTypeId); $relTypeValues = array(); CRM_Contact_BAO_RelationshipType::retrieve($relTypeParams, $relTypeValues); if (CRM_Utils_Array::value('name_a_b', $relTypeValues) == CRM_Utils_Array::value('name_b_a', $relTypeValues)) { $values[$cid]['relationshipTypeDirection'] = '_a_b'; } else { $values[$cid]['relationshipTypeDirection'] = $relDirection == '_a_b' ? '_b_a' : '_a_b'; } } } // CRM-15829 UPDATES // If we're looking for active memberships we must consider pending (id: 5) ones too. // Hence we can't just call CRM_Member_BAO_Membership::getValues below with the active flag, is it would completely miss pending relatioships. // As suggested by @davecivicrm, the pending status id is fetched using the CRM_Member_PseudoConstant::membershipStatus() class and method, since these ids differ from system to system. $pendingStatusId = array_search('Pending', CRM_Member_PseudoConstant::membershipStatus()); $query = 'SELECT * FROM `civicrm_membership_status`'; if ($active) { $query .= ' WHERE `is_current_member` = 1 OR `id` = %1 '; } $dao = CRM_Core_DAO::executeQuery($query, array(1 => array($pendingStatusId, 'Integer'))); while ($dao->fetch()) { $membershipStatusRecordIds[$dao->id] = $dao->id; } // Now get the active memberships for all the contacts. // If contact have any valid membership(s), then add it to // 'values' array. foreach ($values as $cid => $subValues) { $memParams = array('contact_id' => $cid); $memberships = array(); // CRM-15829 UPDATES // Since we want PENDING memberships as well, the $active flag needs to be set to false so that this will return all memberships and we can then filter the memberships based on the status IDs recieved above. CRM_Member_BAO_Membership::getValues($memParams, $memberships, FALSE, TRUE); // CRM-15829 UPDATES // filter out the memberships returned by CRM_Member_BAO_Membership::getValues based on the status IDs fetched on line ~1462 foreach ($memberships as $key => $membership) { if (!isset($memberships[$key]['status_id'])) { continue; } $membershipStatusId = $memberships[$key]['status_id']; if (!isset($membershipStatusRecordIds[$membershipStatusId])) { unset($memberships[$key]); } } if (empty($memberships)) { continue; } //get ownerMembershipIds for related Membership //this is to handle memberships being deleted and recreated if (!empty($memberships['owner_membership_ids'])) { $ownerMemIds[$cid] = $memberships['owner_membership_ids']; unset($memberships['owner_membership_ids']); } $values[$cid]['memberships'] = $memberships; } $deceasedStatusId = array_search('Deceased', CRM_Member_PseudoConstant::membershipStatus()); // done with 'values' array. // Finally add / edit / delete memberships for the related contacts foreach ($values as $cid => $details) { if (!array_key_exists('memberships', $details)) { continue; } $relatedContacts = array_keys(CRM_Utils_Array::value('relatedContacts', $details, array())); $mainRelatedContactId = reset($relatedContacts); foreach ($details['memberships'] as $membershipId => $membershipValues) { $relTypeIds = array(); if ($action & CRM_Core_Action::DELETE) { // Delete memberships of the related contacts only if relationship type exists for membership type $query = "\nSELECT relationship_type_id, relationship_direction\n FROM civicrm_membership_type\n WHERE id = {$membershipValues['membership_type_id']}"; $dao = CRM_Core_DAO::executeQuery($query); $relTypeDirs = array(); while ($dao->fetch()) { $relTypeId = $dao->relationship_type_id; $relDirection = $dao->relationship_direction; } $relTypeIds = explode(CRM_Core_DAO::VALUE_SEPARATOR, $relTypeId); if (in_array($values[$cid]['relationshipTypeId'], $relTypeIds) && !empty($membershipValues['owner_membership_id']) && !empty($values[$mainRelatedContactId]['memberships'][$membershipValues['owner_membership_id']])) { CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipValues['owner_membership_id'], $membershipValues['membership_contact_id']); } continue; } if ($action & CRM_Core_Action::UPDATE && $status & self::PAST && $membershipValues['owner_membership_id']) { // If relationship is PAST and action is UPDATE // then delete the RELATED membership CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipValues['owner_membership_id'], $membershipValues['membership_contact_id']); continue; } // add / edit the memberships for related // contacts. // Get the Membership Type Details. $membershipType = CRM_Member_BAO_MembershipType::getMembershipTypeDetails($membershipValues['membership_type_id']); // Check if contact's relationship type exists in membership type $relTypeDirs = array(); if (!empty($membershipType['relationship_type_id'])) { $relTypeIds = explode(CRM_Core_DAO::VALUE_SEPARATOR, $membershipType['relationship_type_id']); } if (!empty($membershipType['relationship_direction'])) { $relDirections = explode(CRM_Core_DAO::VALUE_SEPARATOR, $membershipType['relationship_direction']); } foreach ($relTypeIds as $key => $value) { $relTypeDirs[] = $value . '_' . $relDirections[$key]; } $relTypeDir = $details['relationshipTypeId'] . $details['relationshipTypeDirection']; if (in_array($relTypeDir, $relTypeDirs)) { // Check if relationship being created/updated is // similar to that of membership type's // relationship. $membershipValues['owner_membership_id'] = $membershipId; unset($membershipValues['id']); unset($membershipValues['membership_contact_id']); unset($membershipValues['contact_id']); unset($membershipValues['membership_id']); foreach ($details['relatedContacts'] as $relatedContactId => $donCare) { $membershipValues['contact_id'] = $relatedContactId; if ($deceasedStatusId && CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $relatedContactId, 'is_deceased')) { $membershipValues['status_id'] = $deceasedStatusId; $membershipValues['skipStatusCal'] = TRUE; } foreach (array('join_date', 'start_date', 'end_date') as $dateField) { if (!empty($membershipValues[$dateField])) { $membershipValues[$dateField] = CRM_Utils_Date::processDate($membershipValues[$dateField]); } } if ($action & CRM_Core_Action::UPDATE) { //if updated relationship is already related to contact don't delete existing inherited membership if (in_array($relTypeId, $relTypeIds) && !empty($values[$relatedContactId]['memberships']) && !empty($ownerMemIds) && in_array($membershipValues['owner_membership_id'], $ownerMemIds[$relatedContactId])) { continue; } //delete the membership record for related //contact before creating new membership record. CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipId, $relatedContactId); } // check whether we have some related memberships still available $query = "\nSELECT count(*)\n FROM civicrm_membership\n LEFT JOIN civicrm_membership_status ON (civicrm_membership_status.id = civicrm_membership.status_id)\n WHERE membership_type_id = {$membershipValues['membership_type_id']} AND owner_membership_id = {$membershipValues['owner_membership_id']}\n AND is_current_member = 1"; $result = CRM_Core_DAO::singleValueQuery($query); if ($result < CRM_Utils_Array::value('max_related', $membershipValues, PHP_INT_MAX)) { CRM_Member_BAO_Membership::create($membershipValues, CRM_Core_DAO::$_nullArray); } } } elseif ($action & CRM_Core_Action::UPDATE) { // if action is update and updated relationship do // not match with the existing // membership=>relationship then we need to // change the status of the membership record to expired for // previous relationship -- CRM-12078. // CRM-16087 we need to pass ownerMembershipId to isRelatedMembershipExpired function if (empty($params['relationship_ids']) && !empty($params['id'])) { $relIds = array($params['id']); } else { $relIds = CRM_Utils_Array::value('relationship_ids', $params); } if (self::isRelatedMembershipExpired($relTypeIds, $contactId, $mainRelatedContactId, $relTypeId, $relIds) && !empty($membershipValues['owner_membership_id']) && !empty($values[$mainRelatedContactId]['memberships'][$membershipValues['owner_membership_id']])) { $membershipValues['status_id'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipStatus', 'Expired', 'id', 'label'); $type = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $membershipValues['membership_type_id'], 'name', 'id'); CRM_Member_BAO_Membership::add($membershipValues); CRM_Core_Session::setStatus(ts("Inherited membership {$type} status was changed to Expired due to the change in relationship type."), ts('Record Updated'), 'alert'); } } } } }
/** * Submit function. * * This is also accessed by unit tests. * * @param array $formValues * * @return array */ public function submit($formValues) { $isTest = $this->_mode == 'test' ? 1 : 0; $joinDate = $startDate = $endDate = NULL; $membershipTypes = $membership = $calcDate = array(); $membershipType = NULL; $mailSend = FALSE; $formValues = $this->setPriceSetParameters($formValues); $params = $softParams = $ids = array(); $allMemberStatus = CRM_Member_PseudoConstant::membershipStatus(); $allContributionStatus = CRM_Contribute_PseudoConstant::contributionStatus(); if ($this->_id) { $ids['membership'] = $params['id'] = $this->_id; } $ids['userId'] = CRM_Core_Session::singleton()->get('userID'); // Set variables that we normally get from context. // In form mode these are set in preProcess. //TODO: set memberships, fixme $this->setContextVariables($formValues); $this->_memTypeSelected = self::getSelectedMemberships($this->_priceSet, $formValues); if (empty($formValues['financial_type_id'])) { $formValues['financial_type_id'] = $this->_priceSet['financial_type_id']; } $config = CRM_Core_Config::singleton(); $this->convertDateFieldsToMySQL($formValues); $membershipTypeValues = array(); foreach ($this->_memTypeSelected as $memType) { $membershipTypeValues[$memType]['membership_type_id'] = $memType; } //take the required membership recur values. if ($this->_mode && !empty($formValues['auto_renew'])) { $params['is_recur'] = $formValues['is_recur'] = TRUE; $mapping = array('frequency_interval' => 'duration_interval', 'frequency_unit' => 'duration_unit'); $count = 0; foreach ($this->_memTypeSelected as $memType) { $recurMembershipTypeValues = CRM_Utils_Array::value($memType, $this->_recurMembershipTypes, array()); foreach ($mapping as $mapVal => $mapParam) { $membershipTypeValues[$memType][$mapVal] = CRM_Utils_Array::value($mapParam, $recurMembershipTypeValues); if (!$count) { $formValues[$mapVal] = CRM_Utils_Array::value($mapParam, $recurMembershipTypeValues); } } $count++; } } $isQuickConfig = $this->_priceSet['is_quick_config']; $termsByType = array(); $lineItem = array($this->_priceSetId => array()); CRM_Price_BAO_PriceSet::processAmount($this->_priceSet['fields'], $formValues, $lineItem[$this->_priceSetId]); if (CRM_Utils_Array::value('tax_amount', $formValues)) { $params['tax_amount'] = $formValues['tax_amount']; } $params['total_amount'] = CRM_Utils_Array::value('amount', $formValues); $submittedFinancialType = CRM_Utils_Array::value('financial_type_id', $formValues); if (!empty($lineItem[$this->_priceSetId])) { foreach ($lineItem[$this->_priceSetId] as &$li) { if (!empty($li['membership_type_id'])) { if (!empty($li['membership_num_terms'])) { $termsByType[$li['membership_type_id']] = $li['membership_num_terms']; } } ///CRM-11529 for quick config backoffice transactions //when financial_type_id is passed in form, update the //lineitems with the financial type selected in form if ($isQuickConfig && $submittedFinancialType) { $li['financial_type_id'] = $submittedFinancialType; } } } $this->storeContactFields($formValues); $params['contact_id'] = $this->_contactID; $fields = array('status_id', 'source', 'is_override', 'campaign_id'); foreach ($fields as $f) { $params[$f] = CRM_Utils_Array::value($f, $formValues); } // fix for CRM-3724 // when is_override false ignore is_admin statuses during membership // status calculation. similarly we did fix for import in CRM-3570. if (empty($params['is_override'])) { $params['exclude_is_admin'] = TRUE; } // process date params to mysql date format. $dateTypes = array('join_date' => 'joinDate', 'start_date' => 'startDate', 'end_date' => 'endDate'); foreach ($dateTypes as $dateField => $dateVariable) { ${$dateVariable} = CRM_Utils_Date::processDate($formValues[$dateField]); } $memTypeNumTerms = empty($termsByType) ? CRM_Utils_Array::value('num_terms', $formValues) : NULL; $calcDates = array(); foreach ($this->_memTypeSelected as $memType) { if (empty($memTypeNumTerms)) { $memTypeNumTerms = CRM_Utils_Array::value($memType, $termsByType, 1); } $calcDates[$memType] = CRM_Member_BAO_MembershipType::getDatesForMembershipType($memType, $joinDate, $startDate, $endDate, $memTypeNumTerms); } foreach ($calcDates as $memType => $calcDate) { foreach (array_keys($dateTypes) as $d) { //first give priority to form values then calDates. $date = CRM_Utils_Array::value($d, $formValues); if (!$date) { $date = CRM_Utils_Array::value($d, $calcDate); } $membershipTypeValues[$memType][$d] = CRM_Utils_Date::processDate($date); } } // max related memberships - take from form or inherit from membership type foreach ($this->_memTypeSelected as $memType) { if (array_key_exists('max_related', $formValues)) { $membershipTypeValues[$memType]['max_related'] = CRM_Utils_Array::value('max_related', $formValues); } $membershipTypeValues[$memType]['custom'] = CRM_Core_BAO_CustomField::postProcess($formValues, $this->_id, 'Membership'); $membershipTypes[$memType] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $memType); } $membershipType = implode(', ', $membershipTypes); // Retrieve the name and email of the current user - this will be the FROM for the receipt email list($userName) = CRM_Contact_BAO_Contact_Location::getEmailDetails($ids['userId']); //CRM-13981, allow different person as a soft-contributor of chosen type if ($this->_contributorContactID != $this->_contactID) { $params['contribution_contact_id'] = $this->_contributorContactID; if (!empty($formValues['soft_credit_type_id'])) { $softParams['soft_credit_type_id'] = $formValues['soft_credit_type_id']; $softParams['contact_id'] = $this->_contactID; } } if (!empty($formValues['record_contribution'])) { $recordContribution = array('total_amount', 'financial_type_id', 'payment_instrument_id', 'trxn_id', 'contribution_status_id', 'check_number', 'campaign_id', 'receive_date'); foreach ($recordContribution as $f) { $params[$f] = CRM_Utils_Array::value($f, $formValues); } if (!$this->_onlinePendingContributionId) { if (empty($formValues['source'])) { $params['contribution_source'] = ts('%1 Membership: Offline signup (by %2)', array(1 => $membershipType, 2 => $userName)); } else { $params['contribution_source'] = $formValues['source']; } } if (empty($params['is_override']) && CRM_Utils_Array::value('contribution_status_id', $params) == array_search('Pending', CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'))) { $params['status_id'] = array_search('Pending', $allMemberStatus); $params['skipStatusCal'] = TRUE; $params['is_pay_later'] = 1; $this->assign('is_pay_later', 1); } if (!empty($formValues['send_receipt'])) { $params['receipt_date'] = CRM_Utils_Array::value('receive_date', $formValues); } //insert financial type name in receipt. $formValues['contributionType_name'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', $formValues['financial_type_id']); } // process line items, until no previous line items. if (!empty($lineItem)) { $params['lineItems'] = $lineItem; $params['processPriceSet'] = TRUE; } $createdMemberships = array(); if ($this->_mode) { $params['total_amount'] = CRM_Utils_Array::value('total_amount', $formValues, 0); if (!$isQuickConfig) { $params['financial_type_id'] = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $this->_priceSetId, 'financial_type_id'); } else { $params['financial_type_id'] = CRM_Utils_Array::value('financial_type_id', $formValues); } $this->_paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getPayment($formValues['payment_processor_id'], $this->_mode); //get the payment processor id as per mode. $params['payment_processor_id'] = $formValues['payment_processor_id'] = $this->_paymentProcessor['id']; $now = date('YmdHis'); $fields = array(); // set email for primary location. $fields['email-Primary'] = 1; $formValues['email-5'] = $formValues['email-Primary'] = $this->_memberEmail; $params['register_date'] = $now; // now set the values for the billing location. foreach ($this->_fields as $name => $dontCare) { $fields[$name] = 1; } // also add location name to the array $formValues["address_name-{$this->_bltID}"] = CRM_Utils_Array::value('billing_first_name', $formValues) . ' ' . CRM_Utils_Array::value('billing_middle_name', $formValues) . ' ' . CRM_Utils_Array::value('billing_last_name', $formValues); $formValues["address_name-{$this->_bltID}"] = trim($formValues["address_name-{$this->_bltID}"]); $fields["address_name-{$this->_bltID}"] = 1; //ensure we don't over-write the payer's email with the member's email if ($this->_contributorContactID == $this->_contactID) { $fields["email-{$this->_bltID}"] = 1; } $nameFields = array('first_name', 'middle_name', 'last_name'); foreach ($nameFields as $name) { $fields[$name] = 1; if (array_key_exists("billing_{$name}", $formValues)) { $formValues[$name] = $formValues["billing_{$name}"]; $formValues['preserveDBName'] = TRUE; } } if ($this->_contributorContactID == $this->_contactID) { //see CRM-12869 for discussion of why we don't do this for separate payee payments CRM_Contact_BAO_Contact::createProfileContact($formValues, $fields, $this->_contributorContactID, NULL, NULL, CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactID, 'contact_type')); } // add all the additional payment params we need $formValues["state_province-{$this->_bltID}"] = $formValues["billing_state_province-{$this->_bltID}"] = CRM_Core_PseudoConstant::stateProvinceAbbreviation($formValues["billing_state_province_id-{$this->_bltID}"]); $formValues["country-{$this->_bltID}"] = $formValues["billing_country-{$this->_bltID}"] = CRM_Core_PseudoConstant::countryIsoCode($formValues["billing_country_id-{$this->_bltID}"]); $formValues['year'] = CRM_Core_Payment_Form::getCreditCardExpirationYear($formValues); $formValues['month'] = CRM_Core_Payment_Form::getCreditCardExpirationMonth($formValues); $formValues['ip_address'] = CRM_Utils_System::ipAddress(); $formValues['amount'] = $params['total_amount']; $formValues['currencyID'] = $config->defaultCurrency; $formValues['description'] = ts("Contribution submitted by a staff person using member's credit card for signup"); $formValues['invoiceID'] = md5(uniqid(rand(), TRUE)); $formValues['financial_type_id'] = $params['financial_type_id']; // at this point we've created a contact and stored its address etc // all the payment processors expect the name and address to be in the // so we copy stuff over to first_name etc. $paymentParams = $formValues; $paymentParams['contactID'] = $this->_contributorContactID; //CRM-10377 if payment is by an alternate contact then we need to set that person // as the contact in the payment params if ($this->_contributorContactID != $this->_contactID) { if (!empty($formValues['soft_credit_type_id'])) { $softParams['contact_id'] = $params['contact_id']; $softParams['soft_credit_type_id'] = $formValues['soft_credit_type_id']; } } if (!empty($formValues['send_receipt'])) { $paymentParams['email'] = $this->_contributorEmail; } CRM_Core_Payment_Form::mapParams($this->_bltID, $formValues, $paymentParams, TRUE); // CRM-7137 -for recurring membership, // we do need contribution and recurring records. $result = NULL; if (!empty($paymentParams['is_recur'])) { $financialType = new CRM_Financial_DAO_FinancialType(); $financialType->id = $params['financial_type_id']; $financialType->find(TRUE); $this->_params = $formValues; $contribution = CRM_Contribute_Form_Contribution_Confirm::processFormContribution($this, $paymentParams, NULL, array('contact_id' => $this->_contributorContactID, 'line_item' => $lineItem, 'is_test' => $isTest, 'campaign_id' => CRM_Utils_Array::value('campaign_id', $paymentParams), 'contribution_page_id' => CRM_Utils_Array::value('contribution_page_id', $formValues), 'source' => CRM_Utils_Array::value('source', $paymentParams, CRM_Utils_Array::value('description', $paymentParams)), 'thankyou_date' => CRM_Utils_Array::value('thankyou_date', $paymentParams), 'payment_instrument_id' => $this->_paymentProcessor['payment_instrument_id']), $financialType, TRUE, FALSE, $this->_bltID); //create new soft-credit record, CRM-13981 if ($softParams) { $softParams['contribution_id'] = $contribution->id; $softParams['currency'] = $contribution->currency; $softParams['amount'] = $contribution->total_amount; CRM_Contribute_BAO_ContributionSoft::add($softParams); } $paymentParams['contactID'] = $this->_contactID; $paymentParams['contributionID'] = $contribution->id; $paymentParams['contributionTypeID'] = $contribution->financial_type_id; $paymentParams['contributionPageID'] = $contribution->contribution_page_id; $paymentParams['contributionRecurID'] = $contribution->contribution_recur_id; $ids['contribution'] = $contribution->id; $params['contribution_recur_id'] = $paymentParams['contributionRecurID']; } if ($params['total_amount'] > 0.0) { $payment = $this->_paymentProcessor['object']; try { $result = $payment->doPayment($paymentParams); $formValues = array_merge($formValues, $result); // Assign amount to template if payment was successful. $this->assign('amount', $params['total_amount']); } catch (PaymentProcessorException $e) { if (!empty($paymentParams['contributionID'])) { CRM_Contribute_BAO_Contribution::failPayment($paymentParams['contributionID'], $this->_contactID, $e->getMessage()); } if (!empty($paymentParams['contributionRecurID'])) { CRM_Contribute_BAO_ContributionRecur::deleteRecurContribution($paymentParams['contributionRecurID']); } CRM_Core_Error::displaySessionError($result); CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/view/membership', "reset=1&action=add&cid={$this->_contactID}&context=&mode={$this->_mode}")); } } if ($formValues['payment_status_id'] != array_search('Completed', $allContributionStatus)) { $params['status_id'] = array_search('Pending', $allMemberStatus); $params['skipStatusCal'] = TRUE; // unset send-receipt option, since receipt will be sent when ipn is received. unset($formValues['send_receipt'], $formValues['send_receipt']); //as membership is pending set dates to null. $memberDates = array('join_date' => 'joinDate', 'start_date' => 'startDate', 'end_date' => 'endDate'); foreach ($memberDates as $dv) { ${$dv} = NULL; foreach ($this->_memTypeSelected as $memType) { $membershipTypeValues[$memType][$dv] = NULL; } } } $params['receive_date'] = $now; $params['invoice_id'] = $formValues['invoiceID']; $params['contribution_source'] = ts('%1 Membership Signup: Credit card or direct debit (by %2)', array(1 => $membershipType, 2 => $userName)); $params['source'] = $formValues['source'] ? $formValues['source'] : $params['contribution_source']; $params['trxn_id'] = CRM_Utils_Array::value('trxn_id', $result); $params['payment_instrument_id'] = 1; $params['is_test'] = $this->_mode == 'live' ? 0 : 1; if (!empty($formValues['send_receipt'])) { $params['receipt_date'] = $now; } else { $params['receipt_date'] = NULL; } $this->set('params', $formValues); $this->assign('trxn_id', CRM_Utils_Array::value('trxn_id', $result)); $this->assign('receive_date', CRM_Utils_Date::mysqlToIso($params['receive_date'])); // required for creating membership for related contacts $params['action'] = $this->_action; //create membership record. $count = 0; foreach ($this->_memTypeSelected as $memType) { if ($count && ($relateContribution = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id))) { $membershipTypeValues[$memType]['relate_contribution_id'] = $relateContribution; } $membershipParams = array_merge($membershipTypeValues[$memType], $params); //CRM-15366 if (!empty($softParams) && empty($paymentParams['is_recur'])) { $membershipParams['soft_credit'] = $softParams; } // This is required to trigger the recording of the membership contribution in the // CRM_Member_BAO_Membership::Create function. // @todo stop setting this & 'teach' the create function to respond to something // appropriate as part of our 2-step always create the pending contribution & then finally add the payment // process - // @see http://wiki.civicrm.org/confluence/pages/viewpage.action?pageId=261062657#Payments&AccountsRoadmap-Movetowardsalwaysusinga2-steppaymentprocess $membershipParams['contribution_status_id'] = CRM_Utils_Array::value('payment_status_id', $result); if (!empty($paymentParams['is_recur'])) { // The earlier process created the line items (although we want to get rid of the earlier one in favour // of a single path! unset($membershipParams['lineItems']); } $membership = CRM_Member_BAO_Membership::create($membershipParams, $ids); $params['contribution'] = CRM_Utils_Array::value('contribution', $membershipParams); unset($params['lineItems']); $this->_membershipIDs[] = $membership->id; $createdMemberships[$memType] = $membership; $count++; } } else { $params['action'] = $this->_action; if ($this->_onlinePendingContributionId && !empty($formValues['record_contribution'])) { // update membership as well as contribution object, CRM-4395 $params['contribution_id'] = $this->_onlinePendingContributionId; $params['componentId'] = $params['id']; $params['componentName'] = 'contribute'; $result = CRM_Contribute_BAO_Contribution::transitionComponents($params, TRUE); if (!empty($result) && !empty($params['contribution_id'])) { $lineItem = array(); $lineItems = CRM_Price_BAO_LineItem::getLineItems($params['contribution_id'], 'contribution', NULL, TRUE, TRUE); $itemId = key($lineItems); $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', $lineItems[$itemId]['price_field_id'], 'price_set_id'); $lineItems[$itemId]['unit_price'] = $params['total_amount']; $lineItems[$itemId]['line_total'] = $params['total_amount']; $lineItems[$itemId]['id'] = $itemId; $lineItem[$priceSetId] = $lineItems; $contributionBAO = new CRM_Contribute_BAO_Contribution(); $contributionBAO->id = $params['contribution_id']; $contributionBAO->contact_id = $params['contact_id']; $contributionBAO->find(); CRM_Price_BAO_LineItem::processPriceSet($params['contribution_id'], $lineItem, $contributionBAO, 'civicrm_membership'); //create new soft-credit record, CRM-13981 if ($softParams) { $softParams['contribution_id'] = $params['contribution_id']; while ($contributionBAO->fetch()) { $softParams['currency'] = $contributionBAO->currency; $softParams['amount'] = $contributionBAO->total_amount; } CRM_Contribute_BAO_ContributionSoft::add($softParams); } } //carry updated membership object. $membership = new CRM_Member_DAO_Membership(); $membership->id = $this->_id; $membership->find(TRUE); $cancelled = TRUE; if ($membership->end_date) { //display end date w/ status message. $endDate = $membership->end_date; if (!in_array($membership->status_id, array(array_search('Cancelled', CRM_Member_PseudoConstant::membershipStatus(NULL, " name = 'Cancelled' ", 'name', FALSE, TRUE)), array_search('Expired', CRM_Member_PseudoConstant::membershipStatus())))) { $cancelled = FALSE; } } // suppress form values in template. $this->assign('cancelled', $cancelled); $createdMemberships[] = $membership; } else { $count = 0; foreach ($this->_memTypeSelected as $memType) { if ($count && !empty($formValues['record_contribution']) && ($relateContribution = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id))) { $membershipTypeValues[$memType]['relate_contribution_id'] = $relateContribution; } $membershipParams = array_merge($params, $membershipTypeValues[$memType]); if (!empty($formValues['int_amount'])) { $init_amount = array(); foreach ($formValues as $key => $value) { if (strstr($key, 'txt-price')) { $init_amount[$key] = $value; } } $membershipParams['init_amount'] = $init_amount; } if (!empty($softParams)) { $membershipParams['soft_credit'] = $softParams; } $membership = CRM_Member_BAO_Membership::create($membershipParams, $ids); $params['contribution'] = CRM_Utils_Array::value('contribution', $membershipParams); unset($params['lineItems']); $this->_membershipIDs[] = $membership->id; $createdMemberships[$memType] = $membership; $count++; } } } if (!empty($lineItem[$this->_priceSetId])) { $invoiceSettings = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME, 'contribution_invoice_settings'); $invoicing = CRM_Utils_Array::value('invoicing', $invoiceSettings); $taxAmount = FALSE; $totalTaxAmount = 0; foreach ($lineItem[$this->_priceSetId] as &$priceFieldOp) { if (!empty($priceFieldOp['membership_type_id'])) { $priceFieldOp['start_date'] = $membershipTypeValues[$priceFieldOp['membership_type_id']]['start_date'] ? CRM_Utils_Date::customFormat($membershipTypeValues[$priceFieldOp['membership_type_id']]['start_date'], '%B %E%f, %Y') : '-'; $priceFieldOp['end_date'] = $membershipTypeValues[$priceFieldOp['membership_type_id']]['end_date'] ? CRM_Utils_Date::customFormat($membershipTypeValues[$priceFieldOp['membership_type_id']]['end_date'], '%B %E%f, %Y') : '-'; } else { $priceFieldOp['start_date'] = $priceFieldOp['end_date'] = 'N/A'; } if ($invoicing && isset($priceFieldOp['tax_amount'])) { $taxAmount = TRUE; $totalTaxAmount += $priceFieldOp['tax_amount']; } } if ($invoicing) { $dataArray = array(); foreach ($lineItem[$this->_priceSetId] as $key => $value) { if (isset($value['tax_amount']) && isset($value['tax_rate'])) { if (isset($dataArray[$value['tax_rate']])) { $dataArray[$value['tax_rate']] = $dataArray[$value['tax_rate']] + CRM_Utils_Array::value('tax_amount', $value); } else { $dataArray[$value['tax_rate']] = CRM_Utils_Array::value('tax_amount', $value); } } } if ($taxAmount) { $this->assign('totalTaxAmount', $totalTaxAmount); $this->assign('taxTerm', CRM_Utils_Array::value('tax_term', $invoiceSettings)); } $this->assign('dataArray', $dataArray); } } $this->assign('lineItem', !empty($lineItem) && !$isQuickConfig ? $lineItem : FALSE); $receiptSend = FALSE; $contributionId = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id); $membershipIds = $this->_membershipIDs; if ($contributionId && !empty($membershipIds)) { $contributionDetails = CRM_Contribute_BAO_Contribution::getContributionDetails(CRM_Export_Form_Select::MEMBER_EXPORT, $this->_membershipIDs); if ($contributionDetails[$membership->id]['contribution_status'] == 'Completed') { $receiptSend = TRUE; } } if (!empty($formValues['send_receipt']) && $receiptSend) { $formValues['contact_id'] = $this->_contactID; $formValues['contribution_id'] = $contributionId; // We really don't need a distinct receipt_text_signup vs receipt_text_renewal as they are // handled in the receipt. But by setting one we avoid breaking templates for now // although at some point we should switch in the templates. $formValues['receipt_text_signup'] = $formValues['receipt_text']; // send email receipt $mailSend = self::emailReceipt($this, $formValues, $membership); } // finally set membership id if already not set if (!$this->_id) { $this->_id = $membership->id; } $isRecur = CRM_Utils_Array::value('is_recur', $params); $this->setStatusMessage($membership, $endDate, $receiptSend, $membershipTypes, $createdMemberships, $isRecur, $calcDates, $mailSend); return $createdMemberships; }
/** * handle the values in import mode * * @param int $onDuplicate the code for what action to take on duplicates * @param array $values the array of values belonging to this line * * @return boolean the result of this processing * @access public */ function import($onDuplicate, &$values) { try { // first make sure this is a valid line $response = $this->summary($values); if ($response != CRM_Import_Parser::VALID) { return $response; } $params =& $this->getActiveFieldParams(); //assign join date equal to start date if join date is not provided if (!CRM_Utils_Array::value('join_date', $params) && CRM_Utils_Array::value('membership_start_date', $params)) { $params['join_date'] = $params['membership_start_date']; } $session = CRM_Core_Session::singleton(); $dateType = $session->get('dateTypes'); $formatted = array(); $customFields = CRM_Core_BAO_CustomField::getFields(CRM_Utils_Array::value('contact_type', $params)); // don't add to recent items, CRM-4399 $formatted['skipRecentView'] = TRUE; $dateLabels = array('join_date' => ts('Member Since'), 'membership_start_date' => ts('Start Date'), 'membership_end_date' => ts('End Date')); foreach ($params as $key => $val) { if ($val) { switch ($key) { case 'join_date': case 'membership_start_date': case 'membership_end_date': if (CRM_Utils_Date::convertToDefaultDate($params, $dateType, $key)) { if (!CRM_Utils_Rule::date($params[$key])) { CRM_Contact_Import_Parser_Contact::addToErrorMsg($dateLabels[$key], $errorMessage); } } else { CRM_Contact_Import_Parser_Contact::addToErrorMsg($dateLabels[$key], $errorMessage); } break; case 'membership_type_id': if (!is_numeric($val)) { unset($params['membership_type_id']); $params['membership_type'] = $val; } break; case 'status_id': if (!is_numeric($val)) { unset($params['status_id']); $params['membership_status'] = $val; } break; case 'is_override': $params[$key] = CRM_Utils_String::strtobool($val); break; } if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) { if ($customFields[$customFieldID]['data_type'] == 'Date') { CRM_Contact_Import_Parser_Contact::formatCustomDate($params, $formatted, $dateType, $key); unset($params[$key]); } else { if ($customFields[$customFieldID]['data_type'] == 'Boolean') { $params[$key] = CRM_Utils_String::strtoboolstr($val); } } } } } //date-Format part ends static $indieFields = NULL; if ($indieFields == NULL) { $tempIndieFields = CRM_Member_DAO_Membership::import(); $indieFields = $tempIndieFields; } $formatValues = array(); foreach ($params as $key => $field) { if ($field == NULL || $field === '') { continue; } $formatValues[$key] = $field; } //format params to meet api v2 requirements. //@todo find a way to test removing this formatting $formatError = $this->membership_format_params($formatValues, $formatted, TRUE); if ($onDuplicate != CRM_Import_Parser::DUPLICATE_UPDATE) { $formatted['custom'] = CRM_Core_BAO_CustomField::postProcess($formatted, CRM_Core_DAO::$_nullObject, NULL, 'Membership'); } else { //fix for CRM-2219 Update Membership // onDuplicate == CRM_Import_Parser::DUPLICATE_UPDATE if (CRM_Utils_Array::value('is_override', $formatted) && !CRM_Utils_Array::value('status_id', $formatted)) { array_unshift($values, 'Required parameter missing: Status'); return CRM_Import_Parser::ERROR; } if (!empty($formatValues['membership_id'])) { $dao = new CRM_Member_BAO_Membership(); $dao->id = $formatValues['membership_id']; $dates = array('join_date', 'start_date', 'end_date'); foreach ($dates as $v) { if (!CRM_Utils_Array::value($v, $formatted)) { $formatted[$v] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $formatValues['membership_id'], $v); } } $formatted['custom'] = CRM_Core_BAO_CustomField::postProcess($formatted, CRM_Core_DAO::$_nullObject, $formatValues['membership_id'], 'Membership'); if ($dao->find(TRUE)) { $ids = array('membership' => $formatValues['membership_id'], 'userId' => $session->get('userID')); $newMembership = CRM_Member_BAO_Membership::create($formatted, $ids, TRUE); if (civicrm_error($newMembership)) { array_unshift($values, $newMembership['is_error'] . ' for Membership ID ' . $formatValues['membership_id'] . '. Row was skipped.'); return CRM_Import_Parser::ERROR; } else { $this->_newMemberships[] = $newMembership->id; return CRM_Import_Parser::VALID; } } else { array_unshift($values, 'Matching Membership record not found for Membership ID ' . $formatValues['membership_id'] . '. Row was skipped.'); return CRM_Import_Parser::ERROR; } } } //Format dates $startDate = CRM_Utils_Date::customFormat(CRM_Utils_Array::value('start_date', $formatted), '%Y-%m-%d'); $endDate = CRM_Utils_Date::customFormat(CRM_Utils_Array::value('end_date', $formatted), '%Y-%m-%d'); $joinDate = CRM_Utils_Date::customFormat(CRM_Utils_Array::value('join_date', $formatted), '%Y-%m-%d'); if ($this->_contactIdIndex < 0) { //retrieve contact id using contact dedupe rule $formatValues['contact_type'] = $this->_contactType; $formatValues['version'] = 3; require_once 'CRM/Utils/DeprecatedUtils.php'; $error = _civicrm_api3_deprecated_check_contact_dedupe($formatValues); if (CRM_Core_Error::isAPIError($error, CRM_Core_ERROR::DUPLICATE_CONTACT)) { $matchedIDs = explode(',', $error['error_message']['params'][0]); if (count($matchedIDs) > 1) { array_unshift($values, 'Multiple matching contact records detected for this row. The membership was not imported'); return CRM_Import_Parser::ERROR; } else { $cid = $matchedIDs[0]; $formatted['contact_id'] = $cid; //fix for CRM-1924 $calcDates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($formatted['membership_type_id'], $joinDate, $startDate, $endDate); self::formattedDates($calcDates, $formatted); //fix for CRM-3570, exclude the statuses those having is_admin = 1 //now user can import is_admin if is override is true. $excludeIsAdmin = FALSE; if (!CRM_Utils_Array::value('is_override', $formatted)) { $formatted['exclude_is_admin'] = $excludeIsAdmin = TRUE; } $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($startDate, $endDate, $joinDate, 'today', $excludeIsAdmin, $formatted['membership_type_id'], $formatted); if (!CRM_Utils_Array::value('status_id', $formatted)) { $formatted['status_id'] = $calcStatus['id']; } elseif (!CRM_Utils_Array::value('is_override', $formatted)) { if (empty($calcStatus)) { array_unshift($values, 'Status in import row (' . $formatValues['status_id'] . ') does not match calculated status based on your configured Membership Status Rules. Record was not imported.'); return CRM_Import_Parser::ERROR; } elseif ($formatted['status_id'] != $calcStatus['id']) { //Status Hold" is either NOT mapped or is FALSE array_unshift($values, 'Status in import row (' . $formatValues['status_id'] . ') does not match calculated status based on your configured Membership Status Rules (' . $calcStatus['name'] . '). Record was not imported.'); return CRM_Import_Parser::ERROR; } } $newMembership = civicrm_api3('membership', 'create', $formatted); $this->_newMemberships[] = $newMembership['id']; return CRM_Import_Parser::VALID; } } else { // Using new Dedupe rule. $ruleParams = array('contact_type' => $this->_contactType, 'used' => 'Unsupervised'); $fieldsArray = CRM_Dedupe_BAO_Rule::dedupeRuleFields($ruleParams); $disp = ''; foreach ($fieldsArray as $value) { if (array_key_exists(trim($value), $params)) { $paramValue = $params[trim($value)]; if (is_array($paramValue)) { $disp .= $params[trim($value)][0][trim($value)] . " "; } else { $disp .= $params[trim($value)] . " "; } } } if (CRM_Utils_Array::value('external_identifier', $params)) { if ($disp) { $disp .= "AND {$params['external_identifier']}"; } else { $disp = $params['external_identifier']; } } array_unshift($values, 'No matching Contact found for (' . $disp . ')'); return CRM_Import_Parser::ERROR; } } else { if (CRM_Utils_Array::value('external_identifier', $formatValues)) { $checkCid = new CRM_Contact_DAO_Contact(); $checkCid->external_identifier = $formatValues['external_identifier']; $checkCid->find(TRUE); if ($checkCid->id != $formatted['contact_id']) { array_unshift($values, 'Mismatch of External identifier :' . $formatValues['external_identifier'] . ' and Contact Id:' . $formatted['contact_id']); return CRM_Import_Parser::ERROR; } } //to calculate dates $calcDates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($formatted['membership_type_id'], $joinDate, $startDate, $endDate); self::formattedDates($calcDates, $formatted); //end of date calculation part //fix for CRM-3570, exclude the statuses those having is_admin = 1 //now user can import is_admin if is override is true. $excludeIsAdmin = FALSE; if (!CRM_Utils_Array::value('is_override', $formatted)) { $formatted['exclude_is_admin'] = $excludeIsAdmin = TRUE; } $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($startDate, $endDate, $joinDate, 'today', $excludeIsAdmin, $formatted['membership_type_id'], $formatted); if (!CRM_Utils_Array::value('status_id', $formatted)) { $formatted['status_id'] = CRM_Utils_Array::value('id', $calcStatus); } elseif (!CRM_Utils_Array::value('is_override', $formatted)) { if (empty($calcStatus)) { array_unshift($values, 'Status in import row (' . CRM_Utils_Array::value('status_id', $formatValues) . ') does not match calculated status based on your configured Membership Status Rules. Record was not imported.'); return CRM_Import_Parser::ERROR; } elseif ($formatted['status_id'] != $calcStatus['id']) { //Status Hold" is either NOT mapped or is FALSE array_unshift($values, 'Status in import row (' . CRM_Utils_Array::value('status_id', $formatValues) . ') does not match calculated status based on your configured Membership Status Rules (' . $calcStatus['name'] . '). Record was not imported.'); return CRM_Import_Parser::ERROR; } } $newMembership = civicrm_api3('membership', 'create', $formatted); $this->_newMemberships[] = $newMembership['id']; return CRM_Import_Parser::VALID; } } catch (Exception $e) { array_unshift($values, $e->getMessage()); return CRM_Import_Parser::ERROR; } }
/** * Function to create / update / delete membership for related contacts. * * This function will create/update/delete membership for related * contact based on 1) contact have active membership 2) that * membership is is extedned by the same relationship type to that * of the existing relationship. * * @param $contactId Int contact id * @param $params array array of values submitted by POST * @param $ids array array of ids * @param $action which action called this function * * @static * */ static function relatedMemberships($contactId, &$params, $ids, $action = CRM_Core_Action::ADD, $active = TRUE) { // Check the end date and set the status of the relationship // accrodingly. $status = self::CURRENT; if (!empty($params['end_date'])) { $endDate = CRM_Utils_Date::setDateDefaults(CRM_Utils_Date::format($params['end_date']), NULL, 'Ymd'); $today = date('Ymd'); if ($today > $endDate) { $status = self::PAST; } } if ($action & CRM_Core_Action::ADD && $status & self::PAST) { // if relationship is PAST and action is ADD, no qustion // of creating RELATED membership and return back to // calling method return; } $rel = explode('_', $params['relationship_type_id']); $relTypeId = $rel[0]; $relDirection = "_{$rel[1]}_{$rel[2]}"; $targetContact = array(); if ($action & CRM_Core_Action::ADD || $action & CRM_Core_Action::DELETE) { $contact = $contactId; $targetContact = CRM_Utils_Array::value('contact_check', $params); } elseif ($action & CRM_Core_Action::UPDATE) { $contact = $ids['contact']; $targetContact = array($ids['contactTarget'] => 1); } // Build the 'values' array for // 1. ContactA // 2. ContactB // This will allow us to check if either of the contacts in // relationship have active memberships. $values = array(); // 1. ContactA $values[$contact] = array('relatedContacts' => $targetContact, 'relationshipTypeId' => $relTypeId, 'relationshipTypeDirection' => $relDirection); // 2. ContactB if (!empty($targetContact)) { foreach ($targetContact as $cid => $donCare) { $values[$cid] = array('relatedContacts' => array($contact => 1), 'relationshipTypeId' => $relTypeId); $relTypeParams = array('id' => $relTypeId); $relTypeValues = array(); CRM_Contact_BAO_RelationshipType::retrieve($relTypeParams, $relTypeValues); if (CRM_Utils_Array::value('name_a_b', $relTypeValues) == CRM_Utils_Array::value('name_b_a', $relTypeValues)) { $values[$cid]['relationshipTypeDirection'] = '_a_b'; } else { $values[$cid]['relationshipTypeDirection'] = $relDirection == '_a_b' ? '_b_a' : '_a_b'; } } } // Now get the active memberships for all the contacts. // If contact have any valid membership(s), then add it to // 'values' array. foreach ($values as $cid => $subValues) { $memParams = array('contact_id' => $cid); $memberships = array(); CRM_Member_BAO_Membership::getValues($memParams, $memberships, $active); if (empty($memberships)) { continue; } $values[$cid]['memberships'] = $memberships; } $deceasedStatusId = array_search('Deceased', CRM_Member_PseudoConstant::membershipStatus()); // done with 'values' array. // Finally add / edit / delete memberships for the related contacts foreach ($values as $cid => $details) { if (!array_key_exists('memberships', $details)) { continue; } $mainRelatedContactId = key(CRM_Utils_Array::value('relatedContacts', $details, array())); foreach ($details['memberships'] as $membershipId => $membershipValues) { $relTypeIds = array(); if ($action & CRM_Core_Action::DELETE) { // Delete memberships of the related contacts only if relationship type exists for membership type $query = "\nSELECT relationship_type_id, relationship_direction\n FROM civicrm_membership_type\n WHERE id = {$membershipValues['membership_type_id']}"; $dao = CRM_Core_DAO::executeQuery($query); $relTypeDirs = array(); while ($dao->fetch()) { $relTypeId = $dao->relationship_type_id; $relDirection = $dao->relationship_direction; } $relTypeIds = explode(CRM_Core_DAO::VALUE_SEPARATOR, $relTypeId); if (in_array($values[$cid]['relationshipTypeId'], $relTypeIds)) { CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipId, $mainRelatedContactId); } continue; } if ($action & CRM_Core_Action::UPDATE && $status & self::PAST && $membershipValues['owner_membership_id']) { // If relationship is PAST and action is UPDATE // then delete the RELATED membership CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipValues['owner_membership_id'], $membershipValues['membership_contact_id']); continue; } // add / edit the memberships for related // contacts. // Get the Membership Type Details. $membershipType = CRM_Member_BAO_MembershipType::getMembershipTypeDetails($membershipValues['membership_type_id']); // Check if contact's relationship type exists in membership type $relTypeDirs = array(); if (CRM_Utils_Array::value('relationship_type_id', $membershipType)) { $relTypeIds = explode(CRM_Core_DAO::VALUE_SEPARATOR, $membershipType['relationship_type_id']); } if (CRM_Utils_Array::value('relationship_direction', $membershipType)) { $relDirections = explode(CRM_Core_DAO::VALUE_SEPARATOR, $membershipType['relationship_direction']); } foreach ($relTypeIds as $key => $value) { $relTypeDirs[] = $value . '_' . $relDirections[$key]; } $relTypeDir = $details['relationshipTypeId'] . $details['relationshipTypeDirection']; if (in_array($relTypeDir, $relTypeDirs)) { // Check if relationship being created/updated is // similar to that of membership type's // relationship. $membershipValues['owner_membership_id'] = $membershipId; unset($membershipValues['id']); unset($membershipValues['membership_contact_id']); unset($membershipValues['contact_id']); unset($membershipValues['membership_id']); foreach ($details['relatedContacts'] as $relatedContactId => $donCare) { $membershipValues['contact_id'] = $relatedContactId; if ($deceasedStatusId && CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $relatedContactId, 'is_deceased')) { $membershipValues['status_id'] = $deceasedStatusId; $membershipValues['skipStatusCal'] = TRUE; } foreach (array('join_date', 'start_date', 'end_date') as $dateField) { if (CRM_Utils_Array::value($dateField, $membershipValues)) { $membershipValues[$dateField] = CRM_Utils_Date::processDate($membershipValues[$dateField]); } } if ($action & CRM_Core_Action::UPDATE) { //delete the membership record for related //contact before creating new membership record. CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipId, $relatedContactId); } // check whether we have some related memberships still available $query = "\nSELECT count(*)\n FROM civicrm_membership\n LEFT JOIN civicrm_membership_status ON (civicrm_membership_status.id = civicrm_membership.status_id)\n WHERE membership_type_id = {$membershipValues['membership_type_id']} AND owner_membership_id = {$membershipValues['owner_membership_id']}\n AND is_current_member = 1"; $result = CRM_Core_DAO::singleValueQuery($query); if ($result < CRM_Utils_Array::value('max_related', $membershipValues, PHP_INT_MAX)) { CRM_Member_BAO_Membership::create($membershipValues, CRM_Core_DAO::$_nullArray); } } } elseif ($action & CRM_Core_Action::UPDATE) { // if action is update and updated relationship do // not match with the existing // membership=>relationship then we need to // delete the membership record created for // previous relationship. if (self::isDeleteRelatedMembership($relTypeIds, $contactId, $mainRelatedContactId, $relTypeId, CRM_Utils_Array::value('relationship_ids', $params))) { CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipId, $mainRelatedContactId); } } } } }
/** * Create memberships for related contacts, taking into account the maximum related memberships. * * @param array $params * Array of key - value pairs. * @param CRM_Core_DAO $dao * Membership object. * * @param bool $reset * * @return array|null * Membership details, if created. * * @throws \CRM_Core_Exception */ public static function createRelatedMemberships(&$params, &$dao, $reset = FALSE) { static $relatedContactIds = array(); if ($reset) { // not sure why a static var is in use here - we need a way to reset it from the test suite $relatedContactIds = array(); return FALSE; } $membership = new CRM_Member_DAO_Membership(); $membership->id = $dao->id; // required since create method doesn't return all the // parameters in the returned membership object if (!$membership->find(TRUE)) { return; } $deceasedStatusId = array_search('Deceased', CRM_Member_PseudoConstant::membershipStatus()); // FIXME : While updating/ renewing the // membership, if the relationship is PAST then // the membership of the related contact must be // expired. // For that, getting Membership Status for which // is_current_member is 0. It works for the // generated data as there is only one membership // status having is_current_member = 0. // But this wont work exactly if there will be // more than one status having is_current_member = 0. $membershipStatus = new CRM_Member_DAO_MembershipStatus(); $membershipStatus->is_current_member = 0; if ($membershipStatus->find(TRUE)) { $expiredStatusId = $membershipStatus->id; } else { $expiredStatusId = array_search('Expired', CRM_Member_PseudoConstant::membershipStatus()); } $allRelatedContacts = array(); $relatedContacts = array(); if (!is_a($membership, 'CRM_Core_Error')) { $allRelatedContacts = CRM_Member_BAO_Membership::checkMembershipRelationship($membership->id, $membership->contact_id, CRM_Utils_Array::value('action', $params)); } // check for loops. CRM-4213 // remove repeated related contacts, which already inherited membership. $relatedContactIds[$membership->contact_id] = TRUE; foreach ($allRelatedContacts as $cid => $status) { if (empty($relatedContactIds[$cid])) { $relatedContactIds[$cid] = TRUE; //don't create membership again for owner contact. $nestedRelationship = FALSE; if ($membership->owner_membership_id) { $nestedRelMembership = new CRM_Member_DAO_Membership(); $nestedRelMembership->id = $membership->owner_membership_id; $nestedRelMembership->contact_id = $cid; $nestedRelationship = $nestedRelMembership->find(TRUE); $nestedRelMembership->free(); } if (!$nestedRelationship) { $relatedContacts[$cid] = $status; } } } //lets cleanup related membership if any. if (empty($relatedContacts)) { self::deleteRelatedMemberships($membership->id); } else { // Edit the params array unset($params['id']); // Reminder should be sent only to the direct membership unset($params['reminder_date']); // unset the custom value ids if (is_array(CRM_Utils_Array::value('custom', $params))) { foreach ($params['custom'] as $k => $v) { unset($params['custom'][$k]['id']); } } if (!isset($params['membership_type_id'])) { $params['membership_type_id'] = $membership->membership_type_id; } // max_related should be set in the parent membership unset($params['max_related']); // Number of inherited memberships available - NULL is interpreted as unlimited, '0' as none $available = $membership->max_related == NULL ? PHP_INT_MAX : $membership->max_related; // will be used to queue potential memberships to be created. $queue = array(); foreach ($relatedContacts as $contactId => $relationshipStatus) { //use existing membership record. $relMembership = new CRM_Member_DAO_Membership(); $relMembership->contact_id = $contactId; $relMembership->owner_membership_id = $membership->id; $relMemIds = array(); if ($relMembership->find(TRUE)) { $params['id'] = $relMemIds['membership'] = $relMembership->id; } $params['contact_id'] = $contactId; $params['owner_membership_id'] = $membership->id; // set status_id as it might have been changed for // past relationship $params['status_id'] = $membership->status_id; if ($deceasedStatusId && CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $contactId, 'is_deceased')) { $params['status_id'] = $deceasedStatusId; } elseif (CRM_Utils_Array::value('action', $params) & CRM_Core_Action::UPDATE && $relationshipStatus == CRM_Contact_BAO_Relationship::PAST) { $params['status_id'] = $expiredStatusId; } //don't calculate status again in create( ); $params['skipStatusCal'] = TRUE; //do create activity if we changed status. if ($params['status_id'] != $relMembership->status_id) { $params['createActivity'] = TRUE; } // we should not created contribution record for related contacts, CRM-3371 unset($params['contribution_status_id']); //CRM-16857: Do not create multiple line-items for inherited membership through priceset. unset($params['lineItems']); unset($params['line_item']); if ($params['status_id'] == $deceasedStatusId || $params['status_id'] == $expiredStatusId) { // related membership is not active so does not count towards maximum CRM_Member_BAO_Membership::create($params, $relMemIds); } else { // related membership already exists, so this is just an update if (isset($params['id'])) { if ($available > 0) { CRM_Member_BAO_Membership::create($params, $relMemIds); $available--; } else { // we have run out of inherited memberships, so delete extras self::deleteMembership($params['id']); } // we need to first check if there will remain inherited memberships, so queue it up } else { $queue[] = $params; } } } // now go over the queue and create any available related memberships reset($queue); while ($available > 0 && ($params = each($queue))) { CRM_Member_BAO_Membership::create($params['value'], $relMemIds); $available--; } } }
function testdeleteRelatedMemberships() { $contactId = Contact::createIndividual(); $membershipType = Membership::createMembershipType(); $params = array('contact_id' => $contactId, 'membership_type_id' => $membershipType->id, 'join_date' => '2008-01-21', 'start_date' => '2008-01-21', 'end_date' => '2008-12-21', 'source' => 'Payment', 'is_override' => 1, 'status_id' => $this->_membershipStatusID); $ids = array(); CRM_Member_BAO_Membership::create($params, $ids); $membershipId = $this->assertDBNotNull('CRM_Member_BAO_Membership', $contactId, 'id', 'contact_id', 'Database check for created membership.'); CRM_Member_BAO_Membership::deleteRelatedMemberships($membershipId); }