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