3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2015
35 * This class generates form components for offline membership form.
37 class CRM_Member_Form_Membership
extends CRM_Member_Form
{
39 protected $_memType = NULL;
41 protected $_onlinePendingContributionId;
45 public $_contributeMode = 'direct';
47 protected $_recurMembershipTypes;
49 protected $_memTypeSelected;
52 * Display name of the member.
56 protected $_memberDisplayName = NULL;
59 * email of the person paying for the membership (used for receipts)
61 protected $_memberEmail = NULL;
64 * Contact ID of the member.
68 public $_contactID = NULL;
71 * Display name of the person paying for the membership (used for receipts)
75 protected $_contributorDisplayName = NULL;
78 * email of the person paying for the membership (used for receipts)
80 protected $_contributorEmail = NULL;
83 * email of the person paying for the membership (used for receipts)
87 protected $_contributorContactID = NULL;
90 * ID of the person the receipt is to go to.
94 protected $_receiptContactId = NULL;
97 * Keep a class variable for ALL membership IDs so
98 * postProcess hook function can do something with it
102 protected $_membershipIDs = array();
105 * An array to hold a list of date fields on the form
106 * so that they can be converted to ISO in a consistent manner
110 protected $_dateFields = array(
111 'receive_date' => array('default' => 'now'),
115 * Get selected membership type from the form values.
117 * @param int $priceSetID
118 * @param array $params
122 public static function getSelectedMemberships($priceSetID, $params) {
123 $memTypeSelected = array();
124 $priceFieldIDS = self
::getPriceFieldIDs($params);
125 if ($priceSetID && is_array($priceFieldIDS)) {
126 foreach ($priceFieldIDS as $priceFieldId) {
127 if ($id = CRM_Core_DAO
::getFieldValue('CRM_Price_DAO_PriceFieldValue', $priceFieldId, 'membership_type_id')) {
128 $memTypeSelected[$id] = $id;
133 $memTypeSelected = array($params['membership_type_id'][1] => $params['membership_type_id'][1]);
135 return $memTypeSelected;
139 * Extract price set fields and values from $params.
141 * @param array $params
145 public static function getPriceFieldIDs($params) {
146 $priceFieldIDS = $priceSet = $fieldIds = array();
147 if (isset(self
::$priceSet) && is_array(self
::$priceSet)) {
148 $priceSet = self
::$_priceSet;
149 if (isset($priceSet['fields']) && is_array($priceSet['fields'])) {
150 $fieldIds = array_keys($priceSet['fields']);
153 foreach ($fieldIds as $fieldId) {
154 if (!empty($params['price_' . $fieldId])) {
155 if (is_array($params['price_' . $fieldId])) {
156 foreach ($params['price_' . $fieldId] as $priceFldVal => $isSet) {
158 $priceFieldIDS[] = $priceFldVal;
163 $priceFieldIDS[] = $params['price_' . $fieldId];
167 return $priceFieldIDS;
171 * Form preProcess function.
175 public function preProcess() {
176 // This string makes up part of the class names, differentiating them (not sure why) from the membership fields.
177 $this->assign('formClass', 'membership');
178 parent
::preProcess();
180 $this->_priceSetId
= CRM_Utils_Array
::value('priceSetId', $_GET);
181 $this->set('priceSetId', $this->_priceSetId
);
182 $this->assign('priceSetId', $this->_priceSetId
);
184 if ($this->_action
& CRM_Core_Action
::DELETE
) {
185 $contributionID = CRM_Member_BAO_Membership
::getMembershipContributionId($this->_id
);
186 // check delete permission for contribution
187 if ($this->_id
&& $contributionID && !CRM_Core_Permission
::checkActionPermission('CiviContribute', $this->_action
)) {
188 CRM_Core_Error
::fatal(ts("This Membership is linked to a contribution. You must have 'delete in CiviContribute' permission in order to delete this record."));
192 if ($this->_action
& CRM_Core_Action
::ADD
) {
193 if (!CRM_Member_BAO_Membership
::statusAvailabilty($this->_contactID
)) {
194 // all possible statuses are disabled - redirect back to contact form
195 CRM_Core_Error
::statusBounce(ts('There are no configured membership statuses. You cannot add this membership until your membership statuses are correctly configured'));
198 if ($this->_contactID
) {
199 //check whether contact has a current membership so we can alert user that they may want to do a renewal instead
200 $contactMemberships = array();
201 $memParams = array('contact_id' => $this->_contactID
);
202 CRM_Member_BAO_Membership
::getValues($memParams, $contactMemberships, TRUE);
203 $cMemTypes = array();
204 foreach ($contactMemberships as $mem) {
205 $cMemTypes[] = $mem['membership_type_id'];
207 if (count($cMemTypes) > 0) {
208 $memberorgs = CRM_Member_BAO_MembershipType
::getMemberOfContactByMemTypes($cMemTypes);
209 $mems_by_org = array();
210 foreach ($contactMemberships as $mem) {
211 $mem['member_of_contact_id'] = CRM_Utils_Array
::value($mem['membership_type_id'], $memberorgs);
212 if (!empty($mem['membership_end_date'])) {
213 $mem['membership_end_date'] = CRM_Utils_Date
::customformat($mem['membership_end_date']);
215 $mem['membership_type'] = CRM_Core_DAO
::getFieldValue('CRM_Member_DAO_MembershipType',
216 $mem['membership_type_id'],
219 $mem['membership_status'] = CRM_Core_DAO
::getFieldValue('CRM_Member_DAO_MembershipStatus',
223 $mem['renewUrl'] = CRM_Utils_System
::url('civicrm/contact/view/membership',
224 "reset=1&action=renew&cid={$this->_contactID}&id={$mem['id']}&context=membership&selectedChild=member"
225 . ($this->_mode ?
'&mode=live' : '')
227 $mem['membershipTab'] = CRM_Utils_System
::url('civicrm/contact/view',
228 "reset=1&force=1&cid={$this->_contactID}&selectedChild=member"
230 $mems_by_org[$mem['member_of_contact_id']] = $mem;
232 $this->assign('existingContactMemberships', $mems_by_org);
236 // In standalone mode we don't have a contact id yet so lookup will be done client-side with this script:
237 $resources = CRM_Core_Resources
::singleton();
238 $resources->addScriptFile('civicrm', 'templates/CRM/Member/Form/MembershipStandalone.js');
240 'typeorgs' => CRM_Member_BAO_MembershipType
::getMembershipTypeOrganization(),
241 'memtypes' => CRM_Core_PseudoConstant
::get('CRM_Member_BAO_Membership', 'membership_type_id'),
242 'statuses' => CRM_Core_PseudoConstant
::get('CRM_Member_BAO_Membership', 'status_id'),
244 $resources->addSetting(array('existingMems' => $passthru));
248 // when custom data is included in this page
249 if (!empty($_POST['hidden_custom'])) {
250 CRM_Custom_Form_CustomData
::preProcess($this);
251 CRM_Custom_Form_CustomData
::buildQuickForm($this);
252 CRM_Custom_Form_CustomData
::setDefaultValues($this);
255 // CRM-4395, get the online pending contribution id.
256 $this->_onlinePendingContributionId
= NULL;
257 if (!$this->_mode
&& $this->_id
&& ($this->_action
& CRM_Core_Action
::UPDATE
)) {
258 $this->_onlinePendingContributionId
= CRM_Contribute_BAO_Contribution
::checkOnlinePendingContribution($this->_id
,
262 $this->assign('onlinePendingContributionId', $this->_onlinePendingContributionId
);
264 $this->setPageTitle(ts('Membership'));
268 * Set default values for the form.
270 public function setDefaultValues() {
272 if ($this->_priceSetId
) {
273 return CRM_Price_BAO_PriceSet
::setDefaultPriceSet($this, $defaults);
276 $defaults = parent
::setDefaultValues();
278 //setting default join date and receive date
279 list($now, $currentTime) = CRM_Utils_Date
::setDateDefaults();
280 if ($this->_action
== CRM_Core_Action
::ADD
) {
281 $defaults['receive_date'] = $now;
282 $defaults['receive_date_time'] = $currentTime;
285 if (is_numeric($this->_memType
)) {
286 $defaults['membership_type_id'] = array();
287 $defaults['membership_type_id'][0] = CRM_Core_DAO
::getFieldValue('CRM_Member_DAO_MembershipType',
289 'member_of_contact_id',
292 $defaults['membership_type_id'][1] = $this->_memType
;
295 $defaults['membership_type_id'] = $this->_memType
;
298 $defaults['num_terms'] = 1;
300 if (!empty($defaults['id'])) {
301 if ($this->_onlinePendingContributionId
) {
302 $defaults['record_contribution'] = $this->_onlinePendingContributionId
;
305 $contributionId = CRM_Core_DAO
::singleValueQuery("
306 SELECT contribution_id
307 FROM civicrm_membership_payment
308 WHERE membership_id = $this->_id
309 ORDER BY contribution_id
312 if ($contributionId) {
313 $defaults['record_contribution'] = $contributionId;
318 //set Soft Credit Type to Gift by default
319 $scTypes = CRM_Core_OptionGroup
::values("soft_credit_type");
320 $defaults['soft_credit_type_id'] = CRM_Utils_Array
::value(ts('Gift'), array_flip($scTypes));
322 if (!empty($defaults['record_contribution']) && !$this->_mode
) {
323 $contributionParams = array('id' => $defaults['record_contribution']);
324 $contributionIds = array();
326 //keep main object campaign in hand.
327 $memberCampaignId = CRM_Utils_Array
::value('campaign_id', $defaults);
329 CRM_Contribute_BAO_Contribution
::getValues($contributionParams, $defaults, $contributionIds);
331 //get back original object campaign id.
332 $defaults['campaign_id'] = $memberCampaignId;
334 if (!empty($defaults['receive_date'])) {
335 list($defaults['receive_date']) = CRM_Utils_Date
::setDateDefaults($defaults['receive_date']);
338 // Contribution::getValues() over-writes the membership record's source field value - so we need to restore it.
339 if (!empty($defaults['membership_source'])) {
340 $defaults['source'] = $defaults['membership_source'];
344 if (empty($defaults['payment_instrument_id'])) {
345 $defaults['payment_instrument_id'] = key(CRM_Core_OptionGroup
::values('payment_instrument', FALSE, FALSE, FALSE, 'AND is_default = 1'));
348 // User must explicitly choose to send a receipt in both add and update mode.
349 $defaults['send_receipt'] = 0;
351 if ($this->_action
& CRM_Core_Action
::UPDATE
) {
352 // in this mode by default uncheck this checkbox
353 unset($defaults['record_contribution']);
356 $subscriptionCancelled = FALSE;
357 if (!empty($defaults['id'])) {
358 $subscriptionCancelled = CRM_Member_BAO_Membership
::isSubscriptionCancelled($this->_id
);
361 $alreadyAutoRenew = FALSE;
362 if (!empty($defaults['contribution_recur_id']) && !$subscriptionCancelled) {
363 $defaults['auto_renew'] = 1;
364 $alreadyAutoRenew = TRUE;
366 $this->assign('alreadyAutoRenew', $alreadyAutoRenew);
368 $this->assign('member_is_test', CRM_Utils_Array
::value('member_is_test', $defaults));
370 $this->assign('membership_status_id', CRM_Utils_Array
::value('status_id', $defaults));
372 if (!empty($defaults['is_pay_later'])) {
373 $this->assign('is_pay_later', TRUE);
376 // set default country from config if no country set
377 $config = CRM_Core_Config
::singleton();
378 if (empty($defaults["billing_country_id-{$this->_bltID}"])) {
379 $defaults["billing_country_id-{$this->_bltID}"] = $config->defaultContactCountry
;
382 if (empty($defaults["billing_state_province_id-{$this->_bltID}"])) {
383 $defaults["billing_state_province_id-{$this->_bltID}"] = $config->defaultContactStateProvince
;
386 $billingDefaults = $this->getProfileDefaults('Billing', $this->_contactID
);
387 $defaults = array_merge($defaults, $billingDefaults);
389 // hack to simplify credit card entry for testing
390 // $defaults['credit_card_type'] = 'Visa';
391 // $defaults['credit_card_number'] = '4807731747657838';
392 // $defaults['cvv2'] = '000';
393 // $defaults['credit_card_exp_date'] = array( 'Y' => '2012', 'M' => '05' );
396 $dates = array('join_date', 'start_date', 'end_date');
397 foreach ($dates as $key) {
398 if (!empty($defaults[$key])) {
399 list($defaults[$key]) = CRM_Utils_Date
::setDateDefaults(CRM_Utils_Array
::value($key, $defaults));
403 //setting default join date if there is no join date
404 if (empty($defaults['join_date'])) {
405 $defaults['join_date'] = $now;
408 if (!empty($defaults['membership_end_date'])) {
409 $this->assign('endDate', $defaults['membership_end_date']);
416 * Build the form object.
418 public function buildQuickForm() {
420 $this->assign('taxRates', json_encode(CRM_Core_PseudoConstant
::getTaxRates()));
422 $this->assign('currency', CRM_Core_Config
::singleton()->defaultCurrencySymbol
);
423 $invoiceSettings = CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::CONTRIBUTE_PREFERENCES_NAME
, 'contribution_invoice_settings');
424 $invoicing = CRM_Utils_Array
::value('invoicing', $invoiceSettings);
425 if (isset($invoicing)) {
426 $this->assign('taxTerm', CRM_Utils_Array
::value('tax_term', $invoiceSettings));
428 // build price set form.
429 $buildPriceSet = FALSE;
430 if ($this->_priceSetId ||
!empty($_POST['price_set_id'])) {
431 if (!empty($_POST['price_set_id'])) {
432 $buildPriceSet = TRUE;
434 $getOnlyPriceSetElements = TRUE;
435 if (!$this->_priceSetId
) {
436 $this->_priceSetId
= $_POST['price_set_id'];
437 $getOnlyPriceSetElements = FALSE;
440 $this->set('priceSetId', $this->_priceSetId
);
441 CRM_Price_BAO_PriceSet
::buildPriceSet($this);
443 $optionsMembershipTypes = array();
444 foreach ($this->_priceSet
['fields'] as $pField) {
445 if (empty($pField['options'])) {
448 foreach ($pField['options'] as $opId => $opValues) {
449 $optionsMembershipTypes[$opId] = CRM_Utils_Array
::value('membership_type_id', $opValues, 0);
453 $this->assign('autoRenewOption', CRM_Price_BAO_PriceSet
::checkAutoRenewForPriceSet($this->_priceSetId
));
455 $this->assign('optionsMembershipTypes', $optionsMembershipTypes);
456 $this->assign('contributionType', CRM_Utils_Array
::value('financial_type_id', $this->_priceSet
));
458 // get only price set form elements.
459 if ($getOnlyPriceSetElements) {
464 // use to build form during form rule.
465 $this->assign('buildPriceSet', $buildPriceSet);
467 if ($this->_action
& CRM_Core_Action
::ADD
) {
468 $buildPriceSet = FALSE;
469 $priceSets = CRM_Price_BAO_PriceSet
::getAssoc(FALSE, 'CiviMember');
470 if (!empty($priceSets)) {
471 $buildPriceSet = TRUE;
474 if ($buildPriceSet) {
475 $this->add('select', 'price_set_id', ts('Choose price set'),
477 '' => ts('Choose price set'),
479 NULL, array('onchange' => "buildAmount( this.value );")
482 $this->assign('hasPriceSets', $buildPriceSet);
485 //need to assign custom data type and subtype to the template
486 $this->assign('customDataType', 'Membership');
487 $this->assign('customDataSubType', $this->_memType
);
488 $this->assign('entityID', $this->_id
);
490 if ($this->_action
& CRM_Core_Action
::DELETE
) {
491 $this->addButtons(array(
494 'name' => ts('Delete'),
495 'spacing' => ' ',
500 'name' => ts('Cancel'),
507 if ($this->_context
== 'standalone') {
508 $this->addEntityRef('contact_id', ts('Contact'), array(
510 'api' => array('extra' => array('email')),
514 $selOrgMemType[0][0] = $selMemTypeOrg[0] = ts('- select -');
516 // retrieve all memberships
517 $allMembershipInfo = array();
518 foreach ($this->allMembershipTypeDetails
as $key => $values) {
519 if ($this->_mode
&& empty($values['minimum_fee'])) {
523 $memberOfContactId = CRM_Utils_Array
::value('member_of_contact_id', $values);
524 if (empty($selMemTypeOrg[$memberOfContactId])) {
525 $selMemTypeOrg[$memberOfContactId] = CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_Contact',
531 $selOrgMemType[$memberOfContactId][0] = ts('- select -');
533 if (empty($selOrgMemType[$memberOfContactId][$key])) {
534 $selOrgMemType[$memberOfContactId][$key] = CRM_Utils_Array
::value('name', $values);
538 // build membership info array, which is used when membership type is selected to:
539 // - set the payment information block
540 // - set the max related block
541 $allMembershipInfo[$key] = array(
542 'financial_type_id' => CRM_Utils_Array
::value('financial_type_id', $values),
543 'total_amount' => CRM_Utils_Money
::format($values['minimum_fee'], NULL, '%a'),
544 'total_amount_numeric' => CRM_Utils_Array
::value('minimum_fee', $values),
545 'auto_renew' => CRM_Utils_Array
::value('auto_renew', $values),
546 'has_related' => isset($values['relationship_type_id']),
547 'max_related' => CRM_Utils_Array
::value('max_related', $values),
551 $this->assign('allMembershipInfo', json_encode($allMembershipInfo));
553 // show organization by default, if only one organization in
555 if (count($selMemTypeOrg) == 2) {
556 unset($selMemTypeOrg[0], $selOrgMemType[0][0]);
558 //sort membership organization and type, CRM-6099
559 natcasesort($selMemTypeOrg);
560 foreach ($selOrgMemType as $index => $orgMembershipType) {
561 natcasesort($orgMembershipType);
562 $selOrgMemType[$index] = $orgMembershipType;
566 'onChange' => "buildMaxRelated(this.value,true); CRM.buildCustomData('Membership', this.value);",
569 if (!empty($this->_recurPaymentProcessors
)) {
570 $memTypeJs['onChange'] = "" . $memTypeJs['onChange'] . 'buildAutoRenew(this.value, null);';
573 $this->add('text', 'max_related', ts('Max related'),
574 CRM_Core_DAO
::getAttribute('CRM_Member_DAO_Membership', 'max_related')
577 $sel = &$this->addElement('hierselect',
578 'membership_type_id',
579 ts('Membership Organization and Type'),
583 $sel->setOptions(array($selMemTypeOrg, $selOrgMemType));
589 $this->applyFilter('__ALL__', 'trim');
591 if ($this->_action
& CRM_Core_Action
::ADD
) {
592 $this->add('text', 'num_terms', ts('Number of Terms'), array('size' => 6));
595 $this->addDate('join_date', ts('Member Since'), FALSE, array('formatType' => 'activityDate'));
596 $this->addDate('start_date', ts('Start Date'), FALSE, array('formatType' => 'activityDate'));
597 $endDate = $this->addDate('end_date', ts('End Date'), FALSE, array('formatType' => 'activityDate'));
599 $elements[] = $endDate;
602 $this->add('text', 'source', ts('Source'),
603 CRM_Core_DAO
::getAttribute('CRM_Member_DAO_Membership', 'source')
606 //CRM-7362 --add campaigns.
609 $campaignId = CRM_Core_DAO
::getFieldValue('CRM_Member_DAO_Membership', $this->_id
, 'campaign_id');
611 CRM_Campaign_BAO_Campaign
::addCampaign($this, $campaignId);
614 $this->add('select', 'status_id', ts('Membership Status'),
615 array('' => ts('- select -')) + CRM_Member_PseudoConstant
::membershipStatus(NULL, NULL, 'label')
617 $statusOverride = $this->addElement('checkbox', 'is_override',
618 ts('Status Override?'), NULL,
619 array('onClick' => 'showHideMemberStatus()')
621 if ($statusOverride) {
622 $elements[] = $statusOverride;
625 $this->addElement('checkbox', 'record_contribution', ts('Record Membership Payment?'));
627 $this->add('text', 'total_amount', ts('Amount'));
628 $this->addRule('total_amount', ts('Please enter a valid amount.'), 'money');
630 $this->addDate('receive_date', ts('Received'), FALSE, array('formatType' => 'activityDateTime'));
632 $this->add('select', 'payment_instrument_id',
633 ts('Payment Method'),
634 array('' => ts('- select -')) + CRM_Contribute_PseudoConstant
::paymentInstrument(),
635 FALSE, array('onChange' => "return showHideByValue('payment_instrument_id','4','checkNumber','table-row','select',false);")
637 $this->add('text', 'trxn_id', ts('Transaction ID'));
638 $this->addRule('trxn_id', ts('Transaction ID already exists in Database.'),
639 'objectExists', array(
640 'CRM_Contribute_DAO_Contribution',
646 $allowStatuses = array();
647 $statuses = CRM_Contribute_PseudoConstant
::contributionStatus();
648 if ($this->_onlinePendingContributionId
) {
649 $statusNames = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
650 foreach ($statusNames as $val => $name) {
651 if (in_array($name, array(
658 $allowStatuses[$val] = $statuses[$val];
662 $allowStatuses = $statuses;
664 $this->add('select', 'contribution_status_id',
665 ts('Payment Status'), $allowStatuses
667 $this->add('text', 'check_number', ts('Check Number'),
668 CRM_Core_DAO
::getAttribute('CRM_Contribute_DAO_Contribution', 'check_number')
672 //add field for amount to allow an amount to be entered that differs from minimum
673 $this->add('text', 'total_amount', ts('Amount'));
675 $this->add('select', 'financial_type_id',
676 ts('Financial Type'),
677 array('' => ts('- select -')) + CRM_Contribute_PseudoConstant
::financialType()
680 $this->addElement('checkbox', 'is_different_contribution_contact', ts('Record Payment from a Different Contact?'));
682 $this->addSelect('soft_credit_type_id', array('entity' => 'contribution_soft'));
683 $this->addEntityRef('soft_credit_contact_id', ts('Payment From'), array('create' => TRUE));
685 $this->addElement('checkbox',
687 ts('Send Confirmation and Receipt?'), NULL,
688 array('onclick' => "showHideByValue( 'send_receipt', '', 'notice', 'table-row', 'radio', false); showHideByValue( 'send_receipt', '', 'fromEmail', 'table-row', 'radio', false);")
691 $this->add('select', 'from_email_address', ts('Receipt From'), $this->_fromEmails
);
693 $this->add('textarea', 'receipt_text', ts('Receipt Message'));
695 // Retrieve the name and email of the contact - this will be the TO for receipt email
696 if ($this->_contactID
) {
697 list($this->_memberDisplayName
,
699 ) = CRM_Contact_BAO_Contact_Location
::getEmailDetails($this->_contactID
);
701 $this->assign('emailExists', $this->_memberEmail
);
702 $this->assign('displayName', $this->_memberDisplayName
);
706 if ($this->_action
& CRM_Core_Action
::UPDATE
) {
707 $recurContributionId = CRM_Core_DAO
::getFieldValue('CRM_Member_DAO_Membership', $this->_id
,
708 'contribution_recur_id'
710 if ($recurContributionId && !CRM_Member_BAO_Membership
::isSubscriptionCancelled($this->_id
)) {
712 if (CRM_Member_BAO_Membership
::isCancelSubscriptionSupported($this->_id
)) {
713 $this->assign('cancelAutoRenew',
714 CRM_Utils_System
::url('civicrm/contribute/unsubscribe', "reset=1&mid={$this->_id}")
717 foreach ($elements as $elem) {
722 $this->assign('isRecur', $isRecur);
724 $this->addFormRule(array('CRM_Member_Form_Membership', 'formRule'), $this);
726 $this->assign('outBound_option', CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::MAILING_PREFERENCES_NAME
,
729 parent
::buildQuickForm();
735 * @param array $params
736 * (ref.) an assoc array of name/value pairs.
738 * @param array $files
739 * @param CRM_Member_Form_Membership $self
741 * @throws CiviCRM_API3_Exception
743 * mixed true or array of errors
745 public static function formRule($params, $files, $self) {
748 $priceSetId = CRM_Utils_Array
::value('price_set_id', $params);
750 $selectedMemberships = self
::getSelectedMemberships($priceSetId, $params);
753 CRM_Price_BAO_PriceField
::priceSetValidation($priceSetId, $params, $errors);
755 $priceFieldIDS = self
::getPriceFieldIDs($params, $self);
757 if (!empty($priceFieldIDS)) {
758 $ids = implode(',', $priceFieldIDS);
760 $count = CRM_Price_BAO_PriceSet
::getMembershipCount($ids);
761 foreach ($count as $occurrence) {
762 if ($occurrence > 1) {
763 $errors['_qf_default'] = ts('Select at most one option associated with the same membership type.');
768 elseif (empty($params['membership_type_id'][1])) {
769 $errors['membership_type_id'] = ts('Please select a membership type.');
773 $numterms = CRM_Utils_Array
::value('num_terms', $params);
774 if ($numterms && intval($numterms) != $numterms) {
775 $errors['num_terms'] = ts('Please enter an integer for the number of terms.');
779 // Return error if empty $self->_memTypeSelected
780 if ($priceSetId && empty($errors) && empty($selectedMemberships)) {
781 $errors['_qf_default'] = ts('Select at least one membership option.');
784 if (!empty($errors) && (count($selectedMemberships) > 1)) {
785 $memberOfContacts = CRM_Member_BAO_MembershipType
::getMemberOfContactByMemTypes($selectedMemberships);
786 $duplicateMemberOfContacts = array_count_values($memberOfContacts);
787 foreach ($duplicateMemberOfContacts as $countDuplicate) {
788 if ($countDuplicate > 1) {
789 $errors['_qf_default'] = ts('Please do not select more than one membership associated with the same organization.');
794 if (!empty($errors)) {
798 if ($priceSetId && !$self->_mode
&& empty($params['record_contribution'])) {
799 $errors['record_contribution'] = ts('Record Membership Payment is required when you using price set.');
802 if (!$priceSetId && $self->_mode
&& empty($params['financial_type_id'])) {
803 $errors['financial_type_id'] = ts('Please enter the financial Type.');
806 if (!empty($params['record_contribution']) && empty($params['payment_instrument_id'])) {
807 $errors['payment_instrument_id'] = ts('Payment Method is a required field.');
810 if (!empty($params['is_different_contribution_contact'])) {
811 if (empty($params['soft_credit_type_id'])) {
812 $errors['soft_credit_type_id'] = ts('Please Select a Soft Credit Type');
814 if (empty($params['soft_credit_contact_id'])) {
815 $errors['soft_credit_contact_id'] = ts('Please select a contact');
819 if (!empty($params['payment_processor_id'])) {
820 // validate payment instrument (e.g. credit card number)
821 CRM_Core_Payment_Form
::validatePaymentInstrument($params['payment_processor_id'], $params, $errors, $self);
825 if (!empty($params['join_date'])) {
827 $joinDate = CRM_Utils_Date
::processDate($params['join_date']);
829 foreach ($selectedMemberships as $memType) {
831 if (!empty($params['start_date'])) {
832 $startDate = CRM_Utils_Date
::processDate($params['start_date']);
835 // if end date is set, ensure that start date is also set
836 // and that end date is later than start date
838 if (!empty($params['end_date'])) {
839 $endDate = CRM_Utils_Date
::processDate($params['end_date']);
842 $membershipDetails = CRM_Member_BAO_MembershipType
::getMembershipTypeDetails($memType);
844 if ($startDate && CRM_Utils_Array
::value('period_type', $membershipDetails) == 'rolling') {
845 if ($startDate < $joinDate) {
846 $errors['start_date'] = ts('Start date must be the same or later than Member since.');
851 if ($membershipDetails['duration_unit'] == 'lifetime') {
852 // Check if status is NOT cancelled or similar. For lifetime memberships, there is no automated
853 // process to update status based on end-date. The user must change the status now.
854 $result = civicrm_api3('MembershipStatus', 'get', array(
856 'is_current_member' => 0,
858 $tmp_statuses = $result['values'];
859 $status_ids = array();
860 foreach ($tmp_statuses as $cur_stat) {
861 $status_ids[] = $cur_stat['id'];
863 if (empty($params['status_id']) ||
in_array($params['status_id'], $status_ids) == FALSE) {
864 $errors['status_id'] = ts('Please enter a status that does NOT represent a current membership status.');
865 $errors['is_override'] = ts('This must be checked because you set an End Date for a lifetime membership');
870 $errors['start_date'] = ts('Start date must be set if end date is set.');
872 if ($endDate < $startDate) {
873 $errors['end_date'] = ts('End date must be the same or later than start date.');
878 // Default values for start and end dates if not supplied on the form.
879 $defaultDates = CRM_Member_BAO_MembershipType
::getDatesForMembershipType($memType,
886 $startDate = CRM_Utils_Array
::value('start_date',
891 $endDate = CRM_Utils_Array
::value('end_date',
896 //CRM-3724, check for availability of valid membership status.
897 if (empty($params['is_override']) && !isset($errors['_qf_default'])) {
898 $calcStatus = CRM_Member_BAO_MembershipStatus
::getMembershipStatusByDate($startDate,
906 if (empty($calcStatus)) {
907 $url = CRM_Utils_System
::url('civicrm/admin/member/membershipStatus', 'reset=1&action=browse');
908 $errors['_qf_default'] = ts('There is no valid Membership Status available for selected membership dates.');
909 $status = ts('Oops, it looks like there is no valid membership status available for the given membership dates. You can <a href="%1">Configure Membership Status Rules</a>.', array(1 => $url));
911 $status .= ' ' . ts('OR You can sign up by setting Status Override? to true.');
913 CRM_Core_Session
::setStatus($status, ts('Membership Status Error'), 'error');
919 $errors['join_date'] = ts('Please enter the Member Since.');
922 if (isset($params['is_override']) &&
923 $params['is_override'] && empty($params['status_id'])
925 $errors['status_id'] = ts('Please enter the status.');
928 //total amount condition arise when membership type having no
930 if (isset($params['record_contribution'])) {
931 if (!$params['financial_type_id']) {
932 $errors['financial_type_id'] = ts('Please enter the financial Type.');
934 if (CRM_Utils_System
::isNull($params['total_amount'])) {
935 $errors['total_amount'] = ts('Please enter the contribution.');
939 // validate contribution status for 'Failed'.
940 if ($self->_onlinePendingContributionId
&& !empty($params['record_contribution']) &&
941 (CRM_Utils_Array
::value('contribution_status_id', $params) ==
942 array_search('Failed', CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name'))
945 $errors['contribution_status_id'] = ts('Please select a valid payment status before updating.');
948 return empty($errors) ?
TRUE : $errors;
952 * Process the form submission.
954 public function postProcess() {
955 if ($this->_action
& CRM_Core_Action
::DELETE
) {
956 CRM_Member_BAO_Membership
::del($this->_id
);
959 // get the submitted form values.
960 $this->_params
= $this->controller
->exportValues($this->_name
);
962 $this->submit($this->_params
);
964 $this->setUserContext();
968 * Send email receipt.
970 * @param CRM_Core_Form $form
972 * @param array $formValues
973 * @param object $membership
977 * true if mail was sent successfully
979 public static function emailReceipt(&$form, &$formValues, &$membership) {
980 // retrieve 'from email id' for acknowledgement
981 $receiptFrom = $formValues['from_email_address'];
983 if (!empty($formValues['payment_instrument_id'])) {
984 $paymentInstrument = CRM_Contribute_PseudoConstant
::paymentInstrument();
985 $formValues['paidBy'] = $paymentInstrument[$formValues['payment_instrument_id']];
988 // retrieve custom data
989 $customFields = $customValues = array();
990 if (property_exists($form, '_groupTree')
991 && !empty($form->_groupTree
)
993 foreach ($form->_groupTree
as $groupID => $group) {
994 if ($groupID == 'info') {
997 foreach ($group['fields'] as $k => $field) {
998 $field['title'] = $field['label'];
999 $customFields["custom_{$k}"] = $field;
1004 $members = array(array('member_id', '=', $membership->id
, 0, 0));
1005 // check whether its a test drive
1006 if ($form->_mode
== 'test') {
1007 $members[] = array('member_test', '=', 1, 0, 0);
1010 CRM_Core_BAO_UFGroup
::getValues($formValues['contact_id'], $customFields, $customValues, FALSE, $members);
1011 $form->assign('customValues', $customValues);
1015 if (!empty($form->_params
['billing_first_name'])) {
1016 $name = $form->_params
['billing_first_name'];
1019 if (!empty($form->_params
['billing_middle_name'])) {
1020 $name .= " {$form->_params['billing_middle_name']}";
1023 if (!empty($form->_params
['billing_last_name'])) {
1024 $name .= " {$form->_params['billing_last_name']}";
1027 $form->assign('billingName', $name);
1029 // assign the address formatted up for display
1030 $addressParts = array(
1031 "street_address-{$form->_bltID}",
1032 "city-{$form->_bltID}",
1033 "postal_code-{$form->_bltID}",
1034 "state_province-{$form->_bltID}",
1035 "country-{$form->_bltID}",
1037 $addressFields = array();
1038 foreach ($addressParts as $part) {
1039 list($n, $id) = explode('-', $part);
1040 if (isset($form->_params
['billing_' . $part])) {
1041 $addressFields[$n] = $form->_params
['billing_' . $part];
1044 $form->assign('address', CRM_Utils_Address
::format($addressFields));
1046 $date = CRM_Utils_Date
::format($form->_params
['credit_card_exp_date']);
1047 $date = CRM_Utils_Date
::mysqlToIso($date);
1048 $form->assign('credit_card_exp_date', $date);
1049 $form->assign('credit_card_number',
1050 CRM_Utils_System
::mungeCreditCard($form->_params
['credit_card_number'])
1052 $form->assign('credit_card_type', $form->_params
['credit_card_type']);
1053 $form->assign('contributeMode', 'direct');
1054 $form->assign('isAmountzero', 0);
1055 $form->assign('is_pay_later', 0);
1056 $form->assign('isPrimary', 1);
1059 $form->assign('module', 'Membership');
1060 $form->assign('contactID', $formValues['contact_id']);
1062 $form->assign('membershipID', CRM_Utils_Array
::value('membership_id', $form->_params
, CRM_Utils_Array
::value('membership_id', $form->_defaultValues
)));
1064 if (!empty($formValues['contribution_id'])) {
1065 $form->assign('contributionID', $formValues['contribution_id']);
1067 elseif (isset($form->_onlinePendingContributionId
)) {
1068 $form->assign('contributionID', $form->_onlinePendingContributionId
);
1071 if (!empty($formValues['contribution_status_id'])) {
1072 $form->assign('contributionStatusID', $formValues['contribution_status_id']);
1073 $form->assign('contributionStatus', CRM_Contribute_PseudoConstant
::contributionStatus($formValues['contribution_status_id'], 'name'));
1076 if (!empty($formValues['is_renew'])) {
1077 $form->assign('receiptType', 'membership renewal');
1080 $form->assign('receiptType', 'membership signup');
1082 $form->assign('receive_date', CRM_Utils_Date
::processDate(CRM_Utils_Array
::value('receive_date', $formValues)));
1083 $form->assign('formValues', $formValues);
1085 if (empty($lineItem)) {
1086 $form->assign('mem_start_date', CRM_Utils_Date
::customFormat($membership->start_date
, '%B %E%f, %Y'));
1087 if (!CRM_Utils_System
::isNull($membership->end_date
)) {
1088 $form->assign('mem_end_date', CRM_Utils_Date
::customFormat($membership->end_date
, '%B %E%f, %Y'));
1090 $form->assign('membership_name', CRM_Member_PseudoConstant
::membershipType($membership->membership_type_id
));
1093 $isBatchProcess = is_a($form, 'CRM_Batch_Form_Entry');
1094 if ((empty($form->_contributorDisplayName
) ||
empty($form->_contributorEmail
)) ||
$isBatchProcess) {
1095 // in this case the form is being called statically from the batch editing screen
1096 // having one class in the form layer call another statically is not greate
1097 // & we should aim to move this function to the BAO layer in future.
1098 // however, we can assume that the contact_id passed in by the batch
1099 // function will be the recipient
1100 list($form->_contributorDisplayName
, $form->_contributorEmail
)
1101 = CRM_Contact_BAO_Contact_Location
::getEmailDetails($formValues['contact_id']);
1102 if (empty($form->_receiptContactId
) ||
$isBatchProcess) {
1103 $form->_receiptContactId
= $formValues['contact_id'];
1106 $template = CRM_Core_Smarty
::singleton();
1107 $taxAmt = $template->get_template_vars('dataArray');
1108 $eventTaxAmt = $template->get_template_vars('totalTaxAmount');
1109 $prefixValue = CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::CONTRIBUTE_PREFERENCES_NAME
, 'contribution_invoice_settings');
1110 $invoicing = CRM_Utils_Array
::value('invoicing', $prefixValue);
1111 if ((!empty($taxAmt) ||
isset($eventTaxAmt)) && (isset($invoicing) && isset($prefixValue['is_email_pdf']))) {
1115 $isEmailPdf = FALSE;
1118 list($mailSend, $subject, $message, $html) = CRM_Core_BAO_MessageTemplate
::sendTemplate(
1120 'groupName' => 'msg_tpl_workflow_membership',
1121 'valueName' => 'membership_offline_receipt',
1122 'contactId' => $form->_receiptContactId
,
1123 'from' => $receiptFrom,
1124 'toName' => $form->_contributorDisplayName
,
1125 'toEmail' => $form->_contributorEmail
,
1126 'PDFFilename' => ts('receipt') . '.pdf',
1127 'isEmailPdf' => $isEmailPdf,
1128 'contributionId' => $formValues['contribution_id'],
1129 'isTest' => (bool) ($form->_action
& CRM_Core_Action
::PREVIEW
),
1139 * This is also accessed by unit tests.
1141 * @param array $formValues
1145 public function submit($formValues) {
1146 $isTest = ($this->_mode
== 'test') ?
1 : 0;
1148 $joinDate = $startDate = $endDate = NULL;
1149 $membershipTypes = $membership = $calcDate = array();
1150 $membershipType = NULL;
1153 $priceSetID = CRM_Utils_Array
::value('price_set_id', $formValues);
1155 $params = $softParams = $ids = array();
1157 $allMemberStatus = CRM_Member_PseudoConstant
::membershipStatus();
1158 $allContributionStatus = CRM_Contribute_PseudoConstant
::contributionStatus();
1161 if (!empty($this->_lineItem
)) {
1162 $lineItems = $this->_lineItem
;
1166 $ids['membership'] = $params['id'] = $this->_id
;
1168 $ids['userId'] = CRM_Core_Session
::singleton()->get('userID');
1170 // Set variables that we normally get from context.
1171 // In form mode these are set in preProcess.
1172 //TODO: set memberships, fixme
1173 $this->setContextVariables($formValues);
1174 $this->_memTypeSelected
= self
::getSelectedMemberships($priceSetID, $formValues);
1176 $config = CRM_Core_Config
::singleton();
1178 $this->convertDateFieldsToMySQL($formValues);
1180 $membershipTypeValues = array();
1181 foreach ($this->_memTypeSelected
as $memType) {
1182 $membershipTypeValues[$memType]['membership_type_id'] = $memType;
1185 //take the required membership recur values.
1186 if ($this->_mode
&& !empty($formValues['auto_renew'])) {
1187 $params['is_recur'] = $this->_params
['is_recur'] = $formValues['is_recur'] = TRUE;
1189 'frequency_interval' => 'duration_interval',
1190 'frequency_unit' => 'duration_unit',
1194 foreach ($this->_memTypeSelected
as $memType) {
1195 $recurMembershipTypeValues = CRM_Utils_Array
::value($memType,
1196 $this->_recurMembershipTypes
, array()
1198 foreach ($mapping as $mapVal => $mapParam) {
1199 $membershipTypeValues[$memType][$mapVal] = CRM_Utils_Array
::value($mapParam,
1200 $recurMembershipTypeValues
1203 $this->_params
[$mapVal] = $formValues[$mapVal] = CRM_Utils_Array
::value($mapParam,
1204 $recurMembershipTypeValues
1212 // process price set and get total amount and line items.
1214 $priceSetID = CRM_Member_BAO_Membership
::createLineItems(
1216 $formValues['membership_type_id'],
1220 $isQuickConfig = FALSE;
1221 if (CRM_Core_DAO
::getFieldValue('CRM_Price_DAO_PriceSet', $priceSetID, 'is_quick_config')) {
1224 $termsByType = array();
1226 $lineItem = array();
1227 CRM_Price_BAO_PriceSet
::processAmount($this->_priceSet
['fields'],
1228 $this->_params
, $lineItem[$priceSetID]);
1229 if (CRM_Utils_Array
::value('tax_amount', $this->_params
)) {
1230 $params['tax_amount'] = $this->_params
['tax_amount'];
1232 $params['total_amount'] = CRM_Utils_Array
::value('amount', $this->_params
);
1233 $submittedFinancialType = CRM_Utils_Array
::value('financial_type_id', $formValues);
1234 if (!empty($lineItem[$priceSetID])) {
1235 foreach ($lineItem[$priceSetID] as &$li) {
1236 if (!empty($li['membership_type_id'])) {
1237 if (!empty($li['membership_num_terms'])) {
1238 $termsByType[$li['membership_type_id']] = $li['membership_num_terms'];
1242 ///CRM-11529 for quick config backoffice transactions
1243 //when financial_type_id is passed in form, update the
1244 //lineitems with the financial type selected in form
1245 if ($isQuickConfig && $submittedFinancialType) {
1246 $li['financial_type_id'] = $submittedFinancialType;
1251 $this->storeContactFields($formValues);
1253 $params['contact_id'] = $this->_contactID
;
1262 foreach ($fields as $f) {
1263 $params[$f] = CRM_Utils_Array
::value($f, $formValues);
1267 // when is_override false ignore is_admin statuses during membership
1268 // status calculation. similarly we did fix for import in CRM-3570.
1269 if (empty($params['is_override'])) {
1270 $params['exclude_is_admin'] = TRUE;
1273 // process date params to mysql date format.
1275 'join_date' => 'joinDate',
1276 'start_date' => 'startDate',
1277 'end_date' => 'endDate',
1279 foreach ($dateTypes as $dateField => $dateVariable) {
1280 $
$dateVariable = CRM_Utils_Date
::processDate($formValues[$dateField]);
1283 $memTypeNumTerms = empty($termsByType) ? CRM_Utils_Array
::value('num_terms', $formValues) : NULL;
1285 $calcDates = array();
1286 foreach ($this->_memTypeSelected
as $memType) {
1287 if (empty($memTypeNumTerms)) {
1288 $memTypeNumTerms = CRM_Utils_Array
::value($memType, $termsByType, 1);
1290 $calcDates[$memType] = CRM_Member_BAO_MembershipType
::getDatesForMembershipType($memType,
1291 $joinDate, $startDate, $endDate, $memTypeNumTerms
1295 foreach ($calcDates as $memType => $calcDate) {
1296 foreach (array_keys($dateTypes) as $d) {
1297 //first give priority to form values then calDates.
1298 $date = CRM_Utils_Array
::value($d, $formValues);
1300 $date = CRM_Utils_Array
::value($d, $calcDate);
1303 $membershipTypeValues[$memType][$d] = CRM_Utils_Date
::processDate($date);
1307 // max related memberships - take from form or inherit from membership type
1308 foreach ($this->_memTypeSelected
as $memType) {
1309 if (array_key_exists('max_related', $formValues)) {
1310 $membershipTypeValues[$memType]['max_related'] = CRM_Utils_Array
::value('max_related', $formValues);
1312 $membershipTypeValues[$memType]['custom'] = CRM_Core_BAO_CustomField
::postProcess($formValues,
1316 $membershipTypes[$memType] = CRM_Core_DAO
::getFieldValue('CRM_Member_DAO_MembershipType',
1321 $membershipType = implode(', ', $membershipTypes);
1323 // Retrieve the name and email of the current user - this will be the FROM for the receipt email
1324 list($userName) = CRM_Contact_BAO_Contact_Location
::getEmailDetails($ids['userId']);
1326 //CRM-13981, allow different person as a soft-contributor of chosen type
1327 if ($this->_contributorContactID
!= $this->_contactID
) {
1328 $params['contribution_contact_id'] = $this->_contributorContactID
;
1329 if (!empty($this->_params
['soft_credit_type_id'])) {
1330 $softParams['soft_credit_type_id'] = $this->_params
['soft_credit_type_id'];
1331 $softParams['contact_id'] = $this->_contactID
;
1334 if (!empty($formValues['record_contribution'])) {
1335 $recordContribution = array(
1337 'financial_type_id',
1338 'payment_instrument_id',
1340 'contribution_status_id',
1346 foreach ($recordContribution as $f) {
1347 $params[$f] = CRM_Utils_Array
::value($f, $formValues);
1350 if (!$this->_onlinePendingContributionId
) {
1351 if (empty($formValues['source'])) {
1352 $params['contribution_source'] = ts('%1 Membership: Offline signup (by %2)', array(
1353 1 => $membershipType,
1358 $params['contribution_source'] = $formValues['source'];
1362 if (empty($params['is_override']) &&
1363 CRM_Utils_Array
::value('contribution_status_id', $params) == array_search('Pending', CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name'))
1365 $params['status_id'] = array_search('Pending', $allMemberStatus);
1366 $params['skipStatusCal'] = TRUE;
1367 $params['is_pay_later'] = 1;
1368 $this->assign('is_pay_later', 1);
1371 if (!empty($formValues['send_receipt'])) {
1372 $params['receipt_date'] = CRM_Utils_Array
::value('receive_date', $formValues);
1375 //insert financial type name in receipt.
1376 $formValues['contributionType_name'] = CRM_Core_DAO
::getFieldValue('CRM_Financial_DAO_FinancialType',
1377 $formValues['financial_type_id']
1381 // process line items, until no previous line items.
1382 if (!empty($lineItem)) {
1383 $params['lineItems'] = $lineItem;
1384 $params['processPriceSet'] = TRUE;
1386 $createdMemberships = array();
1388 if (empty($formValues['total_amount']) && !$priceSetID) {
1389 // if total amount not provided minimum for membership type is used
1390 $params['total_amount'] = $formValues['total_amount'] = CRM_Core_DAO
::getFieldValue('CRM_Member_DAO_MembershipType',
1391 $formValues['membership_type_id'][1], 'minimum_fee'
1395 $params['total_amount'] = CRM_Utils_Array
::value('total_amount', $formValues, 0);
1398 if ($priceSetID && !$isQuickConfig) {
1399 $params['financial_type_id'] = CRM_Core_DAO
::getFieldValue('CRM_Price_DAO_PriceSet',
1405 $params['financial_type_id'] = CRM_Utils_Array
::value('financial_type_id', $formValues);
1408 $this->_paymentProcessor
= CRM_Financial_BAO_PaymentProcessor
::getPayment($formValues['payment_processor_id'],
1412 //get the payment processor id as per mode.
1413 $params['payment_processor_id'] = $this->_params
['payment_processor_id'] = $formValues['payment_processor_id'] = $this->_paymentProcessor
['id'];
1415 $now = date('YmdHis');
1418 // set email for primary location.
1419 $fields['email-Primary'] = 1;
1420 $formValues['email-5'] = $formValues['email-Primary'] = $this->_memberEmail
;
1421 $params['register_date'] = $now;
1423 // now set the values for the billing location.
1424 foreach ($this->_fields
as $name => $dontCare) {
1428 // also add location name to the array
1429 $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);
1431 $formValues["address_name-{$this->_bltID}"] = trim($formValues["address_name-{$this->_bltID}"]);
1433 $fields["address_name-{$this->_bltID}"] = 1;
1434 //ensure we don't over-write the payer's email with the member's email
1435 if ($this->_contributorContactID
== $this->_contactID
) {
1436 $fields["email-{$this->_bltID}"] = 1;
1439 $nameFields = array('first_name', 'middle_name', 'last_name');
1441 foreach ($nameFields as $name) {
1443 if (array_key_exists("billing_$name", $formValues)) {
1444 $formValues[$name] = $formValues["billing_{$name}"];
1445 $formValues['preserveDBName'] = TRUE;
1448 if ($this->_contributorContactID
== $this->_contactID
) {
1449 //see CRM-12869 for discussion of why we don't do this for separate payee payments
1450 CRM_Contact_BAO_Contact
::createProfileContact($formValues, $fields,
1451 $this->_contributorContactID
, NULL, NULL,
1452 CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactID
, 'contact_type')
1456 // add all the additional payment params we need
1457 $this->_params
["state_province-{$this->_bltID}"] = $this->_params
["billing_state_province-{$this->_bltID}"]
1458 = CRM_Core_PseudoConstant
::stateProvinceAbbreviation($formValues["billing_state_province_id-{$this->_bltID}"]);
1459 $this->_params
["country-{$this->_bltID}"] = $this->_params
["billing_country-{$this->_bltID}"] = CRM_Core_PseudoConstant
::countryIsoCode($formValues["billing_country_id-{$this->_bltID}"]);
1461 $this->_params
['year'] = CRM_Core_Payment_Form
::getCreditCardExpirationYear($formValues);
1462 $this->_params
['month'] = CRM_Core_Payment_Form
::getCreditCardExpirationMonth($formValues);
1463 $this->_params
['ip_address'] = CRM_Utils_System
::ipAddress();
1464 $this->_params
['amount'] = $params['total_amount'];
1465 $this->_params
['currencyID'] = $config->defaultCurrency
;
1466 $this->_params
['description'] = ts("Contribution submitted by a staff person using member's credit card for signup");
1467 $this->_params
['invoiceID'] = md5(uniqid(rand(), TRUE));
1468 $this->_params
['financial_type_id'] = $params['financial_type_id'];
1470 // at this point we've created a contact and stored its address etc
1471 // all the payment processors expect the name and address to be in the
1472 // so we copy stuff over to first_name etc.
1473 $paymentParams = $this->_params
;
1474 $paymentParams['contactID'] = $this->_contributorContactID
;
1475 //CRM-10377 if payment is by an alternate contact then we need to set that person
1476 // as the contact in the payment params
1477 if ($this->_contributorContactID
!= $this->_contactID
) {
1478 if (!empty($this->_params
['soft_credit_type_id'])) {
1479 $softParams['contact_id'] = $params['contact_id'];
1480 $softParams['soft_credit_type_id'] = $this->_params
['soft_credit_type_id'];
1483 if (!empty($this->_params
['send_receipt'])) {
1484 $paymentParams['email'] = $this->_contributorEmail
;
1487 CRM_Core_Payment_Form
::mapParams($this->_bltID
, $this->_params
, $paymentParams, TRUE);
1489 // CRM-7137 -for recurring membership,
1490 // we do need contribution and recurring records.
1492 if (!empty($paymentParams['is_recur'])) {
1493 $financialType = new CRM_Financial_DAO_FinancialType();
1494 $financialType->id
= $params['financial_type_id'];
1495 $financialType->find(TRUE);
1496 $contribution = CRM_Contribute_Form_Contribution_Confirm
::processFormContribution($this,
1499 $this->_contributorContactID
,
1508 //create new soft-credit record, CRM-13981
1510 $softParams['contribution_id'] = $contribution->id
;
1511 $softParams['currency'] = $contribution->currency
;
1512 $softParams['amount'] = $contribution->total_amount
;
1513 CRM_Contribute_BAO_ContributionSoft
::add($softParams);
1516 $paymentParams['contactID'] = $this->_contactID
;
1517 $paymentParams['contributionID'] = $contribution->id
;
1518 $paymentParams['contributionTypeID'] = $contribution->financial_type_id
;
1519 $paymentParams['contributionPageID'] = $contribution->contribution_page_id
;
1520 $paymentParams['contributionRecurID'] = $contribution->contribution_recur_id
;
1521 $ids['contribution'] = $contribution->id
;
1522 $params['contribution_recur_id'] = $paymentParams['contributionRecurID'];
1525 if ($params['total_amount'] > 0.0) {
1526 $payment = $this->_paymentProcessor
['object'];
1528 $result = $payment->doPayment($paymentParams);
1529 $this->_params
= array_merge($this->_params
, $result);
1530 // Assign amount to template if payment was successful.
1531 $this->assign('amount', $params['total_amount']);
1533 catch (PaymentProcessorException
$e) {
1534 if (!empty($paymentParams['contributionID'])) {
1535 CRM_Contribute_BAO_Contribution
::failPayment($paymentParams['contributionID'], $this->_contactID
,
1538 if (!empty($paymentParams['contributionRecurID'])) {
1539 CRM_Contribute_BAO_ContributionRecur
::deleteRecurContribution($paymentParams['contributionRecurID']);
1542 CRM_Core_Error
::displaySessionError($result);
1543 CRM_Utils_System
::redirect(CRM_Utils_System
::url('civicrm/contact/view/membership',
1544 "reset=1&action=add&cid={$this->_contactID}&context=&mode={$this->_mode}"
1550 if ($this->_params
['payment_status_id'] != array_search('Completed', $allContributionStatus)) {
1551 $params['status_id'] = array_search('Pending', $allMemberStatus);
1552 $params['skipStatusCal'] = TRUE;
1553 // unset send-receipt option, since receipt will be sent when ipn is received.
1554 unset($this->_params
['send_receipt'], $formValues['send_receipt']);
1555 //as membership is pending set dates to null.
1556 $memberDates = array(
1557 'join_date' => 'joinDate',
1558 'start_date' => 'startDate',
1559 'end_date' => 'endDate',
1561 foreach ($memberDates as $dv) {
1563 foreach ($this->_memTypeSelected
as $memType) {
1564 $membershipTypeValues[$memType][$dv] = NULL;
1568 $params['receive_date'] = $now;
1569 $params['invoice_id'] = $this->_params
['invoiceID'];
1570 $params['contribution_source'] = ts('%1 Membership Signup: Credit card or direct debit (by %2)',
1571 array(1 => $membershipType, 2 => $userName)
1573 $params['source'] = $formValues['source'] ?
$formValues['source'] : $params['contribution_source'];
1574 $params['trxn_id'] = CRM_Utils_Array
::value('trxn_id', $result);
1575 $params['payment_instrument_id'] = 1;
1576 $params['is_test'] = ($this->_mode
== 'live') ?
0 : 1;
1577 if (!empty($this->_params
['send_receipt'])) {
1578 $params['receipt_date'] = $now;
1581 $params['receipt_date'] = NULL;
1584 $this->set('params', $this->_params
);
1585 $this->assign('trxn_id', CRM_Utils_Array
::value('trxn_id', $result));
1586 $this->assign('receive_date',
1587 CRM_Utils_Date
::mysqlToIso($params['receive_date'])
1590 // required for creating membership for related contacts
1591 $params['action'] = $this->_action
;
1593 //create membership record.
1595 foreach ($this->_memTypeSelected
as $memType) {
1597 ($relateContribution = CRM_Member_BAO_Membership
::getMembershipContributionId($membership->id
))
1599 $membershipTypeValues[$memType]['relate_contribution_id'] = $relateContribution;
1602 $membershipParams = array_merge($membershipTypeValues[$memType], $params);
1604 if (!empty($softParams) && empty($paymentParams['is_recur'])) {
1605 $membershipParams['soft_credit'] = $softParams;
1607 // This is required to trigger the recording of the membership contribution in the
1608 // CRM_Member_BAO_Membership::Create function.
1609 // @todo stop setting this & 'teach' the create function to respond to something
1610 // appropriate as part of our 2-step always create the pending contribution & then finally add the payment
1612 // @see http://wiki.civicrm.org/confluence/pages/viewpage.action?pageId=261062657#Payments&AccountsRoadmap-Movetowardsalwaysusinga2-steppaymentprocess
1613 $membershipParams['contribution_status_id'] = CRM_Utils_Array
::value('payment_status_id', $result);
1614 $membership = CRM_Member_BAO_Membership
::create($membershipParams, $ids);
1615 $params['contribution'] = CRM_Utils_Array
::value('contribution', $membershipParams);
1616 unset($params['lineItems']);
1617 $this->_membershipIDs
[] = $membership->id
;
1618 $createdMemberships[$memType] = $membership;
1624 $params['action'] = $this->_action
;
1625 if ($this->_onlinePendingContributionId
&& !empty($formValues['record_contribution'])) {
1627 // update membership as well as contribution object, CRM-4395
1628 $params['contribution_id'] = $this->_onlinePendingContributionId
;
1629 $params['componentId'] = $params['id'];
1630 $params['componentName'] = 'contribute';
1631 $result = CRM_Contribute_BAO_Contribution
::transitionComponents($params, TRUE);
1632 if (!empty($result) && !empty($params['contribution_id'])) {
1633 $lineItem = array();
1634 $lineItems = CRM_Price_BAO_LineItem
::getLineItems($params['contribution_id'], 'contribution', NULL, TRUE, TRUE);
1635 $itemId = key($lineItems);
1636 $priceSetId = CRM_Core_DAO
::getFieldValue('CRM_Price_DAO_PriceField', $lineItems[$itemId]['price_field_id'], 'price_set_id');
1638 $lineItems[$itemId]['unit_price'] = $params['total_amount'];
1639 $lineItems[$itemId]['line_total'] = $params['total_amount'];
1640 $lineItems[$itemId]['id'] = $itemId;
1641 $lineItem[$priceSetId] = $lineItems;
1642 $contributionBAO = new CRM_Contribute_BAO_Contribution();
1643 $contributionBAO->id
= $params['contribution_id'];
1644 $contributionBAO->contact_id
= $params['contact_id'];
1645 $contributionBAO->find();
1646 CRM_Price_BAO_LineItem
::processPriceSet($params['contribution_id'], $lineItem, $contributionBAO, 'civicrm_membership');
1648 //create new soft-credit record, CRM-13981
1650 $softParams['contribution_id'] = $params['contribution_id'];
1651 while ($contributionBAO->fetch()) {
1652 $softParams['currency'] = $contributionBAO->currency
;
1653 $softParams['amount'] = $contributionBAO->total_amount
;
1655 CRM_Contribute_BAO_ContributionSoft
::add($softParams);
1659 //carry updated membership object.
1660 $membership = new CRM_Member_DAO_Membership();
1661 $membership->id
= $this->_id
;
1662 $membership->find(TRUE);
1665 if ($membership->end_date
) {
1666 //display end date w/ status message.
1667 $endDate = $membership->end_date
;
1669 if (!in_array($membership->status_id
, array(
1671 array_search('Cancelled', CRM_Member_PseudoConstant
::membershipStatus(NULL, " name = 'Cancelled' ", 'name', FALSE, TRUE)),
1672 array_search('Expired', CRM_Member_PseudoConstant
::membershipStatus()),
1678 // suppress form values in template.
1679 $this->assign('cancelled', $cancelled);
1681 $createdMemberships[] = $membership;
1685 foreach ($this->_memTypeSelected
as $memType) {
1686 if ($count && !empty($formValues['record_contribution']) &&
1687 ($relateContribution = CRM_Member_BAO_Membership
::getMembershipContributionId($membership->id
))
1689 $membershipTypeValues[$memType]['relate_contribution_id'] = $relateContribution;
1692 $membershipParams = array_merge($params, $membershipTypeValues[$memType]);
1693 if (!empty($formValues['int_amount'])) {
1694 $init_amount = array();
1695 foreach ($formValues as $key => $value) {
1696 if (strstr($key, 'txt-price')) {
1697 $init_amount[$key] = $value;
1700 $membershipParams['init_amount'] = $init_amount;
1703 if (!empty($softParams)) {
1704 $membershipParams['soft_credit'] = $softParams;
1707 $membership = CRM_Member_BAO_Membership
::create($membershipParams, $ids);
1708 $params['contribution'] = CRM_Utils_Array
::value('contribution', $membershipParams);
1709 unset($params['lineItems']);
1711 $this->_membershipIDs
[] = $membership->id
;
1712 $createdMemberships[$memType] = $membership;
1718 if (!empty($lineItem[$priceSetID])) {
1719 $invoiceSettings = CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::CONTRIBUTE_PREFERENCES_NAME
, 'contribution_invoice_settings');
1720 $invoicing = CRM_Utils_Array
::value('invoicing', $invoiceSettings);
1722 $totalTaxAmount = 0;
1723 foreach ($lineItem[$priceSetID] as & $priceFieldOp) {
1724 if (!empty($priceFieldOp['membership_type_id'])) {
1725 $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') : '-';
1726 $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') : '-';
1729 $priceFieldOp['start_date'] = $priceFieldOp['end_date'] = 'N/A';
1731 if ($invoicing && isset($priceFieldOp['tax_amount'])) {
1733 $totalTaxAmount +
= $priceFieldOp['tax_amount'];
1737 $dataArray = array();
1738 foreach ($lineItem[$priceSetID] as $key => $value) {
1739 if (isset($value['tax_amount']) && isset($value['tax_rate'])) {
1740 if (isset($dataArray[$value['tax_rate']])) {
1741 $dataArray[$value['tax_rate']] = $dataArray[$value['tax_rate']] + CRM_Utils_Array
::value('tax_amount', $value);
1744 $dataArray[$value['tax_rate']] = CRM_Utils_Array
::value('tax_amount', $value);
1749 $this->assign('totalTaxAmount', $totalTaxAmount);
1750 $this->assign('taxTerm', CRM_Utils_Array
::value('tax_term', $invoiceSettings));
1752 $this->assign('dataArray', $dataArray);
1755 $this->assign('lineItem', !empty($lineItem) && !$isQuickConfig ?
$lineItem : FALSE);
1757 $receiptSend = FALSE;
1758 $contributionId = CRM_Member_BAO_Membership
::getMembershipContributionId($membership->id
);
1759 $membershipIds = $this->_membershipIDs
;
1760 if ($contributionId && !empty($membershipIds)) {
1761 $contributionDetails = CRM_Contribute_BAO_Contribution
::getContributionDetails(
1762 CRM_Export_Form_Select
::MEMBER_EXPORT
, $this->_membershipIDs
);
1763 if ($contributionDetails[$membership->id
]['contribution_status'] == 'Completed') {
1764 $receiptSend = TRUE;
1768 if (!empty($formValues['send_receipt']) && $receiptSend) {
1769 $formValues['contact_id'] = $this->_contactID
;
1770 $formValues['contribution_id'] = $contributionId;
1771 // We really don't need a distinct receipt_text_signup vs receipt_text_renewal as they are
1772 // handled in the receipt. But by setting one we avoid breaking templates for now
1773 // although at some point we should switch in the templates.
1774 $formValues['receipt_text_signup'] = $formValues['receipt_text'];
1775 // send email receipt
1776 $mailSend = self
::emailReceipt($this, $formValues, $membership);
1779 // finally set membership id if already not set
1781 $this->_id
= $membership->id
;
1785 if (($this->_action
& CRM_Core_Action
::UPDATE
)) {
1786 $statusMsg = $this->getStatusMessageForUpdate($membership, $endDate, $receiptSend);
1788 elseif (($this->_action
& CRM_Core_Action
::ADD
)) {
1789 $statusMsg = $this->getStatusMessageForCreate($endDate, $receiptSend, $membershipTypes, $createdMemberships,
1790 $params, $calcDates, $mailSend);
1793 CRM_Core_Session
::setStatus($statusMsg, ts('Complete'), 'success');
1795 // dusplay message when membership type is changed
1796 if ($this->_id
&& !in_array($this->_memType
, $this->_memTypeSelected
)) {
1797 CRM_Core_Session
::setStatus(
1798 ts('The financial types associated with the old and new membership types are different. You may want to edit the contribution associated with this membership to adjust its financial type.'),
1801 CRM_Core_Session
::setStatus(
1802 ts('The cost of the old and new membership types are different. You may want to edit the contribution associated with this membership to adjust its amount.'),
1806 return $createdMemberships;
1810 * Set context in session.
1812 protected function setUserContext() {
1813 $buttonName = $this->controller
->getButtonName();
1814 $session = CRM_Core_Session
::singleton();
1816 if ($this->_context
== 'standalone') {
1817 if ($buttonName == $this->getButtonName('upload', 'new')) {
1818 $session->replaceUserContext(CRM_Utils_System
::url('civicrm/member/add',
1819 'reset=1&action=add&context=standalone'
1823 $session->replaceUserContext(CRM_Utils_System
::url('civicrm/contact/view',
1824 "reset=1&cid={$this->_contactID}&selectedChild=member"
1828 elseif ($buttonName == $this->getButtonName('upload', 'new')) {
1829 $session->replaceUserContext(CRM_Utils_System
::url('civicrm/contact/view/membership',
1830 "reset=1&action=add&context=membership&cid={$this->_contactID}"
1836 * Get status message for updating membership.
1838 * @param CRM_Member_BAO_Membership $membership
1839 * @param string $endDate
1840 * @param bool $receiptSend
1844 protected function getStatusMessageForUpdate($membership, $endDate, $receiptSend) {
1845 // End date can be modified by hooks, so if end date is set then use it.
1846 $endDate = ($membership->end_date
) ?
$membership->end_date
: $endDate;
1848 $statusMsg = ts('Membership for %1 has been updated.', array(1 => $this->_memberDisplayName
));
1849 if ($endDate && $endDate !== 'null') {
1850 $endDate = CRM_Utils_Date
::customFormat($endDate);
1851 $statusMsg .= ' ' . ts('The membership End Date is %1.', array(1 => $endDate));
1855 $statusMsg .= ' ' . ts('A confirmation and receipt has been sent to %1.', array(1 => $this->_contributorEmail
));
1861 * Get status message for create action.
1863 * @param string $endDate
1864 * @param bool $receiptSend
1865 * @param array $membershipTypes
1866 * @param array $createdMemberships
1867 * @param array $params
1868 * @param array $calcDates
1869 * @param bool $mailSent
1871 * @return array|string
1873 protected function getStatusMessageForCreate($endDate, $receiptSend, $membershipTypes, $createdMemberships,
1874 $params, $calcDates, $mailSent) {
1875 // FIX ME: fix status messages
1877 $statusMsg = array();
1878 foreach ($membershipTypes as $memType => $membershipType) {
1879 $statusMsg[$memType] = ts('%1 membership for %2 has been added.', array(
1880 1 => $membershipType,
1881 2 => $this->_memberDisplayName
,
1884 $membership = $createdMemberships[$memType];
1885 $memEndDate = ($membership->end_date
) ?
$membership->end_date
: $endDate;
1887 //get the end date from calculated dates.
1888 if (!$memEndDate && empty($params['is_recur'])) {
1889 $memEndDate = CRM_Utils_Array
::value('end_date', $calcDates[$memType]);
1892 if ($memEndDate && $memEndDate !== 'null') {
1893 $memEndDate = CRM_Utils_Date
::customFormat($memEndDate);
1894 $statusMsg[$memType] .= ' ' . ts('The new membership End Date is %1.', array(1 => $memEndDate));
1897 $statusMsg = implode('<br/>', $statusMsg);
1898 if ($receiptSend && !empty($mailSent)) {
1899 $statusMsg .= ' ' . ts('A membership confirmation and receipt has been sent to %1.', array(1 => $this->_contributorEmail
));