PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 2.23.2
GiveWP – Donation Plugin and Fundraising Platform v2.23.2
4.16.4 4.16.3 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
444 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.10.0
233 *
234 * @param Give_Payment $payment
235 *
236 * @return array
237 */
238 protected function getReceiptInfo($payment)
239 {
240 $receipt = new DonationReceipt($payment->ID);
241
242 /**
243 * Fire the action for receipt object.
244 *
245 * @since 2.7.0
246 */
247 do_action('give_new_receipt', $receipt);
248
249 $receiptArr = [];
250
251 $sectionIndex = 0;
252 foreach ($receipt as $section) {
253 // Continue if section does not have line items.
254 if ( ! $section->getLineItems()) {
255 continue;
256 }
257
258 if ('PDFReceipt' === $section->id) {
259 continue;
260 }
261
262 if ('Subscription' === $section->id) {
263 continue;
264 }
265
266 $receiptArr[$sectionIndex]['id'] = $section->id;
267
268 if ($section->label) {
269 $receiptArr[$sectionIndex]['label'] = $section->label;
270 }
271
272 /* @var LineItem $lineItem */
273 foreach ($section as $lineItem) {
274 // Continue if line item does not have value.
275 if ( ! $lineItem->value) {
276 continue;
277 }
278
279 // This class is required to highlight total donation amount in receipt.
280 $detailRowClass = '';
281 if (DonationReceipt::DONATIONSECTIONID === $section->id) {
282 $detailRowClass = 'totalAmount' === $lineItem->id ? ' total' : '';
283 }
284
285 $label = html_entity_decode(wp_strip_all_tags($lineItem->label));
286 $value = $lineItem->id === 'paymentStatus' ? $this->getFormattedStatus(
287 $payment->status
288 ) : html_entity_decode(wp_strip_all_tags($lineItem->value));
289
290 $receiptArr[$sectionIndex]['lineItems'][] = [
291 'class' => $detailRowClass,
292 'icon' => $this->getIcon($lineItem->icon),
293 'label' => $label,
294 'value' => $value,
295 ];
296 }
297
298 $sectionIndex++;
299 }
300
301 return $receiptArr;
302 }
303
304 /**
305 * Get icon based on icon HTML string
306 *
307 * @since 2.10.0
308 *
309 * @param string $iconHtml
310 *
311 * @return string
312 */
313 protected function getIcon($iconHtml)
314 {
315 if (empty($iconHtml)) {
316 return '';
317 }
318
319 $iconMap = [
320 'user',
321 'envelope',
322 'globe',
323 'calendar',
324 'building',
325 ];
326
327 foreach ($iconMap as $icon) {
328 if (strpos($iconHtml, $icon) !== false) {
329 return $icon;
330 }
331 }
332
333 return 'globe';
334 }
335
336 /**
337 * Get formatted status object (used for rendering status correctly in Donor Profile)
338 *
339 * @since 2.10.0
340 *
341 * @param string $status
342 *
343 * @return array Formatted status object (with color and label)
344 */
345 protected function getFormattedStatus($status)
346 {
347 $statusMap = [];
348
349 $colorMap = [
350 'publish' => '#7ad03a',
351 'give_subscription' => '#5bc0de',
352 'refunded' => '#777',
353 'failed' => '#a00',
354 'abandoned' => '#333',
355 'revoked' => '#d9534f',
356 'pending' => '#ffba00',
357 ];
358
359 foreach (give_get_payment_statuses() as $key => $value) {
360 if ($status !== $key) {
361 continue;
362 }
363
364 $color = '#888';
365 if (in_array($key, array_keys($colorMap))) {
366 $color = $colorMap[$key];
367 }
368
369 $statusMap[$key] = [
370 'color' => $color,
371 'label' => $value,
372 ];
373 }
374
375 return isset($statusMap[$status]) ? $statusMap[$status] : [
376 'color' => '#FFBA00',
377 'label' => esc_html__('Unknown', 'give'),
378 ];
379 }
380
381 /**
382 * @since 2.10.0
383 *
384 * @param string $amount
385 * @param string $currencyCode
386 *
387 * @return string
388 */
389 protected function getAmountWithSeparators($amount, $currencyCode)
390 {
391 $formatted = give_format_amount(
392 $amount,
393 [
394 'decimal' => false,
395 'sanitize' => false,
396 'currency' => $currencyCode,
397 ]
398 );
399
400 return $formatted ?: $amount;
401 }
402
403 /**
404 * Get formatted payment amount
405 *
406 * @since 2.10.0
407 *
408 * @param Give_Payment $payment
409 * @param float $amount
410 *
411 * @return string Formatted payment amount (with correct decimals and currency symbol)
412 */
413 protected function getformattedAmount($amount, $payment)
414 {
415 return give_currency_filter(
416 give_format_amount(
417 $amount,
418 [
419 'donation_id' => $payment->ID,
420 ]
421 ),
422 [
423 'currency_code' => $payment->currency,
424 'decode_currency' => true,
425 'sanitize' => false,
426 ]
427 );
428 }
429
430 /**
431 * Get donor info
432 *
433 * @since 2.10.0
434 *
435 * @param Give_Payment $payment
436 *
437 * @return array Donor info
438 */
439 protected function getDonorInfo($payment)
440 {
441 return $payment->user_info;
442 }
443 }
444