PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 3.19.4
GiveWP – Donation Plugin and Fundraising Platform v3.19.4
4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / src / DonorDashboards / Repositories / Donations.php
give / src / DonorDashboards / Repositories Last commit date
Donations.php 3 years ago
Donations.php
445 lines
1 <?php
2
3 namespace Give\DonorDashboards\Repositories;
4
5 use Give\Framework\Database\DB;
6 use Give\Receipt\DonationReceipt;
7 use Give\Receipt\LineItem;
8 use Give\ValueObjects\Money;
9 use Give_Payment;
10
11 /**
12 * @since 2.10.0
13 */
14 class Donations
15 {
16 /**
17 * Get donations count for donor
18 *
19 * @since 2.10.0
20 *
21 * @param int $donorId
22 *
23 * @return int
24 */
25 public function getDonationCount($donorId)
26 {
27 $aggregate = $this->getDonationAggregate('count(revenue.id)', $donorId);
28
29 return $aggregate ? $aggregate->result : null;
30 }
31
32 /**
33 * Get donor revenue
34 *
35 * @since 2.10.0
36 *
37 * @param int $donorId
38 *
39 * @return string
40 */
41 public function getRevenue($donorId)
42 {
43 $currencyCode = give_get_option('currency');
44 $aggregate = $this->getDonationAggregate('sum(revenue.amount)', $donorId);
45
46 return $aggregate ?
47 $this->getAmountWithSeparators(
48 Money::ofMinor($aggregate->result, $currencyCode)->getAmount(),
49 $currencyCode
50 ) :
51 null;
52 }
53
54 /**
55 * Get average donor revenue
56 *
57 * @since 2.10.0
58 *
59 * @param int $donorId
60 *
61 * @return string
62 */
63 public function getAverageRevenue($donorId)
64 {
65 $currencyCode = give_get_option('currency');
66 $aggregate = $this->getDonationAggregate('avg(revenue.amount)', $donorId);
67
68 return $aggregate ?
69 $this->getAmountWithSeparators(
70 Money::ofMinor($aggregate->result, $currencyCode)->getAmount(),
71 $currencyCode
72 ) :
73 null;
74 }
75
76 /**
77 * Generates a donation aggregate for a given donor
78 *
79 * @param string $rawAggregate raw SELECT to determine what to aggregate over
80 * @param int $donorId
81 *
82 * @return object
83 */
84 private function getDonationAggregate($rawAggregate, $donorId)
85 {
86 global $wpdb;
87
88 return DB::get_row(
89 DB::prepare(
90 "
91 SELECT {$rawAggregate} as result
92 FROM {$wpdb->give_revenue} as revenue
93 INNER JOIN {$wpdb->posts} as posts ON revenue.donation_id = posts.ID
94 INNER JOIN {$wpdb->prefix}give_donationmeta as donationmeta ON revenue.donation_id = donationmeta.donation_id
95 WHERE donationmeta.meta_key = '_give_payment_donor_id'
96 AND donationmeta.meta_value = %d
97 AND posts.post_status IN ( 'publish', 'give_subscription', 'pending' )
98 ",
99 $donorId
100 )
101 );
102 }
103
104 /**
105 * Get all donation ids by donor ID
106 *
107 * @since 2.10.0
108 *
109 * @param int $donorId
110 *
111 * @return int[] Donation IDs
112 */
113 protected function getDonationIDs($donorId)
114 {
115 $statusKeys = give_get_payment_status_keys();
116 $statusQuery = "'" . implode("','", $statusKeys) . "'";
117
118 global $wpdb;
119
120 return DB::get_col(
121 DB::prepare(
122 "
123 SELECT revenue.donation_id as id
124 FROM {$wpdb->give_revenue} as revenue
125 INNER JOIN {$wpdb->posts} as posts ON revenue.donation_id = posts.ID
126 INNER JOIN {$wpdb->prefix}give_donationmeta as donationmeta ON revenue.donation_id = donationmeta.donation_id
127 WHERE donationmeta.meta_key = '_give_payment_donor_id'
128 AND donationmeta.meta_value = %d
129 AND posts.post_status IN ( {$statusQuery} )
130 ",
131 $donorId
132 )
133 );
134 }
135
136 /**
137 * Get all donations by donor ID
138 *
139 * @since 2.12.2 return null if donation ids is empty
140 * @since 2.10.0
141 *
142 * @param int $donorId
143 *
144 * @return array Donations
145 */
146 public function getDonations($donorId)
147 {
148 $ids = $this->getDonationIds($donorId);
149
150 if (empty($ids)) {
151 return null;
152 }
153
154 $args = [
155 'number' => -1,
156 'post__in' => $ids,
157 ];
158
159 $query = new \Give_Payments_Query($args);
160 $payments = $query->get_payments();
161
162 $donations = [];
163 foreach ($payments as $payment) {
164 $donations[] = [
165 'id' => $payment->ID,
166 'form' => $this->getFormInfo($payment),
167 'payment' => $this->getPaymentInfo($payment),
168 'donor' => $this->getDonorInfo($payment),
169 'receipt' => $this->getReceiptInfo($payment),
170 ];
171 }
172
173 return $donations;
174 }
175
176 /**
177 * Get form info
178 *
179 * @since 2.10.0
180 *
181 * @param Give_Payment $payment
182 *
183 * @return array Payment form info
184 */
185 protected function getFormInfo($payment)
186 {
187 return [
188 'title' => wp_trim_words($payment->form_title, 6, ' [...]'),
189 'id' => $payment->form_id,
190 ];
191 }
192
193 /**
194 * Get payment info
195 *
196 * @since 2.10.0
197 * @since 2.15.0 Use WP time format for donation time.
198 *
199 * @param Give_Payment $payment
200 *
201 * @return array Payment info
202 */
203 protected function getPaymentInfo($payment)
204 {
205 $pdfReceiptUrl = '';
206 if (class_exists('Give_PDF_Receipts') && function_exists('give_pdf_receipts')) {
207 $pdfReceiptUrl = html_entity_decode(give_pdf_receipts()->engine->get_pdf_receipt_url($payment->ID));
208 }
209
210 $gateways = give_get_payment_gateways();
211
212 return [
213 'amount' => $this->getFormattedAmount($payment->subtotal, $payment),
214 'currency' => $payment->currency,
215 'fee' => $this->getFormattedAmount(($payment->total - $payment->subtotal), $payment),
216 'total' => $this->getFormattedAmount($payment->total, $payment),
217 'method' => isset($gateways[$payment->gateway]['checkout_label']) ? $gateways[$payment->gateway]['checkout_label'] : '',
218 'status' => $this->getFormattedStatus($payment->status),
219 'date' => date_i18n(give_date_format('checkout'), strtotime($payment->date)),
220 'time' => date_i18n(get_option('time_format'), strtotime($payment->date)),
221 'mode' => $payment->get_meta('_give_payment_mode'),
222 'pdfReceiptUrl' => $pdfReceiptUrl,
223 'serialCode' => give_is_setting_enabled(give_get_option('sequential-ordering_status', 'disabled'))
224 ? Give()->seq_donation_number->get_serial_code($payment)
225 : $payment->ID,
226 ];
227 }
228
229 /**
230 * Get array containing dynamic receipt information
231 *
232 * @since 2.25.0 replace wp_strip_all_tags with wp_kses_post
233 * @since 2.10.0
234 *
235 * @param Give_Payment $payment
236 *
237 * @return array
238 */
239 protected function getReceiptInfo($payment)
240 {
241 $receipt = new DonationReceipt($payment->ID);
242
243 /**
244 * Fire the action for receipt object.
245 *
246 * @since 2.7.0
247 */
248 do_action('give_new_receipt', $receipt);
249
250 $receiptArr = [];
251
252 $sectionIndex = 0;
253 foreach ($receipt as $section) {
254 // Continue if section does not have line items.
255 if ( ! $section->getLineItems()) {
256 continue;
257 }
258
259 if ('PDFReceipt' === $section->id) {
260 continue;
261 }
262
263 if ('Subscription' === $section->id) {
264 continue;
265 }
266
267 $receiptArr[$sectionIndex]['id'] = $section->id;
268
269 if ($section->label) {
270 $receiptArr[$sectionIndex]['label'] = $section->label;
271 }
272
273 /* @var LineItem $lineItem */
274 foreach ($section as $lineItem) {
275 // Continue if line item does not have value.
276 if ( ! $lineItem->value) {
277 continue;
278 }
279
280 // This class is required to highlight total donation amount in receipt.
281 $detailRowClass = '';
282 if (DonationReceipt::DONATIONSECTIONID === $section->id) {
283 $detailRowClass = 'totalAmount' === $lineItem->id ? ' total' : '';
284 }
285
286 $label = html_entity_decode(wp_strip_all_tags($lineItem->label));
287 $value = $lineItem->id === 'paymentStatus'
288 ? $this->getFormattedStatus($payment->status)
289 : html_entity_decode(wp_kses_post($lineItem->value));
290
291 $receiptArr[$sectionIndex]['lineItems'][] = [
292 'class' => $detailRowClass,
293 'icon' => $this->getIcon($lineItem->icon),
294 'label' => $label,
295 'value' => $value,
296 ];
297 }
298
299 $sectionIndex++;
300 }
301
302 return $receiptArr;
303 }
304
305 /**
306 * Get icon based on icon HTML string
307 *
308 * @since 2.10.0
309 *
310 * @param string $iconHtml
311 *
312 * @return string
313 */
314 protected function getIcon($iconHtml)
315 {
316 if (empty($iconHtml)) {
317 return '';
318 }
319
320 $iconMap = [
321 'user',
322 'envelope',
323 'globe',
324 'calendar',
325 'building',
326 ];
327
328 foreach ($iconMap as $icon) {
329 if (strpos($iconHtml, $icon) !== false) {
330 return $icon;
331 }
332 }
333
334 return 'globe';
335 }
336
337 /**
338 * Get formatted status object (used for rendering status correctly in Donor Profile)
339 *
340 * @since 2.10.0
341 *
342 * @param string $status
343 *
344 * @return array Formatted status object (with color and label)
345 */
346 protected function getFormattedStatus($status)
347 {
348 $statusMap = [];
349
350 $colorMap = [
351 'publish' => '#7ad03a',
352 'give_subscription' => '#5bc0de',
353 'refunded' => '#777',
354 'failed' => '#a00',
355 'abandoned' => '#333',
356 'revoked' => '#d9534f',
357 'pending' => '#ffba00',
358 ];
359
360 foreach (give_get_payment_statuses() as $key => $value) {
361 if ($status !== $key) {
362 continue;
363 }
364
365 $color = '#888';
366 if (in_array($key, array_keys($colorMap))) {
367 $color = $colorMap[$key];
368 }
369
370 $statusMap[$key] = [
371 'color' => $color,
372 'label' => $value,
373 ];
374 }
375
376 return isset($statusMap[$status]) ? $statusMap[$status] : [
377 'color' => '#FFBA00',
378 'label' => esc_html__('Unknown', 'give'),
379 ];
380 }
381
382 /**
383 * @since 2.10.0
384 *
385 * @param string $amount
386 * @param string $currencyCode
387 *
388 * @return string
389 */
390 protected function getAmountWithSeparators($amount, $currencyCode)
391 {
392 $formatted = give_format_amount(
393 $amount,
394 [
395 'decimal' => false,
396 'sanitize' => false,
397 'currency' => $currencyCode,
398 ]
399 );
400
401 return $formatted ?: $amount;
402 }
403
404 /**
405 * Get formatted payment amount
406 *
407 * @since 2.10.0
408 *
409 * @param Give_Payment $payment
410 * @param float $amount
411 *
412 * @return string Formatted payment amount (with correct decimals and currency symbol)
413 */
414 protected function getformattedAmount($amount, $payment)
415 {
416 return give_currency_filter(
417 give_format_amount(
418 $amount,
419 [
420 'donation_id' => $payment->ID,
421 ]
422 ),
423 [
424 'currency_code' => $payment->currency,
425 'decode_currency' => true,
426 'sanitize' => false,
427 ]
428 );
429 }
430
431 /**
432 * Get donor info
433 *
434 * @since 2.10.0
435 *
436 * @param Give_Payment $payment
437 *
438 * @return array Donor info
439 */
440 protected function getDonorInfo($payment)
441 {
442 return $payment->user_info;
443 }
444 }
445