excludesFromSales($donation)) { return; } $tickets = give(EventTicketRepository::class)->queryByDonationId($donation->id)->getAll() ?? []; // Each delete() runs in its own transaction (matches the per-row transaction style elsewhere // in EventTicketRepository); a mid-loop failure can leave a release partially applied. foreach ($tickets as $ticket) { $ticket->delete(); // The ticket row is gone after delete(), so the note carries its identifying details // itself rather than a ticket ID nothing will resolve afterward. DonationNote::create([ 'donationId' => $donation->id, 'content' => sprintf( /* translators: 1: event ID, 2: ticket type ID, 3: donation status */ __('Event ticket released (event #%1$d, ticket type #%2$d) because the donation status changed to "%3$s".', 'give'), $ticket->eventId, $ticket->ticketTypeId, $donation->status->label() ), ]); } } /** * @since 4.16.8.1 */ private function excludesFromSales(Donation $donation): bool { $status = $donation->status; return $status->isCancelled() || $status->isRefunded() || $status->isFailed() || $status->isAbandoned() || $status->isRevoked(); } }