From 4f2d1a4a5f76de9edb7959cba8ef74e4e7f73f89 Mon Sep 17 00:00:00 2001
From: root If so it will set the start date of the new membership to be the day following the end date of the existing active membership. If the user currently has multiple relevant membership types the start date will be one day following the end date of the membership with the latest end date. '.
+ t('"Automatic" indicates that new membership end date will be calculated according to the start date and the membership duration').
+ ' '.
+ t('If this box is ticket, the membership price will be calculated based on the number of days left until the end date compared to the number of days in a regular membership period').
+ ' ' .
t('Price for this membership per term. If this field is enabled, the default minimum membership fee from CiviCRM membership type settings will not be loaded.') .
diff --git a/js/webform_civicrm_admin.js b/js/webform_civicrm_admin.js
index 5e40d3e4c..b98a13074 100644
--- a/js/webform_civicrm_admin.js
+++ b/js/webform_civicrm_admin.js
@@ -512,6 +512,7 @@ var wfCiviAdmin = (function ($, D) {
$target.show();
}
}).change();
+
$('select[name$=_membership_start_date_rules]', context).change(function(e, type) {
var $dateRuleMembershipField = $(this).parent().siblings('[class$="-start-date-memberships"]');
var $relativeToExistingMembership = 2;
@@ -522,6 +523,18 @@ var wfCiviAdmin = (function ($, D) {
$dateRuleMembershipField.hide();
}
}).trigger('change', 'init');
+
+ $('select[name$=_membership_end_date_rules]', context).change(function(e, type) {
+ var $dateRuleMembershipField = $(this).parent().siblings('[class$="-end-date-memberships"]');
+ var $relativeToExistingMembership = 2;
+ if ($(this).val() == $relativeToExistingMembership) {
+ $dateRuleMembershipField.show();
+ }
+ else {
+ $dateRuleMembershipField.hide();
+ }
+ }).trigger('change', 'init');
+
function billingMessages() {
var $pageSelect = $('[name=civicrm_1_contribution_1_contribution_contribution_page_id]');
// Warning about contribution page with no email
From 5726eeec20678b4484d1abaa2c545302b1f1b091 Mon Sep 17 00:00:00 2001
From: root '.
t('\'Automatic\' indicates that the start date will follow normal CiviCRM rules. i.e. New memberships will start immediately from date of sign-up and renewals will extend memberships.').
' '.
- t('User select will create a new webform date component that the administrator can configure in many ways including adding a fixed or relative start or end date.').'
'. t('\'Relative to active membership end date\' will modify the start date of the new membership as follows:
It will first check whether the user has an existing membership of this type. If so it will follow the automatic membership rules.
@@ -320,16 +321,27 @@ class wf_crm_admin_help {If so it will set the start date of the new membership to be the day following the end date of the existing active membership.
If the user currently has multiple relevant membership types the start date will be one day following the end date of the membership with the latest end date.
'); } - + public static function membership_end_date_rules() { print ''. t('"Automatic" indicates that new membership end date will be calculated according to the start date and the membership duration'). '
'; } - + public static function membership_pro_rate_membership() { print ''. - t('If this box is ticket, the membership price will be calculated based on the number of days left until the end date compared to the number of days in a regular membership period'). + t('If this box is ticked, the membership price will be calculated based on the number of days left until the end date compared to the number of days in a regular membership period'). + '
'; + } + public static function membership_start_date_memberships() { + print ''. + t('If you do not select a membership type, new membership will start immediately once the current active membership with the latest end date has expired.'). + '
'; + } + + public static function membership_end_date_memberships() { + print ''. + t('If you do not select a membership type, new membership will end when the current active membership with the latest end date expires.'). '
'; } diff --git a/includes/wf_crm_webform_postprocess.inc b/includes/wf_crm_webform_postprocess.inc index 560a979e8..1e40c4529 100644 --- a/includes/wf_crm_webform_postprocess.inc +++ b/includes/wf_crm_webform_postprocess.inc @@ -83,6 +83,11 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { $this->loadMultiPageData(); $this->validateParticipants(); } + + // Validate end dates as per membership date rules. + if(!empty($this->data['membership'])) { + $this->validateMembershipDateRules(); + } // Process live contribution. If the transaction is unsuccessful it will trigger a form validation error. if ($this->contribution_page) { @@ -103,6 +108,35 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { $form_state['civicrm']['ent'] = $this->ent; $form_state['civicrm']['line_items'] = $this->line_items; } + + /** + * Validate function for membership date rules. + */ + public function validateMembershipDateRules() { + if (!empty($this->data['membership'])) { + foreach ($this->ent['contact'] as $c => $contact) { + if ($contact['id'] && isset($this->all_sets['membership']) && !empty($this->data['membership'][$c]['number_of_membership'])) { + $isError = FALSE; + $membershipFieldName = ''; + foreach (wf_crm_aval($this->data, "membership:$c:membership", array()) as $n => $params) { + $params = $this->processMembershipDateRules($contact['id'], $params, $c, $n); + $membershipFieldName = "civicrm_{$c}_membership_{$n}_membership_membership_type_id"; + if (!empty($params['end_date_rules']) && $params['end_date_rules'] == 2 && empty($params['end_date'])) { + $isError = TRUE; + break; + } + elseif (!empty($params['end_date']) && (strtotime($params['end_date']) < time())) { + $isError = TRUE; + break; + } + } + if ($isError) { + form_set_error($membershipFieldName, 'Unfortuntately you cannot purchase this item as your membership has expired.'); + } + } + } + } + } /** * Process webform submission when it is about to be saved. Called by the following hook: @@ -1186,10 +1220,10 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { $params['contact_id'] = $cid; // The api won't let us manually set status without this weird param $params['skipStatusCal'] = !empty($params['status_id']); - - // Process date rules only for new memberships + + // Process date rules only for new memberships. if (!isset($params['id'])) { - $params = $this->processMembershipDateRules($cid, $params); + $params = $this->processMembershipDateRules($cid, $params, $c, $n); } $result = wf_civicrm_api('membership', 'create', $params); @@ -1219,26 +1253,38 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { } } - /** + /** * Process membership date rules */ - private function processMembershipDateRules($cid, $params) { + private function processMembershipDateRules($cid, $params, $c, $n) { $membershipParams = array ( 'sequential' => 1, 'active_only' => 1, 'contact_id' => $cid, 'options' => array ('sort' => "end_date DESC", 'limit' => 1), ); - + $rawValues = _webform_client_form_submit_flatten($this->node, wf_crm_aval($this->form_state, 'values:submitted')); + // Process start date rules. - if (!empty($params['start_date_rules']) && $params['start_date_rules'] == 2){ + if (!empty($params['start_date_rules']) && $params['start_date_rules'] == 1) { + $fieldName = 'rule_start_date'; + $fieldKey = "civicrm_{$c}_membership_{$n}_membership_{$fieldName}"; + $componentId = $this->getComponent($fieldKey)['cid']; + if (!empty($params['rule_start_date'])) { + $params['start_date'] = $params['rule_start_date']; + } + elseif (!empty($rawValues[$componentId])) { + $params['start_date'] = $rawValues[$componentId]['year'] . '-' . $rawValues[$componentId]['month'] . '-' . $rawValues[$componentId]['day']; + } + } + elseif (!empty($params['start_date_rules']) && $params['start_date_rules'] == 2){ // Handle case when memberships are selected for start date rules. if (!empty($params['start_date_memberships'])) { $membershipParams['membership_type_id'] = array ( 'IN' => $params['start_date_memberships'] ); } - + $activeMemberships = civicrm_api3('Membership', 'get', $membershipParams); if ($activeMemberships['count']) { $activeMembershipsEndDate = new DateTime($activeMemberships['values'][0]['end_date']); @@ -1246,9 +1292,20 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { $params['start_date'] = $start_date->format('Ymd'); } } - + // Process end date rules. - if (!empty($params['end_date_rules']) && $params['end_date_rules'] == 2) { + if (!empty($params['end_date_rules']) && $params['end_date_rules'] == 1) { + $fieldName = 'rule_end_date'; + $fieldKey = "civicrm_{$c}_membership_{$n}_membership_{$fieldName}"; + $componentId = $this->getComponent($fieldKey)['cid']; + if (!empty($params['rule_end_date'])) { + $params['end_date'] = $params['rule_end_date']; + } + elseif (!empty($rawValues[$componentId])) { + $params['start_date'] = $rawValues[$componentId]['year'] . '-' . $rawValues[$componentId]['month'] . '-' . $rawValues[$componentId]['day']; + } + } + elseif (!empty($params['end_date_rules']) && $params['end_date_rules'] == 2) { // Handle case when memberships are selected for end date rules. if (!empty($params['end_date_memberships'])) { $membershipParams['membership_type_id'] = array ( @@ -1258,6 +1315,9 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { $activeMemberships = civicrm_api3('Membership', 'get', $membershipParams); if ($activeMemberships['count']) { $activeMembershipsEndDate = $activeMemberships['values'][0]['end_date']; + if (empty($params['start_date'])) { + $params['start_date'] = date('Y-m-d'); + } $params['end_date'] = $activeMembershipsEndDate; } } @@ -1603,6 +1663,16 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { $membership_financialtype = $item['financial_type_id']; }; + // Pro rate logic. + if (!empty($item['end_date_rules']) + && + !empty($item['pro_rate_memberships']) + && + $item['end_date_rules'] == 2 + ) { + $price = $this->pro_rated_membership_fee($type, $price, $c, $item); + } + if ($price) { $this->line_items[] = array( 'qty' => $item['num_terms'], @@ -1642,6 +1712,39 @@ class wf_crm_webform_postprocess extends wf_crm_webform_base { return round($this->totalContribution, 2); } + /** + * Calculate pro rated membership fee. + * @param Integer $type + * @param Float $price + * @param Integer $c + * @param Array $item + * @return Float $price + */ + private function pro_rated_membership_fee($type, $price, $c, $n, $item) { + $durationInterval = $this->getMembershipTypeField($type, 'duration_interval'); + $durationUnit = $this->getMembershipTypeField($type, 'duration_unit'); + + // Calculate price/day. + $dateToday = date('Y-m-d'); + $dateAfterGiveDuration = date('Y-m-d', strtotime("{$dateToday} +{$durationInterval} {$durationUnit}")); + $dateToday = date_create($dateToday); + $dateAfterGiveDuration = date_create($dateAfterGiveDuration); + $durationInDays = date_diff($dateToday, $dateAfterGiveDuration)->format('%a'); + + $pricePerDay = $price / $durationInDays; + + // Find number of pro rate days. + $params = $this->processMembershipDateRules($this->existing_contacts[$c], $item, $c, $n); + $start_date = date_create($params['start_date']); + $end_date = date_create($params['end_date']); + $proRateDays = date_diff($start_date, $end_date)->format('%a'); + + // Calculate Pro Rated membership fee. + $price = $pricePerDay * $proRateDays; + + return $price; + } + /** * Are billing fields exposed to this webform page? * @return bool diff --git a/js/webform_civicrm_admin.js b/js/webform_civicrm_admin.js index b98a13074..7a4c11359 100644 --- a/js/webform_civicrm_admin.js +++ b/js/webform_civicrm_admin.js @@ -493,7 +493,8 @@ var wfCiviAdmin = (function ($, D) { // Membership constraints $('select[name$=_membership_num_terms]', context).once('crm-mem-date').change(function(e, type) { - var $dateWrappers = $(this).parent().siblings('[class$="-date"]').not('[class$="-status-override-end-date"]'); + var $dateWrappers = $(this).parent().siblings('[class$="-date"]').not('[class$="-status-override-end-date"]') + .not('[class$="-rule-start-date"]').not('[class$="-rule-end-date"]'); if ($(this).val() == '0') { $dateWrappers.show(); if (type !== 'init') { @@ -504,36 +505,38 @@ var wfCiviAdmin = (function ($, D) { $dateWrappers.hide().find('input').prop('checked', false); } }).trigger('change', 'init'); - $('select[name$=_membership_status_id]', context).once('crm-mem-date').change(function(e) { - $target = $(this).parent().siblings('[class$="membership-status-override-end-date"]'); - if ($(this).val() == '0') { - $target.hide().find('input').prop('checked', false); - } else { - $target.show(); - } - }).change(); - $('select[name$=_membership_start_date_rules]', context).change(function(e, type) { - var $dateRuleMembershipField = $(this).parent().siblings('[class$="-start-date-memberships"]'); - var $relativeToExistingMembership = 2; - if ($(this).val() == $relativeToExistingMembership) { - $dateRuleMembershipField.show(); + var $dateWrappers = $(this).parent().siblings('[class$="membership-rule-start-date"]'); + $dateWrappers.show(); + if ($(this).val() == '1') { + if (type !== 'init') { + $('input', $dateWrappers).prop('checked', true); + } } else { - $dateRuleMembershipField.hide(); + $dateWrappers.hide().find('input').prop('checked', false); } }).trigger('change', 'init'); - $('select[name$=_membership_end_date_rules]', context).change(function(e, type) { - var $dateRuleMembershipField = $(this).parent().siblings('[class$="-end-date-memberships"]'); - var $relativeToExistingMembership = 2; - if ($(this).val() == $relativeToExistingMembership) { - $dateRuleMembershipField.show(); + var $dateWrappers = $(this).parent().siblings('[class$="membership-rule-end-date"]'); + $dateWrappers.show(); + if ($(this).val() == '1') { + if (type !== 'init') { + $('input', $dateWrappers).prop('checked', true); + } } else { - $dateRuleMembershipField.hide(); + $dateWrappers.hide().find('input').prop('checked', false); } }).trigger('change', 'init'); + $('select[name$=_membership_status_id]', context).once('crm-mem-date').change(function(e) { + $target = $(this).parent().siblings('[class$="membership-status-override-end-date"]'); + if ($(this).val() == '0') { + $target.hide().find('input').prop('checked', false); + } else { + $target.show(); + } + }).change(); function billingMessages() { var $pageSelect = $('[name=civicrm_1_contribution_1_contribution_contribution_page_id]');