Merge remote branch 'canonical/master' into merge-forward
[civicrm-core.git] / CRM / Member / Form / Membership.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
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. |
13 | |
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. |
18 | |
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 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2014
32 * $Id$
33 *
34 */
35
36 /**
37 * This class generates form components for offline membership form
38 *
39 */
40 class CRM_Member_Form_Membership extends CRM_Member_Form {
41
42 protected $_memType = NULL;
43
44 protected $_onlinePendingContributionId;
45
46 public $_mode;
47
48 public $_contributeMode = 'direct';
49
50 protected $_recurMembershipTypes;
51
52 protected $_memTypeSelected;
53
54 /*
55 * Display name of the member
56 */
57 protected $_memberDisplayName = NULL;
58
59 /*
60 * email of the person paying for the membership (used for receipts)
61 */
62 protected $_memberEmail = NULL;
63
64 /*
65 * Contact ID of the member
66 */
67 protected $_contactID = NULL;
68
69 /*
70 * Display name of the person paying for the membership (used for receipts)
71 */
72 protected $_contributorDisplayName = NULL;
73
74 /*
75 * email of the person paying for the membership (used for receipts)
76 */
77 protected $_contributorEmail = NULL;
78
79 /*
80 * email of the person paying for the membership (used for receipts)
81 */
82 protected $_contributorContactID = NULL;
83
84 /*
85 * ID of the person the receipt is to go to
86 */
87 protected $_receiptContactId = NULL;
88
89 /*
90 * Keep a class variable for ALL membeshipID's so
91 * postProcess hook function can do something with it
92 */
93 protected $_membershipIDs = array();
94
95 /**
96 * An array to hold a list of datefields on the form
97 * so that they can be converted to ISO in a consistent manner
98 *
99 * @var array
100 */
101 protected $_dateFields = array(
102 'receive_date' => array('default' => 'now'),
103 );
104
105 public function preProcess() {
106 //custom data related code
107 $this->_cdType = CRM_Utils_Array::value('type', $_GET);
108 $this->assign('cdType', FALSE);
109 if ($this->_cdType) {
110 $this->assign('cdType', TRUE);
111 return CRM_Custom_Form_CustomData::preProcess($this);
112 }
113
114 // get price set id.
115 $this->_priceSetId = CRM_Utils_Array::value('priceSetId', $_GET);
116 $this->set('priceSetId', $this->_priceSetId);
117 $this->assign('priceSetId', $this->_priceSetId);
118
119 // action
120 $this->_action = CRM_Utils_Request::retrieve('action', 'String', $this, FALSE, 'add');
121 $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this);
122 $this->_contactID = CRM_Utils_Request::retrieve('cid', 'Positive', $this);
123 $this->_processors = array();
124 CRM_Core_Resources::singleton()->addSetting(array('ids' => array('contact' => $this->_contactID)));
125
126 // check for edit permission
127 if (!CRM_Core_Permission::checkActionPermission('CiviMember', $this->_action)) {
128 CRM_Core_Error::fatal(ts('You do not have permission to access this page'));
129 }
130
131 if ($this->_action & CRM_Core_Action::DELETE) {
132 $contributionID = CRM_Member_BAO_Membership::getMembershipContributionId($this->_id);
133 // check delete permission for contribution
134 if ($this->_id && $contributionID && !CRM_Core_Permission::checkActionPermission('CiviContribute', $this->_action)) {
135 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."));
136 }
137 }
138
139 $this->_context = CRM_Utils_Request::retrieve('context', 'String', $this);
140 $this->assign('context', $this->_context);
141
142 if ($this->_id) {
143 $this->_memType = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $this->_id, 'membership_type_id');
144 $this->_membershipIDs[] = $this->_id;
145 }
146
147 $this->_mode = CRM_Utils_Request::retrieve('mode', 'String', $this);
148 $this->assign('membershipMode', $this->_mode);
149
150 if ($this->_mode) {
151 $this->_paymentProcessor = array('billing_mode' => 1);
152 $validProcessors = array();
153 $processors = CRM_Core_PseudoConstant::paymentProcessor(FALSE, FALSE, 'billing_mode IN ( 1, 3 )');
154
155 foreach ($processors as $ppID => $label) {
156 $paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getPayment($ppID, $this->_mode);
157 if ($paymentProcessor['payment_processor_type'] == 'PayPal' && !$paymentProcessor['user_name']) {
158 continue;
159 }
160 elseif ($paymentProcessor['payment_processor_type'] == 'Dummy' && $this->_mode == 'live') {
161 continue;
162 }
163 else {
164 $paymentObject = CRM_Core_Payment::singleton($this->_mode, $paymentProcessor, $this);
165 $error = $paymentObject->checkConfig();
166 if (empty($error)) {
167 $validProcessors[$ppID] = $label;
168 }
169 $paymentObject = NULL;
170 }
171 }
172 if (empty($validProcessors)) {
173 CRM_Core_Error::fatal(ts('Could not find valid payment processor for this page'));
174 }
175 else {
176 $this->_processors = $validProcessors;
177 }
178 // also check for billing information
179 // get the billing location type
180 $locationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id', array(), 'validate');
181 // CRM-8108 remove ts around Billing location type
182 //$this->_bltID = array_search( ts('Billing'), $locationTypes );
183 $this->_bltID = array_search('Billing', $locationTypes);
184 if (!$this->_bltID) {
185 CRM_Core_Error::fatal(ts('Please set a location type of %1', array(1 => 'Billing')));
186 }
187 $this->set('bltID', $this->_bltID);
188 $this->assign('bltID', $this->_bltID);
189
190 $this->_fields = array();
191
192 CRM_Core_Payment_Form::setCreditCardFields($this);
193
194 // this required to show billing block
195 $this->assign_by_ref('paymentProcessor', $paymentProcessor);
196 $this->assign('hidePayPalExpress', TRUE);
197 }
198
199 if ($this->_action & CRM_Core_Action::ADD) {
200 if (!CRM_Member_BAO_Membership::statusAvailabilty($this->_contactID)) {
201 // all possible statuses are disabled - redirect back to contact form
202 CRM_Core_Error::statusBounce(ts('There are no configured membership statuses. You cannot add this membership until your membership statuses are correctly configured'));
203 }
204
205 if ($this->_contactID) {
206 //check whether contact has a current membership so we can alert user that they may want to do a renewal instead
207 $contactMemberships = array();
208 $memParams = array('contact_id' => $this->_contactID);
209 CRM_Member_BAO_Membership::getValues($memParams, $contactMemberships, TRUE);
210 $cMemTypes = array();
211 foreach ($contactMemberships as $mem) {
212 $cMemTypes[] = $mem['membership_type_id'];
213 }
214 if (count($cMemTypes) > 0) {
215 $memberorgs = CRM_Member_BAO_MembershipType::getMemberOfContactByMemTypes($cMemTypes);
216 $mems_by_org = array();
217 foreach ($contactMemberships as $memid => $mem) {
218 $mem['member_of_contact_id'] = CRM_Utils_Array::value($mem['membership_type_id'], $memberorgs);
219 if (!empty($mem['membership_end_date'])) {
220 $mem['membership_end_date'] = CRM_Utils_Date::customformat($mem['membership_end_date']);
221 }
222 $mem['membership_type'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType',
223 $mem['membership_type_id'],
224 'name', 'id'
225 );
226 $mem['membership_status'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipStatus',
227 $mem['status_id'],
228 'label', 'id'
229 );
230 $mem['renewUrl'] = CRM_Utils_System::url('civicrm/contact/view/membership',
231 "reset=1&action=renew&cid={$this->_contactID}&id={$mem['id']}&context=membership&selectedChild=member"
232 . ($this->_mode ? '&mode=live' : '')
233 );
234 $mem['membershipTab'] = CRM_Utils_System::url('civicrm/contact/view',
235 "reset=1&force=1&cid={$this->_contactID}&selectedChild=member"
236 );
237 $mems_by_org[$mem['member_of_contact_id']] = $mem;
238 }
239 $this->assign('existingContactMemberships', $mems_by_org);
240 }
241 }
242 else {
243 // In standalone mode we don't have a contact id yet so lookup will be done client-side with this script:
244 $resources = CRM_Core_Resources::singleton();
245 $resources->addScriptFile('civicrm', 'templates/CRM/Member/Form/MembershipStandalone.js');
246 $passthru = array(
247 'typeorgs' => CRM_Member_BAO_MembershipType::getMembershipTypeOrganization(),
248 'memtypes' => CRM_Core_PseudoConstant::get('CRM_Member_BAO_Membership', 'membership_type_id'),
249 'statuses' => CRM_Core_PseudoConstant::get('CRM_Member_BAO_Membership', 'status_id'),
250 );
251 $resources->addSetting(array('existingMems' => $passthru));
252 }
253 }
254
255 // when custom data is included in this page
256 if (!empty($_POST['hidden_custom'])) {
257 CRM_Custom_Form_CustomData::preProcess($this);
258 CRM_Custom_Form_CustomData::buildQuickForm($this);
259 CRM_Custom_Form_CustomData::setDefaultValues($this);
260 }
261
262 // CRM-4395, get the online pending contribution id.
263 $this->_onlinePendingContributionId = NULL;
264 if (!$this->_mode && $this->_id && ($this->_action & CRM_Core_Action::UPDATE)) {
265 $this->_onlinePendingContributionId = CRM_Contribute_BAO_Contribution::checkOnlinePendingContribution($this->_id,
266 'Membership'
267 );
268 }
269 $this->assign('onlinePendingContributionId', $this->_onlinePendingContributionId);
270 $this->_fromEmails = CRM_Core_BAO_Email::getFromEmail();
271
272 // Set title
273 if ($this->_contactID) {
274 $displayName = CRM_Contact_BAO_Contact::displayName($this->_contactID);
275
276 // Check if this is default domain contact CRM-10482
277 if (CRM_Contact_BAO_Contact::checkDomainContact($this->_contactID)) {
278 $displayName .= ' (' . ts('default organization') . ')';
279 }
280
281 // omitting contactImage from title for now since the summary overlay css doesn't work outside of our crm-container
282 CRM_Utils_System::setTitle(ts('Membership for') . ' ' . $displayName);
283 }
284 parent::preProcess();
285 }
286
287 /**
288 * This function sets the default values for the form. MobileProvider that in edit/view mode
289 * the default values are retrieved from the database
290 *
291 * @access public
292 *
293 * @return void
294 */
295 public function setDefaultValues() {
296 if ($this->_cdType) {
297 return CRM_Custom_Form_CustomData::setDefaultValues($this);
298 }
299
300 if ($this->_priceSetId) {
301 return CRM_Price_BAO_PriceSet::setDefaultPriceSet($this, $defaults);
302 }
303
304 $defaults = parent::setDefaultValues();
305
306 //setting default join date and receive date
307 list($now, $currentTime) = CRM_Utils_Date::setDateDefaults();
308 if ($this->_action == CRM_Core_Action::ADD) {
309 $defaults['receive_date'] = $now;
310 $defaults['receive_date_time'] = $currentTime;
311 }
312
313 if (is_numeric($this->_memType)) {
314 $defaults['membership_type_id'] = array();
315 $defaults['membership_type_id'][0] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType',
316 $this->_memType,
317 'member_of_contact_id',
318 'id'
319 );
320 $defaults['membership_type_id'][1] = $this->_memType;
321 }
322 else {
323 $defaults['membership_type_id'] = $this->_memType;
324 }
325
326 $defaults['num_terms'] = 1;
327
328 if (!empty($defaults['id'])) {
329 if ($this->_onlinePendingContributionId) {
330 $defaults['record_contribution'] = $this->_onlinePendingContributionId;
331 }
332 else {
333 $contributionId = CRM_Core_DAO::singleValueQuery("
334 SELECT contribution_id
335 FROM civicrm_membership_payment
336 WHERE membership_id = $this->_id
337 ORDER BY contribution_id
338 DESC limit 1");
339
340 if ($contributionId) {
341 $defaults['record_contribution'] = $contributionId;
342 }
343 }
344 }
345
346 //set Soft Credit Type to Gift by default
347 $scTypes = CRM_Core_OptionGroup::values("soft_credit_type");
348 $defaults['soft_credit_type_id'] = CRM_Utils_Array::value(ts('Gift'), array_flip($scTypes));
349
350 if (!empty($defaults['record_contribution']) && !$this->_mode) {
351 $contributionParams = array('id' => $defaults['record_contribution']);
352 $contributionIds = array();
353
354 //keep main object campaign in hand.
355 $memberCampaignId = CRM_Utils_Array::value('campaign_id', $defaults);
356
357 CRM_Contribute_BAO_Contribution::getValues($contributionParams, $defaults, $contributionIds);
358
359 //get back original object campaign id.
360 $defaults['campaign_id'] = $memberCampaignId;
361
362 if (!empty($defaults['receive_date'])) {
363 list($defaults['receive_date']) = CRM_Utils_Date::setDateDefaults($defaults['receive_date']);
364 }
365
366 // Contribution::getValues() over-writes the membership record's source field value - so we need to restore it.
367 if (!empty($defaults['membership_source'])) {
368 $defaults['source'] = $defaults['membership_source'];
369 }
370 }
371 //CRM-13420
372 if (empty($defaults['payment_instrument_id'])) {
373 $defaults['payment_instrument_id'] = key(CRM_Core_OptionGroup::values('payment_instrument', FALSE, FALSE, FALSE, 'AND is_default = 1'));
374 }
375
376 // User must explicitly choose to send a receipt in both add and update mode.
377 $defaults['send_receipt'] = 0;
378
379 if ($this->_action & CRM_Core_Action::UPDATE) {
380 // in this mode by default uncheck this checkbox
381 unset($defaults['record_contribution']);
382 }
383
384 if (!empty($defaults['id'])) {
385 $subscriptionCancelled = CRM_Member_BAO_Membership::isSubscriptionCancelled($this->_id);
386 }
387
388 $alreadyAutoRenew = FALSE;
389 if (!empty($defaults['contribution_recur_id']) && !$subscriptionCancelled) {
390 $defaults['auto_renew'] = 1;
391 $alreadyAutoRenew = TRUE;
392 }
393 $this->assign('alreadyAutoRenew', $alreadyAutoRenew);
394
395 $this->assign('member_is_test', CRM_Utils_Array::value('member_is_test', $defaults));
396
397 $this->assign('membership_status_id', CRM_Utils_Array::value('status_id', $defaults));
398
399 if (!empty($defaults['is_pay_later'])) {
400 $this->assign('is_pay_later', TRUE);
401 }
402 if ($this->_mode) {
403 // set default country from config if no country set
404 $config = CRM_Core_Config::singleton();
405 if (empty($defaults["billing_country_id-{$this->_bltID}"])) {
406 $defaults["billing_country_id-{$this->_bltID}"] = $config->defaultContactCountry;
407 }
408
409 if (empty($defaults["billing_state_province_id-{$this->_bltID}"])) {
410 $defaults["billing_state_province_id-{$this->_bltID}"] = $config->defaultContactStateProvince;
411 }
412
413 $billingDefaults = $this->getProfileDefaults('Billing', $this->_contactID);
414 $defaults = array_merge($defaults, $billingDefaults);
415
416 // now fix all state country selectors, set correct state based on country
417 CRM_Core_BAO_Address::fixAllStateSelects($this, $defaults);
418
419 // // hack to simplify credit card entry for testing
420 // $defaults['credit_card_type'] = 'Visa';
421 // $defaults['credit_card_number'] = '4807731747657838';
422 // $defaults['cvv2'] = '000';
423 // $defaults['credit_card_exp_date'] = array( 'Y' => '2012', 'M' => '05' );
424 }
425
426 $dates = array('join_date', 'start_date', 'end_date');
427 foreach ($dates as $key) {
428 if (!empty($defaults[$key])) {
429 list($defaults[$key]) = CRM_Utils_Date::setDateDefaults(CRM_Utils_Array::value($key, $defaults));
430 }
431 }
432
433 //setting default join date if there is no join date
434 if (empty($defaults['join_date'])) {
435 $defaults['join_date'] = $now;
436 }
437
438 if (!empty($defaults['membership_end_date'])) {
439 $this->assign('endDate', $defaults['membership_end_date']);
440 }
441
442 return $defaults;
443 }
444
445 /**
446 * Function to build the form
447 *
448 * @return void
449 * @access public
450 */
451 public function buildQuickForm() {
452 if ($this->_cdType) {
453 return CRM_Custom_Form_CustomData::buildQuickForm($this);
454 }
455
456 $this->assign('taxRates', json_encode(CRM_Core_PseudoConstant::getTaxRates()));
457 // build price set form.
458 $buildPriceSet = FALSE;
459 if ($this->_priceSetId || !empty($_POST['price_set_id'])) {
460 if (!empty($_POST['price_set_id'])) {
461 $buildPriceSet = TRUE;
462 }
463 $getOnlyPriceSetElements = TRUE;
464 if (!$this->_priceSetId) {
465 $this->_priceSetId = $_POST['price_set_id'];
466 $getOnlyPriceSetElements = FALSE;
467 }
468
469 $this->set('priceSetId', $this->_priceSetId);
470 CRM_Price_BAO_PriceSet::buildPriceSet($this);
471
472 $optionsMembershipTypes = array();
473 foreach ($this->_priceSet['fields'] as $pField) {
474 if (empty($pField['options'])) {
475 continue;
476 }
477 foreach ($pField['options'] as $opId => $opValues) {
478 $optionsMembershipTypes[$opId] = CRM_Utils_Array::value('membership_type_id', $opValues, 0);
479 }
480 }
481
482 $this->assign('autoRenewOption', CRM_Price_BAO_PriceSet::checkAutoRenewForPriceSet($this->_priceSetId));
483
484 $this->assign('optionsMembershipTypes', $optionsMembershipTypes);
485 $this->assign('contributionType', CRM_Utils_Array::value('financial_type_id', $this->_priceSet));
486
487 // get only price set form elements.
488 if ($getOnlyPriceSetElements) {
489 return;
490 }
491 }
492
493 // use to build form during form rule.
494 $this->assign('buildPriceSet', $buildPriceSet);
495
496 if ($this->_action & CRM_Core_Action::ADD) {
497 $buildPriceSet = FALSE;
498 $priceSets = CRM_Price_BAO_PriceSet::getAssoc(FALSE, 'CiviMember');
499 if (!empty($priceSets)) {
500 $buildPriceSet = TRUE;
501 }
502
503 if ($buildPriceSet) {
504 $this->add('select', 'price_set_id', ts('Choose price set'),
505 array(
506 '' => ts('Choose price set')
507 ) + $priceSets,
508 NULL, array('onchange' => "buildAmount( this.value );")
509 );
510 }
511 $this->assign('hasPriceSets', $buildPriceSet);
512 }
513
514 //need to assign custom data type and subtype to the template
515 $this->assign('customDataType', 'Membership');
516 $this->assign('customDataSubType', $this->_memType);
517 $this->assign('entityID', $this->_id);
518
519 if ($this->_action & CRM_Core_Action::DELETE) {
520 $this->addButtons(array(
521 array(
522 'type' => 'next',
523 'name' => ts('Delete'),
524 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
525 'isDefault' => TRUE,
526 ),
527 array(
528 'type' => 'cancel',
529 'name' => ts('Cancel'),
530 ),
531 )
532 );
533 return;
534 }
535
536 if ($this->_context == 'standalone') {
537 $this->addEntityRef('contact_id', ts('Contact'), array('create' => TRUE, 'api' => array('extra' => array('email'))), TRUE);
538 }
539
540 $selOrgMemType[0][0] = $selMemTypeOrg[0] = ts('- select -');
541
542 $dao = new CRM_Member_DAO_MembershipType();
543 $dao->domain_id = CRM_Core_Config::domainID();
544 $dao->find();
545
546 // retrieve all memberships
547 $allMemberships = CRM_Member_BAO_Membership::buildMembershipTypeValues($this);
548
549 $allMembershipInfo = $membershipType = array();
550 foreach ($allMemberships as $key => $values) {
551 if (!empty($values['is_active'])) {
552 $membershipType[$key] = CRM_Utils_Array::value('name', $values);
553 if ($this->_mode && empty($values['minimum_fee'])) {
554 continue;
555 }
556 else {
557 $memberOfContactId = CRM_Utils_Array::value('member_of_contact_id', $values);
558 if (empty($selMemTypeOrg[$memberOfContactId])) {
559 $selMemTypeOrg[$memberOfContactId] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
560 $memberOfContactId,
561 'display_name',
562 'id'
563 );
564
565 $selOrgMemType[$memberOfContactId][0] = ts('- select -');
566 }
567 if (empty($selOrgMemType[$memberOfContactId][$key])) {
568 $selOrgMemType[$memberOfContactId][$key] = CRM_Utils_Array::value('name', $values);
569 }
570 }
571
572 // build membership info array, which is used when membership type is selected to:
573 // - set the payment information block
574 // - set the max related block
575 $allMembershipInfo[$key] = array(
576 'financial_type_id' => CRM_Utils_Array::value('financial_type_id', $values),
577 'total_amount' => CRM_Utils_Money::format($values['minimum_fee'], NULL, '%a'),
578 'total_amount_numeric' => CRM_Utils_Array::value('minimum_fee', $values),
579 'auto_renew' => CRM_Utils_Array::value('auto_renew', $values),
580 'has_related' => isset($values['relationship_type_id']),
581 'max_related' => CRM_Utils_Array::value('max_related', $values),
582 );
583 }
584 }
585
586 $this->assign('allMembershipInfo', json_encode($allMembershipInfo));
587
588 // show organization by default, if only one organization in
589 // the list
590 if (count($selMemTypeOrg) == 2) {
591 unset($selMemTypeOrg[0], $selOrgMemType[0][0]);
592 }
593 //sort membership organization and type, CRM-6099
594 natcasesort($selMemTypeOrg);
595 foreach ($selOrgMemType as $index => $orgMembershipType) {
596 natcasesort($orgMembershipType);
597 $selOrgMemType[$index] = $orgMembershipType;
598 }
599
600 $memTypeJs = array('onChange' => "CRM.buildCustomData( 'Membership', this.value );");
601
602 //build the form for auto renew.
603 $recurProcessor = $autoRenew = array();
604 if ($this->_mode || ($this->_action & CRM_Core_Action::UPDATE)) {
605 $autoRenewElement = $this->addElement('checkbox',
606 'auto_renew',
607 ts('Membership renewed automatically'),
608 NULL,
609 array('onclick' => "buildReceiptANDNotice( );")
610 );
611
612 if ($this->_mode) {
613 //get the valid recurring processors.
614 $recurring = CRM_Core_PseudoConstant::paymentProcessor(FALSE, FALSE, 'is_recur = 1');
615 $recurProcessor = array_intersect_assoc($this->_processors, $recurring);
616 $autoRenew = array();
617 if (!empty($recurProcessor)) {
618 if (!empty($membershipType)) {
619 $sql = '
620 SELECT id,
621 auto_renew,
622 duration_unit,
623 duration_interval
624 FROM civicrm_membership_type
625 WHERE id IN ( ' . implode(' , ', array_keys($membershipType)) . ' )';
626 $recurMembershipTypes = CRM_Core_DAO::executeQuery($sql);
627 while ($recurMembershipTypes->fetch()) {
628 $autoRenew[$recurMembershipTypes->id] = $recurMembershipTypes->auto_renew;
629 foreach (array(
630 'id',
631 'auto_renew',
632 'duration_unit',
633 'duration_interval'
634 ) as $fld) {
635 $this->_recurMembershipTypes[$recurMembershipTypes->id][$fld] = $recurMembershipTypes->$fld;
636 }
637 }
638 }
639 $memTypeJs = array(
640 'onChange' =>
641 "CRM.buildCustomData( 'Membership', this.value ); buildAutoRenew(this.value, null );",
642 );
643 }
644 }
645 }
646 $allowAutoRenew = FALSE;
647 if ($this->_mode && !empty($recurProcessor)) {
648 $allowAutoRenew = TRUE;
649 }
650 $this->assign('allowAutoRenew', $allowAutoRenew);
651 $this->assign('autoRenewOptions', json_encode($autoRenew));
652 $this->assign('recurProcessor', json_encode($recurProcessor));
653
654 // for max_related: a little JS to show/hide & set default value
655 $memTypeJs['onChange'] = "buildMaxRelated(this.value,true); " . $memTypeJs['onChange'];
656 $this->add('text', 'max_related', ts('Max related'),
657 CRM_Core_DAO::getAttribute('CRM_Member_DAO_Membership', 'max_related')
658 );
659
660 $sel = & $this->addElement('hierselect',
661 'membership_type_id',
662 ts('Membership Organization and Type'),
663 $memTypeJs
664 );
665
666 $sel->setOptions(array($selMemTypeOrg, $selOrgMemType));
667 $elements = array();
668 if ($sel) {
669 $elements[] = $sel;
670 }
671
672 $this->applyFilter('__ALL__', 'trim');
673
674 if ($this->_action & CRM_Core_Action::ADD) {
675 $this->add('text', 'num_terms', ts('Number of Terms'), array('size' => 6));
676 }
677
678 $this->addDate('join_date', ts('Member Since'), FALSE, array('formatType' => 'activityDate'));
679 $this->addDate('start_date', ts('Start Date'), FALSE, array('formatType' => 'activityDate'));
680 $endDate = $this->addDate('end_date', ts('End Date'), FALSE, array('formatType' => 'activityDate'));
681 if ($endDate) {
682 $elements[] = $endDate;
683 }
684
685 $this->add('text', 'source', ts('Source'),
686 CRM_Core_DAO::getAttribute('CRM_Member_DAO_Membership', 'source')
687 );
688
689 //CRM-7362 --add campaigns.
690 $campaignId = NULL;
691 if ($this->_id) {
692 $campaignId = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $this->_id, 'campaign_id');
693 }
694 CRM_Campaign_BAO_Campaign::addCampaign($this, $campaignId);
695
696 if (!$this->_mode) {
697 $this->add('select', 'status_id', ts('Membership Status'),
698 array('' => ts('- select -')) + CRM_Member_PseudoConstant::membershipStatus(NULL, NULL, 'label')
699 );
700 $statusOverride = $this->addElement('checkbox', 'is_override',
701 ts('Status Override?'), NULL,
702 array('onClick' => 'showHideMemberStatus()')
703 );
704 if ($statusOverride) {
705 $elements[] = $statusOverride;
706 }
707
708 $this->addElement('checkbox', 'record_contribution', ts('Record Membership Payment?'));
709
710 $this->add('text', 'total_amount', ts('Amount'));
711 $this->addRule('total_amount', ts('Please enter a valid amount.'), 'money');
712
713 $this->addDate('receive_date', ts('Received'), FALSE, array('formatType' => 'activityDateTime'));
714
715 $this->add('select', 'payment_instrument_id',
716 ts('Paid By'),
717 array('' => ts('- select -')) + CRM_Contribute_PseudoConstant::paymentInstrument(),
718 FALSE, array('onChange' => "return showHideByValue('payment_instrument_id','4','checkNumber','table-row','select',false);")
719 );
720 $this->add('text', 'trxn_id', ts('Transaction ID'));
721 $this->addRule('trxn_id', ts('Transaction ID already exists in Database.'),
722 'objectExists', array('CRM_Contribute_DAO_Contribution', $this->_id, 'trxn_id')
723 );
724
725 $allowStatuses = array();
726 $statuses = CRM_Contribute_PseudoConstant::contributionStatus();
727 if ($this->_onlinePendingContributionId) {
728 $statusNames = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
729 foreach ($statusNames as $val => $name) {
730 if (in_array($name, array(
731 'In Progress',
732 'Overdue'
733 ))
734 ) {
735 continue;
736 }
737 $allowStatuses[$val] = $statuses[$val];
738 }
739 }
740 else {
741 $allowStatuses = $statuses;
742 }
743 $this->add('select', 'contribution_status_id',
744 ts('Payment Status'), $allowStatuses
745 );
746 $this->add('text', 'check_number', ts('Check Number'),
747 CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Contribution', 'check_number')
748 );
749 }
750 else {
751 //add field for amount to allow an amount to be entered that differs from minimum
752 $this->add('text', 'total_amount', ts('Amount'));
753 }
754 $this->add('select', 'financial_type_id',
755 ts('Financial Type'),
756 array('' => ts('- select -')) + CRM_Contribute_PseudoConstant::financialType()
757 );
758
759 //CRM-10223 - allow contribution to be recorded against different contact
760 // causes a conflict in standalone mode so skip in standalone for now
761 $this->addElement('checkbox', 'is_different_contribution_contact', ts('Record Payment from a Different Contact?'));
762 $this->addSelect('soft_credit_type_id', array('entity' => 'contribution_soft'));
763 $this->addEntityRef('soft_credit_contact_id', ts('Payment From'), array('create' => TRUE));
764
765
766 $this->addElement('checkbox',
767 'send_receipt',
768 ts('Send Confirmation and Receipt?'), NULL,
769 array('onclick' => "showHideByValue( 'send_receipt', '', 'notice', 'table-row', 'radio', false); showHideByValue( 'send_receipt', '', 'fromEmail', 'table-row', 'radio', false);")
770 );
771
772 $this->add('select', 'from_email_address', ts('Receipt From'), $this->_fromEmails);
773
774 $this->add('textarea', 'receipt_text_signup', ts('Receipt Message'));
775 if ($this->_mode) {
776
777 $this->add('select', 'payment_processor_id',
778 ts('Payment Processor'),
779 $this->_processors, TRUE,
780 array('onChange' => "buildAutoRenew( null, this.value );")
781 );
782 CRM_Core_Payment_Form::buildCreditCard($this, TRUE);
783 }
784
785 // Retrieve the name and email of the contact - this will be the TO for receipt email
786 if ($this->_contactID) {
787 list($this->_memberDisplayName,
788 $this->_memberEmail
789 ) = CRM_Contact_BAO_Contact_Location::getEmailDetails($this->_contactID);
790
791 $this->assign('emailExists', $this->_memberEmail);
792 $this->assign('displayName', $this->_memberDisplayName);
793 }
794
795 $isRecur = FALSE;
796 if ($this->_action & CRM_Core_Action::UPDATE) {
797 $recurContributionId = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $this->_id,
798 'contribution_recur_id'
799 );
800 if ($recurContributionId && !CRM_Member_BAO_Membership::isSubscriptionCancelled($this->_id)) {
801 $isRecur = TRUE;
802 if (CRM_Member_BAO_Membership::isCancelSubscriptionSupported($this->_id)) {
803 $this->assign('cancelAutoRenew',
804 CRM_Utils_System::url('civicrm/contribute/unsubscribe', "reset=1&mid={$this->_id}")
805 );
806 }
807 foreach ($elements as $elem) {
808 $elem->freeze();
809 }
810 }
811 }
812 $this->assign('isRecur', $isRecur);
813
814 $this->addFormRule(array('CRM_Member_Form_Membership', 'formRule'), $this);
815
816 $mailingInfo = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::MAILING_PREFERENCES_NAME,
817 'mailing_backend'
818 );
819 $this->assign('outBound_option', $mailingInfo['outBound_option']);
820
821 parent::buildQuickForm();
822 }
823
824 /**
825 * Function for validation
826 *
827 * @param array $params (ref.) an assoc array of name/value pairs
828 *
829 * @param $files
830 * @param $self
831 *
832 * @throws CiviCRM_API3_Exception
833 * @return mixed true or array of errors
834 * @access public
835 * @static
836 */
837 static function formRule($params, $files, $self) {
838 $errors = array();
839
840 $priceSetId = CRM_Utils_Array::value('price_set_id', $params);
841
842 if ($priceSetId) {
843 CRM_Price_BAO_PriceField::priceSetValidation($priceSetId, $params, $errors);
844
845 $priceFieldIDS = array();
846 foreach ($self->_priceSet['fields'] as $priceIds => $dontCare) {
847
848 if (!empty($params['price_' . $priceIds])) {
849 if (is_array($params['price_' . $priceIds])) {
850 foreach ($params['price_' . $priceIds] as $priceFldVal => $isSet) {
851 if ($isSet) {
852 $priceFieldIDS[] = $priceFldVal;
853 }
854 }
855 }
856 else {
857 $priceFieldIDS[] = $params['price_' . $priceIds];
858 }
859 }
860 }
861
862 if (!empty($priceFieldIDS)) {
863 $ids = implode(',', $priceFieldIDS);
864
865 $count = CRM_Price_BAO_PriceSet::getMembershipCount($ids);
866 foreach ($count as $id => $occurance) {
867 if ($occurance > 1) {
868 $errors['_qf_default'] = ts('Select at most one option associated with the same membership type.');
869 }
870 }
871
872 foreach ($priceFieldIDS as $priceFieldId) {
873 if ($id = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceFieldValue', $priceFieldId, 'membership_type_id')) {
874 $self->_memTypeSelected[$id] = $id;
875 }
876 }
877 }
878 }
879 elseif (empty($params['membership_type_id'][1])) {
880 $errors['membership_type_id'] = ts('Please select a membership type.');
881 }
882 else {
883 $self->_memTypeSelected[] = $params['membership_type_id'][1];
884 }
885
886 if (!$priceSetId) {
887 $numterms = CRM_Utils_Array::value('num_terms', $params);
888 if ($numterms && intval($numterms) != $numterms) {
889 $errors['num_terms'] = ts('Please enter an integer for the number of terms.');
890 }
891 }
892
893 // Return error if empty $self->_memTypeSelected
894 if ($priceSetId && empty($errors) && empty($self->_memTypeSelected)) {
895 $errors['_qf_default'] = ts('Select at least one membership option.');
896 }
897
898 if (!empty($errors) && (count($self->_memTypeSelected) > 1)) {
899 $memberOfContacts = CRM_Member_BAO_MembershipType::getMemberOfContactByMemTypes($self->_memTypeSelected);
900 $duplicateMemberOfContacts = array_count_values($memberOfContacts);
901 foreach ($duplicateMemberOfContacts as $countDuplicate) {
902 if ($countDuplicate > 1) {
903 $errors['_qf_default'] = ts('Please do not select more than one membership associated with the same organization.');
904 }
905 }
906 }
907
908 if (!empty($errors)) {
909 return $errors;
910 }
911
912 if ($priceSetId && !$self->_mode && empty($params['record_contribution'])) {
913 $errors['record_contribution'] = ts('Record Membership Payment is required when you using price set.');
914 }
915
916 if (!$priceSetId && $self->_mode && empty($params['financial_type_id'])) {
917 $errors['financial_type_id'] = ts('Please enter the financial Type.');
918 }
919
920 if (!empty($params['record_contribution']) && empty($params['payment_instrument_id'])) {
921 $errors['payment_instrument_id'] = ts('Paid By is a required field.');
922 }
923
924 if (!empty($params['is_different_contribution_contact'])) {
925 if (empty($params['soft_credit_type_id'])) {
926 $errors['soft_credit_type_id'] = ts('Please Select a Soft Credit Type');
927 }
928 if (empty($params['soft_credit_contact_id'])) {
929 $errors['soft_credit_contact_id'] = ts('Please select a contact');
930 }
931 }
932
933 if (!empty($params['payment_processor_id'])) {
934 // make sure that credit card number and cvv are valid
935 CRM_Core_Payment_Form::validateCreditCard($params, $errors);
936 }
937
938 $joinDate = NULL;
939 if (!empty($params['join_date'])) {
940
941 $joinDate = CRM_Utils_Date::processDate($params['join_date']);
942
943 foreach ($self->_memTypeSelected as $memType) {
944 $startDate = NULL;
945 if (!empty($params['start_date'])) {
946 $startDate = CRM_Utils_Date::processDate($params['start_date']);
947 }
948
949 // if end date is set, ensure that start date is also set
950 // and that end date is later than start date
951 $endDate = NULL;
952 if (!empty($params['end_date'])) {
953 $endDate = CRM_Utils_Date::processDate($params['end_date']);
954 }
955
956 $membershipDetails = CRM_Member_BAO_MembershipType::getMembershipTypeDetails($memType);
957
958 if ($startDate && CRM_Utils_Array::value('period_type', $membershipDetails) == 'rolling') {
959 if ($startDate < $joinDate) {
960 $errors['start_date'] = ts('Start date must be the same or later than Member since.');
961 }
962 }
963
964 if ($endDate) {
965 if ($membershipDetails['duration_unit'] == 'lifetime') {
966 // Check if status is NOT cancelled or similar. For lifetime memberships, there is no automated
967 // process to update status based on end-date. The user must change the status now.
968 $result = civicrm_api3('MembershipStatus', 'get', array(
969 'sequential' => 1,
970 'is_current_member' => 0,
971 ));
972 $tmp_statuses = $result['values'];
973 $status_ids = array();
974 foreach($tmp_statuses as $cur_stat) {
975 $status_ids[] = $cur_stat['id'];
976 }
977 if (empty($params['status_id']) || in_array( $params['status_id'] , $status_ids) == false) {
978 $errors['status_id'] = ts('Please enter a status that does NOT represent a current membership status.');
979 $errors['is_override'] = ts('This must be checked because you set an End Date for a lifetime membership');
980 }
981 }
982 else {
983 if (!$startDate) {
984 $errors['start_date'] = ts('Start date must be set if end date is set.');
985 }
986 if ($endDate < $startDate) {
987 $errors['end_date'] = ts('End date must be the same or later than start date.');
988 }
989 }
990 }
991
992 // Default values for start and end dates if not supplied
993 // on the form
994 $defaultDates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($memType,
995 $joinDate,
996 $startDate,
997 $endDate
998 );
999
1000 if (!$startDate) {
1001 $startDate = CRM_Utils_Array::value('start_date',
1002 $defaultDates
1003 );
1004 }
1005 if (!$endDate) {
1006 $endDate = CRM_Utils_Array::value('end_date',
1007 $defaultDates
1008 );
1009 }
1010
1011 //CRM-3724, check for availability of valid membership status.
1012 if (empty($params['is_override']) && !isset($errors['_qf_default'])) {
1013 $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($startDate,
1014 $endDate,
1015 $joinDate,
1016 'today',
1017 TRUE,
1018 $memType,
1019 $params
1020 );
1021 if (empty($calcStatus)) {
1022 $url = CRM_Utils_System::url('civicrm/admin/member/membershipStatus', 'reset=1&action=browse');
1023 $errors['_qf_default'] = ts('There is no valid Membership Status available for selected membership dates.');
1024 $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));
1025 if (!$self->_mode) {
1026 $status .= ' ' . ts('OR You can sign up by setting Status Override? to true.');
1027 }
1028 CRM_Core_Session::setStatus($status, ts('Membership Status Error'), 'error');
1029 }
1030 }
1031 }
1032 }
1033 else {
1034 $errors['join_date'] = ts('Please enter the Member Since.');
1035 }
1036
1037 if (isset($params['is_override']) &&
1038 $params['is_override'] && empty($params['status_id'])) {
1039 $errors['status_id'] = ts('Please enter the status.');
1040 }
1041
1042 //total amount condition arise when membership type having no
1043 //minimum fee
1044 if (isset($params['record_contribution'])) {
1045 if (!$params['financial_type_id']) {
1046 $errors['financial_type_id'] = ts('Please enter the financial Type.');
1047 }
1048 if (CRM_Utils_System::isNull($params['total_amount'])) {
1049 $errors['total_amount'] = ts('Please enter the contribution.');
1050 }
1051 }
1052
1053 // validate contribution status for 'Failed'.
1054 if ($self->_onlinePendingContributionId && !empty($params['record_contribution']) &&
1055 (CRM_Utils_Array::value('contribution_status_id', $params) ==
1056 array_search('Failed', CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'))
1057 )
1058 ) {
1059 $errors['contribution_status_id'] = ts('Please select a valid payment status before updating.');
1060 }
1061
1062 return empty($errors) ? TRUE : $errors;
1063 }
1064
1065 /**
1066 * Function to process the form
1067 *
1068 * @access public
1069 *
1070 * @return void
1071 */
1072 public function postProcess() {
1073 if ($this->_action & CRM_Core_Action::DELETE) {
1074 CRM_Member_BAO_Membership::del($this->_id);
1075 return;
1076 }
1077
1078 $isTest = ($this->_mode == 'test') ? 1 : 0;
1079
1080 $lineItems = NULL;
1081 if (!empty($this->_lineItem)) {
1082 $lineItems = $this->_lineItem;
1083 }
1084
1085 $config = CRM_Core_Config::singleton();
1086 // get the submitted form values.
1087 $this->_params = $formValues = $this->controller->exportValues($this->_name);
1088 $this->convertDateFieldsToMySQL($formValues);
1089
1090 $params = $softParams = $ids = array();
1091
1092 $membershipTypeValues = array();
1093 foreach ($this->_memTypeSelected as $memType) {
1094 $membershipTypeValues[$memType]['membership_type_id'] = $memType;
1095 }
1096
1097 //take the required membership recur values.
1098 if ($this->_mode && !empty($this->_params['auto_renew'])) {
1099 $params['is_recur'] = $this->_params['is_recur'] = $formValues['is_recur'] = TRUE;
1100 $mapping = array(
1101 'frequency_interval' => 'duration_interval',
1102 'frequency_unit' => 'duration_unit',
1103 );
1104
1105 $count = 0;
1106 foreach ($this->_memTypeSelected as $memType) {
1107 $recurMembershipTypeValues = CRM_Utils_Array::value($memType,
1108 $this->_recurMembershipTypes, array()
1109 );
1110 foreach ($mapping as $mapVal => $mapParam) {
1111 $membershipTypeValues[$memType][$mapVal] = CRM_Utils_Array::value($mapParam,
1112 $recurMembershipTypeValues
1113 );
1114 if (!$count) {
1115 $this->_params[$mapVal] = $formValues[$mapVal] = CRM_Utils_Array::value($mapParam,
1116 $recurMembershipTypeValues
1117 );
1118 }
1119 }
1120 $count++;
1121 }
1122
1123 // unset send-receipt option, since receipt will be sent when ipn is received.
1124 unset($this->_params['send_receipt'], $formValues['send_receipt']);
1125 }
1126
1127 // process price set and get total amount and line items.
1128 $lineItem = array();
1129 $priceSetId = NULL;
1130 if (!$priceSetId = CRM_Utils_Array::value('price_set_id', $formValues)) {
1131 CRM_Member_BAO_Membership::createLineItems($this, $formValues['membership_type_id'], $priceSetId);
1132 }
1133 $isQuickConfig = 0;
1134 if ($this->_priceSetId && CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $this->_priceSetId, 'is_quick_config')) {
1135 $isQuickConfig = 1;
1136 }
1137
1138 $termsByType = array();
1139 if ($priceSetId) {
1140 CRM_Price_BAO_PriceSet::processAmount($this->_priceSet['fields'],
1141 $this->_params, $lineItem[$priceSetId]);
1142 if (CRM_Utils_Array::value('tax_amount', $this->_params)) {
1143 $params['tax_amount'] = $this->_params['tax_amount'];
1144 }
1145 $params['total_amount'] = CRM_Utils_Array::value('amount', $this->_params);
1146 $submittedFinancialType = CRM_Utils_Array::value('financial_type_id', $formValues);
1147 if (!empty($lineItem[$priceSetId])) {
1148 foreach ($lineItem[$priceSetId] as &$li) {
1149 if (!empty($li['membership_type_id'])) {
1150 if (!empty($li['membership_num_terms'])) {
1151 $termsByType[$li['membership_type_id']] = $li['membership_num_terms'];
1152 }
1153 }
1154
1155 ///CRM-11529 for quick config backoffice transactions
1156 //when financial_type_id is passed in form, update the
1157 //lineitems with the financial type selected in form
1158 if ($isQuickConfig && $submittedFinancialType) {
1159 $li['financial_type_id'] = $submittedFinancialType;
1160 }
1161 }
1162 }
1163 }
1164
1165 $this->storeContactFields($formValues);
1166
1167 $params['contact_id'] = $this->_contactID;
1168
1169 $fields = array(
1170 'status_id',
1171 'source',
1172 'is_override',
1173 'campaign_id',
1174 );
1175
1176 foreach ($fields as $f) {
1177 $params[$f] = CRM_Utils_Array::value($f, $formValues);
1178 }
1179
1180 // fix for CRM-3724
1181 // when is_override false ignore is_admin statuses during membership
1182 // status calculation. similarly we did fix for import in CRM-3570.
1183 if (empty($params['is_override'])) {
1184 $params['exclude_is_admin'] = TRUE;
1185 }
1186
1187 // process date params to mysql date format.
1188 $dateTypes = array(
1189 'join_date' => 'joinDate',
1190 'start_date' => 'startDate',
1191 'end_date' => 'endDate',
1192 );
1193 foreach ($dateTypes as $dateField => $dateVariable) {
1194 $$dateVariable = CRM_Utils_Date::processDate($formValues[$dateField]);
1195 }
1196
1197 $memTypeNumTerms = CRM_Utils_Array::value('num_terms', $formValues);
1198
1199 $calcDates = array();
1200 foreach ($this->_memTypeSelected as $memType) {
1201 if (empty($memTypeNumTerms)) {
1202 $memTypeNumTerms = CRM_Utils_Array::value($memType, $termsByType, 1);
1203 }
1204 $calcDates[$memType] = CRM_Member_BAO_MembershipType::getDatesForMembershipType($memType,
1205 $joinDate, $startDate, $endDate, $memTypeNumTerms
1206 );
1207 }
1208
1209 foreach ($calcDates as $memType => $calcDate) {
1210 foreach (array_keys($dateTypes) as $d) {
1211 //first give priority to form values then calDates.
1212 $date = CRM_Utils_Array::value($d, $formValues);
1213 if (!$date) {
1214 $date = CRM_Utils_Array::value($d, $calcDate);
1215 }
1216
1217 $membershipTypeValues[$memType][$d] = CRM_Utils_Date::processDate($date);
1218 //$params[$d] = CRM_Utils_Date::processDate( $date );
1219 }
1220 }
1221
1222 // max related memberships - take from form or inherit from membership type
1223 foreach ($this->_memTypeSelected as $memType) {
1224 if (array_key_exists('max_related', $formValues)) {
1225 $membershipTypeValues[$memType]['max_related'] = CRM_Utils_Array::value('max_related', $formValues);
1226 }
1227 }
1228
1229 if ($this->_id) {
1230 $ids['membership'] = $params['id'] = $this->_id;
1231 }
1232
1233 $session = CRM_Core_Session::singleton();
1234 $ids['userId'] = $session->get('userID');
1235
1236 // membership type custom data
1237 foreach ($this->_memTypeSelected as $memType) {
1238 $customFields = CRM_Core_BAO_CustomField::getFields('Membership', FALSE, FALSE,
1239 $memType
1240 );
1241
1242 $customFields = CRM_Utils_Array::crmArrayMerge($customFields,
1243 CRM_Core_BAO_CustomField::getFields('Membership',
1244 FALSE, FALSE,
1245 NULL, NULL, TRUE
1246 )
1247 );
1248
1249 $membershipTypeValues[$memType]['custom'] = CRM_Core_BAO_CustomField::postProcess($formValues,
1250 $customFields,
1251 $this->_id,
1252 'Membership'
1253 );
1254 }
1255
1256 foreach ($this->_memTypeSelected as $memType) {
1257 $membershipTypes[$memType] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType',
1258 $memType
1259 );
1260 }
1261
1262 $membershipType = implode(', ', $membershipTypes);
1263
1264 // Retrieve the name and email of the current user - this will be the FROM for the receipt email
1265 list($userName, $userEmail) = CRM_Contact_BAO_Contact_Location::getEmailDetails($ids['userId']);
1266
1267 //CRM-13981, allow different person as a soft-contributor of chosen type
1268 if ($this->_contributorContactID != $this->_contactID) {
1269 $params['contribution_contact_id'] = $this->_contributorContactID;
1270 if (!empty($this->_params['soft_credit_type_id'])) {
1271 $softParams['soft_credit_type_id'] = $this->_params['soft_credit_type_id'];
1272 $softParams['contact_id'] = $this->_contactID;
1273 }
1274 }
1275 if (!empty($formValues['record_contribution'])) {
1276 $recordContribution = array(
1277 'total_amount',
1278 'financial_type_id',
1279 'payment_instrument_id',
1280 'trxn_id',
1281 'contribution_status_id',
1282 'check_number',
1283 'campaign_id',
1284 'receive_date',
1285 );
1286
1287 foreach ($recordContribution as $f) {
1288 $params[$f] = CRM_Utils_Array::value($f, $formValues);
1289 }
1290
1291 if (!$this->_onlinePendingContributionId) {
1292 if (empty($formValues['source'])) {
1293 $params['contribution_source'] = ts('%1 Membership: Offline signup (by %2)', array(1 => $membershipType, 2 => $userName));
1294 }
1295 else {
1296 $params['contribution_source'] = $formValues['source'];
1297 }
1298 }
1299
1300 if (empty($params['is_override']) &&
1301 CRM_Utils_Array::value('contribution_status_id', $params) == array_search('Pending', CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'))
1302 ) {
1303 $allStatus = CRM_Member_PseudoConstant::membershipStatus();
1304 $params['status_id'] = array_search('Pending', $allStatus);
1305 $params['skipStatusCal'] = TRUE;
1306 $params['is_pay_later'] = 1;
1307 $this->assign('is_pay_later', 1);
1308 }
1309
1310 if (!empty($formValues['send_receipt'])) {
1311 $params['receipt_date'] = CRM_Utils_Array::value('receive_date', $formValues);
1312 }
1313
1314 //insert financial type name in receipt.
1315 $formValues['contributionType_name'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType',
1316 $formValues['financial_type_id']
1317 );
1318 }
1319
1320 // process line items, until no previous line items.
1321 if (!empty($lineItem)) {
1322 $params['lineItems'] = $lineItem;
1323 $params['processPriceSet'] = TRUE;
1324 }
1325 $createdMemberships = array();
1326 if ($this->_mode) {
1327 if (empty($formValues['total_amount']) && !$priceSetId) {
1328 // if total amount not provided minimum for membership type is used
1329 $params['total_amount'] = $formValues['total_amount'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType',
1330 $formValues['membership_type_id'][1], 'minimum_fee'
1331 );
1332 }
1333 else {
1334 $params['total_amount'] = CRM_Utils_Array::value('total_amount', $formValues, 0);
1335 }
1336
1337 if ($priceSetId && !$isQuickConfig) {
1338 $params['financial_type_id'] = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet',
1339 $priceSetId,
1340 'financial_type_id'
1341 );
1342 }
1343 else {
1344 $params['financial_type_id'] = CRM_Utils_Array::value('financial_type_id', $formValues);
1345 }
1346
1347 $this->_paymentProcessor = CRM_Financial_BAO_PaymentProcessor::getPayment($formValues['payment_processor_id'],
1348 $this->_mode
1349 );
1350
1351 //get the payment processor id as per mode.
1352 $params['payment_processor_id'] = $this->_params['payment_processor_id'] = $formValues['payment_processor_id'] = $this->_paymentProcessor['id'];
1353
1354
1355 $now = date('YmdHis');
1356 $fields = array();
1357
1358 // set email for primary location.
1359 $fields['email-Primary'] = 1;
1360 $formValues['email-5'] = $formValues['email-Primary'] = $this->_memberEmail;
1361 $params['register_date'] = $now;
1362
1363 // now set the values for the billing location.
1364 foreach ($this->_fields as $name => $dontCare) {
1365 $fields[$name] = 1;
1366 }
1367
1368 // also add location name to the array
1369 $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);
1370
1371 $formValues["address_name-{$this->_bltID}"] = trim($formValues["address_name-{$this->_bltID}"]);
1372
1373 $fields["address_name-{$this->_bltID}"] = 1;
1374 //ensure we don't over-write the payer's email with the member's email
1375 if ($this->_contributorContactID == $this->_contactID) {
1376 $fields["email-{$this->_bltID}"] = 1;
1377 }
1378
1379 $ctype = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $this->_contactID, 'contact_type');
1380
1381 $nameFields = array('first_name', 'middle_name', 'last_name');
1382
1383 foreach ($nameFields as $name) {
1384 $fields[$name] = 1;
1385 if (array_key_exists("billing_$name", $formValues)) {
1386 $formValues[$name] = $formValues["billing_{$name}"];
1387 $formValues['preserveDBName'] = TRUE;
1388 }
1389 }
1390 if ($this->_contributorContactID == $this->_contactID) {
1391 //see CRM-12869 for discussion of why we don't do this for separate payee payments
1392 CRM_Contact_BAO_Contact::createProfileContact($formValues, $fields,
1393 $this->_contributorContactID, NULL, NULL, $ctype
1394 );
1395 }
1396
1397 // add all the additional payment params we need
1398 $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}"]);
1399 $this->_params["country-{$this->_bltID}"] = $this->_params["billing_country-{$this->_bltID}"] = CRM_Core_PseudoConstant::countryIsoCode($this->_params["billing_country_id-{$this->_bltID}"]);
1400
1401 $this->_params['year'] = CRM_Core_Payment_Form::getCreditCardExpirationYear($this->_params);
1402 $this->_params['month'] = CRM_Core_Payment_Form::getCreditCardExpirationMonth($this->_params);
1403 $this->_params['ip_address'] = CRM_Utils_System::ipAddress();
1404 $this->_params['amount'] = $params['total_amount'];
1405 $this->_params['currencyID'] = $config->defaultCurrency;
1406 $this->_params['payment_action'] = 'Sale';
1407 $this->_params['invoiceID'] = md5(uniqid(rand(), TRUE));
1408 $this->_params['financial_type_id'] = $params['financial_type_id'];
1409
1410 // at this point we've created a contact and stored its address etc
1411 // all the payment processors expect the name and address to be in the
1412 // so we copy stuff over to first_name etc.
1413 $paymentParams = $this->_params;
1414 $paymentParams['contactID'] = $this->_contributorContactID;
1415 //CRM-10377 if payment is by an alternate contact then we need to set that person
1416 // as the contact in the payment params
1417 if ($this->_contributorContactID != $this->_contactID) {
1418 if (!empty($this->_params['soft_credit_type_id'])) {
1419 $softParams['contact_id'] = $params['contact_id'];
1420 $softParams['soft_credit_type_id'] = $this->_params['soft_credit_type_id'];
1421 }
1422 }
1423 if (!empty($this->_params['send_receipt'])) {
1424 $paymentParams['email'] = $this->_contributorEmail;
1425 }
1426
1427 CRM_Core_Payment_Form::mapParams($this->_bltID, $this->_params, $paymentParams, TRUE);
1428
1429 // CRM-7137 -for recurring membership,
1430 // we do need contribution and recuring records.
1431 $result = NULL;
1432 if (!empty($paymentParams['is_recur'])) {
1433 $allStatus = CRM_Member_PseudoConstant::membershipStatus();
1434
1435 $contributionType = new CRM_Financial_DAO_FinancialType();
1436 $contributionType->id = $params['financial_type_id'];
1437 if (!$contributionType->find(TRUE)) {
1438 CRM_Core_Error::fatal('Could not find a system table');
1439 }
1440
1441 $contribution = CRM_Contribute_Form_Contribution_Confirm::processContribution($this,
1442 $paymentParams,
1443 $result,
1444 $this->_contributorContactID,
1445 $contributionType,
1446 TRUE,
1447 FALSE,
1448 $isTest,
1449 $lineItems
1450 );
1451
1452 //create new soft-credit record, CRM-13981
1453 $softParams['contribution_id'] = $contribution->id;
1454 $softParams['currency'] = $contribution->currency;
1455 $softParams['amount'] = $contribution->total_amount;
1456 CRM_Contribute_BAO_ContributionSoft::add($softParams);
1457
1458 $paymentParams['contactID'] = $this->_contactID;
1459 $paymentParams['contributionID'] = $contribution->id;
1460 $paymentParams['contributionTypeID'] = $contribution->financial_type_id;
1461 $paymentParams['contributionPageID'] = $contribution->contribution_page_id;
1462 $paymentParams['contributionRecurID'] = $contribution->contribution_recur_id;
1463 $ids['contribution'] = $contribution->id;
1464 $params['contribution_recur_id'] = $paymentParams['contributionRecurID'];
1465 $params['status_id'] = array_search('Pending', $allStatus);
1466 $params['skipStatusCal'] = TRUE;
1467
1468 //as membership is pending set dates to null.
1469 $memberDates = array(
1470 'join_date' => 'joinDate',
1471 'start_date' => 'startDate',
1472 'end_date' => 'endDate',
1473 );
1474
1475 foreach ($memberDates as $dp => $dv) {
1476 $$dv = NULL;
1477 foreach ($this->_memTypeSelected as $memType) {
1478 $membershipTypeValues[$memType][$dv] = NULL;
1479 }
1480 }
1481 }
1482
1483 if ($params['total_amount'] > 0.0) {
1484 $payment = CRM_Core_Payment::singleton($this->_mode, $this->_paymentProcessor, $this);
1485 $result = & $payment->doDirectPayment($paymentParams);
1486 }
1487
1488 if (is_a($result, 'CRM_Core_Error')) {
1489 //make sure to cleanup db for recurring case.
1490 if (!empty($paymentParams['contributionID'])) {
1491 CRM_Contribute_BAO_Contribution::deleteContribution($paymentParams['contributionID']);
1492 }
1493 if (!empty($paymentParams['contributionRecurID'])) {
1494 CRM_Contribute_BAO_ContributionRecur::deleteRecurContribution($paymentParams['contributionRecurID']);
1495 }
1496
1497 CRM_Core_Error::displaySessionError($result);
1498 CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/view/membership',
1499 "reset=1&action=add&cid={$this->_contactID}&context=&mode={$this->_mode}"
1500 ));
1501 }
1502
1503 if ($result) {
1504 $this->_params = array_merge($this->_params, $result);
1505 //assign amount to template if payment was successful
1506 $this->assign('amount', $params['total_amount']);
1507 }
1508
1509 $params['contribution_status_id'] = !empty($paymentParams['is_recur']) ? 2 : 1;
1510 $params['receive_date'] = $now;
1511 $params['invoice_id'] = $this->_params['invoiceID'];
1512 $params['contribution_source'] = ts('%1 Membership Signup: Credit card or direct debit (by %2)',
1513 array(1 => $membershipType, 2 => $userName)
1514 );
1515 $params['source'] = $formValues['source'] ? $formValues['source'] : $params['contribution_source'];
1516 $params['trxn_id'] = CRM_Utils_Array::value('trxn_id', $result);
1517 $params['payment_instrument_id'] = 1;
1518 $params['is_test'] = ($this->_mode == 'live') ? 0 : 1;
1519 if (!empty($this->_params['send_receipt'])) {
1520 $params['receipt_date'] = $now;
1521 }
1522 else {
1523 $params['receipt_date'] = NULL;
1524 }
1525
1526 $this->set('params', $this->_params);
1527 $this->assign('trxn_id', CRM_Utils_Array::value('trxn_id', $result));
1528 $this->assign('receive_date',
1529 CRM_Utils_Date::mysqlToIso($params['receive_date'])
1530 );
1531
1532 // required for creating membership for related contacts
1533 $params['action'] = $this->_action;
1534
1535 //create membership record.
1536 $count = 0;
1537 foreach ($this->_memTypeSelected as $memType) {
1538 if ($count &&
1539 ($relateContribution = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id))
1540 ) {
1541 $membershipTypeValues[$memType]['relate_contribution_id'] = $relateContribution;
1542 }
1543
1544 $membershipParams = array_merge($membershipTypeValues[$memType], $params);
1545 $membership = CRM_Member_BAO_Membership::create($membershipParams, $ids);
1546
1547 $this->_membershipIDs[] = $membership->id;
1548 $createdMemberships[$memType] = $membership;
1549 $count++;
1550 }
1551
1552 }
1553 else {
1554 $params['action'] = $this->_action;
1555 if ($this->_onlinePendingContributionId && !empty($formValues['record_contribution'])) {
1556
1557 // update membership as well as contribution object, CRM-4395
1558 $params['contribution_id'] = $this->_onlinePendingContributionId;
1559 $params['componentId'] = $params['id'];
1560 $params['componentName'] = 'contribute';
1561 $result = CRM_Contribute_BAO_Contribution::transitionComponents($params, TRUE);
1562 if (!empty($result) && !empty($params['contribution_id'])) {
1563 $lineItem = array();
1564 $lineItems = CRM_Price_BAO_LineItem::getLineItems($params['contribution_id'], 'contribution');
1565 $itemId = key($lineItems);
1566 $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', $lineItems[$itemId]['price_field_id'], 'price_set_id');
1567 $fieldType = NULL;
1568 if ($itemId && !empty($lineItems[$itemId]['price_field_id'])) {
1569 $fieldType = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', $lineItems[$itemId]['price_field_id'], 'html_type');
1570 }
1571 $lineItems[$itemId]['unit_price'] = $params['total_amount'];
1572 $lineItems[$itemId]['line_total'] = $params['total_amount'];
1573 $lineItems[$itemId]['id'] = $itemId;
1574 $lineItem[$priceSetId] = $lineItems;
1575 $contributionBAO = new CRM_Contribute_BAO_Contribution();
1576 $contributionBAO->id = $params['contribution_id'];
1577 $contributionBAO->find();
1578 CRM_Price_BAO_LineItem::processPriceSet($params['contribution_id'], $lineItem, $contributionBAO, 'civicrm_membership');
1579
1580 //create new soft-credit record, CRM-13981
1581 $softParams['contribution_id'] = $params['contribution_id'];
1582
1583 while ($contributionBAO->fetch()) {
1584 $softParams['currency'] = $contributionBAO->currency;
1585 $softParams['amount'] = $contributionBAO->total_amount;
1586 }
1587 CRM_Contribute_BAO_ContributionSoft::add($softParams);
1588 }
1589
1590 //carry updated membership object.
1591 $membership = new CRM_Member_DAO_Membership();
1592 $membership->id = $this->_id;
1593 $membership->find(TRUE);
1594
1595 $cancelled = TRUE;
1596 if ($membership->end_date) {
1597 //display end date w/ status message.
1598 $endDate = $membership->end_date;
1599
1600 $membershipStatues = CRM_Member_PseudoConstant::membershipStatus();
1601 if (!in_array($membership->status_id, array(
1602 array_search('Cancelled', $membershipStatues),
1603 array_search('Expired', $membershipStatues),
1604 ))
1605 ) {
1606 $cancelled = FALSE;
1607 }
1608 }
1609 // suppress form values in template.
1610 $this->assign('cancelled', $cancelled);
1611
1612 // FIX ME: need to recheck this
1613 // here we might updated dates, so get from object.
1614 foreach ($calcDates[$membership->membership_type_id] as $date => & $val) {
1615 if ($membership->$date) {
1616 $val = $membership->$date;
1617 }
1618 }
1619
1620 $createdMemberships[] = $membership;
1621 }
1622 else {
1623 $count = 0;
1624 foreach ($this->_memTypeSelected as $memType) {
1625 if ($count && !empty($formValues['record_contribution']) &&
1626 ($relateContribution = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id))
1627 ) {
1628 $membershipTypeValues[$memType]['relate_contribution_id'] = $relateContribution;
1629 }
1630
1631 $membershipParams = array_merge($params, $membershipTypeValues[$memType]);
1632 if (!empty($formValues['int_amount'])) {
1633 $init_amount = array();
1634 foreach ($formValues as $key => $value) {
1635 if (strstr($key, 'txt-price')) {
1636 $init_amount[$key] = $value;
1637 }
1638 }
1639 $membershipParams['init_amount'] = $init_amount;
1640 }
1641
1642 if (!empty($softParams)) {
1643 $membershipParams['soft_credit'] = $softParams;
1644 }
1645
1646 $membership = CRM_Member_BAO_Membership::create($membershipParams, $ids);
1647
1648 $this->_membershipIDs[] = $membership->id;
1649 $createdMemberships[$memType] = $membership;
1650 $count++;
1651 }
1652 }
1653 }
1654
1655 if (!empty($lineItem[$priceSetId])) {
1656 $invoiceSettings = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME,'contribution_invoice_settings');
1657 $invoicing = CRM_Utils_Array::value('invoicing', $invoiceSettings);
1658 $totalTaxAmount = 0;
1659 foreach ($lineItem[$priceSetId] as & $priceFieldOp) {
1660 if (!empty($priceFieldOp['membership_type_id'])) {
1661 $priceFieldOp['start_date'] = $membershipTypeValues[$priceFieldOp['membership_type_id']]['start_date'] ? CRM_Utils_Date::customFormat($membershipTypeValues[$priceFieldOp['membership_type_id']]['start_date'], '%d%f %b, %Y') : '-';
1662
1663 $priceFieldOp['end_date'] = $membershipTypeValues[$priceFieldOp['membership_type_id']]['end_date'] ? CRM_Utils_Date::customFormat($membershipTypeValues[$priceFieldOp['membership_type_id']]['end_date'], '%d%f %b, %Y') : '-';
1664 }
1665 else {
1666 $priceFieldOp['start_date'] = $priceFieldOp['end_date'] = 'N/A';
1667 }
1668 if ($invoicing && isset($priceFieldOp['tax_amount'])) {
1669 $totalTaxAmount += $priceFieldOp['tax_amount'];
1670 }
1671 }
1672 if ($invoicing) {
1673 $dataArray = array();
1674 foreach ($lineItem[$priceSetId] as $key => $value) {
1675 if (isset($value['tax_amount']) && isset($value['tax_rate'])) {
1676 if (isset($dataArray[$value['tax_rate']])) {
1677 $dataArray[$value['tax_rate']] = $dataArray[$value['tax_rate']] + CRM_Utils_Array::value('tax_amount', $value);
1678 } else {
1679 $dataArray[$value['tax_rate']] = CRM_Utils_Array::value('tax_amount', $value);
1680 }
1681 }
1682 }
1683 $this->assign('totalTaxAmount', $totalTaxAmount);
1684 $this->assign('dataArray', $dataArray);
1685 }
1686 }
1687 $this->assign('lineItem', !empty($lineItem) && !$isQuickConfig ? $lineItem : FALSE);
1688
1689 $receiptSend = FALSE;
1690 if (!empty($formValues['send_receipt'])) {
1691 $receiptSend = TRUE;
1692
1693 $formValues['contact_id'] = $this->_contactID;
1694
1695 $formValues['contribution_id'] = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id);
1696 // send email receipt
1697 $mailSend = self::emailReceipt($this, $formValues, $membership);
1698 }
1699
1700 if (($this->_action & CRM_Core_Action::UPDATE)) {
1701 //end date can be modified by hooks, so if end date is set then use it.
1702 $endDate = ($membership->end_date) ? $membership->end_date : $endDate;
1703
1704 $statusMsg = ts('Membership for %1 has been updated.', array(1 => $this->_memberDisplayName));
1705 if ($endDate && $endDate !== 'null') {
1706 $endDate = CRM_Utils_Date::customFormat($endDate);
1707 $statusMsg .= ' ' . ts('The membership End Date is %1.', array(1 => $endDate));
1708 }
1709 if ($receiptSend) {
1710 $statusMsg .= ' ' . ts('A confirmation and receipt has been sent to %1.', array(1 => $this->_contributorEmail));
1711 }
1712 }
1713 elseif (($this->_action & CRM_Core_Action::ADD)) {
1714 // FIX ME: fix status messages
1715
1716 $statusMsg = array();
1717 foreach ($membershipTypes as $memType => $membershipType) {
1718 $statusMsg[$memType] = ts('%1 membership for %2 has been added.', array(
1719 1 => $membershipType,
1720 2 => $this->_memberDisplayName
1721 ));
1722
1723 $membership = $createdMemberships[$memType];
1724 $memEndDate = ($membership->end_date) ? $membership->end_date : $endDate;
1725
1726 //get the end date from calculated dates.
1727 if (!$memEndDate && empty($params['is_recur'])) {
1728 $memEndDate = CRM_Utils_Array::value('end_date', $calcDates[$memType]);
1729 }
1730
1731 if ($memEndDate && $memEndDate !== 'null') {
1732 $memEndDate = CRM_Utils_Date::customFormat($memEndDate);
1733 $statusMsg[$memType] .= ' ' . ts('The new membership End Date is %1.', array(1 => $memEndDate));
1734 }
1735 }
1736 $statusMsg = implode('<br/>', $statusMsg);
1737 if ($receiptSend && $mailSend) {
1738 $statusMsg .= ' ' . ts('A membership confirmation and receipt has been sent to %1.', array(1 => $this->_contributorEmail));
1739 }
1740 }
1741
1742 // finally set membership id if already not set
1743 if (!$this->_id) {
1744 $this->_id = $membership->id;
1745 }
1746
1747 CRM_Core_Session::setStatus($statusMsg, ts('Complete'), 'success');
1748
1749 $buttonName = $this->controller->getButtonName();
1750 if ($this->_context == 'standalone') {
1751 if ($buttonName == $this->getButtonName('upload', 'new')) {
1752 $session->replaceUserContext(CRM_Utils_System::url('civicrm/member/add',
1753 'reset=1&action=add&context=standalone'
1754 ));
1755 }
1756 else {
1757 $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view',
1758 "reset=1&cid={$this->_contactID}&selectedChild=member"
1759 ));
1760 }
1761 }
1762 elseif ($buttonName == $this->getButtonName('upload', 'new')) {
1763 $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/membership',
1764 "reset=1&action=add&context=membership&cid={$this->_contactID}"
1765 ));
1766 }
1767 }
1768
1769 /**
1770 * Function to send email receipt
1771 *
1772 * @param object $form form object
1773 * @param $formValues
1774 * @param object $membership object
1775 *
1776 * @internal param array $values submitted values
1777 * @return boolean true if mail was sent successfully
1778 * @static
1779 */
1780 static function emailReceipt(&$form, &$formValues, &$membership) {
1781 // retrieve 'from email id' for acknowledgement
1782 $receiptFrom = $formValues['from_email_address'];
1783
1784 if (!empty($formValues['payment_instrument_id'])) {
1785 $paymentInstrument = CRM_Contribute_PseudoConstant::paymentInstrument();
1786 $formValues['paidBy'] = $paymentInstrument[$formValues['payment_instrument_id']];
1787 }
1788
1789 // retrieve custom data
1790 $customFields = $customValues = array();
1791 if (property_exists($form, '_groupTree')
1792 && !empty($form->_groupTree)
1793 ) {
1794 foreach ($form->_groupTree as $groupID => $group) {
1795 if ($groupID == 'info') {
1796 continue;
1797 }
1798 foreach ($group['fields'] as $k => $field) {
1799 $field['title'] = $field['label'];
1800 $customFields["custom_{$k}"] = $field;
1801 }
1802 }
1803 }
1804
1805 $members = array(array('member_id', '=', $membership->id, 0, 0));
1806 // check whether its a test drive
1807 if ($form->_mode == 'test') {
1808 $members[] = array('member_test', '=', 1, 0, 0);
1809 }
1810
1811 CRM_Core_BAO_UFGroup::getValues($formValues['contact_id'], $customFields, $customValues, FALSE, $members);
1812
1813 if ($form->_mode) {
1814 if (!empty($form->_params['billing_first_name'])) {
1815 $name = $form->_params['billing_first_name'];
1816 }
1817
1818 if (!empty($form->_params['billing_middle_name'])) {
1819 $name .= " {$form->_params['billing_middle_name']}";
1820 }
1821
1822 if (!empty($form->_params['billing_last_name'])) {
1823 $name .= " {$form->_params['billing_last_name']}";
1824 }
1825
1826 $form->assign('billingName', $name);
1827
1828 // assign the address formatted up for display
1829 $addressParts = array(
1830 "street_address-{$form->_bltID}",
1831 "city-{$form->_bltID}",
1832 "postal_code-{$form->_bltID}",
1833 "state_province-{$form->_bltID}",
1834 "country-{$form->_bltID}",
1835 );
1836 $addressFields = array();
1837 foreach ($addressParts as $part) {
1838 list($n, $id) = explode('-', $part);
1839 if (isset($form->_params['billing_' . $part])) {
1840 $addressFields[$n] = $form->_params['billing_' . $part];
1841 }
1842 }
1843 $form->assign('address', CRM_Utils_Address::format($addressFields));
1844
1845 $date = CRM_Utils_Date::format($form->_params['credit_card_exp_date']);
1846 $date = CRM_Utils_Date::mysqlToIso($date);
1847 $form->assign('credit_card_exp_date', $date);
1848 $form->assign('credit_card_number',
1849 CRM_Utils_System::mungeCreditCard($form->_params['credit_card_number'])
1850 );
1851 $form->assign('credit_card_type', $form->_params['credit_card_type']);
1852 $form->assign('contributeMode', 'direct');
1853 $form->assign('isAmountzero', 0);
1854 $form->assign('is_pay_later', 0);
1855 $form->assign('isPrimary', 1);
1856 }
1857
1858 $form->assign('module', 'Membership');
1859 $form->assign('contactID', $formValues['contact_id']);
1860
1861 $form->assign('membershipID', CRM_Utils_Array::value('membership_id', $form->_params, CRM_Utils_Array::value('membership_id', $form->_defaultValues)));
1862
1863 if (!empty($formValues['contribution_id'])) {
1864 $form->assign('contributionID', $formValues['contribution_id']);
1865 }
1866 elseif (isset($form->_onlinePendingContributionId)) {
1867 $form->assign('contributionID', $form->_onlinePendingContributionId);
1868 }
1869
1870 if (!empty($formValues['contribution_status_id'])) {
1871 $form->assign('contributionStatusID', $formValues['contribution_status_id']);
1872 $form->assign('contributionStatus', CRM_Contribute_PseudoConstant::contributionStatus($formValues['contribution_status_id'], 'name'));
1873 }
1874
1875 if (!empty($formValues['is_renew'])) {
1876 $form->assign('receiptType', 'membership renewal');
1877 }
1878 else {
1879 $form->assign('receiptType', 'membership signup');
1880 }
1881 $form->assign('receive_date', CRM_Utils_Date::processDate(CRM_Utils_Array::value('receive_date', $formValues)));
1882 $form->assign('formValues', $formValues);
1883
1884 if (empty($lineItem)) {
1885 $form->assign('mem_start_date', CRM_Utils_Date::customFormat($membership->start_date, '%B %E%f, %Y'));
1886 $form->assign('mem_end_date', CRM_Utils_Date::customFormat($membership->end_date, '%B %E%f, %Y'));
1887 $form->assign('membership_name', CRM_Member_PseudoConstant::membershipType($membership->membership_type_id));
1888 }
1889
1890 $form->assign('customValues', $customValues);
1891 $isBatchProcess = is_a($form, 'CRM_Batch_Form_Entry');
1892 if ((empty($form->_contributorDisplayName) || empty($form->_contributorEmail)) || $isBatchProcess) {
1893 // in this case the form is being called statically from the batch editing screen
1894 // having one class in the form layer call another statically is not greate
1895 // & we should aim to move this function to the BAO layer in future.
1896 // however, we can assume that the contact_id passed in by the batch
1897 // function will be the recipient
1898 list(
1899 $form->_contributorDisplayName,
1900 $form->_contributorEmail
1901 ) = CRM_Contact_BAO_Contact_Location::getEmailDetails(
1902 $formValues['contact_id']
1903 );
1904 if (empty($form->_receiptContactId) || $isBatchProcess) {
1905 $form->_receiptContactId = $formValues['contact_id'];
1906 }
1907 }
1908
1909 list($mailSend, $subject, $message, $html) = CRM_Core_BAO_MessageTemplate::sendTemplate(
1910 array(
1911 'groupName' => 'msg_tpl_workflow_membership',
1912 'valueName' => 'membership_offline_receipt',
1913 'contactId' => $form->_receiptContactId,
1914 'from' => $receiptFrom,
1915 'toName' => $form->_contributorDisplayName,
1916 'toEmail' => $form->_contributorEmail,
1917 'isTest' => (bool) ($form->_action & CRM_Core_Action::PREVIEW)
1918 )
1919 );
1920
1921 return TRUE;
1922 }
1923 }
1924