Merge pull request #11881 from yashodha/CRM-21854
[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('taxRates', json_encode(CRM_Core_PseudoConstant::getTaxRates()));
400
401 $this->assign('currency', CRM_Core_Config::singleton()->defaultCurrencySymbol);
402 $invoiceSettings = Civi::settings()->get('contribution_invoice_settings');
403 $invoicing = CRM_Utils_Array::value('invoicing', $invoiceSettings);
404 if (isset($invoicing)) {
405 $this->assign('taxTerm', CRM_Utils_Array::value('tax_term', $invoiceSettings));
406 }
407 // build price set form.
408 $buildPriceSet = FALSE;
409 if ($this->_priceSetId || !empty($_POST['price_set_id'])) {
410 if (!empty($_POST['price_set_id'])) {
411 $buildPriceSet = TRUE;
412 }
413 $getOnlyPriceSetElements = TRUE;
414 if (!$this->_priceSetId) {
415 $this->_priceSetId = $_POST['price_set_id'];
416 $getOnlyPriceSetElements = FALSE;
417 }
418
419 $this->set('priceSetId', $this->_priceSetId);
420 CRM_Price_BAO_PriceSet::buildPriceSet($this);
421
422 $optionsMembershipTypes = array();
423 foreach ($this->_priceSet['fields'] as $pField) {
424 if (empty($pField['options'])) {
425 continue;
426 }
427 foreach ($pField['options'] as $opId => $opValues) {
428 $optionsMembershipTypes[$opId] = CRM_Utils_Array::value('membership_type_id', $opValues, 0);
429 }
430 }
431
432 $this->assign('autoRenewOption', CRM_Price_BAO_PriceSet::checkAutoRenewForPriceSet($this->_priceSetId));
433
434 $this->assign('optionsMembershipTypes', $optionsMembershipTypes);
435 $this->assign('contributionType', CRM_Utils_Array::value('financial_type_id', $this->_priceSet));
436
437 // get only price set form elements.
438 if ($getOnlyPriceSetElements) {
439 return;
440 }
441 }
442
443 // use to build form during form rule.
444 $this->assign('buildPriceSet', $buildPriceSet);
445
446 if ($this->_action & CRM_Core_Action::ADD) {
447 $buildPriceSet = FALSE;
448 $priceSets = CRM_Price_BAO_PriceSet::getAssoc(FALSE, 'CiviMember');
449 if (!empty($priceSets)) {
450 $buildPriceSet = TRUE;
451 }
452
453 if ($buildPriceSet) {
454 $this->add('select', 'price_set_id', ts('Choose price set'),
455 array(
456 '' => ts('Choose price set'),
457 ) + $priceSets,
458 NULL, array('onchange' => "buildAmount( this.value );")
459 );
460 }
461 $this->assign('hasPriceSets', $buildPriceSet);
462 }
463
464 if ($this->_action & CRM_Core_Action::DELETE) {
465 $this->addButtons(array(
466 array(
467 'type' => 'next',
468 'name' => ts('Delete'),
469 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
470 'isDefault' => TRUE,
471 ),
472 array(
473 'type' => 'cancel',
474 'name' => ts('Cancel'),
475 ),
476 ));
477 return;
478 }
479
480 if ($this->_context == 'standalone') {
481 $this->addEntityRef('contact_id', ts('Contact'), array(
482 'create' => TRUE,
483 'api' => array('extra' => array('email')),
484 ), TRUE);
485 }
486
487 $selOrgMemType[0][0] = $selMemTypeOrg[0] = ts('- select -');
488
489 // Throw status bounce when no Membership type or priceset is present
490 if (CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus()
491 && empty($this->allMembershipTypeDetails) && empty($priceSets)
492 ) {
493 CRM_Core_Error::statusBounce(ts('You do not have all the permissions needed for this page.'));
494 }
495 // retrieve all memberships
496 $allMembershipInfo = array();
497 foreach ($this->allMembershipTypeDetails as $key => $values) {
498 if ($this->_mode && empty($values['minimum_fee'])) {
499 continue;
500 }
501 else {
502 $memberOfContactId = CRM_Utils_Array::value('member_of_contact_id', $values);
503 if (empty($selMemTypeOrg[$memberOfContactId])) {
504 $selMemTypeOrg[$memberOfContactId] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
505 $memberOfContactId,
506 'display_name',
507 'id'
508 );
509
510 $selOrgMemType[$memberOfContactId][0] = ts('- select -');
511 }
512 if (empty($selOrgMemType[$memberOfContactId][$key])) {
513 $selOrgMemType[$memberOfContactId][$key] = CRM_Utils_Array::value('name', $values);
514 }
515 }
516 $totalAmount = CRM_Utils_Array::value('minimum_fee', $values);
517 //CRM-18827 - override the default value if total_amount is submitted
518 if (!empty($this->_submitValues['total_amount'])) {
519 $totalAmount = $this->_submitValues['total_amount'];
520 }
521 // build membership info array, which is used when membership type is selected to:
522 // - set the payment information block
523 // - set the max related block
524 $allMembershipInfo[$key] = array(
525 'financial_type_id' => CRM_Utils_Array::value('financial_type_id', $values),
526 'total_amount' => CRM_Utils_Money::format($totalAmount, NULL, '%a'),
527 'total_amount_numeric' => $totalAmount,
528 'auto_renew' => CRM_Utils_Array::value('auto_renew', $values),
529 'has_related' => isset($values['relationship_type_id']),
530 'max_related' => CRM_Utils_Array::value('max_related', $values),
531 );
532 }
533
534 $this->assign('allMembershipInfo', json_encode($allMembershipInfo));
535
536 // show organization by default, if only one organization in
537 // the list
538 if (count($selMemTypeOrg) == 2) {
539 unset($selMemTypeOrg[0], $selOrgMemType[0][0]);
540 }
541 //sort membership organization and type, CRM-6099
542 natcasesort($selMemTypeOrg);
543 foreach ($selOrgMemType as $index => $orgMembershipType) {
544 natcasesort($orgMembershipType);
545 $selOrgMemType[$index] = $orgMembershipType;
546 }
547
548 $memTypeJs = array(
549 'onChange' => "buildMaxRelated(this.value,true); CRM.buildCustomData('Membership', this.value);",
550 );
551
552 if (!empty($this->_recurPaymentProcessors)) {
553 $memTypeJs['onChange'] = "" . $memTypeJs['onChange'] . "buildAutoRenew(this.value, null, '{$this->_mode}');";
554 }
555
556 $this->add('text', 'max_related', ts('Max related'),
557 CRM_Core_DAO::getAttribute('CRM_Member_DAO_Membership', 'max_related')
558 );
559
560 $sel = &$this->addElement('hierselect',
561 'membership_type_id',
562 ts('Membership Organization and Type'),
563 $memTypeJs
564 );
565
566 $sel->setOptions(array($selMemTypeOrg, $selOrgMemType));
567 $elements = array();
568 if ($sel) {
569 $elements[] = $sel;
570 }
571
572 $this->applyFilter('__ALL__', 'trim');
573
574 if ($this->_action & CRM_Core_Action::ADD) {
575 $this->add('text', 'num_terms', ts('Number of Terms'), array('size' => 6));
576 }
577
578 $this->addDate('join_date', ts('Member Since'), FALSE, array('formatType' => 'activityDate'));
579 $this->addDate('start_date', ts('Start Date'), FALSE, array('formatType' => 'activityDate'));
580 $endDate = $this->addDate('end_date', ts('End Date'), FALSE, array('formatType' => 'activityDate'));
581 if ($endDate) {
582 $elements[] = $endDate;
583 }
584
585 $this->add('text', 'source', ts('Source'),
586 CRM_Core_DAO::getAttribute('CRM_Member_DAO_Membership', 'source')
587 );
588
589 //CRM-7362 --add campaigns.
590 $campaignId = NULL;
591 if ($this->_id) {
592 $campaignId = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $this->_id, 'campaign_id');
593 }
594 CRM_Campaign_BAO_Campaign::addCampaign($this, $campaignId);
595
596 if (!$this->_mode) {
597 $this->add('select', 'status_id', ts('Membership Status'),
598 array('' => ts('- select -')) + CRM_Member_PseudoConstant::membershipStatus(NULL, NULL, 'label')
599 );
600
601 $statusOverride = $this->addElement('select', 'is_override', ts('Status Override?'),
602 CRM_Member_StatusOverrideTypes::getSelectOptions()
603 );
604 if ($statusOverride) {
605 $elements[] = $statusOverride;
606 }
607
608 $this->add('datepicker', 'status_override_end_date', ts('Status Override End Date'), '', FALSE, array('minDate' => time(), 'time' => FALSE));
609
610 $this->addElement('checkbox', 'record_contribution', ts('Record Membership Payment?'));
611
612 $this->add('text', 'total_amount', ts('Amount'));
613 $this->addRule('total_amount', ts('Please enter a valid amount.'), 'money');
614
615 $this->addDate('receive_date', ts('Received'), FALSE, array('formatType' => 'activityDateTime'));
616
617 $this->add('select', 'payment_instrument_id',
618 ts('Payment Method'),
619 array('' => ts('- select -')) + CRM_Contribute_PseudoConstant::paymentInstrument(),
620 FALSE, array('onChange' => "return showHideByValue('payment_instrument_id','4','checkNumber','table-row','select',false);")
621 );
622 $this->add('text', 'trxn_id', ts('Transaction ID'));
623 $this->addRule('trxn_id', ts('Transaction ID already exists in Database.'),
624 'objectExists', array(
625 'CRM_Contribute_DAO_Contribution',
626 $this->_id,
627 'trxn_id',
628 )
629 );
630
631 $this->add('select', 'contribution_status_id',
632 ts('Payment Status'), CRM_Contribute_BAO_Contribution_Utils::getContributionStatuses('membership')
633 );
634 $this->add('text', 'check_number', ts('Check Number'),
635 CRM_Core_DAO::getAttribute('CRM_Contribute_DAO_Contribution', 'check_number')
636 );
637 }
638 else {
639 //add field for amount to allow an amount to be entered that differs from minimum
640 $this->add('text', 'total_amount', ts('Amount'));
641 }
642 $this->add('select', 'financial_type_id',
643 ts('Financial Type'),
644 array('' => ts('- select -')) + CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes($financialTypes, $this->_action)
645 );
646
647 $this->addElement('checkbox', 'is_different_contribution_contact', ts('Record Payment from a Different Contact?'));
648
649 $this->addSelect('soft_credit_type_id', array('entity' => 'contribution_soft'));
650 $this->addEntityRef('soft_credit_contact_id', ts('Payment From'), array('create' => TRUE));
651
652 $this->addElement('checkbox',
653 'send_receipt',
654 ts('Send Confirmation and Receipt?'), NULL,
655 array('onclick' => "showEmailOptions()")
656 );
657
658 $this->add('select', 'from_email_address', ts('Receipt From'), $this->_fromEmails);
659
660 $this->add('textarea', 'receipt_text', ts('Receipt Message'));
661
662 // Retrieve the name and email of the contact - this will be the TO for receipt email
663 if ($this->_contactID) {
664 list($this->_memberDisplayName,
665 $this->_memberEmail
666 ) = CRM_Contact_BAO_Contact_Location::getEmailDetails($this->_contactID);
667
668 $this->assign('emailExists', $this->_memberEmail);
669 $this->assign('displayName', $this->_memberDisplayName);
670 }
671
672 $isRecur = FALSE;
673 if ($this->_action & CRM_Core_Action::UPDATE) {
674 $recurContributionId = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $this->_id,
675 'contribution_recur_id'
676 );
677 if ($recurContributionId && !CRM_Member_BAO_Membership::isSubscriptionCancelled($this->_id)) {
678 $isRecur = TRUE;
679 if (CRM_Member_BAO_Membership::isCancelSubscriptionSupported($this->_id)) {
680 $this->assign('cancelAutoRenew',
681 CRM_Utils_System::url('civicrm/contribute/unsubscribe', "reset=1&mid={$this->_id}")
682 );
683 }
684 foreach ($elements as $elem) {
685 $elem->freeze();
686 }
687 }
688 }
689 $this->assign('isRecur', $isRecur);
690
691 $this->addFormRule(array('CRM_Member_Form_Membership', 'formRule'), $this);
692 $mailingInfo = Civi::settings()->get('mailing_backend');
693 $this->assign('isEmailEnabledForSite', ($mailingInfo['outBound_option'] != 2));
694
695 parent::buildQuickForm();
696 }
697
698 /**
699 * Validation.
700 *
701 * @param array $params
702 * (ref.) an assoc array of name/value pairs.
703 *
704 * @param array $files
705 * @param CRM_Member_Form_Membership $self
706 *
707 * @throws CiviCRM_API3_Exception
708 * @return bool|array
709 * mixed true or array of errors
710 */
711 public static function formRule($params, $files, $self) {
712 $errors = array();
713
714 $priceSetId = self::getPriceSetID($params);
715 $priceSetDetails = self::getPriceSetDetails($params);
716
717 $selectedMemberships = self::getSelectedMemberships($priceSetDetails[$priceSetId], $params);
718
719 if (!empty($params['price_set_id'])) {
720 CRM_Price_BAO_PriceField::priceSetValidation($priceSetId, $params, $errors);
721
722 $priceFieldIDS = self::getPriceFieldIDs($params, $priceSetDetails[$priceSetId]);
723
724 if (!empty($priceFieldIDS)) {
725 $ids = implode(',', $priceFieldIDS);
726
727 $count = CRM_Price_BAO_PriceSet::getMembershipCount($ids);
728 foreach ($count as $occurrence) {
729 if ($occurrence > 1) {
730 $errors['_qf_default'] = ts('Select at most one option associated with the same membership type.');
731 }
732 }
733 }
734 // Return error if empty $self->_memTypeSelected
735 if (empty($errors) && empty($selectedMemberships)) {
736 $errors['_qf_default'] = ts('Select at least one membership option.');
737 }
738 if (!$self->_mode && empty($params['record_contribution'])) {
739 $errors['record_contribution'] = ts('Record Membership Payment is required when you use a price set.');
740 }
741 }
742 else {
743 if (empty($params['membership_type_id'][1])) {
744 $errors['membership_type_id'] = ts('Please select a membership type.');
745 }
746 $numterms = CRM_Utils_Array::value('num_terms', $params);
747 if ($numterms && intval($numterms) != $numterms) {
748 $errors['num_terms'] = ts('Please enter an integer for the number of terms.');
749 }
750
751 if (($self->_mode || isset($params['record_contribution'])) && empty($params['financial_type_id'])) {
752 $errors['financial_type_id'] = ts('Please enter the financial Type.');
753 }
754 }
755
756 if (!empty($errors) && (count($selectedMemberships) > 1)) {
757 $memberOfContacts = CRM_Member_BAO_MembershipType::getMemberOfContactByMemTypes($selectedMemberships);
758 $duplicateMemberOfContacts = array_count_values($memberOfContacts);
759 foreach ($duplicateMemberOfContacts as $countDuplicate) {
760 if ($countDuplicate > 1) {
761 $errors['_qf_default'] = ts('Please do not select more than one membership associated with the same organization.');
762 }
763 }
764 }
765
766 if (!empty($errors)) {
767 return $errors;
768 }
769
770 if (!empty($params['record_contribution']) && empty($params['payment_instrument_id'])) {
771 $errors['payment_instrument_id'] = ts('Payment Method is a required field.');
772 }
773
774 if (!empty($params['is_different_contribution_contact'])) {
775 if (empty($params['soft_credit_type_id'])) {
776 $errors['soft_credit_type_id'] = ts('Please Select a Soft Credit Type');
777 }
778 if (empty($params['soft_credit_contact_id'])) {
779 $errors['soft_credit_contact_id'] = ts('Please select a contact');
780 }
781 }
782
783 if (!empty($params['payment_processor_id'])) {
784 // validate payment instrument (e.g. credit card number)
785 CRM_Core_Payment_Form::validatePaymentInstrument($params['payment_processor_id'], $params, $errors, NULL);
786 }
787
788 $joinDate = NULL;
789 if (!empty($params['join_date'])) {
790
791 $joinDate = CRM_Utils_Date::processDate($params['join_date']);
792
793 foreach ($selectedMemberships as $memType) {
794 $startDate = NULL;
795 if (!empty($params['start_date'])) {
796 $startDate = CRM_Utils_Date::processDate($params['start_date']);
797 }
798
799 // if end date is set, ensure that start date is also set
800 // and that end date is later than start date
801 $endDate = NULL;
802 if (!empty($params['end_date'])) {
803 $endDate = CRM_Utils_Date::processDate($params['end_date']);
804 }
805
806 $membershipDetails = CRM_Member_BAO_MembershipType::getMembershipTypeDetails($memType);
807
808 if ($startDate && CRM_Utils_Array::value('period_type', $membershipDetails) == 'rolling') {
809 if ($startDate < $joinDate) {
810 $errors['start_date'] = ts('Start date must be the same or later than Member since.');
811 }
812 }
813
814 if ($endDate) {
815 if ($membershipDetails['duration_unit'] == 'lifetime') {
816 // Check if status is NOT cancelled or similar. For lifetime memberships, there is no automated
817 // process to update status based on end-date. The user must change the status now.
818 $result = civicrm_api3('MembershipStatus', 'get', array(
819 'sequential' => 1,
820 'is_current_member' => 0,
821 ));
822 $tmp_statuses = $result['values'];
823 $status_ids = array();
824 foreach ($tmp_statuses as $cur_stat) {
825 $status_ids[] = $cur_stat['id'];
826 }
827
828 if (empty($params['status_id']) || in_array($params['status_id'], $status_ids) == FALSE) {
829 $errors['status_id'] = ts('Please enter a status that does NOT represent a current membership status.');
830 }
831
832 if (!empty($params['is_override']) && !CRM_Member_StatusOverrideTypes::isPermanent($params['is_override'])) {
833 $errors['is_override'] = ts('Because you set an End Date for a lifetime membership, This must be set to "Override Permanently"');
834 }
835 }
836 else {
837 if (!$startDate) {
838 $errors['start_date'] = ts('Start date must be set if end date is set.');
839 }
840 if ($endDate < $startDate) {
841 $errors['end_date'] = ts('End date must be the same or later than start date.');
842 }
843 }
844 }
845
846 // Default values for start and end dates if not supplied on the form.
847 $defaultDates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($memType,
848 $joinDate,
849 $startDate,
850 $endDate
851 );
852
853 if (!$startDate) {
854 $startDate = CRM_Utils_Array::value('start_date',
855 $defaultDates
856 );
857 }
858 if (!$endDate) {
859 $endDate = CRM_Utils_Array::value('end_date',
860 $defaultDates
861 );
862 }
863
864 //CRM-3724, check for availability of valid membership status.
865 if ((empty($params['is_override']) || CRM_Member_StatusOverrideTypes::isNo($params['is_override'])) && !isset($errors['_qf_default'])) {
866 $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($startDate,
867 $endDate,
868 $joinDate,
869 'today',
870 TRUE,
871 $memType,
872 $params
873 );
874 if (empty($calcStatus)) {
875 $url = CRM_Utils_System::url('civicrm/admin/member/membershipStatus', 'reset=1&action=browse');
876 $errors['_qf_default'] = ts('There is no valid Membership Status available for selected membership dates.');
877 $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));
878 if (!$self->_mode) {
879 $status .= ' ' . ts('OR You can sign up by setting Status Override? to something other than "NO".');
880 }
881 CRM_Core_Session::setStatus($status, ts('Membership Status Error'), 'error');
882 }
883 }
884 }
885 }
886 else {
887 $errors['join_date'] = ts('Please enter the Member Since.');
888 }
889
890 if (!empty($params['is_override']) && CRM_Member_StatusOverrideTypes::isOverridden($params['is_override']) && empty($params['status_id'])) {
891 $errors['status_id'] = ts('Please enter the Membership status.');
892 }
893
894 if (!empty($params['is_override']) && CRM_Member_StatusOverrideTypes::isUntilDate($params['is_override'])) {
895 if (empty($params['status_override_end_date'])) {
896 $errors['status_override_end_date'] = ts('Please enter the Membership override end date.');
897 }
898 }
899
900 //total amount condition arise when membership type having no
901 //minimum fee
902 if (isset($params['record_contribution'])) {
903 if (CRM_Utils_System::isNull($params['total_amount'])) {
904 $errors['total_amount'] = ts('Please enter the contribution.');
905 }
906 }
907
908 // validate contribution status for 'Failed'.
909 if ($self->_onlinePendingContributionId && !empty($params['record_contribution']) &&
910 (CRM_Utils_Array::value('contribution_status_id', $params) ==
911 array_search('Failed', CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'))
912 )
913 ) {
914 $errors['contribution_status_id'] = ts('Please select a valid payment status before updating.');
915 }
916
917 return empty($errors) ? TRUE : $errors;
918 }
919
920 /**
921 * Process the form submission.
922 */
923 public function postProcess() {
924 if ($this->_action & CRM_Core_Action::DELETE) {
925 CRM_Member_BAO_Membership::del($this->_id);
926 return;
927 }
928 // get the submitted form values.
929 $this->_params = $this->controller->exportValues($this->_name);
930 $this->prepareStatusOverrideValues();
931
932 $this->submit();
933
934 $this->setUserContext();
935 }
936
937 /**
938 * Prepares the values related to status override.
939 */
940 private function prepareStatusOverrideValues() {
941 $this->setOverrideDateValue();
942 $this->convertIsOverrideValue();
943 }
944
945 /**
946 * Sets status override end date to empty value if
947 * the selected override option is not 'until date'.
948 */
949 private function setOverrideDateValue() {
950 if (!CRM_Member_StatusOverrideTypes::isUntilDate($this->_params['is_override'])) {
951 $this->_params['status_override_end_date'] = '';
952 }
953 }
954
955 /**
956 * Convert the value of selected (status override?)
957 * option to TRUE if it indicate an overridden status
958 * or FALSE otherwise.
959 */
960 private function convertIsOverrideValue() {
961 $this->_params['is_override'] = CRM_Member_StatusOverrideTypes::isOverridden($this->_params['is_override']);
962 }
963
964 /**
965 * Send email receipt.
966 *
967 * @param CRM_Core_Form $form
968 * Form object.
969 * @param array $formValues
970 * @param object $membership
971 * Object.
972 *
973 * @return bool
974 * true if mail was sent successfully
975 */
976 public static function emailReceipt(&$form, &$formValues, &$membership) {
977 // retrieve 'from email id' for acknowledgement
978 $receiptFrom = CRM_Utils_Array::value('from_email_address', $formValues);
979
980 if (!empty($formValues['payment_instrument_id'])) {
981 $paymentInstrument = CRM_Contribute_PseudoConstant::paymentInstrument();
982 $formValues['paidBy'] = $paymentInstrument[$formValues['payment_instrument_id']];
983 }
984
985 // retrieve custom data
986 $customFields = $customValues = array();
987 if (property_exists($form, '_groupTree')
988 && !empty($form->_groupTree)
989 ) {
990 foreach ($form->_groupTree as $groupID => $group) {
991 if ($groupID == 'info') {
992 continue;
993 }
994 foreach ($group['fields'] as $k => $field) {
995 $field['title'] = $field['label'];
996 $customFields["custom_{$k}"] = $field;
997 }
998 }
999 }
1000
1001 $members = array(array('member_id', '=', $membership->id, 0, 0));
1002 // check whether its a test drive
1003 if ($form->_mode == 'test') {
1004 $members[] = array('member_test', '=', 1, 0, 0);
1005 }
1006
1007 CRM_Core_BAO_UFGroup::getValues($formValues['contact_id'], $customFields, $customValues, FALSE, $members);
1008 $form->assign('customValues', $customValues);
1009
1010 if ($form->_mode) {
1011 $form->assign('address', CRM_Utils_Address::getFormattedBillingAddressFieldsFromParameters(
1012 $form->_params,
1013 $form->_bltID
1014 ));
1015
1016 $date = CRM_Utils_Date::format($form->_params['credit_card_exp_date']);
1017 $date = CRM_Utils_Date::mysqlToIso($date);
1018 $form->assign('credit_card_exp_date', $date);
1019 $form->assign('credit_card_number',
1020 CRM_Utils_System::mungeCreditCard($form->_params['credit_card_number'])
1021 );
1022 $form->assign('credit_card_type', $form->_params['credit_card_type']);
1023 $form->assign('contributeMode', 'direct');
1024 $form->assign('isAmountzero', 0);
1025 $form->assign('is_pay_later', 0);
1026 $form->assign('isPrimary', 1);
1027 }
1028
1029 $form->assign('module', 'Membership');
1030 $form->assign('contactID', $formValues['contact_id']);
1031
1032 $form->assign('membershipID', CRM_Utils_Array::value('membership_id', $form->_params, CRM_Utils_Array::value('membership_id', $form->_defaultValues)));
1033
1034 if (!empty($formValues['contribution_id'])) {
1035 $form->assign('contributionID', $formValues['contribution_id']);
1036 }
1037 elseif (isset($form->_onlinePendingContributionId)) {
1038 $form->assign('contributionID', $form->_onlinePendingContributionId);
1039 }
1040
1041 if (!empty($formValues['contribution_status_id'])) {
1042 $form->assign('contributionStatusID', $formValues['contribution_status_id']);
1043 $form->assign('contributionStatus', CRM_Contribute_PseudoConstant::contributionStatus($formValues['contribution_status_id'], 'name'));
1044 }
1045
1046 if (!empty($formValues['is_renew'])) {
1047 $form->assign('receiptType', 'membership renewal');
1048 }
1049 else {
1050 $form->assign('receiptType', 'membership signup');
1051 }
1052 $form->assign('receive_date', CRM_Utils_Date::processDate(CRM_Utils_Array::value('receive_date', $formValues)));
1053 $form->assign('formValues', $formValues);
1054
1055 if (empty($lineItem)) {
1056 $form->assign('mem_start_date', CRM_Utils_Date::customFormat($membership->start_date, '%B %E%f, %Y'));
1057 if (!CRM_Utils_System::isNull($membership->end_date)) {
1058 $form->assign('mem_end_date', CRM_Utils_Date::customFormat($membership->end_date, '%B %E%f, %Y'));
1059 }
1060 $form->assign('membership_name', CRM_Member_PseudoConstant::membershipType($membership->membership_type_id));
1061 }
1062
1063 $isBatchProcess = is_a($form, 'CRM_Batch_Form_Entry');
1064 if ((empty($form->_contributorDisplayName) || empty($form->_contributorEmail)) || $isBatchProcess) {
1065 // in this case the form is being called statically from the batch editing screen
1066 // having one class in the form layer call another statically is not greate
1067 // & we should aim to move this function to the BAO layer in future.
1068 // however, we can assume that the contact_id passed in by the batch
1069 // function will be the recipient
1070 list($form->_contributorDisplayName, $form->_contributorEmail)
1071 = CRM_Contact_BAO_Contact_Location::getEmailDetails($formValues['contact_id']);
1072 if (empty($form->_receiptContactId) || $isBatchProcess) {
1073 $form->_receiptContactId = $formValues['contact_id'];
1074 }
1075 }
1076 $template = CRM_Core_Smarty::singleton();
1077 $taxAmt = $template->get_template_vars('dataArray');
1078 $eventTaxAmt = $template->get_template_vars('totalTaxAmount');
1079 $prefixValue = Civi::settings()->get('contribution_invoice_settings');
1080 $invoicing = CRM_Utils_Array::value('invoicing', $prefixValue);
1081 if ((!empty($taxAmt) || isset($eventTaxAmt)) && (isset($invoicing) && isset($prefixValue['is_email_pdf']))) {
1082 $isEmailPdf = TRUE;
1083 }
1084 else {
1085 $isEmailPdf = FALSE;
1086 }
1087
1088 list($mailSend, $subject, $message, $html) = CRM_Core_BAO_MessageTemplate::sendTemplate(
1089 array(
1090 'groupName' => 'msg_tpl_workflow_membership',
1091 'valueName' => 'membership_offline_receipt',
1092 'contactId' => $form->_receiptContactId,
1093 'from' => $receiptFrom,
1094 'toName' => $form->_contributorDisplayName,
1095 'toEmail' => $form->_contributorEmail,
1096 'PDFFilename' => ts('receipt') . '.pdf',
1097 'isEmailPdf' => $isEmailPdf,
1098 'contributionId' => $formValues['contribution_id'],
1099 'isTest' => (bool) ($form->_action & CRM_Core_Action::PREVIEW),
1100 )
1101 );
1102
1103 return TRUE;
1104 }
1105
1106 /**
1107 * Submit function.
1108 *
1109 * This is also accessed by unit tests.
1110 *
1111 * @return array
1112 */
1113 public function submit() {
1114 $isTest = ($this->_mode == 'test') ? 1 : 0;
1115 $this->storeContactFields($this->_params);
1116 $this->beginPostProcess();
1117 $formValues = $this->_params;
1118 $joinDate = $startDate = $endDate = NULL;
1119 $membershipTypes = $membership = $calcDate = array();
1120 $membershipType = NULL;
1121 $paymentInstrumentID = $this->_paymentProcessor['object']->getPaymentInstrumentID();
1122
1123 $mailSend = FALSE;
1124 $formValues = $this->setPriceSetParameters($formValues);
1125 $params = $softParams = $ids = array();
1126
1127 $allMemberStatus = CRM_Member_PseudoConstant::membershipStatus();
1128 $allContributionStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
1129 $this->processBillingAddress();
1130
1131 if ($this->_id) {
1132 $ids['membership'] = $params['id'] = $this->_id;
1133 }
1134 $ids['userId'] = CRM_Core_Session::singleton()->get('userID');
1135
1136 // Set variables that we normally get from context.
1137 // In form mode these are set in preProcess.
1138 //TODO: set memberships, fixme
1139 $this->setContextVariables($formValues);
1140
1141 $this->_memTypeSelected = self::getSelectedMemberships(
1142 $this->_priceSet,
1143 $formValues
1144 );
1145 if (empty($formValues['financial_type_id'])) {
1146 $formValues['financial_type_id'] = $this->_priceSet['financial_type_id'];
1147 }
1148
1149 $config = CRM_Core_Config::singleton();
1150
1151 // @todo this is no longer required if we convert some date fields.
1152 $this->convertDateFieldsToMySQL($formValues);
1153
1154 $membershipTypeValues = array();
1155 foreach ($this->_memTypeSelected as $memType) {
1156 $membershipTypeValues[$memType]['membership_type_id'] = $memType;
1157 }
1158
1159 //take the required membership recur values.
1160 if ($this->_mode && !empty($formValues['auto_renew'])) {
1161 $params['is_recur'] = $formValues['is_recur'] = TRUE;
1162 $mapping = array(
1163 'frequency_interval' => 'duration_interval',
1164 'frequency_unit' => 'duration_unit',
1165 );
1166
1167 $count = 0;
1168 foreach ($this->_memTypeSelected as $memType) {
1169 $recurMembershipTypeValues = CRM_Utils_Array::value($memType,
1170 $this->_recurMembershipTypes, array()
1171 );
1172 foreach ($mapping as $mapVal => $mapParam) {
1173 $membershipTypeValues[$memType][$mapVal] = CRM_Utils_Array::value($mapParam,
1174 $recurMembershipTypeValues
1175 );
1176 if (!$count) {
1177 $formValues[$mapVal] = CRM_Utils_Array::value($mapParam,
1178 $recurMembershipTypeValues
1179 );
1180 }
1181 }
1182 $count++;
1183 }
1184 }
1185
1186 $isQuickConfig = $this->_priceSet['is_quick_config'];
1187
1188 $termsByType = array();
1189
1190 $lineItem = array($this->_priceSetId => array());
1191
1192 CRM_Price_BAO_PriceSet::processAmount($this->_priceSet['fields'],
1193 $formValues, $lineItem[$this->_priceSetId], NULL, $this->_priceSetId);
1194
1195 if (CRM_Utils_Array::value('tax_amount', $formValues)) {
1196 $params['tax_amount'] = $formValues['tax_amount'];
1197 }
1198 $params['total_amount'] = CRM_Utils_Array::value('amount', $formValues);
1199 $submittedFinancialType = CRM_Utils_Array::value('financial_type_id', $formValues);
1200 if (!empty($lineItem[$this->_priceSetId])) {
1201 foreach ($lineItem[$this->_priceSetId] as &$li) {
1202 if (!empty($li['membership_type_id'])) {
1203 if (!empty($li['membership_num_terms'])) {
1204 $termsByType[$li['membership_type_id']] = $li['membership_num_terms'];
1205 }
1206 }
1207
1208 ///CRM-11529 for quick config backoffice transactions
1209 //when financial_type_id is passed in form, update the
1210 //lineitems with the financial type selected in form
1211 if ($isQuickConfig && $submittedFinancialType) {
1212 $li['financial_type_id'] = $submittedFinancialType;
1213 }
1214 }
1215 }
1216
1217 $params['contact_id'] = $this->_contactID;
1218
1219 $fields = array(
1220 'status_id',
1221 'source',
1222 'is_override',
1223 'status_override_end_date',
1224 'campaign_id',
1225 );
1226
1227 foreach ($fields as $f) {
1228 $params[$f] = CRM_Utils_Array::value($f, $formValues);
1229 }
1230
1231 // fix for CRM-3724
1232 // when is_override false ignore is_admin statuses during membership
1233 // status calculation. similarly we did fix for import in CRM-3570.
1234 if (empty($params['is_override'])) {
1235 $params['exclude_is_admin'] = TRUE;
1236 }
1237
1238 // process date params to mysql date format.
1239 $dateTypes = array(
1240 'join_date' => 'joinDate',
1241 'start_date' => 'startDate',
1242 'end_date' => 'endDate',
1243 );
1244 foreach ($dateTypes as $dateField => $dateVariable) {
1245 $$dateVariable = CRM_Utils_Date::processDate($formValues[$dateField]);
1246 }
1247
1248 $memTypeNumTerms = empty($termsByType) ? CRM_Utils_Array::value('num_terms', $formValues) : NULL;
1249
1250 $calcDates = array();
1251 foreach ($this->_memTypeSelected as $memType) {
1252 if (empty($memTypeNumTerms)) {
1253 $memTypeNumTerms = CRM_Utils_Array::value($memType, $termsByType, 1);
1254 }
1255 $calcDates[$memType] = CRM_Member_BAO_MembershipType::getDatesForMembershipType($memType,
1256 $joinDate, $startDate, $endDate, $memTypeNumTerms
1257 );
1258 }
1259
1260 foreach ($calcDates as $memType => $calcDate) {
1261 foreach (array_keys($dateTypes) as $d) {
1262 //first give priority to form values then calDates.
1263 $date = CRM_Utils_Array::value($d, $formValues);
1264 if (!$date) {
1265 $date = CRM_Utils_Array::value($d, $calcDate);
1266 }
1267
1268 $membershipTypeValues[$memType][$d] = CRM_Utils_Date::processDate($date);
1269 }
1270 }
1271
1272 // max related memberships - take from form or inherit from membership type
1273 foreach ($this->_memTypeSelected as $memType) {
1274 if (array_key_exists('max_related', $formValues)) {
1275 $membershipTypeValues[$memType]['max_related'] = CRM_Utils_Array::value('max_related', $formValues);
1276 }
1277 $membershipTypeValues[$memType]['custom'] = CRM_Core_BAO_CustomField::postProcess($formValues,
1278 $this->_id,
1279 'Membership'
1280 );
1281 $membershipTypes[$memType] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType',
1282 $memType
1283 );
1284 }
1285
1286 $membershipType = implode(', ', $membershipTypes);
1287
1288 // Retrieve the name and email of the current user - this will be the FROM for the receipt email
1289 list($userName) = CRM_Contact_BAO_Contact_Location::getEmailDetails($ids['userId']);
1290
1291 //CRM-13981, allow different person as a soft-contributor of chosen type
1292 if ($this->_contributorContactID != $this->_contactID) {
1293 $params['contribution_contact_id'] = $this->_contributorContactID;
1294 if (!empty($formValues['soft_credit_type_id'])) {
1295 $softParams['soft_credit_type_id'] = $formValues['soft_credit_type_id'];
1296 $softParams['contact_id'] = $this->_contactID;
1297 }
1298 }
1299 if (!empty($formValues['record_contribution'])) {
1300 $recordContribution = array(
1301 'total_amount',
1302 'financial_type_id',
1303 'payment_instrument_id',
1304 'trxn_id',
1305 'contribution_status_id',
1306 'check_number',
1307 'campaign_id',
1308 'receive_date',
1309 'card_type_id',
1310 'pan_truncation',
1311 );
1312
1313 foreach ($recordContribution as $f) {
1314 $params[$f] = CRM_Utils_Array::value($f, $formValues);
1315 }
1316
1317 if (!$this->_onlinePendingContributionId) {
1318 if (empty($formValues['source'])) {
1319 $params['contribution_source'] = ts('%1 Membership: Offline signup (by %2)', array(
1320 1 => $membershipType,
1321 2 => $userName,
1322 ));
1323 }
1324 else {
1325 $params['contribution_source'] = $formValues['source'];
1326 }
1327 }
1328
1329 if (empty($params['is_override']) &&
1330 CRM_Utils_Array::value('contribution_status_id', $params) != array_search('Completed', $allContributionStatus)
1331 ) {
1332 $params['status_id'] = array_search('Pending', $allMemberStatus);
1333 $params['skipStatusCal'] = TRUE;
1334 $params['is_pay_later'] = 1;
1335 $this->assign('is_pay_later', 1);
1336 }
1337
1338 if (!empty($formValues['send_receipt'])) {
1339 $params['receipt_date'] = CRM_Utils_Array::value('receive_date', $formValues);
1340 }
1341
1342 //insert financial type name in receipt.
1343 $formValues['contributionType_name'] = CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType',
1344 $formValues['financial_type_id']
1345 );
1346 }
1347
1348 // process line items, until no previous line items.
1349 if (!empty($lineItem)) {
1350 $params['lineItems'] = $lineItem;
1351 $params['processPriceSet'] = TRUE;
1352 }
1353 $createdMemberships = array();
1354 if ($this->_mode) {
1355 $params['total_amount'] = CRM_Utils_Array::value('total_amount', $formValues, 0);
1356
1357 //CRM-20264 : Store CC type and number (last 4 digit) during backoffice or online payment
1358 $params['card_type_id'] = CRM_Utils_Array::value('card_type_id', $this->_params);
1359 $params['pan_truncation'] = CRM_Utils_Array::value('pan_truncation', $this->_params);
1360
1361 if (!$isQuickConfig) {
1362 $params['financial_type_id'] = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet',
1363 $this->_priceSetId,
1364 'financial_type_id'
1365 );
1366 }
1367 else {
1368 $params['financial_type_id'] = CRM_Utils_Array::value('financial_type_id', $formValues);
1369 }
1370
1371 //get the payment processor id as per mode. Try removing in favour of beginPostProcess.
1372 $params['payment_processor_id'] = $formValues['payment_processor_id'] = $this->_paymentProcessor['id'];
1373 $params['register_date'] = date('YmdHis');
1374
1375 // add all the additional payment params we need
1376 // @todo the country & state values should be set by the call to $this->assignBillingAddress.
1377 $formValues["state_province-{$this->_bltID}"] = $formValues["billing_state_province-{$this->_bltID}"]
1378 = CRM_Core_PseudoConstant::stateProvinceAbbreviation($formValues["billing_state_province_id-{$this->_bltID}"]);
1379 $formValues["country-{$this->_bltID}"] = $formValues["billing_country-{$this->_bltID}"] = CRM_Core_PseudoConstant::countryIsoCode($formValues["billing_country_id-{$this->_bltID}"]);
1380
1381 $formValues['amount'] = $params['total_amount'];
1382 // @todo this is a candidate for beginPostProcessFunction.
1383 $formValues['currencyID'] = $config->defaultCurrency;
1384 $formValues['description'] = ts("Contribution submitted by a staff person using member's credit card for signup");
1385 $formValues['invoiceID'] = md5(uniqid(rand(), TRUE));
1386 $formValues['financial_type_id'] = $params['financial_type_id'];
1387
1388 // at this point we've created a contact and stored its address etc
1389 // all the payment processors expect the name and address to be in the
1390 // so we copy stuff over to first_name etc.
1391 $paymentParams = $formValues;
1392 $paymentParams['contactID'] = $this->_contributorContactID;
1393 //CRM-10377 if payment is by an alternate contact then we need to set that person
1394 // as the contact in the payment params
1395 if ($this->_contributorContactID != $this->_contactID) {
1396 if (!empty($formValues['soft_credit_type_id'])) {
1397 $softParams['contact_id'] = $params['contact_id'];
1398 $softParams['soft_credit_type_id'] = $formValues['soft_credit_type_id'];
1399 }
1400 }
1401 if (!empty($formValues['send_receipt'])) {
1402 $paymentParams['email'] = $this->_contributorEmail;
1403 }
1404
1405 // This is a candidate for shared beginPostProcess function.
1406 CRM_Core_Payment_Form::mapParams($this->_bltID, $formValues, $paymentParams, TRUE);
1407 // CRM-7137 -for recurring membership,
1408 // we do need contribution and recurring records.
1409 $result = NULL;
1410 if (!empty($paymentParams['is_recur'])) {
1411 $financialType = new CRM_Financial_DAO_FinancialType();
1412 $financialType->id = $params['financial_type_id'];
1413 $financialType->find(TRUE);
1414 $this->_params = $formValues;
1415
1416 $contribution = CRM_Contribute_Form_Contribution_Confirm::processFormContribution($this,
1417 $paymentParams,
1418 NULL,
1419 array(
1420 'contact_id' => $this->_contributorContactID,
1421 'line_item' => $lineItem,
1422 'is_test' => $isTest,
1423 'campaign_id' => CRM_Utils_Array::value('campaign_id', $paymentParams),
1424 'contribution_page_id' => CRM_Utils_Array::value('contribution_page_id', $formValues),
1425 'source' => CRM_Utils_Array::value('source', $paymentParams, CRM_Utils_Array::value('description', $paymentParams)),
1426 'thankyou_date' => CRM_Utils_Array::value('thankyou_date', $paymentParams),
1427 'payment_instrument_id' => $paymentInstrumentID,
1428 ),
1429 $financialType,
1430 FALSE,
1431 $this->_bltID,
1432 TRUE
1433 );
1434
1435 //create new soft-credit record, CRM-13981
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 }
1442
1443 $paymentParams['contactID'] = $this->_contactID;
1444 $paymentParams['contributionID'] = $contribution->id;
1445 $paymentParams['contributionTypeID'] = $contribution->financial_type_id;
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'];
1450 }
1451
1452 if ($params['total_amount'] > 0.0) {
1453 $payment = $this->_paymentProcessor['object'];
1454 try {
1455 $result = $payment->doPayment($paymentParams);
1456 $formValues = array_merge($formValues, $result);
1457 // Assign amount to template if payment was successful.
1458 $this->assign('amount', $params['total_amount']);
1459 }
1460 catch (\Civi\Payment\Exception\PaymentProcessorException $e) {
1461 if (!empty($paymentParams['contributionID'])) {
1462 CRM_Contribute_BAO_Contribution::failPayment($paymentParams['contributionID'], $this->_contactID,
1463 $e->getMessage());
1464 }
1465 if (!empty($paymentParams['contributionRecurID'])) {
1466 CRM_Contribute_BAO_ContributionRecur::deleteRecurContribution($paymentParams['contributionRecurID']);
1467 }
1468
1469 CRM_Core_Session::singleton()->setStatus($e->getMessage());
1470 CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/view/membership',
1471 "reset=1&action=add&cid={$this->_contactID}&context=membership&mode={$this->_mode}"
1472 ));
1473
1474 }
1475 }
1476
1477 if ($formValues['payment_status_id'] != array_search('Completed', $allContributionStatus)) {
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.
1481 unset($formValues['send_receipt'], $formValues['send_receipt']);
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 );
1488 foreach ($memberDates as $dv) {
1489 $$dv = NULL;
1490 foreach ($this->_memTypeSelected as $memType) {
1491 $membershipTypeValues[$memType][$dv] = NULL;
1492 }
1493 }
1494 }
1495 $now = date('YmdHis');
1496 $params['receive_date'] = $now;
1497 $params['invoice_id'] = $formValues['invoiceID'];
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['is_test'] = ($this->_mode == 'live') ? 0 : 1;
1504 if (!empty($formValues['send_receipt'])) {
1505 $params['receipt_date'] = $now;
1506 }
1507 else {
1508 $params['receipt_date'] = NULL;
1509 }
1510
1511 $this->set('params', $formValues);
1512 $this->assign('trxn_id', CRM_Utils_Array::value('trxn_id', $result));
1513 $this->assign('receive_date',
1514 CRM_Utils_Date::mysqlToIso($params['receive_date'])
1515 );
1516
1517 // required for creating membership for related contacts
1518 $params['action'] = $this->_action;
1519
1520 //create membership record.
1521 $count = 0;
1522 foreach ($this->_memTypeSelected as $memType) {
1523 if ($count &&
1524 ($relateContribution = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id))
1525 ) {
1526 $membershipTypeValues[$memType]['relate_contribution_id'] = $relateContribution;
1527 }
1528
1529 $membershipParams = array_merge($membershipTypeValues[$memType], $params);
1530 //CRM-15366
1531 if (!empty($softParams) && empty($paymentParams['is_recur'])) {
1532 $membershipParams['soft_credit'] = $softParams;
1533 }
1534 if (isset($result['fee_amount'])) {
1535 $membershipParams['fee_amount'] = $result['fee_amount'];
1536 }
1537 // This is required to trigger the recording of the membership contribution in the
1538 // CRM_Member_BAO_Membership::Create function.
1539 // @todo stop setting this & 'teach' the create function to respond to something
1540 // appropriate as part of our 2-step always create the pending contribution & then finally add the payment
1541 // process -
1542 // @see http://wiki.civicrm.org/confluence/pages/viewpage.action?pageId=261062657#Payments&AccountsRoadmap-Movetowardsalwaysusinga2-steppaymentprocess
1543 $membershipParams['contribution_status_id'] = CRM_Utils_Array::value('payment_status_id', $result);
1544 if (!empty($paymentParams['is_recur'])) {
1545 // The earlier process created the line items (although we want to get rid of the earlier one in favour
1546 // of a single path!
1547 unset($membershipParams['lineItems']);
1548 }
1549 $membershipParams['payment_instrument_id'] = $paymentInstrumentID;
1550 $membership = CRM_Member_BAO_Membership::create($membershipParams, $ids);
1551 $params['contribution'] = CRM_Utils_Array::value('contribution', $membershipParams);
1552 unset($params['lineItems']);
1553 $this->_membershipIDs[] = $membership->id;
1554 $createdMemberships[$memType] = $membership;
1555 $count++;
1556 }
1557
1558 }
1559 else {
1560 $params['action'] = $this->_action;
1561 if ($this->_onlinePendingContributionId && !empty($formValues['record_contribution'])) {
1562
1563 // update membership as well as contribution object, CRM-4395
1564 $params['contribution_id'] = $this->_onlinePendingContributionId;
1565 $params['componentId'] = $params['id'];
1566 $params['componentName'] = 'contribute';
1567 $result = CRM_Contribute_BAO_Contribution::transitionComponents($params, TRUE);
1568 if (!empty($result) && !empty($params['contribution_id'])) {
1569 $lineItem = array();
1570 $lineItems = CRM_Price_BAO_LineItem::getLineItemsByContributionID($params['contribution_id']);
1571 $itemId = key($lineItems);
1572 $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceField', $lineItems[$itemId]['price_field_id'], 'price_set_id');
1573
1574 $lineItems[$itemId]['unit_price'] = $params['total_amount'];
1575 $lineItems[$itemId]['line_total'] = $params['total_amount'];
1576 $lineItems[$itemId]['id'] = $itemId;
1577 $lineItem[$priceSetId] = $lineItems;
1578 $contributionBAO = new CRM_Contribute_BAO_Contribution();
1579 $contributionBAO->id = $params['contribution_id'];
1580 $contributionBAO->contact_id = $params['contact_id'];
1581 $contributionBAO->find();
1582 CRM_Price_BAO_LineItem::processPriceSet($params['contribution_id'], $lineItem, $contributionBAO, 'civicrm_membership');
1583
1584 //create new soft-credit record, CRM-13981
1585 if ($softParams) {
1586 $softParams['contribution_id'] = $params['contribution_id'];
1587 while ($contributionBAO->fetch()) {
1588 $softParams['currency'] = $contributionBAO->currency;
1589 $softParams['amount'] = $contributionBAO->total_amount;
1590 }
1591 CRM_Contribute_BAO_ContributionSoft::add($softParams);
1592 }
1593 }
1594
1595 //carry updated membership object.
1596 $membership = new CRM_Member_DAO_Membership();
1597 $membership->id = $this->_id;
1598 $membership->find(TRUE);
1599
1600 $cancelled = TRUE;
1601 if ($membership->end_date) {
1602 //display end date w/ status message.
1603 $endDate = $membership->end_date;
1604
1605 if (!in_array($membership->status_id, array(
1606 // CRM-15475
1607 array_search('Cancelled', CRM_Member_PseudoConstant::membershipStatus(NULL, " name = 'Cancelled' ", 'name', FALSE, TRUE)),
1608 array_search('Expired', CRM_Member_PseudoConstant::membershipStatus()),
1609 ))
1610 ) {
1611 $cancelled = FALSE;
1612 }
1613 }
1614 // suppress form values in template.
1615 $this->assign('cancelled', $cancelled);
1616
1617 $createdMemberships[] = $membership;
1618 }
1619 else {
1620 $count = 0;
1621 foreach ($this->_memTypeSelected as $memType) {
1622 if ($count && !empty($formValues['record_contribution']) &&
1623 ($relateContribution = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id))
1624 ) {
1625 $membershipTypeValues[$memType]['relate_contribution_id'] = $relateContribution;
1626 }
1627
1628 $membershipParams = array_merge($params, $membershipTypeValues[$memType]);
1629 if (!empty($formValues['int_amount'])) {
1630 $init_amount = array();
1631 foreach ($formValues as $key => $value) {
1632 if (strstr($key, 'txt-price')) {
1633 $init_amount[$key] = $value;
1634 }
1635 }
1636 $membershipParams['init_amount'] = $init_amount;
1637 }
1638
1639 if (!empty($softParams)) {
1640 $membershipParams['soft_credit'] = $softParams;
1641 }
1642
1643 $membership = CRM_Member_BAO_Membership::create($membershipParams, $ids);
1644 $params['contribution'] = CRM_Utils_Array::value('contribution', $membershipParams);
1645 unset($params['lineItems']);
1646 // skip line item creation for next interation since line item(s) are already created.
1647 $params['skipLineItem'] = TRUE;
1648
1649 $this->_membershipIDs[] = $membership->id;
1650 $createdMemberships[$memType] = $membership;
1651 $count++;
1652 }
1653 }
1654 }
1655
1656 if (!empty($lineItem[$this->_priceSetId])) {
1657 $invoiceSettings = Civi::settings()->get('contribution_invoice_settings');
1658 $invoicing = CRM_Utils_Array::value('invoicing', $invoiceSettings);
1659 $taxAmount = FALSE;
1660 $totalTaxAmount = 0;
1661 foreach ($lineItem[$this->_priceSetId] as & $priceFieldOp) {
1662 if (!empty($priceFieldOp['membership_type_id'])) {
1663 $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') : '-';
1664 $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') : '-';
1665 }
1666 else {
1667 $priceFieldOp['start_date'] = $priceFieldOp['end_date'] = 'N/A';
1668 }
1669 if ($invoicing && isset($priceFieldOp['tax_amount'])) {
1670 $taxAmount = TRUE;
1671 $totalTaxAmount += $priceFieldOp['tax_amount'];
1672 }
1673 }
1674 if ($invoicing) {
1675 $dataArray = array();
1676 foreach ($lineItem[$this->_priceSetId] as $key => $value) {
1677 if (isset($value['tax_amount']) && isset($value['tax_rate'])) {
1678 if (isset($dataArray[$value['tax_rate']])) {
1679 $dataArray[$value['tax_rate']] = $dataArray[$value['tax_rate']] + CRM_Utils_Array::value('tax_amount', $value);
1680 }
1681 else {
1682 $dataArray[$value['tax_rate']] = CRM_Utils_Array::value('tax_amount', $value);
1683 }
1684 }
1685 }
1686 if ($taxAmount) {
1687 $this->assign('totalTaxAmount', $totalTaxAmount);
1688 $this->assign('taxTerm', CRM_Utils_Array::value('tax_term', $invoiceSettings));
1689 }
1690 $this->assign('dataArray', $dataArray);
1691 }
1692 }
1693 $this->assign('lineItem', !empty($lineItem) && !$isQuickConfig ? $lineItem : FALSE);
1694
1695 $receiptSend = FALSE;
1696 $contributionId = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id);
1697 $membershipIds = $this->_membershipIDs;
1698 if ($contributionId && !empty($membershipIds)) {
1699 $contributionDetails = CRM_Contribute_BAO_Contribution::getContributionDetails(
1700 CRM_Export_Form_Select::MEMBER_EXPORT, $this->_membershipIDs);
1701 if ($contributionDetails[$membership->id]['contribution_status'] == 'Completed') {
1702 $receiptSend = TRUE;
1703 }
1704 }
1705
1706 $receiptSent = FALSE;
1707 if (!empty($formValues['send_receipt']) && $receiptSend) {
1708 $formValues['contact_id'] = $this->_contactID;
1709 $formValues['contribution_id'] = $contributionId;
1710 // We really don't need a distinct receipt_text_signup vs receipt_text_renewal as they are
1711 // handled in the receipt. But by setting one we avoid breaking templates for now
1712 // although at some point we should switch in the templates.
1713 $formValues['receipt_text_signup'] = $formValues['receipt_text'];
1714 // send email receipt
1715 $this->assignBillingName();
1716 $mailSend = self::emailReceipt($this, $formValues, $membership);
1717 $receiptSent = TRUE;
1718 }
1719
1720 // finally set membership id if already not set
1721 if (!$this->_id) {
1722 $this->_id = $membership->id;
1723 }
1724
1725 $isRecur = CRM_Utils_Array::value('is_recur', $params);
1726 $this->updateContributionOnMembershipTypeChange($params, $membership);
1727 $this->setStatusMessage($membership, $endDate, $receiptSent, $membershipTypes, $createdMemberships, $isRecur, $calcDates, $mailSend);
1728 return $createdMemberships;
1729 }
1730
1731 /**
1732 * Update related contribution of a membership if update_contribution_on_membership_type_change
1733 * contribution setting is enabled and type is changed on edit
1734 *
1735 * @param array $inputParams
1736 * submitted form values
1737 * @param CRM_Member_DAO_Membership $membership
1738 * Updated membership object
1739 *
1740 */
1741 protected function updateContributionOnMembershipTypeChange($inputParams, $membership) {
1742 if (Civi::settings()->get('update_contribution_on_membership_type_change') &&
1743 ($this->_action & CRM_Core_Action::UPDATE) && // on update
1744 $this->_id && // if ID is present
1745 !in_array($this->_memType, $this->_memTypeSelected) // if selected membership doesn't match with earlier membership
1746 ) {
1747 if (CRM_Utils_Array::value('is_recur', $inputParams)) {
1748 CRM_Core_Session::setStatus(ts('Associated recurring contribution cannot be updated on membership type change.', ts('Error'), 'error'));
1749 return;
1750 }
1751
1752 // fetch lineitems by updated membership ID
1753 $lineItems = CRM_Price_BAO_LineItem::getLineItems($membership->id, 'membership');
1754 // retrieve the related contribution ID
1755 $contributionID = CRM_Core_DAO::getFieldValue(
1756 'CRM_Member_DAO_MembershipPayment',
1757 $membership->id,
1758 'contribution_id',
1759 'membership_id'
1760 );
1761 // get price fields of chosen price-set
1762 $priceSetDetails = CRM_Utils_Array::value(
1763 $this->_priceSetId,
1764 CRM_Price_BAO_PriceSet::getSetDetail(
1765 $this->_priceSetId,
1766 TRUE,
1767 TRUE
1768 )
1769 );
1770
1771 // add price field information in $inputParams
1772 self::addPriceFieldByMembershipType($inputParams, $priceSetDetails['fields'], $membership->membership_type_id);
1773
1774 // update related contribution and financial records
1775 CRM_Price_BAO_LineItem::changeFeeSelections(
1776 $inputParams,
1777 $membership->id,
1778 'membership',
1779 $contributionID,
1780 $priceSetDetails['fields'],
1781 $lineItems
1782 );
1783 CRM_Core_Session::setStatus(ts('Associated contribution is updated on membership type change.'), ts('Success'), 'success');
1784 }
1785 }
1786
1787 /**
1788 * Add selected price field information in $formValues
1789 *
1790 * @param array $formValues
1791 * submitted form values
1792 * @param array $priceFields
1793 * Price fields of selected Priceset ID
1794 * @param int $membershipTypeID
1795 * Selected membership type ID
1796 *
1797 */
1798 public static function addPriceFieldByMembershipType(&$formValues, $priceFields, $membershipTypeID) {
1799 foreach ($priceFields as $priceFieldID => $priceField) {
1800 if (isset($priceField['options']) && count($priceField['options'])) {
1801 foreach ($priceField['options'] as $option) {
1802 if ($option['membership_type_id'] == $membershipTypeID) {
1803 $formValues["price_{$priceFieldID}"] = $option['id'];
1804 break;
1805 }
1806 }
1807 }
1808 }
1809 }
1810 /**
1811 * Set context in session.
1812 */
1813 protected function setUserContext() {
1814 $buttonName = $this->controller->getButtonName();
1815 $session = CRM_Core_Session::singleton();
1816
1817 if ($this->_context == 'standalone') {
1818 if ($buttonName == $this->getButtonName('upload', 'new')) {
1819 $session->replaceUserContext(CRM_Utils_System::url('civicrm/member/add',
1820 'reset=1&action=add&context=standalone'
1821 ));
1822 }
1823 else {
1824 $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view',
1825 "reset=1&cid={$this->_contactID}&selectedChild=member"
1826 ));
1827 }
1828 }
1829 elseif ($buttonName == $this->getButtonName('upload', 'new')) {
1830 $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/membership',
1831 "reset=1&action=add&context=membership&cid={$this->_contactID}"
1832 ));
1833 }
1834 }
1835
1836 /**
1837 * Get status message for updating membership.
1838 *
1839 * @param CRM_Member_BAO_Membership $membership
1840 * @param string $endDate
1841 * @param bool $receiptSend
1842 *
1843 * @return string
1844 */
1845 protected function getStatusMessageForUpdate($membership, $endDate, $receiptSend) {
1846 // End date can be modified by hooks, so if end date is set then use it.
1847 $endDate = ($membership->end_date) ? $membership->end_date : $endDate;
1848
1849 $statusMsg = ts('Membership for %1 has been updated.', array(1 => $this->_memberDisplayName));
1850 if ($endDate && $endDate !== 'null') {
1851 $endDate = CRM_Utils_Date::customFormat($endDate);
1852 $statusMsg .= ' ' . ts('The membership End Date is %1.', array(1 => $endDate));
1853 }
1854
1855 if ($receiptSend) {
1856 $statusMsg .= ' ' . ts('A confirmation and receipt has been sent to %1.', array(1 => $this->_contributorEmail));
1857 }
1858 return $statusMsg;
1859 }
1860
1861 /**
1862 * Get status message for create action.
1863 *
1864 * @param string $endDate
1865 * @param bool $receiptSend
1866 * @param array $membershipTypes
1867 * @param array $createdMemberships
1868 * @param bool $isRecur
1869 * @param array $calcDates
1870 * @param bool $mailSent
1871 *
1872 * @return array|string
1873 */
1874 protected function getStatusMessageForCreate($endDate, $receiptSend, $membershipTypes, $createdMemberships,
1875 $isRecur, $calcDates, $mailSent) {
1876 // FIX ME: fix status messages
1877
1878 $statusMsg = array();
1879 foreach ($membershipTypes as $memType => $membershipType) {
1880 $statusMsg[$memType] = ts('%1 membership for %2 has been added.', array(
1881 1 => $membershipType,
1882 2 => $this->_memberDisplayName,
1883 ));
1884
1885 $membership = $createdMemberships[$memType];
1886 $memEndDate = ($membership->end_date) ? $membership->end_date : $endDate;
1887
1888 //get the end date from calculated dates.
1889 if (!$memEndDate && !$isRecur) {
1890 $memEndDate = CRM_Utils_Array::value('end_date', $calcDates[$memType]);
1891 }
1892
1893 if ($memEndDate && $memEndDate !== 'null') {
1894 $memEndDate = CRM_Utils_Date::customFormat($memEndDate);
1895 $statusMsg[$memType] .= ' ' . ts('The new membership End Date is %1.', array(1 => $memEndDate));
1896 }
1897 }
1898 $statusMsg = implode('<br/>', $statusMsg);
1899 if ($receiptSend && !empty($mailSent)) {
1900 $statusMsg .= ' ' . ts('A membership confirmation and receipt has been sent to %1.', array(1 => $this->_contributorEmail));
1901 }
1902 return $statusMsg;
1903 }
1904
1905 /**
1906 * @param $membership
1907 * @param $endDate
1908 * @param $receiptSend
1909 * @param $membershipTypes
1910 * @param $createdMemberships
1911 * @param $isRecur
1912 * @param $calcDates
1913 * @param $mailSend
1914 */
1915 protected function setStatusMessage($membership, $endDate, $receiptSend, $membershipTypes, $createdMemberships, $isRecur, $calcDates, $mailSend) {
1916 $statusMsg = '';
1917 if (($this->_action & CRM_Core_Action::UPDATE)) {
1918 $statusMsg = $this->getStatusMessageForUpdate($membership, $endDate, $receiptSend);
1919 }
1920 elseif (($this->_action & CRM_Core_Action::ADD)) {
1921 $statusMsg = $this->getStatusMessageForCreate($endDate, $receiptSend, $membershipTypes, $createdMemberships,
1922 $isRecur, $calcDates, $mailSend);
1923 }
1924
1925 CRM_Core_Session::setStatus($statusMsg, ts('Complete'), 'success');
1926 //CRM-15187
1927 // display message when membership type is changed
1928 if (($this->_action & CRM_Core_Action::UPDATE) && $this->_id && !in_array($this->_memType, $this->_memTypeSelected)) {
1929 $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->_id, 'membership');
1930 $maxID = max(array_keys($lineItem));
1931 $lineItem = $lineItem[$maxID];
1932 $membershipTypeDetails = $this->allMembershipTypeDetails[$membership->membership_type_id];
1933 if ($membershipTypeDetails['financial_type_id'] != $lineItem['financial_type_id']) {
1934 CRM_Core_Session::setStatus(
1935 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.'),
1936 ts('Warning')
1937 );
1938 }
1939 if ($membershipTypeDetails['minimum_fee'] != $lineItem['line_total']) {
1940 CRM_Core_Session::setStatus(
1941 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.'),
1942 ts('Warning')
1943 );
1944 }
1945 }
1946 }
1947
1948 }