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