3 require_once 'contributioncancelactions.civix.php';
5 use CRM_Contributioncancelactions_ExtensionUtil
as E
;
7 use Civi\Api4\LineItem
;
8 use Civi\Api4\Participant
;
11 * Implements hook_civicrm_preProcess().
13 * This enacts the following
14 * - find and cancel any related pending memberships
15 * - (not yet implemented) find and cancel any related pending participant records
16 * - (not yet implemented) find any related pledge payment records. Remove the contribution id.
18 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_post
20 function contributioncancelactions_civicrm_post($op, $objectName, $objectId, $objectRef) {
21 if ($op === 'edit' && $objectName === 'Contribution') {
22 if ('Cancelled' === CRM_Core_PseudoConstant
::getName('CRM_Contribute_BAO_Contribution', 'contribution_status_id', $objectRef->contribution_status_id
)) {
23 contributioncancelactions_cancel_related_pending_memberships((int) $objectId);
24 contributioncancelactions_cancel_related_pending_participant_records((int) $objectId);
25 contributioncancelactions_update_related_pledge((int) $objectId, (int) $objectRef->contribution_status_id
);
31 * Update any related pledge when a contribution is cancelled.
33 * This updates the status of the pledge and amount paid.
35 * The functionality should probably be give more thought in that it currently
36 * does not un-assign the contribution id from the pledge payment. However,
37 * at time of writing the goal is to move rather than fix functionality.
39 * @param int $contributionID
40 * @param int $contributionStatusID
42 * @throws CiviCRM_API3_Exception
44 function contributioncancelactions_update_related_pledge(int $contributionID, int $contributionStatusID) {
45 $pledgePayments = civicrm_api3('PledgePayment', 'get', ['contribution_id' => $contributionID])['values'];
46 if (!empty($pledgePayments)) {
47 $pledgePaymentIDS = array_keys($pledgePayments);
48 $pledgePayment = reset($pledgePayments);
49 CRM_Pledge_BAO_PledgePayment
::updatePledgePaymentStatus($pledgePayment['pledge_id'], $pledgePaymentIDS, $contributionStatusID);
54 * Find and cancel any pending participant records.
56 * @param int $contributionID
57 * @throws CiviCRM_API3_Exception
59 function contributioncancelactions_cancel_related_pending_participant_records($contributionID): void
{
60 $pendingStatuses = CRM_Event_PseudoConstant
::participantStatus(NULL, "class = 'Pending'");
61 $waitingStatuses = CRM_Event_PseudoConstant
::participantStatus(NULL, "class = 'Waiting'");
62 $cancellableParticipantRecords = civicrm_api3('ParticipantPayment', 'get', [
63 'contribution_id' => $contributionID,
64 'participant_id.status_id' => ['IN' => array_merge(array_keys($pendingStatuses), array_keys($waitingStatuses))],
66 if (empty($cancellableParticipantRecords)) {
69 Participant
::update(FALSE)
70 ->addWhere('id', 'IN', array_keys($cancellableParticipantRecords))
71 ->setValues(['status_id:name' => 'Cancelled'])
76 * Find and cancel any pending memberships.
78 * @param int $contributionID
79 * @throws API_Exception
80 * @throws CiviCRM_API3_Exception
82 function contributioncancelactions_cancel_related_pending_memberships($contributionID): void
{
83 $connectedMemberships = (array) LineItem
::get(FALSE)->setWhere([
84 ['contribution_id', '=', $contributionID],
85 ['entity_table', '=', 'civicrm_membership'],
86 ])->execute()->indexBy('entity_id');
88 if (empty($connectedMemberships)) {
91 // @todo we don't have v4 membership api yet so v3 for now.
92 $connectedMemberships = array_keys(civicrm_api3('Membership', 'get', [
93 'status_id' => 'Pending',
94 'id' => ['IN' => array_keys($connectedMemberships)],
96 if (empty($connectedMemberships)) {
99 foreach ($connectedMemberships as $membershipID) {
100 civicrm_api3('Membership', 'create', ['status_id' => 'Cancelled', 'id' => $membershipID, 'is_override' => 1]);