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

Enable Price Sets to be used in conjunction with online and offline Membership Signup and Renewal

    Details

    • Type: New Feature
    • Status: Done/Fixed
    • Priority: Major
    • Resolution: Fixed/Completed
    • Affects Version/s: 3.4.4, 4.0.4
    • Fix Version/s: 3.4.6, 4.0.6
    • Component/s: CiviMember
    • Labels:
      None

      Description

      ========
      Summary
      ========
      Enable the usage of price sets as an alternative for structuring online (self-service) and back-office membership signup and renewal.

      Price options in Membership price sets can be tied to a specific membership type. When that price option is selected, a membership of that type is created (or renewed). Each price field can have options presented as one or more checkboxes, a set of radio buttons, or a dropdown (select). By configuring several price fields - each with their own set of membership types - a single online contribution page can support any number of categories of membership (and thus allow the user to "purchase" > 1 membership in a single transaction). Additional price fields can be included in the price set offering non-membership options such as a magazine subscription. For this iteration, multiple membership purchases will be linked to a single contribution record.

      The membership block in online contribution pages will support EITHER the currently used 'simple' radio button set of memberships OR a price set. When a price set is used in a membership block, the contribution type for the membership payment will be derived from the price set. This contribution type over-rides contribution type(s) associated with membership types (necessary because > 1 membership may be purchased by the user but only one contribution record will be created for the total amount of the selected price fields / price options). The ability to generate a separate additional contribution record for selections in the 'contribution amounts' block will NOT be available if a membership price set if enabled. However, a price set field can be configured with choices for additional contribution amounts to be added to the checkout total.

      Back-office staff will also be able to select a membership price set when creating or renewing memberships (similar to the existing ability to choose a contribution price set from the New Contribution form).

      Price sets currently support date-based options and positive and negative values & hence allow a range of options. One contribution will be created for the entire transaction.

      EXAMPLE: A price set with 3 price fields. National membership (has 3 price options), Regional membership (checkbox), optional magazine subscription.

      National Membership : [ x ] General $125.00
      [ ] Student $ 50.00
      [ ] Senior $ 75.00

      Join your local chapter [ x ] $15.00

      Subscribe to Green Times [ x ] $35.00

      Total Amount $ 175.00

      ===============
      Schema / Database
      ===============
      1. civicrm_price_set_entity
      No schema change needed. Price sets used for online membership signup / renewal will set 'civicrm_membership_block' as entity_table and civicrm_membership_block.id as entity_id.

      2. civicrm_price_set

      • The price_set table has an extends column which uses integer values (1=event, 2=contribution) - so we can assign 3 when extends = membership.
      • Define one new column:
      • contribution_type_id INT NULL FK to civicrm_contribution_type.id

      NOTE: We are adding contribution type to the price set table because we need a place to store the "over-ride" contribution_type_id which will be assigned to the membership price set contribution record. We can not use the contribution types associated with membership types because we can have > 1 membership created during a price set "purchase". Since price sets can be selected both for an online contribution page membership block AND in the New / Renew Membership form, civicrm_price_set is the best place to store this "default".

      3. civicrm_price_value

      • Define a new column:
      • membership_type_id INT NULL FK to civicrm_membership_type.id

      4. civicrm_line_item
      Line item rows which record these price set purchases will be linked to the CONTRIBUTION record (rather than the membership record). Although the line item table uses entity_table / entity_id model which would allow us to link line items directly to a membership record - this would make it very difficult to provide a consolidated view of the "purchase" (since line items from a single transaction would potentially be linked to several memberships and to a contribution record for the non-membership items).

      =============
      Implementation
      =============
      1. Price set forms
      1.1 Add / Edit Price Set (CRM/Price/Form/Set.php)

      • New checkbox item in Used For field (extends) for Membership
      • Form Rule - A price set can not be used for Event or Contribution if it is used forMembership. If user checks Membership plus another extends value, form rule error is: "If you plan on using this price set for membership signup and renewal, you can not also use it for Events or Contributions. However, a membership price set may include additional fields for non-membership options that requires an additional fee (e.g. magazine subscription)."

      IF price set is used for "Membership" - add a required field for Contribution Type (do not show this field for Contribution and Event price sets).
      Field Type = select
      Label = "Contribution Type (Membership Fees)"
      Options = all enabled contribution types
      Required

      1.2 Add Price Field
      If price field belongs to a price set used for Memberships:

      • Insert 1 new column in the Price Field Options table for user to select associated membership type for that price option row. Table layout in this case is:

      Default Membership Type Label Amount Description Weight Active
      [ ] [ - select - v] [x ]

      • Also use jQuery to dynamically set default values for Label and Amount field based on Membership type selected. Label = Membership Type 'name', Amount = 'minimum_fee'. User can override the default values for those fields. This creates a lot more flexibility for offering special deals on memberships via the UI - since user can offer a discounted fee for a certain period of time using the price set field's date-based availability without creating multiple instances of the membership type. You will need to ensure that the membership fee charged is based on price_field_value.amount rather then membership_type.minimum_fee when price set is used for signup / renewal.
      • ISSUE: I don't see anywhere that we actually use / display the Description field for civicrm_price_value rows other than when you edit or view the price option. Perhaps we should remove it from the table above for now (save horizontal space). If folks really need it for some reason we can put it back and they can still edit it from Price/Form/Option.php. The Description column hasn't been working for Contribution Price Sets for a while in any case (in the Price/Form/Field.php Price options table, the column is present but not field is rendered in the rows). I don't recall seeing any bug reports so I'm guessing it's not needed.

      1.3 Add / Edit Price Options
      If the parent price field belongs to a price set used for Memberships:

      • Insert 1 new field in the form (Membership Type).
      • Membership Type field is first on the form. Inline help below it: "If a membership type is selected, a membership will be created or renewed when users select this option. Leave this blank if you are using this for non-membership options (e.g. magazine subscription).
      • Hide the Participant Count and Max Participant fields.
      • Use jQuery to dynamically set default values for Option Label and Option Amount (same as above)

      NOTE: The Auto-renew feature is enabled for a membership price set automatically if ALL membership types linked to price field options have auto-renew enabled. This approach is needed because we are only creating a single recurring transaction for the "purchase" - so the end-user's auto-renew choice will be applied to all memberships that they sign up for.

      --------------
      2. Configure Contribution Page : Membership Settings form (CRM/Member/Form/MembershipBlock,php)
      2.1 If one or more enabled Price Sets which extend Membership are present, add a dropdown to this form to 'Select Membership Price Set'. Dropdown contains '- none -', plus all enabled 'used for membership' price sets. Insert this field above the Membership Types section for the form.

      If a price set is selected:

      • HIDE the following:
      • The entire Membership Types block (table w/ membership type fields)
      • Require Membership Signup - NOTE: The required property is handled at price set field level.
      • Separate Membership Payment - NOTE: This feature is not supported with price sets.
      • Display Membership Fee - NOTE: This property is handled at price set field / price option levels.

      2.2 Form Rule
      We will not support BOTH a price set configured for the contribution page 'Amount' section AND a price set for the membership signup / renewal section. If user selects a price set on this form and has already selected one on the Amounts form, formRule error is: "You can not use a price set for Memberships and for Contribution Amounts. However, a membership price set may include additional fields for non-membership options that requires an additional fee (e.g. magazine subscription) or an additional voluntary contribution."

      2.3 Post process changes

      • Create / update price_set_entity row.
      • Create / update membership_block: Clear values in membership_types and membership_type_default if a price set is being used.

      --------------
      3. Online Contribution Pages (CRM/Contribute/Form/Contribution/Main.php, Confirm.php, Thankyou.php)
      3.1 Main contribution form (Main.php)
      If a membership price set is enabled for this contribution page, replace the membership block with the price set (including the usual dynamic 'Total Amount' line (same as for Contribution price set).

      NOTE: Change the label for this total for both Membership and Contributions to 'Total Amount' rather than 'Total Fee' (which I think is a hangover from Event price sets).

      3.1.a Auto-renew membership option
      Add the auto_renew checkbox to the price-set driven membership block if ALL membership types linked to price field options in the price set have auto-renew enabled. Checkbox should be in mode 1 (user can select the option) unless ALL associated membership types have auto_renew = 2 (then auto-renew is required, checkbox is checked and read-only).

      3.1b. Online Renewals with Price Set
      If user is logged in, check for existing memberships with same type as price set options. If one or more matching membership found:

      • membership block is in "renew" mode (renew title, renew message text etc.)
      • select/check price option or options which match the existing membership by default
      • display existing membership text next to price field row - e.g. "Your National Student membership expires on September 27, 2011."

      3.2. Confirm page / Thankyou page

      • Display the price set line items instead of the membership fees block (same display as Contribution price set).
      • Include the auto-renew option "message" if auto-renew is requested by user (or forced).

      3.3 Post process
      NOTE: Given that we will be processing price-set driven membership create / renew from both online contribution page flow and from the Membership form - please evaluate whether we can centralize some of the code currently done in the form class (Form/Membership.php).

      • Contribution record / financial transaction amount set by selected price set field values / options. Submit recurring contribution (auto-renew mode) if auto_renew option is true.
      • Create / update membership records for each price set option that has a membership type value assigned. Set auto-renew flag in membership record based on passed auto_renew value.
      • Create membership_payment records linking contribution to membership record(s)
      • Insert civicrm_line_item rows for each purchased price set field (entity_table = civicrm_contribution, entity_id = contribution.id)

      3.4 System Workflow Message Templates

      • Add purchased price set line items to the online and offline membership receipts (replaces membership fees). Line item 'label' column will indicate the membership(s) purchased when applicable. EXAMPLE:

      ------------------------------------------------------------------
      Item Qty Each Total
      -----------------------------------------------------------------
      National Membership 1 $ 50.00 $ 50.00
      Wall Poster (full color) 1 $ 10.00 $ 10.00

      Total Amount: $ 60.00

      • Include auto-renew text in the message if auto_renew is true for the transaction.

      NOTE: The current 3.4 version of System-workflow message template for "Memberships - Receipt (on-line)" contains logic for displaying contribution price set line items.

      Price set value logic needs to be added to the 'Memberships - Signup and Renewal Receipts (off-line)' message template.

      3.5 Hook to modify membership price set options for Online Contribution flow

      • Ensure that the existing hook_civicrm_buildForm hook can be used to modify the price fields array in the online contribution flow (e.g change option prices, hide price options etc.)

      3.6 IPN changes for auto-renew memberships

      • Modify IPN code as needed to check for multiple memberships associated with a given contribution_recur record. All associated memberships need to be renewed when the recurring contribution is posted.

      3.7. Update pending contribution status functionality needs tohandle cases where there are > 1 membership record associated with the contribution (i.e multiple rows in membership_payment for the same contribution_id). If contribution record status is changed to completed, all linked memberships need to have their status updated.

      --------------
      4. Offline Membership Signup (Add/Edit Membership: CRM/Member/Form/Membership.php)
      4.1 New Membership - Build form

      • If one or more price sets Used For "Membership" are enabled, include a new dropdown to the right side of the "Membership Organization and Type" dropdowns:

      Membership Org and Type [ - select - v] [ - select - v] OR [ - choose price set - v]

      (same layout as Add / Edit Contribution form)

      • If user selects a price set, display the price set fields below the membership org / type row. If user selects empty option in dropdown, again hide the price set fields.
      • Dynamic total below price fields updates as user selects price set values (same as offline contribution form). Change label for both Contribution and Membership forms from "Total Fee(s)" to "Total Amount".
      • 'total_amount' input field in Membership Payment and Receipt fieldset should be set to read-only and updated in synch with Total Amount display in price set block. (We could also choose to hide that field - but I think it's clearer to keep the display in the payment and receipt section.
      • Add the auto_renew checkbox to the price-set driven membership block if ALL membership types linked to price field options in the price set have auto-renew enabled.

      4.2. Post process

      • (same as online - insert line_item rows for each purchased price set item)
      • offline receipt changes to handle line items (as noted above)

      4.3 Edit Membership

      • Currently we allow user to change membership type and various membership dates in Edit mode, but we do not allow for modification of associated contribution record (nor do we ever create an additional contribution record in Edit mode). Therefore, we will NOT expose the price set functionality on this form in edit mode.

      --------------
      5. Offline Membership Renewal (CRM/Member/Form/MembershipRenewal.php)
      Membership Price Sets will NOT be supported for offline renewals.

      --------------
      6. View Membership / View Contribution
      Given that a price-set driven membership transaction may encompass several memberships plus non-membership items, I think we need to restrict display of the price set line items to the associated contribution record. This means:

      • no change to current view membership screen
      • view and edit contribution forms should display (read-only) the associated line item data as a table. Memberships will be indicated by the line item label (same as in receipts above) - so this is really no change from display of Contribution price set contributions (probably no code changes needed).

      --------------
      7. Navigation menu

      • Add two items under Memberships in the default navigation menu (below a 'separator' line): New Price Set; Manage Price Sets. Same items added to Administer -> CiviMember.

      --------------
      8. Bug fix

      • When adding a price set field in Contribution price set, the Price Options table includes a Description column header, but the "description" text input fields are missing from the rows for some reason. (If the price set is used for Events, the "description" input fields are present in the rows.)

      ========
      Upgrades
      ========

      • Alter table statements for civicrm_price_set and civicrm_price_value
      • System workflow message template changes for online and off-line membership receipts.
      • Navigation menu changes (add price set items in Memberships and Admin > CiviMember menus).

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                dgg David Greenberg
                Reporter:
                dgg David Greenberg
              • Votes:
                2 Vote for this issue
                Watchers:
                6 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: