/**
  * like test_REG_final_price_matches_total_of_filtering_line_item_tree,
  * but makes sure the tickets have sub-prices, because that has shown to have some
  * bugs with calculations so far
  */
 function test_REG_final_price_matches_total_of_filtering_line_item_tree__with_sub_line_items()
 {
     $transaction = $this->new_typical_transaction(array('ticket_types' => 2, 'fixed_ticket_price_modifiers' => 2));
     //add another ticket purchase for one of the same events
     $event1 = EEM_Event::instance()->get_one(array(array('Registration.TXN_ID' => $transaction->ID())));
     $event_line_item = EEM_Line_Item::instance()->get_one(array(array('TXN_ID' => $transaction->ID(), 'OBJ_type' => 'Event', 'OBJ_ID' => $event1->ID())));
     $discount = $this->new_model_obj_with_dependencies('Line_Item', array('LIN_type' => EEM_Line_Item::type_line_item, 'LIN_name' => 'event discount', 'LIN_total' => -8, 'LIN_unit_price' => -8, 'LIN_percent' => 0, 'LIN_quantity' => 1, 'LIN_parent' => $event_line_item->ID(), 'LIN_percent' => null, 'LIN_order' => count($event_line_item->children())));
     $transaction->total_line_item()->recalculate_pre_tax_total();
     //and add an unrelated purchase
     EEH_Line_Item::add_unrelated_item($transaction->total_line_item(), 'Transaction-Wide Discount', -5);
     $totals = EEH_Line_Item::calculate_reg_final_prices_per_line_item($transaction->total_line_item());
     //		honestly the easiest way to confirm the total was right is to visualize the tree
     //		var_dump( $totals );
     //		EEH_Line_Item::visualize( $transaction->total_line_item() );
     //for each registration on the tranasction, verify the REG_final_price
     //indicated by EEH_Line_Item::calculate_reg_final_prices_per_line_item matches
     //what the line item filters would have returned
     EEH_Autoloader::register_line_item_filter_autoloaders();
     foreach ($transaction->registrations() as $registration) {
         $ticket_line_item = EEM_Line_Item::instance()->get_line_item_for_registration($registration);
         $reg_final_price_from_line_item_helper = $totals[$ticket_line_item->ID()];
         //now get the line item filter's final price
         $filters = new EE_Line_Item_Filter_Collection();
         $filters->add(new EE_Single_Registration_Line_Item_Filter($registration));
         $line_item_filter_processor = new EE_Line_Item_Filter_Processor($filters, $transaction->total_line_item());
         $filtered_line_item_tree = $line_item_filter_processor->process();
         $reg_final_price_from_line_item_filter = $filtered_line_item_tree->total();
         $this->assertLessThan(0.2, abs($reg_final_price_from_line_item_filter - $reg_final_price_from_line_item_helper));
     }
 }
 /**
  * * also test that if you call this in order to get the taxable total, that it doesn't update
  * the totals to ONLY be taxable totals
  * @group 7026
  */
 function test_recalculate_pre_tax_total__dont_save_if_ignoring_nontaxables()
 {
     //make a txn where NOTHING is taxable
     $txn = $this->new_typical_transaction(array('ticket_types' => 2, 'taxable_tickets' => 1));
     $proper_line_items = EEM_Line_Item::instance()->get_all_of_type_for_transaction(EEM_Line_Item::type_line_item, $txn->ID());
     $this->assertEquals(2, count($proper_line_items));
     $taxable_one = FALSE;
     $nontaxable_one = FALSE;
     $taxable_line_item = NULL;
     foreach ($proper_line_items as $line_item) {
         if ($line_item->is_taxable()) {
             $taxable_one = TRUE;
             $taxable_line_item = $line_item;
         } else {
             $nontaxable_one = TRUE;
         }
     }
     $this->assertTrue($taxable_one);
     $this->assertTrue($nontaxable_one);
     $this->assertNotEquals(0, $txn->tax_total());
     $total_line_item = $txn->total_line_item();
     $old_total = $total_line_item->total();
     //when we calculate the pre-tax, including only taxable items (ie, we're wanting
     //to know how much to apply taxes to) we don't change the grand or ticket totals
     $pretax_total = $total_line_item->taxable_total();
     //because there is only one taxable line item, the taxable total should equals its total
     $this->assertEquals($taxable_line_item->total(), $pretax_total);
     //check we didn't assign the taxable total to be the grand total
     $this->assertNotEquals($pretax_total, $total_line_item->total());
     $this->assertEquals($old_total, $total_line_item->total());
     //find tickets subtotal and make sure it hasn't been assigned to be the taxable total either
     //temporarily commented out because this throws an error.
     //$this->assertNotEquals( $pretax_total, $total_line_item->get_child_line_item('tickets')->total() );
 }
 /**
  * sets the _counts_per_line_item_code from the provided registrations
  * @param EE_Registration[] $registrations
  * @return void
  */
 protected function _calculate_counts_per_line_item_code($registrations)
 {
     foreach ($registrations as $registration) {
         $line_item_code = EEM_Line_Item::instance()->get_var(EEM_Line_Item::instance()->line_item_for_registration_query_params($registration, array('limit' => 1)), 'LIN_code');
         if ($line_item_code) {
             if (!isset($this->_counts_per_line_item_code[$line_item_code])) {
                 $this->_counts_per_line_item_code[$line_item_code] = 1;
             } else {
                 $this->_counts_per_line_item_code[$line_item_code]++;
             }
         }
     }
 }
 /**
  * @group 7965
  */
 function test_delete_registrations_with_no_transaction()
 {
     $deletable_count = 5;
     $safe_count = 8;
     for ($i = 0; $i < $deletable_count; $i++) {
         $this->new_model_obj_with_dependencies('Line_Item', array('TXN_ID' => 0, 'LIN_timestamp' => time() - WEEK_IN_SECONDS * 2));
     }
     for ($i = 0; $i < $safe_count; $i++) {
         $this->new_model_obj_with_dependencies('Line_Item');
     }
     $deleted = EEM_Line_Item::instance()->delete_line_items_with_no_transaction();
     $this->assertEquals($deletable_count, $deleted);
 }
 /**
  * 		instantiate the EEM_Line_Item singleton
  *
  * 		@access public
  * 		@param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any incoming timezone data that gets saved).  Note this just sends the timezone info to the date time model field objects.  Default is NULL (and will be assumed using the set timezone in the 'timezone_string' wp option)
  * 		@return \EEM_Line_Item
  */
 public static function instance($timezone = NULL)
 {
     // check if instance of EEM_Line_Item already exists
     if (!self::$_instance instanceof EEM_Line_Item) {
         // instantiate Price_model
         self::$_instance = new self($timezone);
     }
     //set timezone if we have in incoming string
     if (!empty($timezone)) {
         self::$_instance->set_timezone($timezone);
     }
     // EEM_Line_Item object
     return self::$_instance;
 }
 function test_migrate_pretax_total()
 {
     $script = EE_Registry::instance()->load_dms('EE_DMS_Core_4_8_0');
     $stage = new EE_DMS_4_8_0_pretax_totals();
     // ok let's create a line item to with the LIN_code='tickets'
     $tickets_subtotal = $this->new_model_obj_with_dependencies('Line_Item', array('LIN_code' => 'tickets'));
     // and another that DOESN"T match it
     $other_line_item = $this->new_model_obj_with_dependencies('Line_Item', array('LIN_code' => 'not-tickets'));
     $stage->migration_step();
     $new_tickets_subtotal = EEM_Line_Item::instance()->refresh_entity_map_from_db($tickets_subtotal->ID());
     $this->assertEquals('pre-tax-subtotal', $new_tickets_subtotal->get('LIN_code'));
     $new_other_line_item = EEM_Line_Item::instance()->refresh_entity_map_from_db($other_line_item->ID());
     $this->assertEquals('not-tickets', $new_other_line_item->get('LIN_code'));
 }
 /**
  * Gets all the line items which are unrelated to tickets on this transaction
  * @return EE_Line_Item[]
  */
 public function non_ticket_line_items()
 {
     return EEM_Line_Item::instance()->get_all_non_ticket_line_items_for_transaction($this->ID());
 }
 /**
  *
  * @throws EE_Error
  */
 public function test_distanced_HABTM_join()
 {
     try {
         EEM_Line_Item::instance()->get_all(array(array('Ticket.Datetime.EVT_ID' => 1, 'TXN_ID' => 1)));
         $this->assertTrue(TRUE);
     } catch (EE_Error $e) {
         throw $e;
     }
 }
 /**
  * This helper method can be used by any incoming data handlers to setup the data correctly.  All that is required is that $this->reg_objs be set.
  * @throws \EE_Error
  */
 protected function _assemble_data()
 {
     //verify that reg_objs is set
     if (!is_array($this->reg_objs) && !reset($this->reg_objs) instanceof EE_Registration) {
         throw new EE_Error(__('In order to assemble the data correctly, the "reg_objs" property must be an array of EE_Registration objects', 'event_espresso'));
     }
     //get all attendee and events associated with the registrations in this transaction
     $events = $event_setup = $evtcache = $tickets = $datetimes = array();
     $answers = $questions = $attendees = $line_items = $registrations = array();
     $total_ticket_count = 0;
     if (!empty($this->reg_objs)) {
         $event_attendee_count = array();
         foreach ($this->reg_objs as $reg) {
             //account for filtered registrations by status.
             if (!empty($this->filtered_reg_status) && $this->filtered_reg_status !== $reg->status_ID()) {
                 continue;
             }
             $evt_id = $reg->event_ID();
             /** @type EE_Ticket $ticket */
             $ticket = $reg->get_first_related('Ticket');
             $relateddatetime = $ticket->datetimes();
             $total_ticket_count++;
             $tickets[$ticket->ID()]['ticket'] = $ticket;
             $tickets[$ticket->ID()]['count'] = is_array($tickets[$ticket->ID()]) && isset($tickets[$ticket->ID()]['count']) ? $tickets[$ticket->ID()]['count'] + 1 : 1;
             $tickets[$ticket->ID()]['att_objs'][$reg->attendee_ID()] = $reg->attendee();
             $tickets[$ticket->ID()]['dtt_objs'] = $relateddatetime;
             $tickets[$ticket->ID()]['reg_objs'][$reg->ID()] = $reg;
             $event = $reg->event();
             $tickets[$ticket->ID()]['EE_Event'] = $event;
             $evtcache[$evt_id] = $event;
             $eventsetup[$evt_id]['reg_objs'][$reg->ID()] = $reg;
             $eventsetup[$evt_id]['tkt_objs'][$ticket->ID()] = $ticket;
             $eventsetup[$evt_id]['att_objs'][$reg->attendee_ID()] = $reg->attendee();
             $event_attendee_count[$evt_id] = isset($event_attendee_count[$evt_id]) ? $event_attendee_count[$evt_id] + 1 : 0;
             $attendees[$reg->attendee_ID()]['line_ref'][] = $evt_id;
             $attendees[$reg->attendee_ID()]['att_obj'] = $reg->attendee();
             $attendees[$reg->attendee_ID()]['reg_objs'][$reg->ID()] = $reg;
             //$attendees[ $reg->attendee_ID() ]['registration_id'] = $reg->ID();
             $attendees[$reg->attendee_ID()]['attendee_email'] = $reg->attendee() instanceof EE_Attendee ? $reg->attendee()->email() : '';
             $attendees[$reg->attendee_ID()]['tkt_objs'][$ticket->ID()] = $ticket;
             $attendees[$reg->attendee_ID()]['evt_objs'][$evt_id] = $event;
             //registrations
             $registrations[$reg->ID()]['tkt_obj'] = $ticket;
             $registrations[$reg->ID()]['evt_obj'] = $event;
             $registrations[$reg->ID()]['reg_obj'] = $reg;
             $registrations[$reg->ID()]['att_obj'] = $reg->attendee();
             //set up answer objects
             $rel_ans = $reg->get_many_related('Answer');
             foreach ($rel_ans as $ansid => $answer) {
                 if (!isset($questions[$ansid])) {
                     $questions[$ansid] = $answer->get_first_related('Question');
                 }
                 $answers[$ansid] = $answer;
                 $registrations[$reg->ID()]['ans_objs'][$ansid] = $answer;
             }
             foreach ($relateddatetime as $dtt_id => $datetime) {
                 $eventsetup[$evt_id]['dtt_objs'][$dtt_id] = $datetime;
                 $registrations[$reg->ID()]['dtt_objs'][$dtt_id] = $datetime;
                 if (isset($datetimes[$dtt_id])) {
                     continue;
                     //already have this info in the datetimes array.
                 }
                 $datetimes[$dtt_id]['tkt_objs'][] = $ticket;
                 $datetimes[$dtt_id]['datetime'] = $datetime;
                 $datetimes[$dtt_id]['evt_objs'][$evt_id] = $event;
                 $datetimes[$dtt_id]['reg_objs'][$reg->ID()] = $reg;
             }
         }
         //let's loop through the unique event=>reg items and setup data on them
         if (!empty($eventsetup)) {
             foreach ($eventsetup as $evt_id => $items) {
                 if ($this->txn instanceof EE_Transaction) {
                     $ticket_line_items_for_event = EEM_Line_Item::instance()->get_all(array(array('Ticket.Datetime.EVT_ID' => $evt_id, 'TXN_ID' => $this->txn->ID()), 'default_where_conditions' => 'none'));
                 } else {
                     $ticket_line_items_for_event = array();
                 }
                 $events[$evt_id] = array('ID' => $evt_id, 'event' => $evtcache[$evt_id], 'name' => $evtcache[$evt_id] instanceof EE_Event ? $evtcache[$evt_id]->name() : '', 'total_attendees' => $event_attendee_count[$evt_id], 'reg_objs' => $items['reg_objs'], 'tkt_objs' => $items['tkt_objs'], 'att_objs' => $items['att_objs'], 'dtt_objs' => isset($items['dtt_objs']) ? $items['dtt_objs'] : array(), 'line_items' => $ticket_line_items_for_event);
                 //make sure the tickets have the line items setup for them.
                 foreach ($ticket_line_items_for_event as $line_id => $line_item) {
                     if ($line_item instanceof EE_Line_Item) {
                         $tickets[$line_item->ticket()->ID()]['line_item'] = $line_item;
                         $tickets[$line_item->ticket()->ID()]['sub_line_items'] = $line_item->children();
                         $line_items[$line_item->ID()]['children'] = $line_item->children();
                         $line_items[$line_item->ID()]['EE_Ticket'] = $line_item->ticket();
                     }
                 }
             }
         }
         $this->grand_total_line_item = $this->txn instanceof EE_Transaction ? $this->txn->total_line_item() : null;
     }
     //lets set the attendees and events properties
     $this->attendees = $attendees;
     $this->events = $events;
     $this->tickets = $tickets;
     $this->line_items_with_children = $line_items;
     $this->datetimes = $datetimes;
     $this->questions = $questions;
     $this->answers = $answers;
     $this->total_ticket_count = $total_ticket_count;
     $this->registrations = $registrations;
     if ($this->txn instanceof EE_Transaction) {
         $this->tax_line_items = $this->txn->tax_items();
         $this->additional_line_items = $this->txn->non_ticket_line_items();
         $this->payments = $this->txn->payments();
         //setup primary registration if we have a single transaction object to work with
         //let's get just the primary_attendee_data!  First we get the primary registration object.
         $primary_reg = $this->txn->primary_registration();
         // verify
         if ($primary_reg instanceof EE_Registration) {
             // get attendee object
             if ($primary_reg->attendee() instanceof EE_Attendee) {
                 //now we can setup the primary_attendee_data array
                 $this->primary_attendee_data = array('registration_id' => $primary_reg->ID(), 'att_obj' => $primary_reg->attendee(), 'reg_obj' => $primary_reg, 'primary_att_obj' => $primary_reg->attendee(), 'primary_reg_obj' => $primary_reg);
             } else {
                 EE_Error::add_error(__('Incoming data does not have a valid Attendee object for the primary registrant.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
             }
         } else {
             EE_Error::add_error(__('Incoming data does not have a valid Registration object for the primary registrant.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
         }
     }
 }
 /**
  * Updates the registration' final prices based on the current line item tree (taking into account
  * discounts, taxes, and other line items unrelated to tickets.)
  * @param EE_Transaction $transaction
  * @param boolean $save_regs whether to immediately save registrations in this function or not
  * @return void
  */
 public function update_registration_final_prices($transaction, $save_regs = true)
 {
     $reg_final_price_per_ticket_line_item = EEH_Line_Item::calculate_reg_final_prices_per_line_item($transaction->total_line_item());
     foreach ($transaction->registrations() as $registration) {
         $line_item = EEM_Line_Item::instance()->get_line_item_for_registration($registration);
         if (isset($reg_final_price_per_ticket_line_item[$line_item->ID()])) {
             $registration->set_final_price($reg_final_price_per_ticket_line_item[$line_item->ID()]);
             if ($save_regs) {
                 $registration->save();
             }
         }
     }
     //and make sure there's no rounding problem
     $this->fix_reg_final_price_rounding_issue($transaction);
 }
 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();
     }
 }
 public function send_invoice($download = FALSE)
 {
     $template_args = array();
     $EE = EE_Registry::instance();
     //allow the request to override the default theme defined in the invoice settings
     $theme_requested = isset($_REQUEST['theme']) && $_REQUEST['theme'] > 0 && $_REQUEST['theme'] < 8 ? absint($_REQUEST['theme']) : null;
     $themes = array(1 => "simple.css", 2 => "bauhaus.css", 3 => "ejs.css", 4 => "horizon.css", 5 => "lola.css", 6 => "tranquility.css", 7 => "union.css");
     //Get the CSS file
     if (isset($themes[$theme_requested])) {
         $template_args['invoice_css'] = $themes[$theme_requested];
     } else {
         $template_args['invoice_css'] = $this->invoice_payment_method->get_extra_meta('legacy_invoice_css', TRUE, 'simple.css');
     }
     if (is_dir(EVENT_ESPRESSO_GATEWAY_DIR . '/invoice')) {
         $template_args['base_url'] = EVENT_ESPRESSO_GATEWAY_URL . 'Invoice/lib/templates/';
     } else {
         $template_args['base_url'] = EE_GATEWAYS . '/Invoice/lib/templates/';
     }
     $primary_attendee = $this->transaction->primary_registration()->attendee();
     $template_args['organization'] = $EE->CFG->organization->get_pretty('name');
     $template_args['street'] = empty($EE->CFG->organization->address_2) ? $EE->CFG->organization->get_pretty('address_1') : $EE->CFG->organization->get_pretty('address_1') . '<br>' . $EE->CFG->organization->get_pretty('address_2');
     $template_args['city'] = $EE->CFG->organization->get_pretty('city');
     $template_args['state'] = EE_Registry::instance()->load_model('State')->get_one_by_ID($EE->CFG->organization->STA_ID);
     $template_args['country'] = EE_Registry::instance()->load_model('Country')->get_one_by_ID($EE->CFG->organization->CNT_ISO);
     $template_args['zip'] = $EE->CFG->organization->get_pretty('zip');
     $template_args['email'] = $EE->CFG->organization->get_pretty('email');
     $template_args['registration_code'] = $this->registration->reg_code();
     $template_args['registration_date'] = $this->registration->date();
     $template_args['name'] = $primary_attendee->full_name();
     $template_args['attendee_address'] = $primary_attendee->address();
     $template_args['attendee_address2'] = $primary_attendee->address2();
     $template_args['attendee_city'] = $primary_attendee->city();
     $attendee_state = $primary_attendee->state_obj();
     if ($attendee_state) {
         $attendee_state_name = $attendee_state->name();
     } else {
         $attendee_state_name = '';
     }
     $template_args['attendee_state'] = $attendee_state_name;
     $template_args['attendee_zip'] = $primary_attendee->zip();
     $template_args['ship_name'] = $template_args['name'];
     $template_args['ship_address'] = $template_args['attendee_address'];
     $template_args['ship_city'] = $template_args['attendee_city'];
     $template_args['ship_state'] = $template_args['attendee_state'];
     $template_args['ship_zip'] = $template_args['attendee_zip'];
     $template_args['total_cost'] = number_format($this->transaction->total(), 2, '.', '');
     $template_args['transaction'] = $this->transaction;
     $template_args['amount_pd'] = $this->transaction->paid();
     $template_args['amount_owed'] = $this->transaction->total() - $this->transaction->paid();
     $template_args['payments'] = $this->transaction->approved_payments();
     $template_args['net_total'] = '';
     $template_args['edit_reg_info_url'] = $this->registration->edit_attendee_information_url();
     $template_args['retry_payment_url'] = $this->registration->payment_overview_url();
     $template_args['show_line_item_description'] = $this->check_if_any_line_items_have_a_description($this->transaction->total_line_item());
     if ($template_args['amount_pd'] != $template_args['total_cost']) {
         //$template_args['net_total'] = $this->espressoInvoiceTotals( __('SubTotal', 'event_espresso'), $this->transaction->total());//$this->session_data['cart']['REG']['sub_total']);
         $tax_items = $this->transaction->tax_items();
         if (!empty($tax_items)) {
             foreach ($tax_items as $tax) {
                 $template_args['net_total'] .= $this->espressoInvoiceTotals($tax->name(), $tax->total());
             }
         }
         $difference = $template_args['amount_pd'] - $template_args['total_cost'];
         if ($difference < 0) {
             $text = __('Discount', 'event_espresso');
         } else {
             $text = __('Extra', 'event_espresso');
         }
         $template_args['discount'] = $this->espressoInvoiceTotals($text, $difference);
     }
     $template_args['currency_symbol'] = $EE->CFG->currency->sign;
     $template_args['template_payment_instructions'] = wpautop(stripslashes_deep(html_entity_decode($this->invoice_payment_method->get_extra_meta('pdf_instructions', TRUE), ENT_QUOTES)));
     $template_args['shameless_plug'] = apply_filters('FHEE_Invoice__send_invoice__shameless_plug', true);
     if (isset($_GET['receipt'])) {
         //receipt-specific stuff
         $events_for_txn = EEM_Event::instance()->get_all(array(array('Registration.TXN_ID' => $this->transaction->ID())));
         $ticket_line_items_per_event = array();
         $registrations_per_line_item = array();
         $venues_for_events = array();
         foreach ($events_for_txn as $event_id => $event) {
             $line_items_for_this_event = EEM_Line_Item::instance()->get_all(array(array('Ticket.Datetime.EVT_ID' => $event_id, 'TXN_ID' => $this->transaction->ID())));
             $ticket_line_items_per_event[$event_id] = $line_items_for_this_event;
             foreach ($line_items_for_this_event as $line_item_id => $line_item) {
                 $ticket = $line_item->ticket();
                 $registrations_for_this_ticket = EEM_Registration::instance()->get_all(array(array('TKT_ID' => $ticket->ID(), 'TXN_ID' => $this->transaction->ID())));
                 $registrations_per_line_item[$line_item_id] = $registrations_for_this_ticket;
             }
             $venues_for_events = array_merge($venues_for_events, $event->venues());
         }
         $tax_total_line_item = EEM_Line_Item::instance()->get_one(array(array('TXN_ID' => $this->transaction->ID(), 'LIN_type' => EEM_Line_Item::type_tax_sub_total)));
         $questions_to_skip = array(EEM_Attendee::system_question_fname, EEM_Attendee::system_question_lname, EEM_Attendee::system_question_email);
         $template_args['events_for_txn'] = $events_for_txn;
         $template_args['ticket_line_items_per_event'] = $ticket_line_items_per_event;
         $template_args['registrations_per_line_item'] = $registrations_per_line_item;
         $template_args['venues_for_events'] = $venues_for_events;
         $template_args['tax_total_line_item'] = $tax_total_line_item;
         $template_args['questions_to_skip'] = $questions_to_skip;
         //			d($template_args);
         $template_args['download_link'] = $this->registration->receipt_url('download');
     } else {
         //it's just an invoice we're accessing
         $template_args['download_link'] = $this->registration->invoice_url('download');
     }
     //Get the HTML as an object
     $templates_relative_path = 'modules/gateways/Invoice/lib/templates/';
     $template_header = EEH_Template::locate_template($templates_relative_path . 'invoice_header.template.php', $template_args, TRUE, TRUE);
     if (isset($_GET['receipt'])) {
         $template_body = EEH_Template::locate_template($templates_relative_path . 'receipt_body.template.php', $template_args, TRUE, TRUE);
     } else {
         $template_body = EEH_Template::locate_template($templates_relative_path . 'invoice_body.template.php', $template_args, TRUE, TRUE);
     }
     $template_footer = EEH_Template::locate_template($templates_relative_path . 'invoice_footer.template.php', $template_args, TRUE, TRUE);
     $copies = !empty($_REQUEST['copies']) ? $_REQUEST['copies'] : 1;
     $content = $this->espresso_replace_invoice_shortcodes($template_header);
     for ($x = 1; $x <= $copies; $x++) {
         $content .= $this->espresso_replace_invoice_shortcodes($template_body);
     }
     $content .= $this->espresso_replace_invoice_shortcodes($template_footer);
     //Check if debugging or mobile is set
     if (!empty($_REQUEST['html'])) {
         echo $content;
         exit(0);
     }
     $invoice_name = $template_args['organization'] . ' ' . __('Invoice #', 'event_espresso') . $template_args['registration_code'] . __(' for ', 'event_espresso') . $template_args['name'];
     $invoice_name = str_replace(' ', '_', $invoice_name);
     //Create the PDF
     if (array_key_exists('html', $_GET)) {
         echo $content;
     } else {
         //only load dompdf if nobody else has yet...
         if (!defined('DOMPDF_DIR')) {
             define('DOMPDF_ENABLE_REMOTE', TRUE);
             define('DOMPDF_ENABLE_JAVASCRIPT', FALSE);
             define('DOMPDF_ENABLE_CSS_FLOAT', TRUE);
             require_once EE_THIRD_PARTY . 'dompdf/dompdf_config.inc.php';
         }
         $dompdf = new DOMPDF();
         $dompdf->load_html($content);
         $dompdf->render();
         $dompdf->stream($invoice_name . ".pdf", array('Attachment' => $download));
     }
     exit(0);
 }
 public function test_delete_items()
 {
     //known to fail
     $ticket_types = 4;
     $transaction = $this->new_typical_transaction(array('ticket_types' => $ticket_types));
     $latest_line_item = EEM_Line_Item::instance()->get_one(array(array('LIN_type' => EEM_Line_Item::type_line_item), 'order_by' => array('LIN_ID' => 'DESC')));
     $cart = EE_Cart::get_cart_from_txn($transaction);
     $removals = $cart->delete_items(array($latest_line_item->code()));
     //should remove the ticket line item and its sub-line-item for the price
     $this->assertEquals(2, $removals);
     $this->assertEquals($ticket_types - 1, $cart->all_ticket_quantity_count());
     $cart_items = $cart->get_tickets();
     $this->assertArrayDoesNotContain($latest_line_item, $cart_items);
 }
 /**
  *        remove an attendee from event in the event cart
  *
  * @access    protected
  * @param int $line_item_id
  * @return \EE_Line_Item|null
  */
 protected function get_line_item($line_item_id = 0)
 {
     $line_item = null;
     //EEH_Debug_Tools::printr( $line_item_id, '$line_item_id', __FILE__, __LINE__ );
     if (is_int($line_item_id)) {
         //EEH_Debug_Tools::printr( absint( $line_item_id ), 'absint( $line_item_id )', __FILE__, __LINE__ );
         $line_item = EEM_Line_Item::instance()->get_one_by_ID(absint($line_item_id));
     }
     // get line item from db
     //EEH_Debug_Tools::printr( $line_item, '$line_item', __FILE__, __LINE__ );
     if ($line_item instanceof EE_Line_Item) {
         return $line_item;
     }
     $line_item_id = sanitize_text_field($line_item_id);
     //EEH_Debug_Tools::printr( $line_item_id, '$line_item_id', __FILE__, __LINE__ );
     // or... search thru cart
     $tickets_in_cart = EE_Registry::instance()->CART->get_tickets();
     foreach ($tickets_in_cart as $ticket_in_cart) {
         if ($ticket_in_cart instanceof EE_Line_Item && $ticket_in_cart->code() == $line_item_id) {
             $line_item = $ticket_in_cart;
             if ($line_item instanceof EE_Line_Item) {
                 return $line_item;
             }
         }
     }
     // couldn't find the line item !?!?!
     EE_Error::add_error(__('The specified item could not be found in the cart, therefore the quantity could not be adjusted. Please refresh the page and try again.', 'event_espresso'), __FILE__, __FUNCTION__, __LINE__);
     return null;
 }
 /**
  * clone_and_reset_line_item
  *
  * clones the incoming object
  * resets any fields that represent database primary keys
  * resets total
  *
  * @param \EEI_Line_Item $line_item
  * @return \EEI_Line_Item
  */
 protected function clone_and_reset_line_item(EEI_Line_Item $line_item)
 {
     // we don't actually want to work with the original line item, so clone it
     $cloned_line_item = clone $line_item;
     $cloned_line_item->set('LIN_ID', null);
     $cloned_line_item->set('LIN_parent', null);
     $cloned_line_item->clear_related_line_item_cache();
     foreach (array_keys(EEM_Line_Item::instance()->relation_settings()) as $relation_name) {
         $cloned_line_item->clear_cache($relation_name, null, true);
     }
     $cloned_line_item->set_allow_persist(false);
     return $cloned_line_item;
 }
 /**
  * @group 8193
  */
 public function test_calculate_reg_final_prices_per_line_item__3_taxable_tickets_with_an_event_wide_discount()
 {
     $transaction = $this->new_typical_transaction(array('ticket_types' => 2));
     //add another ticket purchase for one of the same events
     $event1 = EEM_Event::instance()->get_one(array(array('Registration.TXN_ID' => $transaction->ID())));
     $event_line_item = EEM_Line_Item::instance()->get_one(array(array('TXN_ID' => $transaction->ID(), 'OBJ_type' => 'Event', 'OBJ_ID' => $event1->ID())));
     $discount = $this->new_model_obj_with_dependencies('Line_Item', array('LIN_type' => EEM_Line_Item::type_line_item, 'LIN_name' => 'event discount', 'LIN_total' => -8, 'LIN_unit_price' => -8, 'LIN_percent' => 0, 'LIN_quantity' => 1, 'LIN_parent' => $event_line_item->ID(), 'LIN_percent' => null, 'LIN_order' => count($event_line_item->children())));
     $transaction->total_line_item()->recalculate_pre_tax_total();
     //and add an unrelated purchase
     EEH_Line_Item::add_unrelated_item($transaction->total_line_item(), 'Transaction-Wide Discount', -5);
     $totals = EEH_Line_Item::calculate_reg_final_prices_per_line_item($transaction->total_line_item());
     //		honestly the easiest way to confirm the total was right is to visualize the tree
     //		var_dump( $totals );
     //		EEH_Line_Item::visualize( $transaction->total_line_item() );
     //verify that if we added the REG_final_prices onto the regs as derived from $totals,
     //that it would equal the grand total
     $sum_of_regs_final_prices = 0;
     foreach ($transaction->registrations() as $reg) {
         $ticket_line_item = EEM_Line_Item::instance()->get_line_item_for_registration($reg);
         $sum_of_regs_final_prices += $totals[$ticket_line_item->ID()];
     }
     $this->assertEquals($totals['total'], $sum_of_regs_final_prices);
     //ok now let's verify the 'REG_final_price' for each ticket's line item is what we expect it to be
     //so there should be 3 ticket line items right?
     $ticket_line_items = EEM_Line_Item::instance()->get_all(array(array('TXN_ID' => $transaction->ID(), 'OBJ_type' => 'Ticket')));
     //one ticket should be 10 pre-tax
     $ten_dollar_ticket = EEM_Line_Item::instance()->get_one(array(array('TXN_ID' => $transaction->ID(), 'LIN_unit_price' => 10, 'LIN_type' => EEM_Line_Item::type_line_item)));
     $this->assertEquals(3.05, round($totals[$ten_dollar_ticket->ID()], 2));
     //one ticket should be 20 pre-tax
     $twenty_dollar_ticket = EEM_Line_Item::instance()->get_one(array(array('TXN_ID' => $transaction->ID(), 'LIN_unit_price' => 20, 'LIN_type' => EEM_Line_Item::type_line_item)));
     $this->assertEquals(18.45, round($totals[$twenty_dollar_ticket->ID()], 2));
 }
 /**
  * Overwrites the previous tax by clearing out the old taxes, and creates a new
  * tax and updates the total line item accordingly
  * @param EE_Line_Item $total_line_item
  * @param float $amount
  * @param string $name
  * @param string $description
  * @param string $code
  * @param boolean $add_to_existing_line_item
  *                                           if true, and a duplicate line item with the same code is found,
  *                                           $amount will be added onto it; otherwise will simply set the taxes to match $amount
  * @return EE_Line_Item the new tax line item created
  */
 public static function set_total_tax_to(EE_Line_Item $total_line_item, $amount, $name = NULL, $description = NULL, $code = NULL, $add_to_existing_line_item = false)
 {
     $tax_subtotal = self::get_taxes_subtotal($total_line_item);
     $taxable_total = $total_line_item->taxable_total();
     if ($add_to_existing_line_item) {
         $new_tax = $tax_subtotal->get_child_line_item($code);
         EEM_Line_Item::instance()->delete(array(array('LIN_code' => array('!=', $code), 'LIN_parent' => $tax_subtotal->ID())));
     } else {
         $new_tax = null;
         $tax_subtotal->delete_children_line_items();
     }
     if ($new_tax) {
         $new_tax->set_total($new_tax->total() + $amount);
         $new_tax->set_percent($taxable_total ? $new_tax->total() / $taxable_total * 100 : 0);
     } else {
         //no existing tax item. Create it
         $new_tax = EE_Line_Item::new_instance(array('TXN_ID' => $total_line_item->TXN_ID(), 'LIN_name' => $name ? $name : __('Tax', 'event_espresso'), 'LIN_desc' => $description ? $description : '', 'LIN_percent' => $taxable_total ? $amount / $taxable_total * 100 : 0, 'LIN_total' => $amount, 'LIN_parent' => $tax_subtotal->ID(), 'LIN_type' => EEM_Line_Item::type_tax, 'LIN_code' => $code));
     }
     $new_tax = apply_filters('FHEE__EEH_Line_Item__set_total_tax_to__new_tax_subtotal', $new_tax, $total_line_item);
     $new_tax->save();
     $tax_subtotal->set_total($new_tax->total());
     $tax_subtotal->save();
     $total_line_item->recalculate_total_including_taxes();
     return $new_tax;
 }
 /**
  * @group 7358
  */
 public function test_get_raw()
 {
     $l2 = EE_Line_Item::new_instance(array());
     $this->assertTrue(1 == $l2->get_raw('LIN_quantity'));
     $l2->save();
     $l2_from_db = EEM_Line_Item::reset()->get_one_by_ID($l2->ID());
     //double check its NULL in the DB
     $qty_col_with_one_result = EEM_Line_Item::instance()->get_col(array(array('LIN_ID' => $l2->ID())), 'LIN_quantity');
     $qty_col_in_db = reset($qty_col_with_one_result);
     $this->assertTrue(1 == $qty_col_in_db);
     //and now verify get_raw is returning that same value
     $this->assertTrue(1 == $l2_from_db->get_raw('LIN_quantity'));
 }