Skip to content

Fix stale membership_type_id overriding price set selections on membership form#35145

Open
erawat wants to merge 1 commit intocivicrm:masterfrom
compucorp:fix-membership-priceset-stale-type-id
Open

Fix stale membership_type_id overriding price set selections on membership form#35145
erawat wants to merge 1 commit intocivicrm:masterfrom
compucorp:fix-membership-priceset-stale-type-id

Conversation

@erawat
Copy link
Contributor

@erawat erawat commented Mar 19, 2026

Overview

When a non-quick-config price set is selected on the back-office membership form, creating a membership fails with DB Error: constraint violation because membership_type_id is missing from the INSERT. This happens because a stale membership_type_id value from the org/type selector overrides the price set selections.

Before

  1. Go to a contact's membership tab → Add Membership
  2. Select a non-quick-config price set from the "Choose price set" dropdown
  3. Select membership options from the price set fields
  4. Submit
  5. Result: DB Error: constraint violation — membership is not created

After

The same steps now correctly create memberships for all selected price set options.

Technical Details

The membership form has two selection modes: an org/type dropdown (membership_type_id[0]/membership_type_id[1]) and a price set selector. When switching to a price set, JavaScript sets membership_type_id[1] to 0, but a stale value can remain if the user previously browsed membership types.

getSelectedMemberships() checks membership_type_id[1] first:

if (isset($params['membership_type_id']) && !empty($params['membership_type_id'][1])) {
    $memTypeSelected = [$params['membership_type_id'][1] => ...];
}

When membership_type_id[1] has a stale value (e.g. 52), only that single type is returned — all price set selections are ignored. getMembershipParameters() then only sets membership_type_id for type 52, but the form tries to create memberships for all types from the price set line items, resulting in INSERTs without membership_type_id.

The fix adds && empty($params['price_set_id']) so that when a price set is active, membership types are always derived from the price field selections instead.

Comments

Tested on a site with a non-quick-config membership price set containing 9 fields (Select and CheckBox types) covering 60+ membership types. Verified that all combinations work correctly after the fix.

@civibot
Copy link

civibot bot commented Mar 19, 2026

🤖 Thank you for contributing to CiviCRM! ❤️ We will need to test and review this PR. 👷

Introduction for new contributors...
  • If this is your first PR, an admin will greenlight automated testing with the command ok to test or add to whitelist.
  • A series of tests will automatically run. You can see the results at the bottom of this page (if there are any problems, it will include a link to see what went wrong).
  • A demo site will be built where anyone can try out a version of CiviCRM that includes your changes.
  • If this process needs to be repeated, an admin will issue the command test this please to rerun tests and build a new demo site.
  • Before this PR can be merged, it needs to be reviewed. Please keep in mind that reviewers are volunteers, and their response time can vary from a few hours to a few weeks depending on their availability and their knowledge of this particular part of CiviCRM.
  • A great way to speed up this process is to "trade reviews" with someone - find an open PR that you feel able to review, and leave a comment like "I'm reviewing this now, could you please review mine?" (include a link to yours). You don't have to wait for a response to get started (and you don't have to stop at one!) the more you review, the faster this process goes for everyone 😄
  • To ensure that you are credited properly in the final release notes, please add yourself to contributor-key.yml
  • For more information about contributing, see CONTRIBUTING.md.
Quick links for reviewers...

➡️ Online demo of this PR 🔗

@civibot civibot bot added the master label Mar 19, 2026
erawat added a commit to compucorp/civicrm-core that referenced this pull request Mar 19, 2026
erawat added a commit to compucorp/civicrm-core that referenced this pull request Mar 19, 2026
…rship form

When a non-quick-config price set is selected on the back-office membership
form, the membership_type_id field from the org/type selector may retain a
stale value. getSelectedMemberships() checks membership_type_id[1] first
and if set, uses it as the sole selected membership type — ignoring all
price set selections entirely.

This causes membership creation to fail with a DB constraint violation
because getMembershipParameters() only sets membership_type_id for the
types in _memTypeSelected, while the form tries to create memberships
for all types from the price set line items.

The fix adds a check for price_set_id so that when a price set is active,
membership types are always derived from the price field selections.
@erawat erawat force-pushed the fix-membership-priceset-stale-type-id branch from 3a9051d to eb24de4 Compare March 20, 2026 11:03
@larssandergreen
Copy link
Contributor

I wonder if it makes sense to guard against the form submitting conflicting values like this instead of fixing the form so it doesn't submit conflicting values?

It looks like if you cleared #membership_type_id_1 in here when priceSetId has a value, then it wouldn't be an issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants