Uploaded image for project: 'CiviCRM'
  1. CiviCRM
  2. CRM-1039

CiviMember - Business Rules for Setting Membership Start and End Dates, and Membership Status

    Details

    • Type: New Feature
    • Status: Done/Fixed
    • Priority: Major
    • Resolution: Fixed/Completed
    • Affects Version/s: None
    • Fix Version/s: 1.5
    • Component/s: None
    • Labels:
      None

      Description

      This specification covers business rules for setting membership record start date, end date and status based on the associated MembershipType properties and the configured status-setting rules contained in the active MembershipStatus record properties. APIs and underlying code which insert or update Membership records should be reviewed to make sure they properly implement these rules.

      1. Set start date and end date
      1.1 New membership record (insert)
      For a new membership, we insert a civicrm_membership record AND a civicrm_membership_log record. We use the same values for start and end date in BOTH records. Membership.join_date is set to current date for all cases.

      • IF membership_type.period_type = 'rolling', THEN
      • start_date = current date
      • end_date = start_date + ( duration_unit x duration_interval ) - 1 day
        (same values used for both membership and membership_log records)

      EXAMPLE: period_type = rolling

      • membership_type duration = 1 year
      • today = 20060614
        .... Start Date is 20060614 (Jun 14, 2006)
        .... End Date is 20070613 (Jun 13, 2007)
      • IF membership_type.period_type = 'fixed', AND fixed_period_rollover_day (MMDD) is null OR today is less than fixed_period_rollover_day, THEN
      • start_date = immediately prior fixed_period_start_day expressed as a date
      • end_date = start_date + ( duration_unit x duration_interval ) - 1day

      EXAMPLE: period_type = fixed, rollover day is null

      • membership_type duration = 1 year
      • fixed period_start_day = 0101
      • fixed_period_rollover_day = null
      • today = 20060614
        .... Start Date is 20060101 (Jan 1, 2006)
        .... End Date is 20061231 (Dec 31, 2006)
      • IF membership_type.period_type = 'fixed', AND today is GREATER THAN OR EQUAL TO fixed_period_rollover_day, THEN
      • start_date = immediately prior fixed_period_start_day expressed as a date
      • end_date = start_date + ( duration_unit x duration_interval ) + ( duration_unit x duration_interval ) - 1 day

      EXAMPLE: period_type = fixed, today is later than rollover day

      • membership_type duration = 1 year
      • fixed period_start_day = 0101
      • fixed_period_rollover_day = 1201 (e.g. December 1)
      • today = 20061204 (Dec 4, 2006)
        .... Start Date is 20060101 (Jan 1, 2006)
        .... End Date is 20071231 (Dec 31, 2007)

      1.2 Renewing membership records
      On renewal, we update the civicrm_membership record and insert a new civicrm_membership_log record. We do NOT update civicrm_membership.start_date UNLESS the current membership_status.is_current is FALSE (i.e. the membership has lapsed). However, membership_log.start_date always is set to the CURRENT membership period start_date. Membership.join_date is NEVER updated programatically - it can only be modified manually in the Edit Membership form.

      • IF membership_type.period_type = 'rolling' OR 'fixed', and membership_status.is_current is TRUE, THEN
      • membership.start_date = NO UPDATE
      • membership_log.start_date = current_membership_period_start_date = current end_date + 1 day
      • membership.end_date = current_membership_period_start_date + ( duration_unit x duration_interval ) - 1 day
      • IF membership_type.period_type = 'rolling' or 'fixed', and membership_status.is_current is FALSE, THEN
      • membership.start_date = membership_log.start_date = current_membership_period_start_date = current end_date + 1 day
      • membership.end_date = current_membership_period_start_date + ( duration_unit x duration_interval ) - 1 day

      2. Setting membership status
      These rules must be defined in a function that can be invoked during membership signup and renewal, AND can be invoked by a cron script which runs periodically and updates all membership record status values.

      Inputs to the function are:
      status_date (defaults to today) + membership.start_date + membership.end_date + membership.join_date

      Select membership_status by looping through records WHERE is_active = 1 AND is_admin != 1 ORDER BY weight ASC. For each "valid" record, see if we are within the status "range":

      status_date >= start_event (conditionally adjusted by start adjust unit x interval)
      status_date <= end_event (conditionally adjusted by end adjust unit x interval)

      Function returns status.id and status.name of FIRST status record for which status_date (e.g. today) is in range. If no matching status records are found - assign the status.id of the DEFAULT membership_status record (membership_status.is_default = TRUE). If there is no DEFAULT membership_status record, then assign the active status record with the lowest weight.

      NOTE: Ordering this loop by weight is important as there may be more than one matching status - and we want to return the matching status with the lowest weight.

      EXAMPLE 1:
      Today = June 23, 2006
      membership.start_date = Jan 1, 2006
      membership.end_date = Dec 31, 2006
      Based on the sample membership_status records, we would match on status.id =2 -> "Current"

      EXAMPLE 2:
      Today = June 23, 2006
      membership.start_date = Jun 1, 2005
      membership.end_date = May 31, 2006
      Based on the sample membership_status records, we would match on status.id =3 -> "Grace"

        Attachments

          Activity

            People

            • Assignee:
              anil Anil Kokitkar
              Reporter:
              dgg David Greenberg
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: