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