3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
12 use Civi\Api4\Contribution
;
17 * @copyright CiviCRM LLC https://civicrm.org/licensing
21 * This class generates form components for Payment-Instrument.
23 class CRM_Contribute_Form_ContributionView
extends CRM_Core_Form
{
26 * Set variables up before form is built.
28 * @throws \CRM_Core_Exception
29 * @throws \API_Exception
31 public function preProcess() {
34 // Check permission for action.
35 if (!CRM_Core_Permission
::checkActionPermission('CiviContribute', $this->_action
)) {
36 CRM_Core_Error
::statusBounce(ts('You do not have permission to access this page.'));
38 $params = ['id' => $id];
39 $context = CRM_Utils_Request
::retrieve('context', 'Alphanumeric', $this);
40 $this->assign('context', $context);
42 // Note than this get could be restricted by ACLs in an extension
43 $contribution = Contribution
::get(TRUE)->addWhere('id', '=', $id)->addSelect('*')->execute()->first();
44 if (empty($contribution)) {
45 CRM_Core_Error
::statusBounce(ts('Access to contribution not permitted'));
47 // We just cast here because it was traditionally an array called values - would be better
48 // just to use 'contribution'.
49 $values = (array) $contribution;
50 $contributionStatus = CRM_Core_PseudoConstant
::getName('CRM_Contribute_BAO_Contribution', 'contribution_status_id', $values['contribution_status_id']);
52 if (!isset($this->get_template_vars()['hookDiscount'])) {
53 $this->assign('hookDiscount', ['message' => '']);
55 $this->addExpectedSmartyVariables([
56 'pricesetFieldsCount',
59 // currencySymbol maybe doesn't make sense but is probably old?
63 // @todo - it might have been better to create a new form that extends this
64 // for template contributions rather than overloading this form.
65 $force_create_template = CRM_Utils_Request
::retrieve('force_create_template', 'Boolean', $this, FALSE, FALSE);
66 if ($force_create_template && !empty($values['contribution_recur_id']) && empty($values['is_template'])) {
67 // Create a template contribution.
68 $templateContributionId = CRM_Contribute_BAO_ContributionRecur
::ensureTemplateContributionExists($values['contribution_recur_id']);
69 if (!empty($templateContributionId)) {
70 $id = $templateContributionId;
71 $params = ['id' => $id];
72 $values = CRM_Contribute_BAO_Contribution
::getValuesWithMappings($params);
75 $this->assign('is_template', $values['is_template']);
77 CRM_Contribute_BAO_Contribution
::resolveDefaults($values);
79 $values['contribution_page_title'] = '';
80 if (!empty($values['contribution_page_id'])) {
81 $contribPages = CRM_Contribute_PseudoConstant
::contributionPage(NULL, TRUE);
82 $values['contribution_page_title'] = CRM_Utils_Array
::value(CRM_Utils_Array
::value('contribution_page_id', $values), $contribPages);
85 // get received into i.e to_financial_account_id from last trxn
86 $financialTrxnId = CRM_Core_BAO_FinancialTrxn
::getFinancialTrxnId($this->getID(), 'DESC');
87 $values['to_financial_account'] = '';
88 $values['payment_processor_name'] = '';
89 if (!empty($financialTrxnId['financialTrxnId'])) {
90 $values['to_financial_account_id'] = CRM_Core_DAO
::getFieldValue('CRM_Financial_DAO_FinancialTrxn', $financialTrxnId['financialTrxnId'], 'to_financial_account_id');
91 if ($values['to_financial_account_id']) {
92 $values['to_financial_account'] = CRM_Contribute_PseudoConstant
::financialAccount($values['to_financial_account_id']);
94 $values['payment_processor_id'] = CRM_Core_DAO
::getFieldValue('CRM_Financial_DAO_FinancialTrxn', $financialTrxnId['financialTrxnId'], 'payment_processor_id');
95 if ($values['payment_processor_id']) {
96 $values['payment_processor_name'] = CRM_Core_DAO
::getFieldValue('CRM_Financial_DAO_PaymentProcessor', $values['payment_processor_id'], 'name');
100 if (!empty($values['contribution_recur_id'])) {
101 $sql = "SELECT installments, frequency_interval, frequency_unit FROM civicrm_contribution_recur WHERE id = %1";
102 $params = [1 => [$values['contribution_recur_id'], 'Integer']];
103 $dao = CRM_Core_DAO
::executeQuery($sql, $params);
105 $values['recur_installments'] = $dao->installments
;
106 $values['recur_frequency_unit'] = $dao->frequency_unit
;
107 $values['recur_frequency_interval'] = $dao->frequency_interval
;
112 $participantLineItems = \Civi\Api4\LineItem
::get()
113 ->addSelect('entity_id', 'participant.role_id:label', 'participant.fee_level', 'participant.contact_id', 'contact.display_name')
114 ->addJoin('Participant AS participant', 'LEFT', ['participant.id', '=', 'entity_id'])
115 ->addJoin('Contact AS contact', 'LEFT', ['contact.id', '=', 'participant.contact_id'])
116 ->addWhere('entity_table', '=', 'civicrm_participant')
117 ->addWhere('contribution_id', '=', $id)
120 catch (API_Exception
$e) {
121 // likely don't have permission for events/participants
122 $participantLineItems = [];
125 $associatedParticipants = FALSE;
126 foreach ($participantLineItems as $participant) {
127 $associatedParticipants[] = [
128 'participantLink' => CRM_Utils_System
::url('civicrm/contact/view/participant',
129 "action=view&reset=1&id={$participant['entity_id']}&cid={$participant['participant.contact_id']}&context=home"
131 'participantName' => $participant['contact.display_name'],
132 'fee' => implode(', ', $participant['participant.fee_level']),
133 'role' => implode(', ', $participant['participant.role_id:label']),
136 $this->assign('associatedParticipants', $associatedParticipants);
138 $groupTree = CRM_Core_BAO_CustomGroup
::getTree('Contribution', NULL, $id, 0, $values['financial_type_id'] ??
NULL,
139 NULL, TRUE, NULL, FALSE, CRM_Core_Permission
::VIEW
);
140 CRM_Core_BAO_CustomGroup
::buildCustomDataView($this, $groupTree, FALSE, NULL, NULL, NULL, $id);
143 $dao = new CRM_Contribute_DAO_ContributionProduct();
144 $dao->contribution_id
= $id;
145 if ($dao->find(TRUE)) {
146 $premiumId = $dao->id
;
147 $productID = $dao->product_id
;
150 $this->assign('premium', '');
152 $productDAO = new CRM_Contribute_DAO_Product();
153 $productDAO->id
= $productID;
154 $productDAO->find(TRUE);
156 $this->assign('premium', $productDAO->name
);
157 $this->assign('option', $dao->product_option
);
158 $this->assign('fulfilled', $dao->fulfilled_date
);
162 $noteValue = CRM_Core_BAO_Note
::getNote(CRM_Utils_Array
::value('id', $values), 'civicrm_contribution');
163 $values['note'] = array_values($noteValue);
165 // show billing address location details, if exists
166 $values['billing_address'] = '';
167 if (!empty($values['address_id'])) {
168 $addressParams = ['id' => $values['address_id']];
169 $addressDetails = CRM_Core_BAO_Address
::getValues($addressParams, FALSE, 'id');
170 $addressDetails = array_values($addressDetails);
171 $values['billing_address'] = $addressDetails[0]['display'];
174 //assign soft credit record if exists.
175 $SCRecords = CRM_Contribute_BAO_ContributionSoft
::getSoftContribution($this->getID(), TRUE);
176 $this->assign('softContributions', empty($SCRecords['soft_credit']) ?
NULL : $SCRecords['soft_credit']);
177 // unset doesn't complain if array member missing
178 unset($SCRecords['soft_credit']);
179 foreach ($SCRecords as $name => $value) {
180 $this->assign($name, $value);
183 $lineItems = [CRM_Price_BAO_LineItem
::getLineItemsByContributionID(($id))];
184 $this->assign('lineItem', $lineItems);
185 $values['totalAmount'] = $values['total_amount'];
186 $this->assign('displayLineItemFinancialType', TRUE);
188 //do check for campaigns
189 $values['campaign'] = '';
190 if ($campaignId = CRM_Utils_Array
::value('campaign_id', $values)) {
191 $campaigns = CRM_Campaign_BAO_Campaign
::getCampaigns($campaignId);
192 $values['campaign'] = $campaigns[$campaignId];
194 if ($contributionStatus === 'Refunded') {
195 $this->assign('refund_trxn_id', CRM_Core_BAO_FinancialTrxn
::getRefundTransactionTrxnID($id));
198 // assign values to the template
199 $this->assignVariables($values, array_keys($values));
200 $invoicing = CRM_Invoicing_Utils
::isInvoicingEnabled();
201 $this->assign('invoicing', $invoicing);
202 $this->assign('isDeferred', Civi
::settings()->get('deferred_revenue_enabled'));
203 if ($invoicing && isset($values['tax_amount'])) {
204 $this->assign('totalTaxAmount', $values['tax_amount']);
207 // omitting contactImage from title for now since the summary overlay css doesn't work outside of our crm-container
208 $displayName = CRM_Contact_BAO_Contact
::displayName($values['contact_id']);
209 $this->assign('displayName', $displayName);
210 // Check if this is default domain contact CRM-10482
211 if (CRM_Contact_BAO_Contact
::checkDomainContact($values['contact_id'])) {
212 $displayName .= ' (' . ts('default organization') . ')';
215 if (empty($values['is_template'])) {
216 $this->setTitle(ts('View Contribution from') . ' ' . $displayName);
219 $this->setTitle(ts('View Template Contribution from') . ' ' . $displayName);
222 // add viewed contribution to recent items list
223 $url = CRM_Utils_System
::url('civicrm/contact/view/contribution',
224 "action=view&reset=1&id={$values['id']}&cid={$values['contact_id']}&context=home"
227 $title = $displayName . ' - (' . CRM_Utils_Money
::format($values['total_amount'], $values['currency']) . ' ' . ' - ' . $values['financial_type'] . ')';
230 if (CRM_Core_Permission
::checkActionPermission('CiviContribute', CRM_Core_Action
::UPDATE
)) {
231 $recentOther['editUrl'] = CRM_Utils_System
::url('civicrm/contact/view/contribution',
232 "action=update&reset=1&id={$values['id']}&cid={$values['contact_id']}&context=home"
235 if (CRM_Core_Permission
::checkActionPermission('CiviContribute', CRM_Core_Action
::DELETE
)) {
236 $recentOther['deleteUrl'] = CRM_Utils_System
::url('civicrm/contact/view/contribution',
237 "action=delete&reset=1&id={$values['id']}&cid={$values['contact_id']}&context=home"
240 CRM_Utils_Recent
::add($title,
244 $values['contact_id'],
248 $statusOptionValueNames = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'name');
249 $contributionStatus = $statusOptionValueNames[$values['contribution_status_id']];
250 $this->assign('addRecordPayment', in_array($contributionStatus, ['Partially paid', 'Pending refund', 'Pending']));
251 $this->assignPaymentInfoBlock($id);
254 if ($this->controller
->_key
) {
255 $searchKey = $this->controller
->_key
;
258 if ($this->isHasAccess('update')) {
259 $urlParams = "reset=1&id={$id}&cid={$values['contact_id']}&action=update&context={$context}";
260 if (($context === 'fulltext' ||
$context === 'search') && $searchKey) {
261 $urlParams = "reset=1&id={$id}&cid={$values['contact_id']}&action=update&context={$context}&key={$searchKey}";
263 if (!$contribution['is_template']) {
264 foreach (CRM_Contribute_BAO_Contribution
::getContributionPaymentLinks($this->getID(), $contributionStatus) as $paymentButton) {
265 $paymentButton['icon'] = 'fa-plus-circle';
266 $linkButtons[] = $paymentButton;
270 'title' => ts('Edit'),
271 'url' => 'civicrm/contact/view/contribution',
273 'icon' => 'fa-pencil',
281 if ($this->isHasAccess('delete')) {
282 $urlParams = "reset=1&id={$id}&cid={$values['contact_id']}&action=delete&context={$context}";
283 if (($context === 'fulltext' ||
$context === 'search') && $searchKey) {
284 $urlParams = "reset=1&id={$id}&cid={$values['contact_id']}&action=delete&context={$context}&key={$searchKey}";
287 'title' => ts('Delete'),
288 'url' => 'civicrm/contact/view/contribution',
290 'icon' => 'fa-trash',
298 $pdfUrlParams = "reset=1&id={$id}&cid={$values['contact_id']}";
299 $emailUrlParams = "reset=1&id={$id}&cid={$values['contact_id']}&select=email";
300 if (Civi
::settings()->get('invoicing') && !$contribution['is_template']) {
301 if (($values['contribution_status'] !== 'Refunded') && ($values['contribution_status'] !== 'Cancelled')) {
302 $invoiceButtonText = ts('Download Invoice');
305 $invoiceButtonText = ts('Download Invoice and Credit Note');
308 'title' => $invoiceButtonText,
309 'url' => 'civicrm/contribute/invoice',
310 'qs' => $pdfUrlParams,
311 'icon' => 'fa-download',
314 'title' => ts('Email Invoice'),
315 'url' => 'civicrm/contribute/invoice/email',
316 'qs' => $emailUrlParams,
317 'icon' => 'fa-paper-plane',
320 $this->assign('linkButtons', $linkButtons ??
[]);
321 // These next 3 parameters are used to construct a url in PaymentInfo.tpl
322 $this->assign('contactId', $values['contact_id']);
323 $this->assign('componentId', $id);
324 $this->assign('component', 'contribution');
325 $this->assignPaymentInfoBlock($id);
329 * Build the form object.
331 public function buildQuickForm() {
335 'name' => ts('Done'),
336 'spacing' => ' ',
343 * Assign the values to build the payment info block.
345 * @todo - this is a bit too much copy & paste from AbstractEditPayment
346 * (justifying on the basis it's 'pretty short' and in a different inheritance
347 * tree. I feel like traits are probably the longer term answer).
354 protected function assignPaymentInfoBlock($id) {
355 // component is used in getPaymentInfo primarily to retrieve the contribution id, we
356 // already have that.
357 $paymentInfo = CRM_Contribute_BAO_Contribution
::getPaymentInfo($id, 'contribution', TRUE);
358 $title = ts('View Payment');
359 $this->assign('transaction', TRUE);
360 $this->assign('payments', $paymentInfo['transaction']);
361 $this->assign('paymentLinks', $paymentInfo['payment_links']);
366 * @param string $action
370 private function isHasAccess(string $action): bool {
372 return Contribution
::checkAccess()
374 ->addValue('id', $this->getID())
375 ->execute()->first()['access'];
377 catch (API_Exception
$e) {
383 * Get the contribution ID.
387 private function getID(): int {
388 $id = $this->get('id');
390 CRM_Core_Error
::statusBounce('Contribution ID is required');