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