Completed
Branch BUG-10220-spco-permalinks (9ba45e)
by
unknown
14:48 queued 11s
created

EEM_Transaction::delete_junk_transactions()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 60
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 25
nc 4
nop 0
dl 0
loc 60
rs 8.9618
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php if ( ! defined('EVENT_ESPRESSO_VERSION')) {
2
    exit('No direct script access allowed');
3
}
4
require_once(EE_MODELS . 'EEM_Base.model.php');
5
6
/**
7
 *
8
 * Transaction Model
9
 *
10
 * @package            Event Espresso
11
 * @subpackage         includes/models/
12
 * @author             Brent Christensen
13
 *
14
 */
15
class EEM_Transaction extends EEM_Base
16
{
17
    
18
    // private instance of the Transaction object
19
    protected static $_instance;
20
    
21
    /**
22
     * Status ID(STS_ID on esp_status table) to indicate the transaction is complete,
23
     * but payment is pending. This is the state for transactions where payment is promised
24
     * from an offline gateway.
25
     */
26
    //	const open_status_code = 'TPN';
27
    
28
    /**
29
     * Status ID(STS_ID on esp_status table) to indicate the transaction failed,
30
     * either due to a technical reason (server or computer crash during registration),
31
     *  or some other reason that prevent the collection of any useful contact information from any of the registrants
32
     */
33
    const failed_status_code = 'TFL';
34
    
35
    /**
36
     * Status ID(STS_ID on esp_status table) to indicate the transaction was abandoned,
37
     * either due to a technical reason (server or computer crash during registration),
38
     * or due to an abandoned cart after registrant chose not to complete the registration process
39
     * HOWEVER...
40
     * an abandoned TXN differs from a failed TXN in that it was able to capture contact information for at least one
41
     * registrant
42
     */
43
    const abandoned_status_code = 'TAB';
44
    
45
    /**
46
     * Status ID(STS_ID on esp_status table) to indicate an incomplete transaction,
47
     * meaning that monies are still owing: TXN_paid < TXN_total
48
     */
49
    const incomplete_status_code = 'TIN';
50
    
51
    /**
52
     * Status ID (STS_ID on esp_status table) to indicate a complete transaction.
53
     * meaning that NO monies are owing: TXN_paid == TXN_total
54
     */
55
    const complete_status_code = 'TCM';
56
    
57
    /**
58
     *  Status ID(STS_ID on esp_status table) to indicate the transaction is overpaid.
59
     *  This is the same as complete, but site admins actually owe clients the moneys!  TXN_paid > TXN_total
60
     */
61
    const overpaid_status_code = 'TOP';
62
    
63
    
64
    /**
65
     *    private constructor to prevent direct creation
66
     *
67
     * @Constructor
68
     * @access protected
69
     *
70
     * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any
71
     *                         incoming timezone data that gets saved). Note this just sends the timezone info to the
72
     *                         date time model field objects.  Default is NULL (and will be assumed using the set
73
     *                         timezone in the 'timezone_string' wp option)
74
     *
75
     * @return EEM_Transaction
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
76
     * @throws \EE_Error
77
     */
78
    protected function __construct($timezone)
79
    {
80
        $this->singular_item = __('Transaction', 'event_espresso');
81
        $this->plural_item   = __('Transactions', 'event_espresso');
82
        
83
        $this->_tables                 = array(
0 ignored issues
show
Documentation Bug introduced by
It seems like array('TransactionTable'...ransaction', 'TXN_ID')) of type array<string,object<EE_P...ct<EE_Primary_Table>"}> is incompatible with the declared type array<integer,object<EE_Table_Base>> of property $_tables.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
84
            'TransactionTable' => new EE_Primary_Table('esp_transaction', 'TXN_ID')
85
        );
86
        $this->_fields                 = array(
0 ignored issues
show
Documentation Bug introduced by
It seems like array('TransactionTable'...so'), false, array()))) of type array<string,array<strin...ized_Text_Field>\"}>"}> is incompatible with the declared type array<integer,object<EE_Model_Field_Base>> of property $_fields.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
87
            'TransactionTable' => array(
88
                'TXN_ID'           => new EE_Primary_Key_Int_Field('TXN_ID', __('Transaction ID', 'event_espresso')),
89
                'TXN_timestamp'    => new EE_Datetime_Field('TXN_timestamp',
90
                    __('date when transaction was created', 'event_espresso'), false, EE_Datetime_Field::now,
91
                    $timezone),
92
                'TXN_total'        => new EE_Money_Field('TXN_total',
93
                    __('Total value of Transaction', 'event_espresso'), false, 0),
94
                'TXN_paid'         => new EE_Money_Field('TXN_paid',
95
                    __('Amount paid towards transaction to date', 'event_espresso'), false, 0),
96
                'STS_ID'           => new EE_Foreign_Key_String_Field('STS_ID', __('Status ID', 'event_espresso'),
97
                    false, EEM_Transaction::failed_status_code, 'Status'),
98
                'TXN_session_data' => new EE_Serialized_Text_Field('TXN_session_data',
99
                    __('Serialized session data', 'event_espresso'), true, ''),
100
                'TXN_hash_salt'    => new EE_Plain_Text_Field('TXN_hash_salt',
101
                    __('Transaction Hash Salt', 'event_espresso'), true, ''),
102
                'PMD_ID'           => new EE_Foreign_Key_Int_Field('PMD_ID',
103
                    __("Last Used Payment Method", 'event_espresso'), true, null, 'Payment_Method'),
104
                'TXN_reg_steps'    => new EE_Serialized_Text_Field('TXN_reg_steps',
105
                    __('Registration Steps', 'event_espresso'), false, array()),
106
            )
107
        );
108
        $this->_model_relations        = array(
0 ignored issues
show
Documentation Bug introduced by
It seems like array('Registration' => ...EE_Has_Many_Relation()) of type array<string,object<EE_H...E_Has_Many_Relation>"}> is incompatible with the declared type array<integer,object<EE_Model_Relation_Base>> of property $_model_relations.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
109
            'Registration'   => new EE_Has_Many_Relation(),
110
            'Payment'        => new EE_Has_Many_Relation(),
111
            'Status'         => new EE_Belongs_To_Relation(),
112
            'Line_Item'      => new EE_Has_Many_Relation(false),
113
            //you can delete a transaction without needing to delete its line items
114
            'Payment_Method' => new EE_Belongs_To_Relation(),
115
            'Message'        => new EE_Has_Many_Relation()
116
        );
117
        $this->_model_chain_to_wp_user = 'Registration.Event';
118
        parent::__construct($timezone);
119
        
120
    }
121
    
122
    
123
    /**
124
     *    txn_status_array
125
     * get list of transaction statuses
126
     *
127
     * @access public
128
     * @return array
129
     */
130
    public static function txn_status_array()
131
    {
132
        return apply_filters(
133
            'FHEE__EEM_Transaction__txn_status_array',
134
            array(
135
                EEM_Transaction::overpaid_status_code,
136
                EEM_Transaction::complete_status_code,
137
                EEM_Transaction::incomplete_status_code,
138
                EEM_Transaction::abandoned_status_code,
139
                EEM_Transaction::failed_status_code,
140
            )
141
        );
142
    }
143
    
144
    /**
145
     *        get the revenue per day  for the Transaction Admin page Reports Tab
146
     *
147
     * @access        public
148
     *
149
     * @param string $period
150
     *
151
     * @return \stdClass[]
152
     */
153
    public function get_revenue_per_day_report($period = '-1 month')
154
    {
155
        $sql_date = $this->convert_datetime_for_query('TXN_timestamp', date('Y-m-d H:i:s', strtotime($period)),
156
            'Y-m-d H:i:s', 'UTC');
157
        
158
        $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'TXN_timestamp');
159
        
160
        return $this->_get_all_wpdb_results(
161
            array(
162
                array(
163
                    'TXN_timestamp' => array('>=', $sql_date)
164
                ),
165
                'group_by' => 'txnDate',
166
                'order_by' => array('TXN_timestamp' => 'ASC')
167
            ),
168
            OBJECT,
169
            array(
170
                'txnDate' => array('DATE(' . $query_interval . ')', '%s'),
171
                'revenue' => array('SUM(TransactionTable.TXN_paid)', '%d')
172
            )
173
        );
174
    }
175
    
176
    
177
    /**
178
     *        get the revenue per event  for the Transaction Admin page Reports Tab
179
     *
180
     * @access        public
181
     *
182
     * @param string $period
183
     *
184
     * @throws \EE_Error
185
     * @return mixed
186
     */
187
    public function get_revenue_per_event_report($period = '-1 month')
188
    {
189
        global $wpdb;
190
        $transaction_table       = $wpdb->prefix . 'esp_transaction';
191
        $registration_table      = $wpdb->prefix . 'esp_registration';
192
        $event_table             = $wpdb->posts;
193
        $payment_table           = $wpdb->prefix . 'esp_payment';
194
        $sql_date                = date('Y-m-d H:i:s', strtotime($period));
195
        $approved_payment_status = EEM_Payment::status_id_approved;
196
        $extra_event_on_join     = '';
197
        //exclude events not authored by user if permissions in effect
198
        if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) {
199
            $extra_event_on_join = ' AND Event.post_author = ' . get_current_user_id();
200
        }
201
        
202
        return $wpdb->get_results(
203
            "SELECT
204
			Transaction_Event.event_name AS event_name,
205
			SUM(Transaction_Event.paid) AS revenue
206
			FROM
207
				(
208
					SELECT
209
						DISTINCT Payment.TXN_ID,
210
						Event.post_title AS event_name,
211
						Payment.PAY_amount AS paid
212
					FROM $transaction_table AS TransactionTable
213
						JOIN $registration_table AS Registration
214
							ON Registration.TXN_ID = TransactionTable.TXN_ID
215
						JOIN $payment_table AS Payment
216
							ON Payment.TXN_ID = Registration.TXN_ID
217
							AND Payment.PAY_timestamp > '$sql_date'
218
							AND Payment.STS_ID = '$approved_payment_status'
219
						JOIN $event_table AS Event ON Registration.EVT_ID = Event.ID
220
							$extra_event_on_join
221
				) AS Transaction_Event
222
			GROUP BY event_name",
223
            OBJECT
224
        );
225
    }
226
    
227
    
228
    /**
229
     * Gets the current transaction given the reg_url_link, or assumes the reg_url_link is in the
230
     * $_REQUEST global variable. Either way, tries to find the current transaction (through
231
     * the registration pointed to by reg_url_link), if not returns null
232
     *
233
     * @param string $reg_url_link
234
     *
235
     * @return EE_Transaction
236
     */
237
    public function get_transaction_from_reg_url_link($reg_url_link = '')
238
    {
239
        return $this->get_one(array(
240
            array(
241
                'Registration.REG_url_link' => ! empty($reg_url_link) ? $reg_url_link : EE_Registry::instance()->REQ->get('e_reg_url_link',
242
                    '')
243
            )
244
        ));
245
    }
246
    
247
    
248
    /**
249
     * Updates the provided EE_Transaction with all the applicable payments
250
     * (or fetch the EE_Transaction from its ID)
251
     *
252
     * @deprecated
253
     *
254
     * @param EE_Transaction|int $transaction_obj_or_id
255
     * @param boolean            $save_txn whether or not to save the transaction during this function call
256
     *
257
     * @return boolean
258
     * @throws \EE_Error
259
     */
260 View Code Duplication
    public function update_based_on_payments($transaction_obj_or_id, $save_txn = true)
0 ignored issues
show
Unused Code introduced by
The parameter $save_txn is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
261
    {
262
        EE_Error::doing_it_wrong(
263
            __CLASS__ . '::' . __FUNCTION__,
264
            sprintf(__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
265
                'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'),
266
            '4.6.0'
267
        );
268
        /** @type EE_Transaction_Processor $transaction_processor */
269
        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
270
        
271
        return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment(
272
            $this->ensure_is_obj($transaction_obj_or_id)
0 ignored issues
show
Documentation introduced by
$this->ensure_is_obj($transaction_obj_or_id) is of type object<EE_Base_Class>|null, but the function expects a object<EE_Transaction>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
273
        );
274
    }
275
    
276
    /**
277
     * Deletes "junk" transactions that were probably added by bots. There might be TONS
278
     * of these, so we are very careful to NOT select (which the models do even when deleting),
279
     * and so we only use wpdb directly and NOT do any joins.
280
     * The downside to this approach is that is addons are listening for object deletions
281
     * on EEM_Base::delete() they won't be notified of this.
282
     * @global WPDB $wpdb
283
     * @return mixed
284
     */
285
    public function delete_junk_transactions()
286
    {
287
        /** @type WPDB $wpdb */
288
        global $wpdb;
289
        $deleted             = false;
290
        $time_to_leave_alone = apply_filters(
291
            'FHEE__EEM_Transaction__delete_junk_transactions__time_to_leave_alone', WEEK_IN_SECONDS
292
        );
293
        
294
        
295
        /**
296
         * This allows code to filter the query arguments used for retrieving the transaction IDs to delete.
297
         * Useful for plugins that want to exclude transactions matching certain query parameters.
298
         * The query parameters should be in the format accepted by the EEM_Base model queries.
299
         */
300
        $ids_query = apply_filters(
301
            'FHEE__EEM_Transaction__delete_junk_transactions__initial_query_args',
302
            array(
303
                0 => array(
304
                    'STS_ID'        => EEM_Transaction::failed_status_code,
305
                    'TXN_timestamp' => array('<', time() - $time_to_leave_alone)
306
                )
307
            ),
308
            $time_to_leave_alone
309
        );
310
        
311
        
312
        /**
313
         * This filter is for when code needs to filter the list of transaction ids that represent transactions
314
         * about to be deleted based on some other criteria that isn't easily done via the query args filter.
315
         */
316
        $txn_ids = apply_filters(
317
            'FHEE__EEM_Transaction__delete_junk_transactions__transaction_ids_to_delete',
318
            EEM_Transaction::instance()->get_col($ids_query, 'TXN_ID'),
319
            $time_to_leave_alone
320
        );
321
        //now that we have the ids to delete
322
        if ( ! empty($txn_ids) && is_array($txn_ids)) {
323
            // first, make sure these TXN's are removed the "ee_locked_transactions" array
324
            EEM_Transaction::unset_locked_transactions($txn_ids);
325
            // let's get deletin'...
326
            // Why no wpdb->prepare?  Because the data is trusted.
327
            // We got the ids from the original query to get them FROM
328
            // the db (which is sanitized) so no need to prepare them again.
329
            $query   = '
330
				DELETE
331
				FROM ' . $this->table() . '
332
				WHERE
333
					TXN_ID IN ( ' . implode(",", $txn_ids) . ')';
334
            $deleted = $wpdb->query($query);
335
        }
336
        if ($deleted) {
337
            /**
338
             * Allows code to do something after the transactions have been deleted.
339
             */
340
            do_action('AHEE__EEM_Transaction__delete_junk_transactions__successful_deletion', $txn_ids);
341
        }
342
        
343
        return $deleted;
344
    }
345
    
346
    
347
    /**
348
     * @param array $transaction_IDs
349
     *
350
     * @return bool
351
     */
352
    public static function unset_locked_transactions(array $transaction_IDs)
353
    {
354
        $locked_transactions = get_option('ee_locked_transactions', array());
355
        $update              = false;
356
        foreach ($transaction_IDs as $TXN_ID) {
357
            if (isset($locked_transactions[$TXN_ID])) {
358
                unset($locked_transactions[$TXN_ID]);
359
                $update = true;
360
            }
361
        }
362
        if ($update) {
363
            update_option('ee_locked_transactions', $locked_transactions);
364
        }
365
        
366
        return $update;
367
    }
368
    
369
    
370
}
371
// End of file EEM_Transaction.model.php
372
// Location: /includes/models/EEM_Transaction.model.php
373