diff --git a/CRM/Contact/BAO/Relationship.php b/CRM/Contact/BAO/Relationship.php index f856699a3a7a..76e61e8f6595 100644 --- a/CRM/Contact/BAO/Relationship.php +++ b/CRM/Contact/BAO/Relationship.php @@ -2380,6 +2380,25 @@ protected static function addInheritedMembership($membershipValues) { AND is_current_member = 1"; $result = CRM_Core_DAO::singleValueQuery($query); if ($result < CRM_Utils_Array::value('max_related', $membershipValues, PHP_INT_MAX)) { + // Convert custom_xx_id fields to custom_xx + // See https://lab.civicrm.org/dev/membership/-/issues/37 + // This makes sure the value is copied and not the looked up value. + // Which is the case when the custom field is a contact reference field. + // The custom_xx contains the display name of the contact, instead of the contact id. + // The contact id is then available in custom_xx_id. + foreach ($membershipValues as $field => $value) { + if (stripos($field, 'custom_') !== 0) { + // No a custom field + continue; + } + $custom_id = substr($field, 7); + if (substr($custom_id, -3) === '_id') { + $custom_id = substr($custom_id, 0, -3); + unset($membershipValues[$field]); + $membershipValues['custom_' . $custom_id] = $value; + } + } + civicrm_api3('Membership', 'create', $membershipValues); } return $membershipValues; diff --git a/tests/phpunit/CRM/Member/BAO/MembershipTest.php b/tests/phpunit/CRM/Member/BAO/MembershipTest.php index ea233d0a13b3..564fbaae5010 100644 --- a/tests/phpunit/CRM/Member/BAO/MembershipTest.php +++ b/tests/phpunit/CRM/Member/BAO/MembershipTest.php @@ -932,6 +932,55 @@ public function testMembershipUpdateDoesNotDeleteRelatedMembershipsByMistake(): $this->membershipStatusDelete($otherStatusID); } + public function testRelatedMembershipWithContactReferenceCustomField() { + $relatedContactId = $this->individualCreate(); + $customContactId = $this->individualCreate(); + $membershipOrganizationId = $this->organizationCreate(); + $organizationId = $this->organizationCreate(); + + $membershipTypeWithRelationship = $this->createMembershipType($membershipOrganizationId, TRUE); + $customGroup = $this->customGroupCreate(['extends' => 'Membership']); + $customField = $this->customFieldCreate([ + 'custom_group_id' => $customGroup['id'], + 'data_type' => 'ContactReference', + 'html_type' => 'Autocomplete-Select', + 'default_value' => '', + ]); + + // Creating membership of organisation + $membership = $this->callAPISuccess("Membership", "create", [ + 'membership_type_id' => $membershipTypeWithRelationship["id"], + 'contact_id' => $organizationId, + 'status_id' => $this->_membershipStatusID, + 'custom_' . $customField['id'] => $customContactId, + ]); + + $membership = $membership['values'][$membership["id"]]; + + // Create relationship between organization and individual contact + $relationship = $this->callAPISuccess('Relationship', 'create', [ + // Employer of relationship + 'relationship_type_id' => 5, + 'contact_id_a' => $relatedContactId, + 'contact_id_b' => $organizationId, + 'is_active' => 1, + ]); + + // Check count of related memberships. It should be one for individual contact. + $relatedMembershipsCount = $this->getRelatedMembershipsCount($membership["id"]); + $this->assertEquals(1, $relatedMembershipsCount, 'Related membership count should be 1.'); + + $relatedMembership = $this->callAPISuccess("Membership", "getsingle", [ + 'owner_membership_id' => $membership["id"], + ]); + + $this->assertEquals($customContactId, $relatedMembership['custom_' . $customField['id'] . '_id']); + + $this->callAPISuccess('Relationship', 'delete', ['id' => $relationship['id']]); + $relatedMembershipsCount = $this->getRelatedMembershipsCount($membership["id"]); + $this->assertEquals(0, $relatedMembershipsCount, 'Related membership count should be 0.'); + } + /** * Creates the given amount of contacts. *