Passed
Pull Request — 3.3.x (#95)
by Mario
04:11
created

transactions_controller::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 44
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 23
nc 1
nop 18
dl 0
loc 44
rs 9.552
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
/**
3
 *
4
 * PayPal Donation extension for the phpBB Forum Software package.
5
 *
6
 * @copyright (c) 2015-2020 Skouat
7
 * @license GNU General Public License, version 2 (GPL-2.0)
8
 *
9
 */
10
11
namespace skouat\ppde\controller\admin;
12
13
use phpbb\auth\auth;
14
use phpbb\config\config;
15
use phpbb\language\language;
16
use phpbb\log\log;
17
use phpbb\request\request;
18
use phpbb\template\template;
19
use phpbb\user;
20
use phpbb\user_loader;
21
use skouat\ppde\actions\core;
22
use skouat\ppde\actions\currency;
23
use skouat\ppde\exception\transaction_exception;
24
use skouat\ppde\operators\transactions;
25
use Symfony\Component\DependencyInjection\ContainerInterface;
26
27
/**
28
 * @property array              args               Array of args for hidden fiels
29
 * @property config             config             Config object
30
 * @property ContainerInterface container          Service container interface
31
 * @property string             id_prefix_name     Prefix name for identifier in the URL
32
 * @property string             lang_key_prefix    Prefix for the messages thrown by exceptions
33
 * @property language           language           Language user object
34
 * @property log                log                The phpBB log system.
35
 * @property string             module_name        Name of the module currently used
36
 * @property request            request            Request object.
37
 * @property bool               submit             State of submit $_POST variable
38
 * @property template           template           Template object
39
 * @property string             u_action           Action URL
40
 * @property user               user               User object.
41
 * @property user_loader        user_loader        User loader object
42
 */
43
class transactions_controller extends admin_main
44
{
45
	public $ppde_operator;
46
	protected $adm_relative_path;
47
	protected $auth;
48
	protected $user_loader;
49
	protected $entry_count;
50
	protected $last_page_offset;
51
	protected $php_ext;
52
	protected $phpbb_admin_path;
53
	protected $phpbb_root_path;
54
	protected $ppde_actions;
55
	protected $ppde_actions_currency;
56
	protected $ppde_entity;
57
	protected $table_prefix;
58
	protected $table_ppde_transactions;
59
60
	/**
61
	 * Constructor
62
	 *
63
	 * @param auth                             $auth                       Authentication object
64
	 * @param config                           $config                     Config object
65
	 * @param ContainerInterface               $container                  Service container interface
66
	 * @param language                         $language                   Language user object
67
	 * @param log                              $log                        The phpBB log system
68
	 * @param core                             $ppde_actions               PPDE actions object
69
	 * @param currency                         $ppde_actions_currency      PPDE currency actions object
70
	 * @param \skouat\ppde\entity\transactions $ppde_entity_transactions   Entity object
71
	 * @param transactions                     $ppde_operator_transactions Operator object
72
	 * @param request                          $request                    Request object
73
	 * @param template                         $template                   Template object
74
	 * @param user                             $user                       User object.
75
	 * @param user_loader                      $user_loader                User loader object
76
	 * @param string                           $adm_relative_path          phpBB admin relative path
77
	 * @param string                           $phpbb_root_path            phpBB root path
78
	 * @param string                           $php_ext                    phpEx
79
	 * @param string                           $table_prefix               The table prefix
80
	 * @param string                           $table_ppde_transactions    Name of the table used to store data
81
	 *
82
	 * @access public
83
	 */
84
	public function __construct(
85
		auth $auth,
86
		config $config,
87
		ContainerInterface $container,
88
		language $language,
89
		log $log,
90
		core $ppde_actions,
91
		currency $ppde_actions_currency,
92
		\skouat\ppde\entity\transactions $ppde_entity_transactions,
93
		transactions $ppde_operator_transactions,
94
		request $request,
95
		template $template,
96
		user $user,
97
		user_loader $user_loader,
98
		string $adm_relative_path,
99
		string $phpbb_root_path,
100
		string $php_ext,
101
		string $table_prefix,
102
		string $table_ppde_transactions
103
	)
104
	{
105
		$this->auth = $auth;
106
		$this->config = $config;
107
		$this->container = $container;
108
		$this->language = $language;
109
		$this->log = $log;
110
		$this->ppde_actions = $ppde_actions;
111
		$this->ppde_actions_currency = $ppde_actions_currency;
112
		$this->ppde_entity = $ppde_entity_transactions;
113
		$this->ppde_operator = $ppde_operator_transactions;
114
		$this->request = $request;
115
		$this->template = $template;
116
		$this->user = $user;
117
		$this->user_loader = $user_loader;
118
		$this->adm_relative_path = $adm_relative_path;
119
		$this->phpbb_admin_path = $phpbb_root_path . $adm_relative_path;
120
		$this->phpbb_root_path = $phpbb_root_path;
121
		$this->php_ext = $php_ext;
122
		$this->table_prefix = $table_prefix;
123
		$this->table_ppde_transactions = $table_ppde_transactions;
124
		parent::__construct(
125
			'transactions',
126
			'PPDE_DT',
127
			'transaction'
128
		);
129
	}
130
131
	/**
132
	 * {@inheritdoc}
133
	 */
134
	public function display(): void
135
	{
136
		/** @type \phpbb\pagination $pagination */
137
		$pagination = $this->container->get('pagination');
138
139
		// Sorting
140
		$limit_days = [
141
			0   => $this->language->lang('ALL_ENTRIES'),
142
			1   => $this->language->lang('1_DAY'),
143
			7   => $this->language->lang('7_DAYS'),
144
			14  => $this->language->lang('2_WEEKS'),
145
			30  => $this->language->lang('1_MONTH'),
146
			90  => $this->language->lang('3_MONTHS'),
147
			180 => $this->language->lang('6_MONTHS'),
148
			365 => $this->language->lang('1_YEAR'),
149
		];
150
		$sort_by_text = [
151
			'txn'      => $this->language->lang('PPDE_DT_SORT_TXN_ID'),
152
			'u'        => $this->language->lang('PPDE_DT_SORT_DONORS'),
153
			'ipn'      => $this->language->lang('PPDE_DT_SORT_IPN_STATUS'),
154
			'ipn_test' => $this->language->lang('PPDE_DT_SORT_IPN_TYPE'),
155
			'ps'       => $this->language->lang('PPDE_DT_SORT_PAYMENT_STATUS'),
156
			't'        => $this->language->lang('SORT_DATE'),
157
		];
158
		$sort_by_sql = [
159
			'txn'      => 'txn.txn_id',
160
			'u'        => 'u.username_clean',
161
			'ipn'      => 'txn.confirmed',
162
			'ipn_test' => 'txn.test_ipn',
163
			'ps'       => 'txn.payment_status',
164
			't'        => 'txn.payment_date',
165
		];
166
167
		$s_limit_days = $s_sort_key = $s_sort_dir = $u_sort_param = '';
168
		gen_sort_selects($limit_days, $sort_by_text, $this->args['hidden_fields']['st'], $this->args['hidden_fields']['sk'], $this->args['hidden_fields']['sd'], $s_limit_days, $s_sort_key, $s_sort_dir, $u_sort_param);
169
170
		// Define where and sort sql for use in displaying transactions
171
		$sql_where = ($this->args['hidden_fields']['st']) ? (time() - ($this->args['hidden_fields']['st'] * 86400)) : 0;
172
		$sql_sort = $sort_by_sql[$this->args['hidden_fields']['sk']] . ' ' . (($this->args['hidden_fields']['sd'] === 'd') ? 'DESC' : 'ASC');
173
174
		$keywords = $this->request->variable('keywords', '', true);
175
		$keywords_param = !empty($keywords) ? '&amp;keywords=' . urlencode(htmlspecialchars_decode($keywords)) : '';
176
177
		// Grab log data
178
		$log_data = [];
179
		$log_count = 0;
180
181
		$this->view_txn_log($log_data, $log_count, (int) $this->config['topics_per_page'], $this->args['hidden_fields']['start'], $sql_where, $sql_sort, $keywords);
182
183
		$base_url = $this->u_action . '&amp;' . $u_sort_param . $keywords_param;
184
		$pagination->generate_template_pagination($base_url, 'pagination', 'start', $log_count, (int) $this->config['topics_per_page'], $this->args['hidden_fields']['start']);
185
186
		$this->template->assign_vars([
187
			'S_CLEARLOGS'  => $this->auth->acl_get('a_ppde_manage'),
188
			'S_KEYWORDS'   => $keywords,
189
			'S_LIMIT_DAYS' => $s_limit_days,
190
			'S_SORT_KEY'   => $s_sort_key,
191
			'S_SORT_DIR'   => $s_sort_dir,
192
			'U_ACTION'     => $this->u_action . '&amp;' . $u_sort_param . $keywords_param . '&amp;start=' . $this->args['hidden_fields']['start'],
193
		]);
194
195
		array_map([$this, 'display_log_assign_template_vars'], $log_data);
196
	}
197
198
	/**
199
	 * View log
200
	 *
201
	 * @param array  &$log         The result array with the logs
202
	 * @param mixed  &$log_count   If $log_count is set to false, we will skip counting all entries in the
203
	 *                             database. Otherwise an integer with the number of total matching entries is returned.
204
	 * @param int     $limit       Limit the number of entries that are returned
205
	 * @param int     $offset      Offset when fetching the log entries, f.e. when paginating
206
	 * @param int     $limit_days
207
	 * @param string  $sort_by     SQL order option, e.g. 'l.log_time DESC'
208
	 * @param string  $keywords    Will only return log entries that have the keywords in log_operation or log_data
209
	 *
210
	 * @return int Returns the offset of the last valid page, if the specified offset was invalid (too high)
211
	 * @access private
212
	 */
213
	private function view_txn_log(&$log, &$log_count, $limit = 0, $offset = 0, $limit_days = 0, $sort_by = 'txn.payment_date DESC', $keywords = ''): int
214
	{
215
		$count_logs = ($log_count !== false);
216
217
		$log = $this->get_logs($count_logs, $limit, $offset, $limit_days, $sort_by, $keywords);
218
		$log_count = $this->get_log_count();
219
220
		return $this->get_valid_offset();
221
	}
222
223
	/**
224
	 * @param bool   $count_logs
225
	 * @param int    $limit
226
	 * @param int    $offset
227
	 * @param int    $log_time
228
	 * @param string $sort_by
229
	 * @param string $keywords
230
	 *
231
	 * @return array $log
232
	 * @access private
233
	 */
234
	private function get_logs($count_logs = true, $limit = 0, $offset = 0, $log_time = 0, $sort_by = 'txn.payment_date DESC', $keywords = ''): array
235
	{
236
		$this->entry_count = 0;
237
		$this->last_page_offset = $offset;
238
		$url_ary = [];
239
240
		if ($this->phpbb_admin_path && $this->ppde_actions->is_in_admin())
241
		{
242
			$url_ary['profile_url'] = append_sid($this->phpbb_admin_path . 'index.' . $this->php_ext, 'i=users&amp;mode=overview');
243
			$url_ary['txn_url'] = append_sid($this->phpbb_admin_path . 'index.' . $this->php_ext, 'i=-skouat-ppde-acp-ppde_module&amp;mode=transactions');
244
245
		}
246
		else
247
		{
248
			$url_ary['profile_url'] = append_sid($this->phpbb_root_path . 'memberlist.' . $this->php_ext, 'mode=viewprofile');
249
			$url_ary['txn_url'] = '';
250
		}
251
252
		$get_logs_sql_ary = $this->ppde_operator->get_logs_sql_ary($keywords, $sort_by, $log_time);
253
254
		if ($count_logs)
255
		{
256
			$this->entry_count = $this->ppde_operator->query_sql_count($get_logs_sql_ary, 'txn.transaction_id');
257
258
			if ($this->entry_count === 0)
259
			{
260
				// Save the queries, because there are no logs to display
261
				$this->last_page_offset = 0;
262
263
				return [];
264
			}
265
266
			// Return the user to the last page that is valid
267
			while ($this->last_page_offset >= $this->entry_count)
268
			{
269
				$this->last_page_offset = max(0, $this->last_page_offset - $limit);
270
			}
271
		}
272
273
		return $this->ppde_operator->build_log_ary($get_logs_sql_ary, $url_ary, $limit, $this->last_page_offset);
274
	}
275
276
	/**
277
	 * @return int
278
	 */
279
	public function get_log_count(): int
280
	{
281
		return (int) $this->entry_count ?: 0;
282
	}
283
284
	/**
285
	 * @return int
286
	 */
287
	public function get_valid_offset(): int
288
	{
289
		return (int) $this->last_page_offset ?: 0;
290
	}
291
292
	/**
293
	 * Gets vars from POST then build a array of them
294
	 *
295
	 * @param string $id     Module id
296
	 * @param string $mode   Module categorie
297
	 * @param string $action Action name
298
	 *
299
	 * @return void
300
	 * @access private
301
	 */
302
	public function set_hidden_fields($id, $mode, $action): void
303
	{
304
		$this->args['action'] = $action;
305
		$this->args['hidden_fields'] = [
306
			'start'     => $this->request->variable('start', 0),
307
			'delall'    => $this->request->variable('delall', false, false, \phpbb\request\request_interface::POST),
308
			'delmarked' => $this->request->variable('delmarked', false, false, \phpbb\request\request_interface::POST),
309
			'i'         => $id,
310
			'mark'      => $this->request->variable('mark', [0]),
311
			'mode'      => $mode,
312
			'st'        => $this->request->variable('st', 0),
313
			'sk'        => $this->request->variable('sk', 't'),
314
			'sd'        => $this->request->variable('sd', 'd'),
315
		];
316
317
		// Prepares args depending actions
318
		if (($this->args['hidden_fields']['delmarked'] || $this->args['hidden_fields']['delall']) && $this->auth->acl_get('a_ppde_manage'))
319
		{
320
			$this->args['action'] = 'delete';
321
		}
322
		else if ($this->request->is_set('approve'))
323
		{
324
			$this->args['action'] = 'approve';
325
			$this->args['hidden_fields'] = array_merge($this->args['hidden_fields'], [
326
				'approve'             => true,
327
				'id'                  => $this->request->variable('id', 0),
328
				'txn_errors_approved' => $this->request->variable('txn_errors_approved', 0),
329
			]);
330
		}
331
		else if ($this->request->is_set('add'))
332
		{
333
			$this->args['action'] = 'add';
334
		}
335
		else if ($this->request->is_set_post('change'))
336
		{
337
			$this->args['action'] = 'change';
338
		}
339
	}
340
341
	public function get_hidden_fields(): array
342
	{
343
		return array_merge(
344
			['i'                           => $this->args['hidden_fields']['i'],
345
			 'mode'                        => $this->args['hidden_fields']['mode'],
346
			 'action'                      => $this->args['action'],
347
			 $this->id_prefix_name . '_id' => $this->args[$this->id_prefix_name . '_id']],
348
			$this->args['hidden_fields']);
349
	}
350
351
	/**
352
	 * {@inheritdoc}
353
	 */
354
	public function change(): void
355
	{
356
		$username = $this->request->variable('username', '', true);
357
		$donor_id = $this->request->variable('donor_id', 0);
358
359
		try
360
		{
361
			$user_id = $this->validate_user_id($username, $donor_id);
362
		}
363
		catch (transaction_exception $e)
364
		{
365
			trigger_error(implode('<br>', $e->get_errors()) . adm_back_link($this->u_action), E_USER_WARNING);
366
		}
367
368
		// Request Identifier of the transaction
369
		$transaction_id = $this->request->variable('id', 0);
370
371
		$this->ppde_entity->load($transaction_id);
372
373
		if (!$this->ppde_entity->data_exists($this->ppde_entity->build_sql_data_exists()))
374
		{
375
			trigger_error($this->language->lang('PPDE_DT_NO_TRANSACTION') . adm_back_link($this->u_action), E_USER_WARNING);
376
		}
377
378
		$log_action = $this->ppde_entity
379
			->set_user_id($user_id)
380
			->add_edit_data()
381
		;
382
383
		$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_' . $this->lang_key_prefix . '_' . strtoupper($log_action));
384
		trigger_error($this->language->lang($this->lang_key_prefix . '_' . strtoupper($log_action)) . adm_back_link($this->u_action));
385
	}
386
387
	/**
388
	 * Returns the intended user ID
389
	 *
390
	 * @param string $username
391
	 * @param int    $donor_id
392
	 *
393
	 * @return int
394
	 * @throws transaction_exception
395
	 * @access private
396
	 */
397
	private function validate_user_id($username, $donor_id = 0): int
398
	{
399
		if (($username === '') && ($donor_id === ANONYMOUS || $this->request->is_set('u')))
400
		{
401
			return ANONYMOUS;
402
		}
403
404
		$user_id = ($username !== '') ? $this->user_loader->load_user_by_username($username) : $donor_id;
405
406
		if ($user_id <= ANONYMOUS)
407
		{
408
			throw (new transaction_exception())->set_errors([$this->language->lang('PPDE_MT_DONOR_NOT_FOUND')]);
409
		}
410
411
		return $user_id;
412
	}
413
414
	public function approve(): void
415
	{
416
		$transaction_id = (int) $this->args['hidden_fields']['id'];
417
		$txn_approved = empty($this->args['hidden_fields']['txn_errors_approved']);
418
419
		// Update DB record
420
		$this->ppde_entity->load($transaction_id);
421
		$this->ppde_entity->set_txn_errors_approved($txn_approved);
422
		$this->ppde_entity->save(false);
423
424
		// Prepare transaction settings before doing actions
425
		$transaction_data = $this->ppde_entity->get_data($this->ppde_operator->build_sql_data($transaction_id));
426
		$this->ppde_actions->set_transaction_data($transaction_data[0]);
427
		$this->ppde_actions->set_ipn_test_properties($this->ppde_entity->get_test_ipn());
428
		$this->ppde_actions->is_donor_is_member();
429
430
		if ($txn_approved)
431
		{
432
			$this->do_transactions_actions(!$this->ppde_actions->get_ipn_test() && $this->ppde_actions->get_donor_is_member());
433
		}
434
435
		$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_' . $this->lang_key_prefix . '_UPDATED', time());
436
	}
437
438
	/**
439
	 * Does actions for validated transaction
440
	 *
441
	 * @param bool $is_member
442
	 *
443
	 * @return void
444
	 * @access private
445
	 */
446
	private function do_transactions_actions($is_member): void
447
	{
448
		$this->ppde_actions->update_overview_stats();
449
		$this->ppde_actions->update_raised_amount();
450
451
		if ($is_member)
452
		{
453
			$this->ppde_actions->update_donor_stats();
454
			$this->ppde_actions->donors_group_user_add();
455
			$this->ppde_actions->notification->notify_donor_donation_received();
456
		}
457
	}
458
459
	/**
460
	 * {@inheritdoc}
461
	 */
462
	public function add(): void
463
	{
464
		$errors = [];
465
466
		$transaction_data = $this->request_transaction_vars();
467
468
		if ($this->request->is_set_post('submit'))
469
		{
470
			try
471
			{
472
				$this->ppde_actions->log_to_db($this->build_data_ary($transaction_data));
473
474
				// Prepare transaction settings before doing actions
475
				$this->ppde_actions->set_transaction_data($transaction_data);
476
				$this->ppde_actions->is_donor_is_member();
477
478
				$this->do_transactions_actions($this->ppde_actions->get_donor_is_member() && !$transaction_data['MT_ANONYMOUS']);
479
480
				$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_PPDE_MT_ADDED', time(), [$transaction_data['MT_USERNAME']]);
481
				trigger_error($this->language->lang('PPDE_MT_ADDED') . adm_back_link($this->u_action));
482
			}
483
			catch (transaction_exception $e)
484
			{
485
				$errors = $e->get_errors();
486
			}
487
		}
488
489
		$this->ppde_actions_currency->build_currency_select_menu((int) $this->config['ppde_default_currency']);
490
491
		$this->s_error_assign_template_vars($errors);
492
493
		$this->template->assign_vars($transaction_data);
494
495
		$this->template->assign_vars([
496
			'U_ACTION'             => $this->u_action,
497
			'U_BACK'               => $this->u_action,
498
			'S_ADD'                => true,
499
			'ANONYMOUS_USER_ID'    => ANONYMOUS,
500
			'U_FIND_USERNAME'      => append_sid($this->phpbb_root_path . 'memberlist.' . $this->php_ext, 'mode=searchuser&amp;form=manual_transaction&amp;field=username&amp;select_single=true'),
501
			'PAYMENT_TIME_FORMATS' => $this->get_payment_time_examples(),
502
		]);
503
	}
504
505
	/**
506
	 * Returns requested data from manual transaction form
507
	 *
508
	 * @return array
509
	 * @access private
510
	 */
511
	private function request_transaction_vars(): array
512
	{
513
		return [
514
			'MT_ANONYMOUS'          => $this->request->is_set('u'),
515
			'MT_USERNAME'           => $this->request->variable('username', '', true),
516
			'MT_FIRST_NAME'         => $this->request->variable('first_name', '', true),
517
			'MT_LAST_NAME'          => $this->request->variable('last_name', '', true),
518
			'MT_PAYER_EMAIL'        => $this->request->variable('payer_email', '', true),
519
			'MT_RESIDENCE_COUNTRY'  => $this->request->variable('residence_country', ''),
520
			'MT_MC_GROSS'           => $this->request->variable('mc_gross', (float) 0),
521
			'MT_MC_CURRENCY'        => $this->request->variable('mc_currency', ''),
522
			'MT_MC_FEE'             => $this->request->variable('mc_fee', (float) 0),
523
			'MT_PAYMENT_DATE_YEAR'  => $this->request->variable('payment_date_year', (int) $this->user->format_date(time(), 'Y')),
524
			'MT_PAYMENT_DATE_MONTH' => $this->request->variable('payment_date_month', (int) $this->user->format_date(time(), 'n')),
525
			'MT_PAYMENT_DATE_DAY'   => $this->request->variable('payment_date_day', (int) $this->user->format_date(time(), 'j')),
526
			'MT_PAYMENT_TIME'       => $this->request->variable('payment_time', $this->user->format_date(time(), 'H:i:s')),
527
			'MT_MEMO'               => $this->request->variable('memo', '', true),
528
		];
529
	}
530
531
	/**
532
	 * Prepare data array before send it to $this->entity
533
	 *
534
	 * @param array $transaction_data
535
	 *
536
	 * @return array
537
	 * @throws transaction_exception
538
	 * @access private
539
	 */
540
	private function build_data_ary($transaction_data): array
541
	{
542
		$errors = [];
543
544
		try
545
		{
546
			$user_id = $this->validate_user_id($transaction_data['MT_USERNAME']);
547
		}
548
		catch (transaction_exception $e)
549
		{
550
			$errors = $e->get_errors();
551
		}
552
553
		$payment_date = implode('-', [
554
			$transaction_data['MT_PAYMENT_DATE_YEAR'],
555
			$transaction_data['MT_PAYMENT_DATE_MONTH'],
556
			$transaction_data['MT_PAYMENT_DATE_DAY'],
557
		]);
558
559
		$payment_date_timestamp_at_midnight = $this->user->get_timestamp_from_format('Y-m-d H:i:s', $payment_date . ' 00:00:00');
560
		$payment_time = $transaction_data['MT_PAYMENT_TIME'];
561
		$payment_time_timestamp = strtotime($payment_time);
562
563
		// Normalize payment time to start from today at midnight
564
		$payment_time_timestamp_from_midnight = $payment_time_timestamp - strtotime('00:00:00');
565
566
		$payment_date_time = $payment_date_timestamp_at_midnight + $payment_time_timestamp_from_midnight;
567
568
		$errors = array_merge($errors,
569
			$this->mc_gross_too_low($transaction_data),
570
			$this->mc_fee_negative($transaction_data),
571
			$this->mc_fee_too_high($transaction_data),
572
			$this->payment_date_timestamp_at_midnight($payment_date_timestamp_at_midnight, $payment_date),
573
			$this->payment_time_timestamp($payment_time_timestamp, $payment_date),
574
			$this->payment_date_time((string) $payment_date_time));
575
576
		if (count($errors))
577
		{
578
			throw (new transaction_exception())->set_errors($errors);
579
		}
580
581
		return [
582
			'business'          => $this->config['ppde_account_id'],
583
			'confirmed'         => true,
584
			'exchange_rate'     => '',
585
			'first_name'        => $transaction_data['MT_FIRST_NAME'],
586
			'item_name'         => '',
587
			'item_number'       => implode('_', ['uid', $user_id, time()]),
588
			'last_name'         => $transaction_data['MT_LAST_NAME'],
589
			'mc_currency'       => $transaction_data['MT_MC_CURRENCY'],
590
			'mc_gross'          => $transaction_data['MT_MC_GROSS'],
591
			'mc_fee'            => $transaction_data['MT_MC_FEE'],
592
			'net_amount'        => (float) 0, // This value is calculated in core_actions:log_to_db()
593
			'parent_txn_id'     => '',
594
			'payer_email'       => $transaction_data['MT_PAYER_EMAIL'],
595
			'payer_id'          => '',
596
			'payer_status'      => '',
597
			'payment_date'      => $payment_date_time,
598
			'payment_status'    => 'Completed',
599
			'payment_type'      => '',
600
			'memo'              => $transaction_data['MT_MEMO'],
601
			'receiver_id'       => '',
602
			'receiver_email'    => '',
603
			'residence_country' => strtoupper($transaction_data['MT_RESIDENCE_COUNTRY']),
604
			'settle_amount'     => (float) 0,
605
			'settle_currency'   => '',
606
			'test_ipn'          => false,
607
			'txn_errors'        => '',
608
			'txn_id'            => 'PPDE' . gen_rand_string(13),
609
			'txn_type'          => 'ppde_manual_donation',
610
			'user_id'           => $user_id,
611
		];
612
	}
613
614
	/**
615
	 * Tests if mc_gross is to low
616
	 *
617
	 * @param array $data
618
	 *
619
	 * @return array
620
	 * @access private
621
	 */
622
	private function mc_gross_too_low($data): array
623
	{
624
		if ($data['MT_MC_GROSS'] <= 0)
625
		{
626
			return [$this->language->lang('PPDE_MT_MC_GROSS_TOO_LOW')];
627
		}
628
629
		return [];
630
	}
631
632
	/**
633
	 * Tests if mc_fee has a negative value
634
	 *
635
	 * @param array $data
636
	 *
637
	 * @return array
638
	 * @access private
639
	 */
640
	private function mc_fee_negative($data): array
641
	{
642
		if ($data['MT_MC_FEE'] < 0)
643
		{
644
			return [$this->language->lang('PPDE_MT_MC_FEE_NEGATIVE')];
645
		}
646
647
		return [];
648
	}
649
650
	/**
651
	 * Tests if mc_fee is to high
652
	 *
653
	 * @param array $data
654
	 *
655
	 * @return array
656
	 * @access private
657
	 */
658
	private function mc_fee_too_high($data): array
659
	{
660
		if ($data['MT_MC_FEE'] >= $data['MT_MC_GROSS'])
661
		{
662
			return [$this->language->lang('PPDE_MT_MC_FEE_TOO_HIGH')];
663
		}
664
665
		return [];
666
	}
667
668
	/**
669
	 * Tests if the date is valid
670
	 *
671
	 * @param string|false $payment_date_timestamp_at_midnight
672
	 * @param string       $payment_date
673
	 *
674
	 * @return array
675
	 * @access private
676
	 */
677
	private function payment_date_timestamp_at_midnight($payment_date_timestamp_at_midnight, $payment_date): array
678
	{
679
		if ($payment_date_timestamp_at_midnight === false)
680
		{
681
			return [$this->language->lang('PPDE_MT_PAYMENT_DATE_ERROR', $payment_date)];
682
		}
683
684
		return [];
685
	}
686
687
	/**
688
	 * @param int|false $payment_time_timestamp
689
	 * @param string    $payment_date
690
	 *
691
	 * @return array
692
	 * @access private
693
	 */
694
	private function payment_time_timestamp($payment_time_timestamp, $payment_date): array
695
	{
696
		if ($payment_time_timestamp === false)
697
		{
698
			return [$this->language->lang('PPDE_MT_PAYMENT_TIME_ERROR', $payment_date)];
699
		}
700
701
		return [];
702
	}
703
704
	/**
705
	 * @param string $payment_date_time
706
	 *
707
	 * @return array
708
	 * @access private
709
	 */
710
	private function payment_date_time($payment_date_time): array
711
	{
712
		if ($payment_date_time > time())
713
		{
714
			return [$this->language->lang('PPDE_MT_PAYMENT_DATE_FUTURE', $this->user->format_date($payment_date_time))];
715
		}
716
717
		return [];
718
	}
719
720
	/**
721
	 * Returns a list of valid times that the user can provide in the manual transaction form
722
	 *
723
	 * @return array Array of strings representing the current time, each in a different format
724
	 * @access private
725
	 */
726
	private function get_payment_time_examples(): array
727
	{
728
		$formats = [
729
			'H:i:s',
730
			'G:i',
731
			'h:i:s a',
732
			'g:i A',
733
		];
734
735
		$examples = [];
736
737
		foreach ($formats as $format)
738
		{
739
			$examples[] = $this->user->format_date(time(), $format);
740
		}
741
742
		return $examples;
743
	}
744
745
	/**
746
	 * {@inheritdoc}
747
	 */
748
	public function view(): void
749
	{
750
		// Request Identifier of the transaction
751
		$transaction_id = $this->request->variable('id', 0);
752
753
		// add additional fields to the table schema needed by entity->import()
754
		$additional_table_schema = [
755
			'item_username'    => ['name' => 'username', 'type' => 'string'],
756
			'item_user_colour' => ['name' => 'user_colour', 'type' => 'string'],
757
		];
758
759
		// Grab transaction data
760
		$data_ary = $this->ppde_entity->get_data($this->ppde_operator->build_sql_data($transaction_id), $additional_table_schema);
761
762
		array_map([$this, 'action_assign_template_vars'], $data_ary);
763
764
		$this->template->assign_vars([
765
			'U_FIND_USERNAME' => append_sid($this->phpbb_root_path . 'memberlist.' . $this->php_ext, 'mode=searchuser&amp;form=view_transactions&amp;field=username&amp;select_single=true'),
766
			'U_ACTION'        => $this->u_action,
767
			'U_BACK'          => $this->u_action,
768
			'S_VIEW'          => true,
769
		]);
770
	}
771
772
	/**
773
	 * {@inheritdoc}
774
	 */
775
	public function delete(): void
776
	{
777
		$where_sql = '';
778
779
		if ($this->args['hidden_fields']['delmarked'] && count($this->args['hidden_fields']['mark']))
780
		{
781
			$where_sql = $this->ppde_operator->build_marked_where_sql($this->args['hidden_fields']['mark']);
782
		}
783
784
		if ($where_sql || $this->args['hidden_fields']['delall'])
785
		{
786
			$this->ppde_entity->delete(0, '', $where_sql, $this->args['hidden_fields']['delall']);
787
			$this->ppde_actions->set_ipn_test_properties(true);
788
			$this->ppde_actions->update_overview_stats();
789
			$this->ppde_actions->set_ipn_test_properties(false);
790
			$this->ppde_actions->update_overview_stats();
791
			$this->log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_' . $this->lang_key_prefix . '_PURGED', time());
792
		}
793
	}
794
795
	/**
796
	 * Set log output vars for display in the template
797
	 *
798
	 * @param array $row
799
	 *
800
	 * @return void
801
	 * @access protected
802
	 */
803
	protected function display_log_assign_template_vars($row): void
804
	{
805
		$this->template->assign_block_vars('log', [
806
			'CONFIRMED'        => ($row['confirmed']) ? $this->language->lang('PPDE_DT_VERIFIED') : $this->language->lang('PPDE_DT_UNVERIFIED'),
807
			'DATE'             => $this->user->format_date($row['payment_date']),
808
			'ID'               => $row['transaction_id'],
809
			'PAYMENT_STATUS'   => $this->language->lang(['PPDE_DT_PAYMENT_STATUS_VALUES', strtolower($row['payment_status'])]),
810
			'TXN_ID'           => $row['txn_id'],
811
			'USERNAME'         => $row['username_full'],
812
			'S_CONFIRMED'      => (bool) $row['confirmed'],
813
			'S_PAYMENT_STATUS' => strtolower($row['payment_status']) === 'completed',
814
			'S_TXN_ERRORS'     => !empty($row['txn_errors']),
815
			'S_TEST_IPN'       => (bool) $row['test_ipn'],
816
		]);
817
	}
818
819
	/**
820
	 * Set output vars for display in the template
821
	 *
822
	 * @param array $data
823
	 *
824
	 * @return void
825
	 * @access protected
826
	 */
827
	protected function action_assign_template_vars($data)
828
	{
829
		$s_hidden_fields = build_hidden_fields([
830
			'id'                  => $data['transaction_id'],
831
			'donor_id'            => $data['user_id'],
832
			'txn_errors_approved' => $data['txn_errors_approved'],
833
		]);
834
835
		$currency_mc_data = $this->ppde_actions_currency->get_currency_data($data['mc_currency']);
836
		$currency_settle_data = $this->ppde_actions_currency->get_currency_data($data['settle_currency']);
837
838
		$this->template->assign_vars([
839
			'BOARD_USERNAME' => get_username_string('full', $data['user_id'], $data['username'], $data['user_colour'], $this->language->lang('GUEST'), append_sid($this->phpbb_admin_path . 'index.' . $this->php_ext, 'i=users&amp;mode=overview')),
840
			'EXCHANGE_RATE'  => '1 ' . $data['mc_currency'] . ' = ' . $data['exchange_rate'] . ' ' . $data['settle_currency'],
841
			'ITEM_NAME'      => $data['item_name'],
842
			'ITEM_NUMBER'    => $data['item_number'],
843
			'MC_GROSS'       => $this->ppde_actions_currency->format_currency((float) $data['mc_gross'], $currency_mc_data[0]['currency_iso_code'], $currency_mc_data[0]['currency_symbol'], (bool) $currency_mc_data[0]['currency_on_left']),
844
			'MC_FEE'         => $this->ppde_actions_currency->format_currency((float) $data['mc_fee'], $currency_mc_data[0]['currency_iso_code'], $currency_mc_data[0]['currency_symbol'], (bool) $currency_mc_data[0]['currency_on_left']),
845
			'MC_NET'         => $this->ppde_actions_currency->format_currency((float) $data['net_amount'], $currency_mc_data[0]['currency_iso_code'], $currency_mc_data[0]['currency_symbol'], (bool) $currency_mc_data[0]['currency_on_left']),
846
			'MEMO'           => $data['memo'],
847
			'NAME'           => $data['first_name'] . ' ' . $data['last_name'],
848
			'PAYER_EMAIL'    => $data['payer_email'],
849
			'PAYER_ID'       => $data['payer_id'],
850
			'PAYER_STATUS'   => $data['payer_status'] ? $this->language->lang('PPDE_DT_VERIFIED') : $this->language->lang('PPDE_DT_UNVERIFIED'),
851
			'PAYMENT_DATE'   => $this->user->format_date($data['payment_date']),
852
			'PAYMENT_STATUS' => $this->language->lang(['PPDE_DT_PAYMENT_STATUS_VALUES', strtolower($data['payment_status'])]),
853
			'RECEIVER_EMAIL' => $data['receiver_email'],
854
			'RECEIVER_ID'    => $data['receiver_id'],
855
			'SETTLE_AMOUNT'  => $this->ppde_actions_currency->format_currency((float) $data['settle_amount'], $currency_settle_data[0]['currency_iso_code'], $currency_settle_data[0]['currency_symbol'], (bool) $currency_settle_data[0]['currency_on_left']),
856
			'TXN_ID'         => $data['txn_id'],
857
858
			'L_PPDE_DT_SETTLE_AMOUNT'         => $this->language->lang('PPDE_DT_SETTLE_AMOUNT', $data['settle_currency']),
859
			'L_PPDE_DT_EXCHANGE_RATE_EXPLAIN' => $this->language->lang('PPDE_DT_EXCHANGE_RATE_EXPLAIN', $this->user->format_date($data['payment_date'])),
860
			'S_CONVERT'                       => !($data['settle_amount'] == 0 && empty($data['exchange_rate'])),
861
			'S_ERROR'                         => !empty($data['txn_errors']),
862
			'S_ERROR_APPROVED'                => !empty($data['txn_errors_approved']),
863
			'S_HIDDEN_FIELDS'                 => $s_hidden_fields,
864
			'ERROR_MSG'                       => (!empty($data['txn_errors'])) ? $data['txn_errors'] : '',
865
		]);
866
	}
867
}
868