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

Partial payments for Memberships

    Details

    • Epic Name:
      Back-office Membership Membership Enhancements
    • Versioning Impact:
      Patch (backwards-compatible bug fixes)
    • Documentation Required?:
      User and Admin Doc
    • Funding Source:
      Contributed Code

      Description

      Description
      Provides back-office staff with the following additional capabilities:

      1. Record partial payment for a Membership Creation. Then record one or more additional payments until the Membership fee is completely paid.

      Part 1:

      Description
      -------------
      Summary
      -------------
      Back-office staff may:

      • Record partial payment for a Membership Creation.
      • Both the contribution and the Membership record will be assigned a status of Partially Paid until the balance owing is zero. This will allow staff to easily locate partially paid registrations.

      ---------------------
      Implementation
      ----------------------
      1. Define new Membership status Rule: 'Partially paid'

      • Status is 'Counted', Class='Positive', Reserved=TRUE, Visibility=Admin, Active=TRUE
      • Add to civicrm_data
      • Insert in upgrades

      2. New Membership Creation (modifications)
      currently (4.4) the Total Amount (Payment Info field set) defaults to total owing AND the user can change that to a smaller amount. However we don't do anything special in that case. We need to make the following changes to postProcessing to handle this condition.

      Client Side form behaviors (jQuery)
      ------------------------------------------------

      • If user enters a Total Amount less than the calculated total fee, set Contribution Status to 'Partially paid' (user MAY override this and change it to something else later)
      • When user clicks "Save", if the Total Amount entered is less than calculated fees AND the contribution status!= 'Partially paid', put up a jScript confirm dialog:
        "Payment amount is less than the amount owed. Expected Contribution status is 'Partially paid'. Are you sure you want to set the contribution status to $statusLabel? Click OK to continue, Cancel to change your entries."

      Post Process changes
      -------------------------------

      • New contribution record is always inserted with the total OWING (calculated fees) as the total_amount. If total_amount = total owing, NO changes in the rest of the postProcess flow.

      If the total_amount on the form is less than the amount owing:

      • Contribution status is set to 'Partially paid'.
      • Financial trxn record is created with total_amount = the amount actually being paid (total_amount from the form). Financial_trxn status is Completed. TO account = the applicable ASSET account (based in payment_instrument)
      • A second financial_trxn record is created for the BALANCE owing. Rules for setting values for this transaction are the same as for a new Pending pay-later transaction:
      • to_financial_account_id = account with "Accounts Receivable Account is" relationship to the financial type of the contribution
      • from_financial_account_id = NULL
      • status = Completed

      Tests
      -------

      • Extend unit tests to cover membership create with partial payment
      • Extend web-tests to cover the above workflow (membership registration with partial payment)

      2 Part:
      Description
      -------------
      Summary
      -------------
      Back-office staff may:

      • Record one or more additional payments against "Partially paid" or "Pending pay later" membership - until the registration fee is completely paid.
      • Members may be sent receipts for each payment
      • Payments will be recorded as financial transactions against the original contribution record.
      • View existing payments (financial transactions)
      • When balance owing is 0, contribution status will be updated to Completed. Membership status can be set in payment form but comply to default rules when balance owing is 0.
      • Record a refund (used when registration selections are changed and fee was overpaid - see CRM-13973).

      ---------------------
      Implementation
      ----------------------
      1. Implement BAO function which calculates 'amount owing' or 'refund due' for a given Membership record.

      • SUM(line_item.line_total) for all line_item rows linked to the membership row MINUS SUM(financial_trxn.total_amount) for all financial_trxn rows linked to the contribution associated with the membership row AND where financial_trxn.status_id = 1 (Completed).
      • Positive number = Amount Owed,
      • Negative number = Refund Due


      2. Using the same form for submitting a Financial Transaction against an existing contribution linked to a membership.

          • IMPORTANT ***: Going forward we are using the same form for applying payments against a Partially Paid membership contribution, so the form class should be structured to support conditional 'integration' with other component transactions.

      3.1 Form elements

      • Form elements are a subset of fields exposed in Contribution form (CRM_Contribute_Form_Contribution), but this is a basic create-only form so we'll make use of new form class which only handles this case. (For Memberships we are using the same form what we have used for Events).
      • For this project, the form will always create a financial_trxn (payment or refund) against a partially paid contribution linked to the passed-in membership record. Contact Name (contact display_name) and Membership title are read-only elements on the top of the form.
      • URL params for contact id and membership id are required / passed to the form.
      • All form fields are columns in financial_trxn table EXCEPT for "Send Receipt" and "Receipt From".
      • add a text area to the form for purpose to provide optional email_text - shown conditionally if [x] Send Receipt checked
      • For 'Refund Due' case:
      • Payment Amount label => Refund Amount
      • Form block title = New Membership Refund
      • Page title = Refund for $displayName
      • Additional client-side form behavior (same as contribution form Additional Details): Net Amount = Payment Amount - Fee Amount

      3.2 Pre process

      • Amount Owed OR Refund Due for this membership should be calculated during preProcess. This value should be the default for the Payment Amount/Refund Due field AND displayed next to the amount input box.
      • If related member (contact) does not have a valid email address, display status re: can not send a receipt and hide the Send Receipt and From fields (same as for contribution form).

      3.3 Form rules

      • If amount owed, payment amount must be < = Amount Owed
      • If refund due, refund amount must = Refund Due (we do not want to support 'partially refunded' membership records at this point).
      • Net Amount = Payment Amount (OR Refund Amount) - Fee Amount

      3.4 Post Process
      NOTE: Use existing Financial Trxn / Financial Item BAO's as much as possible. Do not put transaction process logic in the form class (create new BAO(s) if necessary).

      • Insert new financial_trxn and entity_financial_trxn (keyed to contribution row). Financial Trxn status is completed. Payment instrument, check number, financial type etc are stored per form values.

      ------------------
      For Payments
      ------------------

      • update related contribution status to Completed (from 'Pending refund')
      • update related Membership status to Default Rule (from 'Pending refund')
      • If [x] Send Receipt is checked, we need a new function / message template for sending Payment/Refund Receipts. In the interest of keeping the template simple, The 'Additional Payment Receipt or Refund Notification' message template is ideally intended to be used for both event and membership payments and refunds. Best if you can tweak it / add some variables so that it handles both cases.
      • For Payments – use new activity (type = Payment) for the new payment action. Data pattern similar to Contribution activity:
        Source Contact = logged in user's contact
        Target Contact = payee contact
        Subject = "$paymentAmount - Offline payment for $eventTitle (Title Need to be changed with $membershipType)
      • For Refunds – use new activity (type = Refund) for the new payment action. Data pattern similar to Contribution activity:
        Source Contact = logged in user's contact
        Target Contact = payee contact
        Subject = "$refundAmount - Offline refund for $eventTitle (Title Need to be changed with $membershipType)
      • Cancel on form should return to last form or page that the user was on. Successful submit should return to contact's Memberships tab in most cases. If the form is accessed via Find Memberships, then return to the search form with session key (search results s/b preserved if possible).


      ***Yet to get more information on this Credit Card Block ***
      4. Live Mode (submit credit card payment) - Payments only

      • This mode is available if one or more of the required processor(s) enabled (allowBackofficeCreditCard - same rules as contribution form class). This is NOT available for 'Pending refund' contributions / membership records.
      • Submit button title for this mode is 'Submit Credit Card Payment' (not shown on screenshot)
      • Post process invokes selected processor plugin to submit the payment. Rules for entity updates same as above.
      • Activity subject in LIVE mode = "$paymentAmount - Submit credit card payment for $eventTitle

      5. Modifications to Edit Membership and View Membership forms
      5.1 Selections block: I don't think the intent is to support changing the selected membership type, NOR changing membership-related price set selections. Also even if a membership price set is used we don't need to show the line items in the View or Edit Membership pages, so we may not need to add a Selections section. We do need a new Fees section to show the owed / paid / balance info.

      5.2 If 'Amount Paid' is > 0, add "view payments" link to the Fees table (text link and link on Amount Paid amount value). Clicking link loads a new jQuery dialog pop-up which displays payments already made against the associated contribution (e.g. financial_trxn records). We need to filter the financial_trxn rows to only show actual payments (not transfers to AR account etc.). I think we can do this by only showing transactions where the "TO ACCOUNT" financial_account_type_id is 'Asset' (check with Dave/Pradeep to confirm this).
      **I’m assuming, we can mimic this similar to Events **

      See ViewPaymentsPopup.png screenshot for table elements and layout.


      6. Expose "Record Payment" button / action link for Membership records with "Partially paid" status.

      Users should be able to navigate to 'New Membership Payment' form from the following buttons and action links:

      • Add a 'Record Payment' action link to the Membership selector actions IF Membership status for that row is 'Partially paid' or 'Pending pay later' (this should be available from contact's Membership tab as well as Find Membership / Membership Dashboard). Same behaviour as 'Record Payment' button.

      7. Tests

      Need to check the unit and web tests added for the analogous event/participant issues. Any new or modified BAO's or API's should result in new or extended unit tests. There should be web tests for each of the new UI interactions (i.e. create partially paid membership, make another partial payment, make a completing payment).

      8. Scheduled Reminders

      The use case I would see here is the ability to send reminders to contacts with partially paid memberships (similarly to how we've implemented for event participants). However we don't currently include membership status in the Scheduled Reminders criteria - and we would probably need one or more additional 'events' beyond 'Membership Join Date' and 'Membership End Date' to make this useful (e.g. 'Last Payment Date', 'Membership Start Date'). A simple thing we could do is just add a new token for display of a membership's balance -

      {membership.balance}

      . Then users could create a smart group of partially paid members and thus handle some key use cases.

        Attachments

          Activity

            People

            • Assignee:
              ramesh Ramesh
              Reporter:
              sri_techie sri
            • Votes:
              6 Vote for this issue
              Watchers:
              14 Start watching this issue

              Dates

              • Created:
                Updated: