/**
  * @group 7965
  */
 function test_delete_junk_transactions()
 {
     $old_txn_count = EEM_Transaction::instance()->count();
     $pretend_bot_creations = 9;
     $pretend_real_recent_txns = 3;
     $pretend_real_good_txns = 5;
     $this->factory->transaction->create_many($pretend_bot_creations, array('TXN_timestamp' => time() - WEEK_IN_SECONDS * 2, 'STS_ID' => EEM_Transaction::failed_status_code));
     $this->factory->transaction->create_many($pretend_real_recent_txns, array('TXN_timestamp' => time() - EE_Registry::instance()->SSN->lifespan() + MINUTE_IN_SECONDS, 'STS_ID' => EEM_Transaction::failed_status_code));
     $this->factory->transaction->create_many($pretend_real_good_txns, array('STS_ID' => EEM_Transaction::abandoned_status_code));
     $num_deleted = EEM_Transaction::instance()->delete_junk_transactions();
     $this->assertEquals($pretend_bot_creations, $num_deleted);
 }
 function test_save_autoincrement_pk()
 {
     //test saving something with an auto-increment PK
     $t = EE_Transaction::new_instance();
     $id = $t->save();
     $this->assertNotNull($id);
     $this->assertEquals($t->ID(), $id);
     $t2 = EEM_Transaction::instance()->get_one_by_ID($id);
     $this->assertEquals($id, $t2->ID());
     //and check that its correctly saved to the model's entity map
     $existing_t_in_entity_map = EEM_Transaction::instance()->get_from_entity_map($id);
     $this->assertInstanceOf('EE_Transaction', $existing_t_in_entity_map);
 }
 function test_generate_restrictions__basic_only()
 {
     //currently transactions only have the basic cap
     //if they get an 'ee_edit_others_transactions' cap, this test will need updating
     $generator = new EE_Restriction_Generator_Protected();
     $generator->_construct_finalize(EEM_Transaction::instance(), EEM_Base::caps_read);
     $restrictions = $generator->generate_restrictions();
     foreach ($restrictions as $default_where_conditions) {
         $default_where_conditions->_finalize_construct(EEM_Registration::instance());
     }
     $this->assertArrayHasKey('ee_read_transactions', $restrictions);
     $this->assertInstanceOf('EE_Return_None_Where_Conditions', $restrictions['ee_read_transactions']);
     $this->assertEquals(1, count($restrictions));
 }
 /**
  * This generates the dummy relation objects for use in a new registration.
  *
  * @since 4.3.0
  *
  * @param array $args
  */
 private function _set_new_relations($args)
 {
     //transaction
     $this->_transaction = empty($args['TXN_ID']) ? $this->factory->transaction->create() : EEM_Transaction::instance()->get_one_by_ID($args['TXN_ID']);
     $this->_transaction = empty($this->_transaction) ? $this->factory->transaction->create() : $this->_transaction;
     //ticket
     $this->_ticket = empty($args['TKT_ID']) ? $this->factory->ticket_chained->create() : EEM_Ticket::instance()->get_one_by_ID($args['TKT_ID']);
     $this->_ticket = empty($this->_ticket) ? $this->factory->ticket_chained->create() : $this->_ticket;
     //attendee
     $this->_attendee = empty($args['ATT_ID']) ? $this->factory->attendee->create() : EEM_Attendee::instance()->get_one_by_ID($args['ATT_ID']);
     $this->_attendee = empty($this->_attendee) ? $this->factory->attendee->create() : $this->_attendee;
     //status
     $this->_status = empty($arg['STS_ID']) ? $this->factory->status->create(array('STS_ID' => EEM_Registration::status_id_pending_payment, 'STS_type' => 'registration', 'STS_code' => 'PENDING_PAYMENT')) : EEM_Status::instance()->get_one_by_ID($args['STS_ID']);
     $this->_status = empty($this->_status) ? $this->factory->status->create(array('STS_ID' => EEM_Registration::status_id_pending_payment, 'STS_type' => 'registration', 'STS_code' => 'PENDING_PAYMENT')) : $this->_status;
 }
 /**
  * Callback for FHEE__EE_Admin_Page___display_admin_list_table_page__before_list_table__template_arg for adding
  * helpful title.
  *
  * @param string $content Current content
  * @param string $page_slug Page slug for page
  * @param array $req_data Incoming request data
  * @param string $req_action 'action' value for page
  *
  * @return string   If correct page and conditions are met, the new string. Otherwise existing string.
  */
 public static function before_events_list_table_content($content, $page_slug, $req_data, $req_action)
 {
     if ($page_slug !== 'espresso_events' || $req_action !== 'default' || empty($req_data['TXN_ID'])) {
         return $content;
     }
     $transaction = EEM_Transaction::instance()->get_one_by_ID($req_data['TXN_ID']);
     if ($transaction instanceof EE_Transaction) {
         $query_args = array('page' => 'espresso_transactions', 'action' => 'view_transaction', 'TXN_ID' => $req_data['TXN_ID']);
         EE_Registry::instance()->load_helper('URL');
         $url = EEH_URL::add_query_args_and_nonce($query_args, admin_url('admin.php'));
         $link_text = '<a href="' . $url . '">' . $transaction->ID() . '</a>';
         $content .= '<h2>' . sprintf(__('Events Registered for in Transaction # %s', 'event_espresso'), $link_text) . '</h2>';
     }
     return $content;
 }
 /**
  * _validate_return
  *
  * @access private
  * @return bool
  */
 private function _validate_offsite_return()
 {
     $TXN_ID = (int) EE_Registry::instance()->REQ->get('spco_txn', 0);
     if ($TXN_ID != $this->checkout->transaction->ID()) {
         // Houston... we might have a problem
         $invalid_TXN = false;
         // first gather some info
         $valid_TXN = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
         $primary_registrant = $valid_TXN instanceof EE_Transaction ? $valid_TXN->primary_registration() : null;
         // let's start by retrieving the cart for this TXN
         $cart = EE_Cart::get_cart_from_txn($this->checkout->transaction);
         if ($cart instanceof EE_Cart) {
             // verify that the current cart has tickets
             $tickets = $cart->get_tickets();
             if (empty($tickets)) {
                 $invalid_TXN = true;
             }
         } else {
             $invalid_TXN = true;
         }
         $valid_TXN_SID = $primary_registrant instanceof EE_Registration ? $primary_registrant->session_ID() : null;
         // validate current Session ID and compare against valid TXN session ID
         if (EE_Session::instance()->id() === null) {
             $invalid_TXN = true;
         } else {
             if (EE_Session::instance()->id() === $valid_TXN_SID) {
                 // WARNING !!!
                 // this could be PayPal sending back duplicate requests (ya they do that)
                 // or it **could** mean someone is simply registering AGAIN after having just done so
                 // so now we need to determine if this current TXN looks valid or not
                 /** @type EE_Transaction_Processor $transaction_processor */
                 $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
                 // has this step even been started ?
                 if ($transaction_processor->reg_step_completed($this->checkout->transaction, $this->slug() === false)) {
                     // really? you're half way through this reg step, but you never started it ?
                     $invalid_TXN = true;
                 }
             }
         }
         if ($invalid_TXN) {
             // is the valid TXN completed ?
             if ($valid_TXN instanceof EE_Transaction) {
                 /** @type EE_Transaction_Processor $transaction_processor */
                 $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
                 // has this step even been started ?
                 $reg_step_completed = $transaction_processor->reg_step_completed($valid_TXN, $this->slug());
                 if ($reg_step_completed !== false && $reg_step_completed !== true) {
                     // so it **looks** like this is a double request from PayPal
                     // so let's try to pick up where we left off
                     $this->checkout->transaction = $valid_TXN;
                     $this->checkout->refresh_all_entities(true);
                     return;
                 }
             }
             // you appear to be lost?
             $this->_redirect_wayward_request($primary_registrant);
         }
     }
 }
 public static function clean_out_junk_transactions()
 {
     if (EE_Maintenance_Mode::instance()->models_can_query()) {
         EEM_Transaction::instance('')->delete_junk_transactions();
         EEM_Registration::instance('')->delete_registrations_with_no_transaction();
         EEM_Line_Item::instance('')->delete_line_items_with_no_transaction();
     }
 }
 /**
  * Handles an instant payment notification when the transaction is known (by default).
  * @param array $req_data
  * @param EE_Transaction $transaction
  * @return EE_Payment
  * @throws EE_Error
  */
 public function handle_ipn($req_data, $transaction)
 {
     $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
     if (!$this->_gateway instanceof EE_Offsite_Gateway) {
         throw new EE_Error(sprintf(__("Could not handle IPN because '%s' is not an offsite gateway", "event_espresso"), print_r($this->_gateway, TRUE)));
     }
     $payment = $this->_gateway->handle_payment_update($req_data, $transaction);
     return $payment;
 }
 /**
  * Deletes all registrations with no transactions. Note that this needs to be very efficient
  * and so it uses wpdb directly
  * @global WPDB $wpdb
  * @return int number deleted
  */
 public function delete_registrations_with_no_transaction()
 {
     /** @type WPDB $wpdb */
     global $wpdb;
     return $wpdb->query('DELETE r FROM ' . $this->table() . ' r LEFT JOIN ' . EEM_Transaction::instance()->table() . ' t ON r.TXN_ID = t.TXN_ID WHERE t.TXN_ID IS NULL');
 }
 /**
  * Data that has been stored in persistent storage that was prepped by _convert_data_for_persistent_storage
  * can be sent into this method and converted back into the format used for instantiating with this data handler.
  *
  * @param array  $data
  *
  * @return array
  */
 public static function convert_data_from_persistent_storage($data)
 {
     $prepped_data = array(0 => isset($data['Transaction']) ? EEM_Transaction::instance()->get_one_by_ID($data['Transaction']) : null, 1 => isset($data['Payment']) ? EEM_Payment::instance()->get_one_by_ID($data['Payment']) : null, 2 => isset($data['filter']) ? $data['filter'] : null);
     return $prepped_data;
 }
 /**
  * _revenue_per_event_report
  * generates Business Report showing total revenue per event
  *
  * @access private
  * @param string $period
  * @return int
  */
 private function _revenue_per_event_report($period = '-1 month')
 {
     $report_ID = 'txn-admin-revenue-per-event-report-dv';
     $report_JS = 'espresso_txn_admin_revenue_per_event';
     wp_enqueue_script($report_JS, TXN_CAF_ASSETS_URL . $report_JS . '_report.js', array('jqplot-all'), '1.0', TRUE);
     $TXN = EEM_Transaction::instance();
     $results = $TXN->get_revenue_per_event_report($period);
     //EEH_Debug_Tools::printr( $results, '$registrations_per_event' );
     $revenue = array();
     $results = (array) $results;
     foreach ($results as $result) {
         $event_name = stripslashes(html_entity_decode($result->event_name, ENT_QUOTES, 'UTF-8'));
         $event_name = wp_trim_words($event_name, 5, '...');
         $revenue[] = array($event_name, (double) $result->revenue);
     }
     $span = $period == 'week' ? 9 : 33;
     $report_title = __('Total Revenue per Event');
     $report_params = array('title' => $report_title, 'id' => $report_ID, 'revenue' => $revenue, 'span' => $span, 'width' => ceil(900 / $span), 'noTxnMsg' => sprintf(__('<h2>%s</h2><p>There are currently no transaction records in the last month for this report.</p>', 'event_espresso'), $report_title));
     wp_localize_script($report_JS, 'revenuePerEvent', $report_params);
     return $report_ID;
 }
 /**
  * 	_payments_and_amount_owing_rows
  *
  * @param EE_Line_Item $line_item
  * @return mixed
  */
 private function _payments_and_amount_owing_rows(EE_Line_Item $line_item)
 {
     $html = '';
     $transaction = EEM_Transaction::instance()->get_one_by_ID($line_item->TXN_ID());
     if ($transaction instanceof EE_Transaction) {
         $payments = $transaction->approved_payments();
         if (!empty($payments)) {
             foreach ($payments as $payment) {
                 if ($payment instanceof EE_Payment) {
                     //$owing = $owing - $payment->amount();
                     $payment_desc = sprintf(__('Payment%1$s Received: %2$s', 'event_espresso'), $payment->txn_id_chq_nmbr() != '' ? ' <span class="small-text">(#' . $payment->txn_id_chq_nmbr() . ')</span> ' : '', $payment->timestamp());
                     // start of row
                     $html .= EEH_HTML::tr('', '', 'total_tr odd');
                     // payment desc
                     $html .= EEH_HTML::td($payment_desc, '', '', '', ' colspan="3"');
                     // total td
                     $html .= EEH_HTML::td(EEH_Template::format_currency($payment->amount(), false, false), '', 'total jst-rght');
                     // end of row
                     $html .= EEH_HTML::trx();
                 }
             }
             //if ( $line_item->total() ) {
             //	// start of row
             //	$html .= EEH_HTML::tr( '', '', 'total_tr odd' );
             //	// total td
             //	$html .= EEH_HTML::td( __('Amount Owing', 'event_espresso'), '',  'total_currency total jst-rght',  '',  ' colspan="3"' );
             //	// total td
             //	$html .= EEH_HTML::td( EEH_Template::format_currency( $this->grand_total(), false, false ), '',  'total jst-rght' );
             //	// end of row
             //	$html .= EEH_HTML::trx();
             //}
         }
     }
     return $html;
 }
 /**
  * The purpose of this method is to just initialize SPCO for manual admin registration handling
  *
  * Note, it is fully expected that eventually things will be abstracted a bit more conveniently for the Admin usage of SPCO but this is a quick and dirty method to get things implemented with as much DRY as possible.
  *
  * @access public
  * @return void
  */
 public function init_for_admin()
 {
     // load classes
     EE_Registry::instance()->load_model('Gateways');
     $this->_cart = EE_Registry::instance()->load_core('Cart');
     if (empty(EE_Registry::instance()->REQ)) {
         EE_Registry::instance()->load_core('Request_Handler');
     }
     $this->_current_step = 'attendee_information';
     $this->_transaction = EE_Registry::instance()->SSN->get_session_data('transaction');
     // verify transaction
     if ($this->_transaction instanceof EE_Transaction) {
         // but if this transaction has already been saved to the db... then let's pull that
         $ID = $this->_transaction->ID();
         if ($ID) {
             if (!($this->_transaction = EEM_Transaction::instance()->get_one_by_ID($ID))) {
                 EE_Error::add_error(__('The Transaction could not be retrieved from the db when attempting to process your registration information', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
                 return;
             }
         }
     } else {
         $this->_initialize_transaction();
     }
     // and verify registrations have been set (first check cached REGs)
     if ($this->_transaction->registrations(array(), TRUE) == NULL) {
         // then check the db
         if ($this->_transaction->registrations() == NULL) {
             $this->_initialize_registrations();
         }
     }
     if (!defined('SPCO_TEMPLATES_PATH')) {
         self::set_definitions();
     }
     $this->set_templates();
 }
 function test_wp_user_field_name()
 {
     $this->assertEquals('EVT_wp_user', EEM_Event::instance()->wp_user_field_name());
     $this->assertEquals('Registration.Event.EVT_wp_user', EEM_Transaction::instance()->wp_user_field_name());
     $this->assertEquals('TKT_wp_user', EEM_Ticket::instance()->wp_user_field_name());
 }
 /**
  * return the transaction object for a given transaction ID.
  *
  * @since 4.3.0
  *
  * @param int $TXN_ID the transaction id for the transaction to attempt to retrieve
  *
  * @return mixed null|EE_Transaction
  */
 public function get_object_by_id($TXN_ID)
 {
     return EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
 }
Beispiel #16
0
 /**
  * Update lead status of the specified payment
  *
  * @param Pronamic_Pay_Payment $payment
  * @param bool                 $can_redirect
  */
 public function update_status_unknown_to_success(Pronamic_Pay_Payment $payment, $can_redirect = false)
 {
     if (!(version_compare(EVENT_ESPRESSO_VERSION, '4', '>=') && version_compare(EVENT_ESPRESSO_VERSION, '4.6', '<'))) {
         return;
     }
     // Eevent Espresso 4.0 to 4.6
     $gateway = EEM_Gateways::instance()->get_gateway('pronamic_pay_ideal');
     if ($gateway) {
         $transaction_id = $payment->get_source_id();
         // @see https://github.com/eventespresso/event-espresso-core/blob/4.2.2.reg/admin_pages/transactions/Transactions_Admin_Page.core.php#L332-L337
         $transaction_model = EEM_Transaction::instance();
         $transaction = $transaction_model->get_one_by_ID($transaction_id);
         global $pronamic_payment, $pronamic_url;
         $pronamic_payment = $payment;
         $gateway->handle_ipn_for_transaction($transaction);
         unset($pronamic_payment);
         // Redirect URL
         if ($can_redirect) {
             wp_redirect($pronamic_url, 303);
             exit;
         }
     }
 }
 /**
  * Checks that we can correctly apply backend read caps where there is only
  * one cap controlling access to the model
  * @group model_caps
  */
 public function test_get_all__caps_admin_read__basic()
 {
     $this->assertEquals(0, EEM_Transaction::instance()->count());
     $this->new_typical_transaction();
     $current_user = $this->_ensure_current_user_set();
     //let's test first on transactions, which just have a single cap controlling access
     //which the current user doesn't have so nothing should be found
     $this->assertEquals(0, EEM_Transaction::instance()->count(array('caps' => EEM_Base::caps_read_admin)));
     //now give the user permission to access transactions and make sure he can
     $current_user->add_cap('ee_read_transactions');
     $this->assertEquals(EEM_Transaction::instance()->count(), EEM_Transaction::instance()->count(array('caps' => EEM_Base::caps_read_admin)));
 }
 protected function __construct(EEM_Gateways &$model)
 {
     do_action('AHEE_log', __FILE__, __FUNCTION__, '');
     //echo '<h4>$this->_gateway_name : ' . $this->_gateway_name . '  <br /><span style="font-size:10px;font-weight:normal;">' . __FILE__ . '<br />line no: ' . __LINE__ . '</span></h4>';
     if (!defined('GATEWAYS_ADMIN_URL')) {
         define('GATEWAYS_ADMIN_URL', admin_url('admin.php?page=espresso_payment_settings'));
     }
     $this->_EEM_Gateways = $model;
     require_once EE_MODELS . 'EEM_Transaction.model.php';
     require_once EE_CLASSES . 'EE_Transaction.class.php';
     $this->_TXN = EEM_Transaction::instance();
     require_once EE_MODELS . 'EEM_Payment.model.php';
     require_once EE_CLASSES . 'EE_Payment.class.php';
     $this->_PAY = EEM_Payment::instance();
     require_once EE_MODELS . 'EEM_Registration.model.php';
     require_once EE_CLASSES . 'EE_Registration.class.php';
     $this->_REG = EEM_Registration::instance();
     if (!$this->_btn_img) {
         $this->_btn_img = EE_GATEWAYS_URL . $this->_gateway_name . DS . 'lib' . DS . $this->_button_base;
     }
     $this->_set_default_properties();
     $this->_handle_payment_settings();
     if (is_admin() && !empty($_GET['page']) && $_GET['page'] == 'espresso_payment_settings') {
         $this->_gateways_admin();
     } else {
         $this->_gateways_frontend();
     }
     //load formatter helper and form fields helper
     EE_Registry::instance()->load_helper('Formatter');
     EE_Registry::instance()->load_helper('Form_Fields');
 }
 /**
  *  get_transactions
  *    get transactions for given parameters (used by list table)
  *
  * @param  int     $perpage how many transactions displayed per page
  * @param  boolean $count return the count or objects
  * @param string   $view
  * @return mixed int = count || array of transaction objects
  */
 public function get_transactions($perpage, $count = FALSE, $view = '')
 {
     $TXN = EEM_Transaction::instance();
     $start_date = isset($this->_req_data['txn-filter-start-date']) ? wp_strip_all_tags($this->_req_data['txn-filter-start-date']) : date('D M j, Y', strtotime('-10 year'));
     $end_date = isset($this->_req_data['txn-filter-end-date']) ? wp_strip_all_tags($this->_req_data['txn-filter-end-date']) : date('D M j, Y');
     //make sure our timestamps start and end right at the boundaries for each day
     $start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
     $end_date = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
     //convert to timestamps
     $start_date = strtotime($start_date);
     $end_date = strtotime($end_date);
     //makes sure start date is the lowest value and vice versa
     $start_date = min($start_date, $end_date);
     $end_date = max($start_date, $end_date);
     //set orderby
     $this->_req_data['orderby'] = !empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
     switch ($this->_req_data['orderby']) {
         case 'TXN_ID':
             $orderby = 'TXN_ID';
             break;
         case 'ATT_fname':
             $orderby = 'Registration.Attendee.ATT_fname';
             break;
         case 'event_name':
             $orderby = 'Registration.Event.EVT_name';
             break;
         default:
             //'TXN_timestamp'
             $orderby = 'TXN_timestamp';
     }
     $sort = isset($this->_req_data['order']) && !empty($this->_req_data['order']) ? $this->_req_data['order'] : 'DESC';
     $current_page = isset($this->_req_data['paged']) && !empty($this->_req_data['paged']) ? $this->_req_data['paged'] : 1;
     $per_page = isset($perpage) && !empty($perpage) ? $perpage : 10;
     $per_page = isset($this->_req_data['perpage']) && !empty($this->_req_data['perpage']) ? $this->_req_data['perpage'] : $per_page;
     $offset = ($current_page - 1) * $per_page;
     $limit = array($offset, $per_page);
     $_where = array('TXN_timestamp' => array('BETWEEN', array($start_date, $end_date)), 'Registration.REG_count' => 1);
     if (isset($this->_req_data['EVT_ID'])) {
         $_where['Registration.EVT_ID'] = $this->_req_data['EVT_ID'];
     }
     if (isset($this->_req_data['s'])) {
         $search_string = '%' . $this->_req_data['s'] . '%';
         $_where['OR'] = array('Registration.Event.EVT_name' => array('LIKE', $search_string), 'Registration.Event.EVT_desc' => array('LIKE', $search_string), 'Registration.Event.EVT_short_desc' => array('LIKE', $search_string), 'Registration.Attendee.ATT_fname' => array('LIKE', $search_string), 'Registration.Attendee.ATT_lname' => array('LIKE', $search_string), 'Registration.Attendee.ATT_short_bio' => array('LIKE', $search_string), 'Registration.Attendee.ATT_email' => array('LIKE', $search_string), 'Registration.Attendee.ATT_address' => array('LIKE', $search_string), 'Registration.Attendee.ATT_address2' => array('LIKE', $search_string), 'Registration.Attendee.ATT_city' => array('LIKE', $search_string), 'Registration.REG_final_price' => array('LIKE', $search_string), 'Registration.REG_code' => array('LIKE', $search_string), 'Registration.REG_count' => array('LIKE', $search_string), 'Registration.REG_group_size' => array('LIKE', $search_string), 'Registration.Ticket.TKT_name' => array('LIKE', $search_string), 'Registration.Ticket.TKT_description' => array('LIKE', $search_string), 'Payment.PAY_source' => array('LIKE', $search_string), 'Payment.Payment_Method.PMD_name' => array('LIKE', $search_string), 'TXN_session_data' => array('LIKE', $search_string));
     }
     //failed transactions
     $failed = !empty($this->_req_data['status']) && $this->_req_data['status'] == 'failed' && !$count || $count && $view == 'failed' ? TRUE : FALSE;
     $abandoned = !empty($this->_req_data['status']) && $this->_req_data['status'] == 'abandoned' && !$count || $count && $view == 'abandoned' ? TRUE : FALSE;
     if ($failed) {
         $_where['STS_ID'] = EEM_Transaction::failed_status_code;
     } else {
         if ($abandoned) {
             $_where['STS_ID'] = EEM_Transaction::abandoned_status_code;
         } else {
             $_where['STS_ID'] = array('!=', EEM_Transaction::failed_status_code);
             $_where['STS_ID*'] = array('!=', EEM_Transaction::abandoned_status_code);
         }
     }
     $query_params = array($_where, 'order_by' => array($orderby => $sort), 'limit' => $limit);
     $transactions = $count ? $TXN->count(array($_where), 'TXN_ID', TRUE) : $TXN->get_all($query_params);
     return $transactions;
 }
 /**
  * _revenue_per_event_report
  * generates Business Report showing total revenue per event.
  *
  * @param string $period  The period (acceptable by PHP Datetime constructor) for which the report is generated.
  * @return int
  */
 private function _revenue_per_event_report($period = '-1 month')
 {
     $report_ID = 'txn-admin-revenue-per-event-report-dv';
     $TXN = EEM_Transaction::instance();
     $results = $TXN->get_revenue_per_event_report($period);
     $results = (array) $results;
     $revenue = array();
     $subtitle = '';
     if ($results) {
         $revenue[] = array(__('Event (only events that have a revenue greater than 1 are shown)', 'event_espresso'), __('Total Revenue', 'event_espresso'));
         foreach ($results as $result) {
             if ($result->revenue > 1) {
                 $event_name = stripslashes(html_entity_decode($result->event_name, ENT_QUOTES, 'UTF-8'));
                 $event_name = wp_trim_words($event_name, 5, '...');
                 $revenue[] = array($event_name, (double) $result->revenue);
             }
         }
         //setup the date range.
         EE_Registry::instance()->load_helper('DTT_Helper');
         $beginning_date = new DateTime('now' . $period, new DateTimeZone(EEH_DTT_Helper::get_timezone()));
         $ending_date = new DateTime('now', new DateTimeZone(EEH_DTT_Helper::get_timezone()));
         $subtitle = sprintf(_x('For the period: %s to %s', 'Used to give date range', 'event_espresso'), $beginning_date->format('Y-m-d'), $ending_date->format('Y-m-d'));
     }
     $report_title = __('Total Revenue per Event');
     $report_params = array('title' => $report_title, 'subtitle' => $subtitle, 'id' => $report_ID, 'revenue' => $revenue, 'noResults' => empty($revenue), 'noTxnMsg' => sprintf(__('%sThere are currently no transaction records in the last month for this report.%s', 'event_espresso'), '<h2>' . $report_title . '</h2><p>', '</p>'));
     wp_localize_script('ee-txn-reports-js', 'txnRevPerEvent', $report_params);
     return $report_ID;
 }
    /**
     * Deletes line items with no transaction who have passed the transaction cutoff time.
     * This needs to be very efficient
     * because if there are spam bots afoot there will be LOTS of line items
     * @return int count of how many deleted
     */
    public function delete_line_items_with_no_transaction()
    {
        /** @type WPDB $wpdb */
        global $wpdb;
        $time_to_leave_alone = apply_filters('FHEE__EEM_Line_Item__delete_line_items_with_no_transaction__time_to_leave_alone', WEEK_IN_SECONDS);
        $query = $wpdb->prepare('DELETE li
				FROM ' . $this->table() . ' li
				LEFT JOIN ' . EEM_Transaction::instance()->table() . ' t ON li.TXN_ID = t.TXN_ID
				WHERE t.TXN_ID IS NULL AND li.LIN_timestamp < %s', gmdate('Y-m-d H:i:s', time() - $time_to_leave_alone));
        return $wpdb->query($query);
    }
 /**
  *    _payments_and_amount_owing_rows
  *
  * @param EE_Line_Item $line_item
  * @param array        $options
  * @return mixed
  */
 private function _payments_and_amount_owing_rows(EE_Line_Item $line_item, $options = array())
 {
     $html = '';
     $owing = $line_item->total();
     $transaction = EEM_Transaction::instance()->get_one_by_ID($line_item->TXN_ID());
     if ($transaction instanceof EE_Transaction) {
         $registration_payments = array();
         $registrations = !empty($options['registrations']) ? $options['registrations'] : $transaction->registrations();
         foreach ($registrations as $registration) {
             if ($registration instanceof EE_Registration && $registration->owes_monies_and_can_pay()) {
                 $registration_payments = $registration_payments + $registration->registration_payments();
             }
         }
         if (!empty($registration_payments)) {
             foreach ($registration_payments as $registration_payment) {
                 if ($registration_payment instanceof EE_Registration_Payment) {
                     $owing = $owing - $registration_payment->amount();
                     $payment = $registration_payment->payment();
                     if ($payment instanceof EE_Payment) {
                         $payment_desc = sprintf(__('Payment%1$s Received: %2$s', 'event_espresso'), $payment->txn_id_chq_nmbr() != '' ? ' <span class="small-text">(#' . $payment->txn_id_chq_nmbr() . ')</span> ' : '', $payment->timestamp());
                     } else {
                         $payment_desc = '';
                     }
                     // start of row
                     $html .= EEH_HTML::tr('', '', 'total_tr odd');
                     // payment desc
                     $html .= EEH_HTML::td($payment_desc, '', '', '', ' colspan="3"');
                     // total td
                     $html .= EEH_HTML::td(EEH_Template::format_currency($registration_payment->amount(), false, false), '', 'total jst-rght');
                     // end of row
                     $html .= EEH_HTML::trx();
                 }
             }
             if ($line_item->total()) {
                 // start of row
                 $html .= EEH_HTML::tr('', '', 'total_tr odd');
                 // total td
                 $html .= EEH_HTML::td(__('Amount Owing', 'event_espresso'), '', 'total_currency total jst-rght', '', ' colspan="3"');
                 // total td
                 $html .= EEH_HTML::td(EEH_Template::format_currency($owing, false, false), '', 'total jst-rght');
                 // end of row
                 $html .= EEH_HTML::trx();
             }
         }
     }
     $this->_grand_total = $owing;
     return $html;
 }
 /**
  * This should be called each time there may have been an update to a
  * payment on a transaction (ie, we asked for a payment to process a
  * payment for a transaction, or we told a payment method about an IPN, or
  * we told a payment method to
  * "finalize_payment_for" (a transaction), or we told a payment method to
  * process a refund. This should handle firing the correct hooks to
  * indicate
  * what exactly happened and updating the transaction appropriately). This
  * could be integrated directly into EE_Transaction upon save, but we want
  * this logic to be separate from 'normal' plain-jane saving and updating
  * of transactions and payments, and to be tied to payment processing.
  * Note: this method DOES NOT save the payment passed into it. It is the responsibility
  * of previous code to decide whether or not to save (because the payment passed into
  * this method might be a temporary, never-to-be-saved payment from an offline gateway,
  * in which case we only want that payment object for some temporary usage during this request,
  * but we don't want it to be saved).
  *
  * @param EE_Transaction|int $transaction
  * @param EE_Payment     $payment
  * @param boolean        $update_txn
  *                        whether or not to call
  *                        EE_Transaction_Processor::
  *                        update_transaction_and_registrations_after_checkout_or_payment()
  *                        (you can save 1 DB query if you know you're going
  *                        to save it later instead)
  * @param bool           $IPN
  *                        if processing IPNs or other similar payment
  *                        related activities that occur in alternate
  *                        requests than the main one that is processing the
  *                        TXN, then set this to true to check whether the
  *                        TXN is locked before updating
  * @throws \EE_Error
  */
 public function update_txn_based_on_payment($transaction, $payment, $update_txn = true, $IPN = false)
 {
     $do_action = 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__not_successful';
     /** @type EE_Transaction $transaction */
     $transaction = EEM_Transaction::instance()->ensure_is_obj($transaction);
     // can we freely update the TXN at this moment?
     if ($IPN && $transaction->is_locked()) {
         // don't update the transaction at this exact moment
         // because the TXN is active in another request
         EE_Cron_Tasks::schedule_update_transaction_with_payment(time(), $transaction->ID(), $payment->ID());
     } else {
         // verify payment and that it has been saved
         if ($payment instanceof EE_Payment && $payment->ID()) {
             if ($payment->payment_method() instanceof EE_Payment_Method && $payment->payment_method()->type_obj() instanceof EE_PMT_Base) {
                 $payment->payment_method()->type_obj()->update_txn_based_on_payment($payment);
                 // update TXN registrations with payment info
                 $this->process_registration_payments($transaction, $payment);
             }
             $do_action = $payment->just_approved() ? 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__successful' : $do_action;
         } else {
             // send out notifications
             add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
             $do_action = 'AHEE__EE_Payment_Processor__update_txn_based_on_payment__no_payment_made';
         }
         // if this is an IPN, then we want to know the initial TXN status prior to updating the TXN
         // so that we know whether the status has changed and notifications should be triggered
         if ($IPN) {
             /** @type EE_Transaction_Processor $transaction_processor */
             $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
             $transaction_processor->set_old_txn_status($transaction->status_ID());
         }
         if ($payment->status() !== EEM_Payment::status_id_failed) {
             /** @type EE_Transaction_Payments $transaction_payments */
             $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
             // set new value for total paid
             $transaction_payments->calculate_total_payments_and_update_status($transaction);
             // call EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment() ???
             if ($update_txn) {
                 $this->_post_payment_processing($transaction, $payment, $IPN);
             }
         }
         // granular hook for others to use.
         do_action($do_action, $transaction, $payment);
         do_action('AHEE_log', __CLASS__, __FUNCTION__, $do_action, '$do_action');
         //global hook for others to use.
         do_action('AHEE__EE_Payment_Processor__update_txn_based_on_payment', $transaction, $payment);
     }
 }
    /**
     * Deletes "junk" transactions that were probably added by bots. There might be TONS
     * of these, so we are very careful to NOT select (which the models do even when deleting),
     * and so we only use wpdb directly and NOT do any joins.
     * The downside to this approach is that is addons are listening for object deletions
     * on EEM_Base::delete() they won't be notified of this.
     * @global WPDB $wpdb
     * @return mixed
     */
    public function delete_junk_transactions()
    {
        /** @type WPDB $wpdb */
        global $wpdb;
        $deleted = false;
        $time_to_leave_alone = apply_filters('FHEE__EEM_Transaction__delete_junk_transactions__time_to_leave_alone', WEEK_IN_SECONDS);
        /**
         * This allows code to filter the query arguments used for retrieving the transaction IDs to delete.
         * Useful for plugins that want to exclude transactions matching certain query parameters.
         * The query parameters should be in the format accepted by the EEM_Base model queries.
         */
        $ids_query = apply_filters('FHEE__EEM_Transaction__delete_junk_transactions__initial_query_args', array(0 => array('STS_ID' => EEM_Transaction::failed_status_code, 'TXN_timestamp' => array('<', time() - $time_to_leave_alone))), $time_to_leave_alone);
        /**
         * This filter is for when code needs to filter the list of transaction ids that represent transactions
         * about to be deleted based on some other criteria that isn't easily done via the query args filter.
         */
        $txn_ids = apply_filters('FHEE__EEM_Transaction__delete_junk_transactions__transaction_ids_to_delete', EEM_Transaction::instance()->get_col($ids_query, 'TXN_ID'), $time_to_leave_alone);
        //now that we have the ids to delete
        if (!empty($txn_ids) && is_array($txn_ids)) {
            // first, make sure these TXN's are removed the "ee_locked_transactions" array
            EEM_Transaction::unset_locked_transactions($txn_ids);
            // let's get deletin'...
            // Why no wpdb->prepare?  Because the data is trusted.
            // We got the ids from the original query to get them FROM
            // the db (which is sanitized) so no need to prepare them again.
            $query = '
				DELETE
				FROM ' . $this->table() . '
				WHERE
					TXN_ID IN ( ' . implode(",", $txn_ids) . ')';
            $deleted = $wpdb->query($query);
        }
        if ($deleted) {
            /**
             * Allows code to do something after the transactions have been deleted.
             */
            do_action('AHEE__EEM_Transaction__delete_junk_transactions__successful_deletion', $txn_ids);
        }
        return $deleted;
    }
 /**
  * Export a custom CSV of registration info including: A bunch of the reg fields, the time of the event, the price name,
  * and the questions associated with the registrations
  * @param int $event_id
  */
 function report_registrations_for_event($event_id = NULL)
 {
     $reg_fields_to_include = array('TXN_ID', 'ATT_ID', 'REG_ID', 'REG_date', 'REG_code', 'REG_count', 'REG_final_price');
     $att_fields_to_include = array('ATT_fname', 'ATT_lname', 'ATT_email', 'ATT_address', 'ATT_address2', 'ATT_city', 'STA_ID', 'CNT_ISO', 'ATT_zip', 'ATT_phone');
     $registrations_csv_ready_array = array();
     $reg_model = EE_Registry::instance()->load_model('Registration');
     $query_params = apply_filters('FHEE__EE_Export__report_registration_for_event', array(array('OR' => array('Transaction.STS_ID' => array('NOT IN', array(EEM_Transaction::failed_status_code, EEM_Transaction::abandoned_status_code)), 'STS_ID' => EEM_Registration::status_id_approved), 'Ticket.TKT_deleted' => array('IN', array(true, false))), 'order_by' => array('Transaction.TXN_ID' => 'asc', 'REG_count' => 'asc'), 'force_join' => array('Transaction', 'Ticket', 'Attendee'), 'caps' => EEM_Base::caps_read_admin), $event_id);
     if ($event_id) {
         $query_params[0]['EVT_ID'] = $event_id;
     } else {
         $query_params['force_join'][] = 'Event';
     }
     $registration_rows = $reg_model->get_all_wpdb_results($query_params);
     //get all questions which relate to someone in this group
     $registration_ids = array();
     foreach ($registration_rows as $reg_row) {
         $registration_ids[] = intval($reg_row['Registration.REG_ID']);
     }
     //		EEM_Question::instance()->show_next_x_db_queries();
     $questions_for_these_regs_rows = EEM_Question::instance()->get_all_wpdb_results(array(array('Answer.REG_ID' => array('IN', $registration_ids))));
     foreach ($registration_rows as $reg_row) {
         if (is_array($reg_row)) {
             $reg_csv_array = array();
             if (!$event_id) {
                 //get the event's name and Id
                 $reg_csv_array[__('Event', 'event_espresso')] = sprintf(__('%1$s (%2$s)', 'event_espresso'), $this->_prepare_value_from_db_for_display(EEM_Event::instance(), 'EVT_name', $reg_row['Event_CPT.post_title']), $reg_row['Event_CPT.ID']);
             }
             $is_primary_reg = $reg_row['Registration.REG_count'] == '1' ? true : false;
             /*@var $reg_row EE_Registration */
             foreach ($reg_fields_to_include as $field_name) {
                 $field = $reg_model->field_settings_for($field_name);
                 if ($field_name == 'REG_final_price') {
                     $value = $this->_prepare_value_from_db_for_display($reg_model, $field_name, $reg_row['Registration.REG_final_price'], 'localized_float');
                 } elseif ($field_name == 'REG_count') {
                     $value = sprintf(__('%s of %s', 'event_espresso'), $this->_prepare_value_from_db_for_display($reg_model, 'REG_count', $reg_row['Registration.REG_count']), $this->_prepare_value_from_db_for_display($reg_model, 'REG_group_size', $reg_row['Registration.REG_group_size']));
                 } elseif ($field_name == 'REG_date') {
                     $value = $this->_prepare_value_from_db_for_display($reg_model, $field_name, $reg_row['Registration.REG_date'], 'no_html');
                 } else {
                     $value = $this->_prepare_value_from_db_for_display($reg_model, $field_name, $reg_row[$field->get_qualified_column()]);
                 }
                 $reg_csv_array[$this->_get_column_name_for_field($field)] = $value;
                 if ($field_name == 'REG_final_price') {
                     //add a column named Currency after the final price
                     $reg_csv_array[__("Currency", "event_espresso")] = EE_Config::instance()->currency->code;
                 }
             }
             //get pretty status
             $stati = EEM_Status::instance()->localized_status(array($reg_row['Registration.STS_ID'] => __('unknown', 'event_espresso'), $reg_row['TransactionTable.STS_ID'] => __('unknown', 'event_espresso')), FALSE, 'sentence');
             $reg_csv_array[__("Registration Status", 'event_espresso')] = $stati[$reg_row['Registration.STS_ID']];
             //get pretty trnasaction status
             $reg_csv_array[__("Transaction Status", 'event_espresso')] = $stati[$reg_row['TransactionTable.STS_ID']];
             $reg_csv_array[__('Transaction Amount Due', 'event_espresso')] = $is_primary_reg ? $this->_prepare_value_from_db_for_display(EEM_Transaction::instance(), 'TXN_total', $reg_row['TransactionTable.TXN_total'], 'localized_float') : '0.00';
             $reg_csv_array[__('Amount Paid', 'event_espresso')] = $is_primary_reg ? $this->_prepare_value_from_db_for_display(EEM_Transaction::instance(), 'TXN_paid', $reg_row['TransactionTable.TXN_paid'], 'localized_float') : '0.00';
             $payment_methods = array();
             $gateway_txn_ids_etc = array();
             $payment_times = array();
             if ($is_primary_reg && $reg_row['TransactionTable.TXN_ID']) {
                 $payments_info = EEM_Payment::instance()->get_all_wpdb_results(array(array('TXN_ID' => $reg_row['TransactionTable.TXN_ID'], 'STS_ID' => EEM_Payment::status_id_approved), 'force_join' => array('Payment_Method')), ARRAY_A, 'Payment_Method.PMD_admin_name as name, Payment.PAY_txn_id_chq_nmbr as gateway_txn_id, Payment.PAY_timestamp as payment_time');
                 foreach ($payments_info as $payment_method_and_gateway_txn_id) {
                     $payment_methods[] = isset($payment_method_and_gateway_txn_id['name']) ? $payment_method_and_gateway_txn_id['name'] : __('Unknown', 'event_espresso');
                     $gateway_txn_ids_etc[] = isset($payment_method_and_gateway_txn_id['gateway_txn_id']) ? $payment_method_and_gateway_txn_id['gateway_txn_id'] : '';
                     $payment_times[] = isset($payment_method_and_gateway_txn_id['payment_time']) ? $payment_method_and_gateway_txn_id['payment_time'] : '';
                 }
             }
             $reg_csv_array[__('Payment Date(s)', 'event_espresso')] = implode(',', $payment_times);
             $reg_csv_array[__('Payment Method(s)', 'event_espresso')] = implode(",", $payment_methods);
             $reg_csv_array[__('Gateway Transaction ID(s)', 'event_espresso')] = implode(',', $gateway_txn_ids_etc);
             //get whether or not the user has checked in
             $reg_csv_array[__("Check-Ins", "event_espresso")] = $reg_model->count_related($reg_row['Registration.REG_ID'], 'Checkin');
             //get ticket of registration and its price
             $ticket_model = EE_Registry::instance()->load_model('Ticket');
             if ($reg_row['Ticket.TKT_ID']) {
                 $ticket_name = $this->_prepare_value_from_db_for_display($ticket_model, 'TKT_name', $reg_row['Ticket.TKT_name']);
                 $datetimes_strings = array();
                 foreach (EEM_Datetime::instance()->get_all_wpdb_results(array(array('Ticket.TKT_ID' => $reg_row['Ticket.TKT_ID']), 'order_by' => array('DTT_EVT_start' => 'ASC'), 'default_where_conditions' => 'none')) as $datetime) {
                     $datetimes_strings[] = $this->_prepare_value_from_db_for_display(EEM_Datetime::instance(), 'DTT_EVT_start', $datetime['Datetime.DTT_EVT_start']);
                 }
             } else {
                 $ticket_name = __('Unknown', 'event_espresso');
                 $datetimes_strings = array(__('Unknown', 'event_espresso'));
             }
             $reg_csv_array[$ticket_model->field_settings_for('TKT_name')->get_nicename()] = $ticket_name;
             $reg_csv_array[__("Datetimes of Ticket", "event_espresso")] = implode(", ", $datetimes_strings);
             //get datetime(s) of registration
             //add attendee columns
             foreach ($att_fields_to_include as $att_field_name) {
                 $field_obj = EEM_Attendee::instance()->field_settings_for($att_field_name);
                 if ($reg_row['Attendee_CPT.ID']) {
                     if ($att_field_name == 'STA_ID') {
                         $value = EEM_State::instance()->get_var(array(array('STA_ID' => $reg_row['Attendee_Meta.STA_ID'])), 'STA_name');
                     } elseif ($att_field_name == 'CNT_ISO') {
                         $value = EEM_Country::instance()->get_var(array(array('CNT_ISO' => $reg_row['Attendee_Meta.CNT_ISO'])), 'CNT_name');
                     } else {
                         $value = $this->_prepare_value_from_db_for_display(EEM_Attendee::instance(), $att_field_name, $reg_row[$field_obj->get_qualified_column()]);
                     }
                 } else {
                     $value = '';
                 }
                 $reg_csv_array[$this->_get_column_name_for_field($field_obj)] = $value;
             }
             //make sure each registration has the same questions in the same order
             foreach ($questions_for_these_regs_rows as $question_row) {
                 if (!isset($reg_csv_array[$question_row['Question.QST_admin_label']])) {
                     $reg_csv_array[$question_row['Question.QST_admin_label']] = null;
                 }
             }
             //now fill out the questions THEY answered
             foreach (EEM_Answer::instance()->get_all_wpdb_results(array(array('REG_ID' => $reg_row['Registration.REG_ID']), 'force_join' => array('Question'))) as $answer_row) {
                 /* @var $answer EE_Answer */
                 if ($answer_row['Question.QST_ID']) {
                     $question_label = $this->_prepare_value_from_db_for_display(EEM_Question::instance(), 'QST_admin_label', $answer_row['Question.QST_admin_label']);
                 } else {
                     $question_label = sprintf(__('Question $s', 'event_espresso'), $answer_row['Answer.QST_ID']);
                 }
                 if (isset($answer_row['Question.QST_type']) && $answer_row['Question.QST_type'] == EEM_Question::QST_type_state) {
                     $reg_csv_array[$question_label] = EEM_State::instance()->get_state_name_by_ID($answer_row['Answer.ANS_value']);
                 } else {
                     $reg_csv_array[$question_label] = $this->_prepare_value_from_db_for_display(EEM_Answer::instance(), 'ANS_value', $answer_row['Answer.ANS_value']);
                 }
             }
             $registrations_csv_ready_array[] = apply_filters('FHEE__EE_Export__report_registrations__reg_csv_array', $reg_csv_array, $reg_row);
         }
     }
     //if we couldn't export anything, we want to at least show the column headers
     if (empty($registrations_csv_ready_array)) {
         $reg_csv_array = array();
         $model_and_fields_to_include = array('Registration' => $reg_fields_to_include, 'Attendee' => $att_fields_to_include);
         foreach ($model_and_fields_to_include as $model_name => $field_list) {
             $model = EE_Registry::instance()->load_model($model_name);
             foreach ($field_list as $field_name) {
                 $field = $model->field_settings_for($field_name);
                 $reg_csv_array[$this->_get_column_name_for_field($field)] = null;
                 //$registration->get($field->get_name());
             }
         }
         $registrations_csv_ready_array[] = $reg_csv_array;
     }
     if ($event_id) {
         $event_slug = EEM_Event::instance()->get_var(array(array('EVT_ID' => $event_id)), 'EVT_slug');
         if (!$event_slug) {
             $event_slug = __('unknown', 'event_espresso');
         }
     } else {
         $event_slug = __('all', 'event_espresso');
     }
     $filename = sprintf("registrations-for-%s", $event_slug);
     $handle = $this->EE_CSV->begin_sending_csv($filename);
     $this->EE_CSV->write_data_array_to_csv($handle, $registrations_csv_ready_array);
     $this->EE_CSV->end_sending_csv($handle);
 }
 /**
  * Creates a line item for the taxes subtotal and finds all the tax prices
  * and applies taxes to it
  * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total
  * @param EE_Transaction $transaction
  * @return EE_Line_Item
  */
 protected static function create_default_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = NULL)
 {
     $tax_line_item = EE_Line_Item::new_instance(array('LIN_code' => 'taxes', 'LIN_name' => __('Taxes', 'event_espresso'), 'LIN_type' => EEM_Line_Item::type_tax_sub_total));
     if ($transaction) {
         $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction);
         $total_line_item->set_TXN_ID($transaction);
     }
     $total_line_item->add_child_line_item($tax_line_item);
     //and lastly, add the actual taxes
     self::apply_taxes($total_line_item);
     return $tax_line_item;
 }