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