/**
  * generate_ONE_registration_from_line_item
  *
  * Although a ticket line item may have a quantity greater than 1,
  * this method will ONLY CREATE ONE REGISTRATION !!!
  * Regardless of the ticket line item quantity.
  * This means that any code calling this method is responsible for ensuring
  * that the final registration count matches the ticket line item quantity.
  * This was done to make it easier to match the number of registrations
  * to the number of tickets in the cart, when the cart has been edited
  * after SPCO has already been initialized. So if an additional ticket was added to the cart, you can simply pass
  * the line item to this method to add a second ticket, and in this case, you would not want to add 2 tickets.
  *
  * @param EE_Line_Item $line_item
  * @param \EE_Transaction $transaction
  * @param int $att_nmbr
  * @param int $total_ticket_count
  * @return \EE_Registration | null
  * @throws \EE_Error
  */
 public function generate_ONE_registration_from_line_item(EE_Line_Item $line_item, EE_Transaction $transaction, $att_nmbr = 1, $total_ticket_count = 1)
 {
     // grab the related ticket object for this line_item
     $ticket = $line_item->ticket();
     if (!$ticket instanceof EE_Ticket) {
         EE_Error::add_error(sprintf(__("Line item %s did not contain a valid ticket", "event_espresso"), $line_item->ID()), __FILE__, __FUNCTION__, __LINE__);
         return null;
     }
     $first_datetime = $ticket->get_first_related('Datetime');
     if (!$first_datetime instanceof EE_Datetime) {
         EE_Error::add_error(sprintf(__("The ticket (%s) is not associated with any valid datetimes.", "event_espresso"), $ticket->name()), __FILE__, __FUNCTION__, __LINE__);
         return null;
     }
     $event = $first_datetime->get_first_related('Event');
     if (!$event instanceof EE_Event) {
         EE_Error::add_error(sprintf(__("The ticket (%s) is not associated with a valid event.", "event_espresso"), $ticket->name()), __FILE__, __FUNCTION__, __LINE__);
         return null;
     }
     $reg_url_link = $this->generate_reg_url_link($att_nmbr, $line_item);
     // now create a new registration for the ticket
     $registration = EE_Registration::new_instance(array('EVT_ID' => $event->ID(), 'TXN_ID' => $transaction->ID(), 'TKT_ID' => $ticket->ID(), 'STS_ID' => EEM_Registration::status_id_incomplete, 'REG_date' => $transaction->datetime(), 'REG_final_price' => $ticket->get_ticket_total_with_taxes(), 'REG_session' => EE_Registry::instance()->SSN->id(), 'REG_count' => $att_nmbr, 'REG_group_size' => $total_ticket_count, 'REG_url_link' => $reg_url_link));
     $registration->set_reg_code($this->generate_reg_code($registration));
     $registration->save();
     $registration->_add_relation_to($event, 'Event', array(), $event->ID());
     $registration->_add_relation_to($line_item->ticket(), 'Ticket', array(), $line_item->ticket()->ID());
     $transaction->_add_relation_to($registration, 'Registration');
     return $registration;
 }
 function test_generate_code()
 {
     $t = EE_Transaction::new_instance();
     $t->save();
     $l = EE_Line_Item::new_instance(array('OBJ_type' => 'Transaction', 'OBJ_ID' => $t->ID()));
     $this->assertNotNull($l->generate_code());
 }
 /**
  *	@remove ALL items from cart and delete total as well
  *	@access public
  *	@return bool
  */
 public function delete_cart()
 {
     EE_Registry::instance()->load_helper('Line_Item');
     $deleted = EEH_Line_Item::delete_all_child_items($this->_grand_total);
     if ($deleted) {
         $deleted += $this->_grand_total->delete();
     }
     return $deleted;
 }
 /**
  *	@save cart to session
  *	@access public
  *	@return TRUE on success, FALSE on fail
  */
 public function save_cart()
 {
     EEH_Line_Item::ensure_taxes_applied($this->_grand_total);
     //make sure we don't cache the transaction because it can get stale
     if ($this->_grand_total->get_one_from_cache('Transaction') instanceof EE_Transaction && $this->_grand_total->get_one_from_cache('Transaction')->ID()) {
         $this->_grand_total->clear_cache('Transaction', null, true);
     }
     return EE_Registry::instance()->SSN->set_cart($this);
 }
 /**
  * @save cart to session
  * @access public
  * @param bool $apply_taxes
  * @return TRUE on success, FALSE on fail
  */
 public function save_cart($apply_taxes = TRUE)
 {
     if ($apply_taxes && $this->_grand_total instanceof EE_Line_Item) {
         EEH_Line_Item::ensure_taxes_applied($this->_grand_total);
         //make sure we don't cache the transaction because it can get stale
         if ($this->_grand_total->get_one_from_cache('Transaction') instanceof EE_Transaction && $this->_grand_total->get_one_from_cache('Transaction')->ID()) {
             $this->_grand_total->clear_cache('Transaction', null, true);
         }
     }
     if ($this->_session instanceof EE_Session) {
         return $this->_session->set_cart($this);
     } else {
         return false;
     }
 }
 /**
  * @param EE_Line_Item $line_item
  * @param array        $options
  * @return mixed
  */
 public function display_line_item(EE_Line_Item $line_item, $options = array())
 {
     EE_Registry::instance()->load_helper('HTML');
     $html = '';
     // set some default options and merge with incoming
     $default_options = array('show_desc' => TRUE, 'odd' => FALSE);
     $options = array_merge($default_options, (array) $options);
     switch ($line_item->type()) {
         case EEM_Line_Item::type_total:
             // loop thru children
             foreach ($line_item->children() as $child_line_item) {
                 // recursively feed children back into this method
                 //					$html .= $this->display_line_item( $child_line_item, $options );
             }
             //				$html .= $this->_separator_row( $options );
             //				$html .= $this->_total_row( $line_item, __('Total', 'event_espresso'), $options );
             break;
         case EEM_Line_Item::type_sub_total:
             // loop thru children
             foreach ($line_item->children() as $child_line_item) {
                 // recursively feed children back into this method
                 //					$html .= $this->display_line_item( $child_line_item, $options );
             }
             //				$html .= $this->_total_row( $line_item, __('Sub-Total', 'event_espresso'), $options );
             break;
         case EEM_Line_Item::type_tax_sub_total:
             // loop thru children
             foreach ($line_item->children() as $child_line_item) {
                 // recursively feed children back into this method
                 //					$html .= $this->display_line_item( $child_line_item, $options );
             }
             //				$html .= $this->_total_row( $line_item, __('Tax Total', 'event_espresso'), $options );
             break;
         case EEM_Line_Item::type_line_item:
             // item row
             //				$html .= $this->_item_row( $line_item, $options );
             // got any kids?
             foreach ($line_item->children() as $child_line_item) {
                 //					$this->display_line_item( $child_line_item, $options );
             }
             break;
         case EEM_Line_Item::type_sub_line_item:
             //				$html .= $this->_sub_item_row( $line_item, $options );
             break;
         case EEM_Line_Item::type_tax:
             //				$html .= $this->_tax_row( $line_item, $options );
             break;
     }
     return $html;
 }
 function test_finalize()
 {
     $t = EE_Transaction::new_instance(array('STS_ID' => EEM_Transaction::complete_status_code));
     $t->save();
     $e = EE_Event::new_instance();
     $e->save();
     $tkt = EE_Ticket::new_instance();
     $tkt->save();
     $d = EE_Datetime::new_instance(array('EVT_ID' => $e->ID()));
     $d->save();
     $tkt->_add_relation_to($d, 'Datetime');
     /** @type EE_Registration_Processor $registration_processor */
     $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
     $reg_url = $registration_processor->generate_reg_url_link(1, EE_Line_Item::new_instance(array('LIN_name' => $tkt->name(), 'LIN_desc' => $tkt->description(), 'LIN_unit_price' => $tkt->price(), 'LIN_quantity' => 1, 'LIN_is_taxable' => $tkt->taxable(), 'LIN_order' => 0, 'LIN_total' => $tkt->price(), 'LIN_type' => EEM_Line_Item::type_line_item, 'OBJ_ID' => $tkt->ID(), 'OBJ_type' => 'Ticket')));
     $r = EE_REgistration::new_instance(array('EVT_ID' => $e->ID(), 'TXN_ID' => $t->ID(), 'TKT_ID' => $tkt->ID(), 'STS_ID' => EEM_Registration::status_id_pending_payment, 'REG_url_link' => $reg_url));
     $r->set_reg_code($registration_processor->generate_reg_code($r));
     $registration_processor->update_registration_after_checkout_or_payment($r);
     $this->assertNotNull($r->reg_code());
     $this->assertEquals(EEM_Registration::status_id_approved, $r->status_ID());
 }
 /**
  */
 function test_filter__removed_subtotals_with_no_ticket_children()
 {
     //verify that normal subtotals stay, but subtotals with no ticket children get removed
     //so create a total
     $total = EE_Line_Item::new_instance(array('LIN_name' => 'total', 'LIN_code' => 'total', 'LIN_type' => EEM_Line_Item::type_total));
     //and a subttoal WITH a ticket (but the subtotal itself was erroneously labelled as quantity 0)
     $subtotal_with_tkt = EE_Line_Item::new_instance(array('LIN_name' => 'subtotal-with-tkt', 'LIN_code' => 'subttoal-with-tkt', 'LIN_type' => EEM_Line_Item::type_sub_total, 'LIN_quantity' => 0));
     $total->add_child_line_item($subtotal_with_tkt);
     $tkt1 = EE_Line_Item::new_instance(array('LIN_name' => 'tkt1', 'LIN_code' => 'tkt1', 'LIN_type' => EEM_Line_Item::type_line_item, 'OBJ_type' => 'Ticket', 'LIN_quantity' => 1));
     $subtotal_with_tkt->add_child_line_item($tkt1);
     //and another subtotal with a ticket but quantity 0, and another non-ticket line item with quantity 1
     $subtotal_without_tkt = EE_Line_Item::new_instance(array('LIN_name' => 'subtotal-without-tkt', 'LIN_code' => 'subttoal-without-tkt', 'LIN_type' => EEM_Line_Item::type_sub_total, 'LIN_quantity' => 0));
     $total->add_child_line_item($subtotal_without_tkt);
     $tkt2 = EE_Line_Item::new_instance(array('LIN_name' => 'tkt2', 'LIN_code' => 'tkt2', 'LIN_type' => EEM_Line_Item::type_line_item, 'OBJ_type' => 'Ticket', 'LIN_quantity' => 0));
     $subtotal_without_tkt->add_child_line_item($tkt2);
     $non_tkt_li = EE_Line_Item::new_instance(array('LIN_name' => 'non_tkt_li', 'LIN_code' => 'non_tkt_li', 'LIN_type' => EEM_Line_Item::type_line_item, 'OBJ_type' => null, 'LIN_quantity' => 1));
     $subtotal_without_tkt->add_child_line_item($non_tkt_li);
     //only the subtotal without a ticket should get filtered out
     $filter = new EE_Non_Zero_Line_Item_Filter();
     $filter->process($total);
     $totals_children = $total->children();
     $this->assertContains($subtotal_with_tkt, $totals_children);
     $this->assertNotContains($subtotal_without_tkt, $totals_children);
 }
 /**
  * get_all_promotion_line_items
  * searches the cart for any and all existing promotion line items
  *
  * @since   1.0.0
  *
  * @param EE_Line_Item $parent_line_item
  * @return EE_Line_Item[]
  */
 public function get_all_promotion_line_items(EE_Line_Item $parent_line_item)
 {
     return $this->get_all(array(array('TXN_ID' => $parent_line_item->TXN_ID(), 'LIN_parent' => $parent_line_item->ID(), 'OBJ_type' => 'Promotion')));
 }
 /**
  * generate_ONE_registration_from_line_item
  *
  * Although a ticket line item may have a quantity greater than 1,
  * this method will ONLY CREATE ONE REGISTRATION !!!
  * Regardless of the ticket line item quantity.
  * This means that any code calling this method is responsible for ensuring
  * that the final registration count matches the ticket line item quantity.
  * This was done to make it easier to match the number of registrations
  * to the number of tickets in the cart, when the cart has been edited
  * after SPCO has already been initialized. So if an additional ticket was added to the cart, you can simply pass
  * the line item to this method to add a second ticket, and in this case, you would not want to add 2 tickets.
  *
  * @param EE_Line_Item $line_item
  * @param \EE_Transaction $transaction
  * @param int $att_nmbr
  * @param int $total_ticket_count
  * @return \EE_Registration | null
  * @throws \EE_Error
  */
 public function generate_ONE_registration_from_line_item(EE_Line_Item $line_item, EE_Transaction $transaction, $att_nmbr = 1, $total_ticket_count = 1)
 {
     // grab the related ticket object for this line_item
     $ticket = $line_item->ticket();
     if (!$ticket instanceof EE_Ticket) {
         EE_Error::add_error(sprintf(__("Line item %s did not contain a valid ticket", "event_espresso"), $line_item->ID()), __FILE__, __FUNCTION__, __LINE__);
         return null;
     }
     $first_datetime = $ticket->get_first_related('Datetime');
     if (!$first_datetime instanceof EE_Datetime) {
         EE_Error::add_error(sprintf(__("The ticket (%s) is not associated with any valid datetimes.", "event_espresso"), $ticket->name()), __FILE__, __FUNCTION__, __LINE__);
         return null;
     }
     $event = $first_datetime->get_first_related('Event');
     if (!$event instanceof EE_Event) {
         EE_Error::add_error(sprintf(__("The ticket (%s) is not associated with a valid event.", "event_espresso"), $ticket->name()), __FILE__, __FUNCTION__, __LINE__);
         return null;
     }
     $reg_url_link = $this->generate_reg_url_link($att_nmbr, $line_item);
     if ($this->_reg_final_price_per_tkt_line_item === null) {
         $this->_reg_final_price_per_tkt_line_item = EEH_Line_Item::calculate_reg_final_prices_per_line_item($transaction->total_line_item());
     }
     //ok now find this new registration's final price
     if (isset($this->_reg_final_price_per_tkt_line_item[$line_item->ID()])) {
         $final_price = $this->_reg_final_price_per_tkt_line_item[$line_item->ID()];
     } else {
         $message = sprintf(__('The ticket line item (ID:%1$d) had no entry in the reg_final_price_per_tkt_line_item array.', 'event_espresso'), $line_item->ID());
         if (WP_DEBUG) {
             throw new EE_Error($message);
         } else {
             EE_Log::instance()->log(__CLASS__, __FUNCTION__, $message);
         }
         $final_price = $ticket->get_ticket_total_with_taxes();
     }
     // now create a new registration for the ticket
     $registration = EE_Registration::new_instance(array('EVT_ID' => $event->ID(), 'TXN_ID' => $transaction->ID(), 'TKT_ID' => $ticket->ID(), 'STS_ID' => EEM_Registration::status_id_incomplete, 'REG_date' => $transaction->datetime(), 'REG_final_price' => $final_price, 'REG_session' => EE_Registry::instance()->SSN->id(), 'REG_count' => $att_nmbr, 'REG_group_size' => $total_ticket_count, 'REG_url_link' => $reg_url_link));
     $registration->set_reg_code($this->generate_reg_code($registration));
     $registration->save();
     $registration->_add_relation_to($event, 'Event', array(), $event->ID());
     $registration->_add_relation_to($line_item->ticket(), 'Ticket', array(), $line_item->ticket()->ID());
     $transaction->_add_relation_to($registration, 'Registration');
     return $registration;
 }
 protected function _setup_data()
 {
     //need to figure out the running total for test purposes so... we're going to create a temp cart and add the tickets to it!
     EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
     $cart = EE_Cart::reset();
     //add tickets to cart
     foreach ($this->tickets as $ticket) {
         $cart->add_ticket_to_cart($ticket['ticket']);
     }
     //setup txn property
     $this->txn = EE_Transaction::new_instance(array('TXN_timestamp' => time(), 'TXN_total' => 0, 'TXN_paid' => 0, 'STS_ID' => EEM_Transaction::incomplete_status_code, 'TXN_session_data' => NULL, 'TXN_hash_salt' => NULL, 'TXN_ID' => 999999));
     //setup reg_objects
     //note we're setting up a reg object for each attendee in each event but ALSO adding to the reg_object array.
     $this->reg_objs = array();
     $regid = 9999990;
     foreach ($this->_attendees as $key => $attendee) {
         //note we need to setup reg_objects for each event this attendee belongs to
         $regatt = $attendee['att_obj']->ID();
         $regtxn = $this->txn->ID();
         $regcnt = 1;
         foreach ($attendee['line_ref'] as $evtid) {
             foreach ($this->_events[$evtid]['tkt_objs'] as $ticket) {
                 $reg_array = array('EVT_ID' => $evtid, 'ATT_ID' => $regatt, 'TXN_ID' => $regtxn, 'TKT_ID' => $ticket->ID(), 'STS_ID' => EEM_Registration::status_id_pending_payment, 'REG_date' => time(), 'REG_final_price' => $ticket->get('TKT_price'), 'REG_session' => 'dummy_session_id', 'REG_code' => $regid . '-dummy-generated-code', 'REG_url_link' => $regcnt . '-daafpapasdlfakasdfpqasdfasdf', 'REG_count' => $regcnt, 'REG_group_size' => $this->_events[$evtid]['total_attendees'], 'REG_att_is_going' => TRUE, 'REG_ID' => $regid);
                 $REG_OBJ = EE_Registration::new_instance($reg_array);
                 $this->_attendees[$key]['reg_objs'][$regid] = $REG_OBJ;
                 $this->_events[$evtid]['reg_objs'][] = $REG_OBJ;
                 $this->reg_objs[] = $REG_OBJ;
                 $this->tickets[$ticket->ID()]['reg_objs'][$regid] = $REG_OBJ;
                 $regcnt++;
                 $regid++;
             }
         }
     }
     //setup line items!
     EE_Registry::instance()->load_helper('Line_Item');
     $line_item_total = EEH_Line_Item::create_total_line_item($this->txn);
     //add tickets
     foreach ($this->tickets as $tktid => $item) {
         $qty = $item['count'];
         $ticket = $item['ticket'];
         EEH_Line_Item::add_ticket_purchase($line_item_total, $ticket, $qty);
     }
     $shipping_line_item = EE_Line_Item::new_instance(array('LIN_name' => __('Shipping Surcharge', 'event_espresso'), 'LIN_desc' => __('Sent via Millenium Falcon', 'event_espresso'), 'LIN_unit_price' => 20, 'LIN_quantity' => 1, 'LIN_is_taxable' => TRUE, 'LIN_total' => 20, 'LIN_type' => EEM_Line_Item::type_line_item));
     EEH_Line_Item::add_item($line_item_total, $shipping_line_item);
     $this->additional_line_items = array($shipping_line_item);
     //now let's add taxes
     EEH_Line_Item::apply_taxes($line_item_total);
     //now we should be able to get the items we need from this object
     $event_line_items = EEH_Line_Item::get_pre_tax_subtotal($line_item_total)->children();
     $line_items = array();
     foreach ($event_line_items as $line_id => $line_item) {
         if (!$line_item instanceof EE_Line_Item || $line_item->OBJ_type() !== 'Event') {
             continue;
         }
         $ticket_line_items = EEH_Line_Item::get_ticket_line_items($line_item);
         foreach ($ticket_line_items as $ticket_line_id => $ticket_line_item) {
             if (!$ticket_line_item instanceof EE_Line_Item) {
                 continue;
             }
             $this->tickets[$ticket_line_item->OBJ_ID()]['line_item'] = $ticket_line_item;
             $this->tickets[$ticket_line_item->OBJ_ID()]['sub_line_items'] = $ticket_line_item->children();
             $line_items[$ticket_line_item->ID()]['children'] = $ticket_line_item->children();
             $line_items[$ticket_line_item->ID()]['EE_Ticket'] = $this->tickets[$ticket_line_item->OBJ_ID()]['ticket'];
         }
     }
     $this->line_items_with_children = $line_items;
     $this->tax_line_items = $line_item_total->tax_descendants();
     //add proper total to transaction object.
     $grand_total = $line_item_total->recalculate_total_including_taxes();
     $this->grand_total_line_item = $line_item_total;
     $this->txn->set_total($grand_total);
     //add additional details for each registration
     foreach ($this->reg_objs as $reg) {
         $this->_registrations[$reg->ID()]['tkt_obj'] = $this->tickets[$reg->get('TKT_ID')]['ticket'];
         $this->_registrations[$reg->ID()]['evt_obj'] = $this->_events[$reg->get('EVT_ID')]['event'];
         $this->_registrations[$reg->ID()]['reg_obj'] = $reg;
         $this->_registrations[$reg->ID()]['ans_objs'] = $this->_attendees[$reg->get('ATT_ID')]['ans_objs'];
         $this->_registrations[$reg->ID()]['att_obj'] = $this->_attendees[$reg->get('ATT_ID')]['att_obj'];
         $this->_registrations[$reg->ID()]['dtt_objs'] = $this->tickets[$reg->get('TKT_ID')]['dtt_objs'];
     }
     //events and attendees
     $this->events = $this->_events;
     $this->attendees = $this->_attendees;
     $this->registrations = $this->_registrations;
     $attendees_to_shift = $this->_attendees;
     //setup primary attendee property
     $this->primary_attendee_data = array('fname' => $this->_attendees[999999991]['att_obj']->fname(), 'lname' => $this->_attendees[999999991]['att_obj']->lname(), 'email' => $this->_attendees[999999991]['att_obj']->email(), 'att_obj' => $this->_attendees[999999991]['att_obj'], 'reg_obj' => array_shift($attendees_to_shift[999999991]['reg_objs']));
     //reg_info property
     //note this isn't referenced by any shortcode parsers so we'll ignore for now.
     $this->reg_info = array();
     //let's set a reg_obj for messengers expecting one.
     $this->reg_obj = array_pop($this->_attendees[999999991]['reg_objs']);
     //the below are just dummy items.
     $this->user_id = 1;
     $this->ip_address = '192.0.2.1';
     $this->user_agent = '';
     $this->init_access = time();
     $this->last_access = time();
 }
 /**
  *    _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;
 }
 /**
  * Creates a new, unsaved line item, but if it's a ticket line item
  * with a total of 0, or a subtotal of 0, returns null instead
  * @param EE_Line_Item      $line_item
  * @return EE_Line_Item
  */
 public static function non_empty_line_item(EE_Line_Item $line_item)
 {
     if ($line_item->type() === EEM_Line_Item::type_line_item && $line_item->OBJ_type() === 'Ticket' && $line_item->quantity() == 0) {
         return null;
     }
     $new_li_fields = $line_item->model_field_array();
     //don't set the total. We'll leave that up to the code that calculates it
     unset($new_li_fields['LIN_ID']);
     unset($new_li_fields['LIN_parent']);
     return EE_Line_Item::new_instance($new_li_fields);
 }
 /**
  * Process payment start
  *
  * @param EE_Line_Item $total_line_item
  * @param $transaction
  */
 public function process_payment_start(EE_Line_Item $total_line_item, $transaction = null)
 {
     if (!$transaction) {
         $transaction = $total_line_item->transaction();
     }
     $config_id = $this->_payment_settings['config_id'];
     $gateway = Pronamic_WP_Pay_Plugin::get_gateway($config_id);
     if ($gateway) {
         $data = new Pronamic_WP_Pay_Extensions_EventEspresso_PaymentData($this, $total_line_item, $transaction);
         $payment = Pronamic_WP_Pay_Plugin::start($config_id, $gateway, $data);
         $error = $gateway->get_error();
         if (!is_wp_error($error)) {
             $offsite_form = $this->submitPayment();
             $offsite_form['form'] = $gateway->get_form_html($payment, true);
             $this->_EEM_Gateways->set_off_site_form($offsite_form);
             $this->redirect_after_reg_step_3();
         }
     }
 }
 /**
  * @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'));
 }
 /**
  * is_applicable_item
  * control which events have promotions applied to them
  *
  * @param bool          $is_applicable_item
  * @param \EE_Line_Item $object_type_line_item
  * @return bool
  */
 public function is_applicable_item($is_applicable_item = true, EE_Line_Item $object_type_line_item)
 {
     $is_applicable_item = $object_type_line_item->total() > 0 ? $is_applicable_item : false;
     return $is_applicable_item;
 }
 /**
  * 		Processes the final step of SPCO in order to process payments
  * 		@access public
  * 		@param EE_Line_Item $total_line_item the line item whose total takes all other line items on this transaction into account
  *		@param EE_Transaction $transaction
  * 		@return 	mixed	void or FALSE on fail
  */
 public function process_payment_start(EE_Line_Item $line_item, EE_Transaction $transaction = NULL, $total_to_charge = NULL)
 {
     do_action('AHEE_log', __FILE__, __FUNCTION__, '');
     if (empty($transaction)) {
         $transaction = $line_item->transaction();
     }
     EE_Registry::instance()->load_helper('Template');
     // free event?
     if ($line_item->total() == EEH_Template::format_currency(0, TRUE)) {
         $transaction->set_status(EEM_Transaction::complete_status_code);
         $transaction->save();
         $transaction->finalize();
         $response = array('msg' => array('success' => TRUE));
     } else {
         try {
             $response = array('msg' => $this->selected_gateway_obj()->process_payment_start($line_item, $transaction, $total_to_charge));
         } catch (EE_Error $e) {
             $response = array('msg' => array('error' => $e->getMessage()));
         }
         //make sure we remove the credit card and other sensitive data, as we dont want to store that in the db
         $this->_clean_billing_info_in_session($transaction);
     }
     // add return URL
     $response['forward_url'] = $this->_get_return_page_url($transaction);
     return $response;
 }
 /**
  * Creates a bunch of registrations and returns an array of all the "approved" ones
  * @param array $ticket_quantities top-level-keys are ticket IDs,
  * next-level keys are either 'included' or 'not'.
  * @param EE_Line_Item $grand_total
  * @return a flat array of all the registrations that were for 'included'
  */
 protected function _create_regs($ticket_quantities, $grand_total)
 {
     $txn = $this->new_model_obj_with_dependencies('Transaction');
     $regs_to_include = array();
     foreach ($ticket_quantities as $ticket_id => $approved_or_not_counts) {
         foreach ($approved_or_not_counts as $key => $count) {
             for ($i = 0; $i < $count; $i++) {
                 $r = $this->new_model_obj_with_dependencies('Registration', array('TXN_ID' => $txn->ID(), 'TKT_ID' => $ticket_id));
                 if ($key == 'included') {
                     $regs_to_include[] = $r;
                 }
             }
         }
     }
     $grand_total->save_this_and_descendants_to_txn($txn->ID());
     return $regs_to_include;
 }
 public function process_payment_start(EE_Line_Item $total_line_item, $transaction = null, $total_to_pay = NULL)
 {
     $paypal_settings = $this->_payment_settings;
     $paypal_id = $paypal_settings['paypal_id'];
     $paypal_cur = $paypal_settings['currency_format'];
     $no_shipping = $paypal_settings['no_shipping'];
     $item_num = 1;
     /* @var $transaction EE_Transaction */
     if (!$transaction) {
         $transaction = $total_line_item->transaction();
     }
     $primary_registrant = $transaction->primary_registration();
     if ($total_to_pay === NULL && $total_to_pay != $transaction->total() && !$transaction->paid()) {
         //and there have been no payments on the transaction yet anyways
         //so let's create a nice looking invoice including everything
         foreach ($total_line_item->get_items() as $line_item) {
             $this->addField('item_name_' . $item_num, substr(sprintf(__('%s for %s', 'event_espresso'), $line_item->name(), $line_item->ticket_event_name()), 0, 127));
             $this->addField('amount_' . $item_num, $line_item->unit_price());
             $this->addField('quantity_' . $item_num, $line_item->quantity());
             $item_num++;
         }
         foreach ($total_line_item->tax_descendants() as $tax_line_item) {
             $this->addField('item_name_' . $item_num, substr($tax_line_item->name(), 0, 127));
             $this->addField('amount_' . $item_num, $tax_line_item->total());
             $this->addField('quantity_' . $item_num, '1');
             $item_num++;
         }
     } else {
         //we're only charging for part of the transaction's total
         if ($total_to_pay) {
             //client code specified how much to charge
             $description = sprintf(__("Partial payment of %s", "event_espresso"), $total_to_pay);
         } elseif ($transaction->paid()) {
             //they didn't specify how much, but there has already been a payment, so let's just charge on what's left
             $total_to_pay = $transaction->remaining();
             $description = sprintf(__("Total paid to date: %s, and this charge is for the balance.", "event_espresso"), $transaction->get_pretty('TXN_paid'));
         } else {
             throw new EE_Error(sprintf(__("Thats impossible!!", "event_espresso")));
         }
         $this->addField('item_name_' . $item_num, sprintf(__("Amount owing for registration %s", 'event_espresso'), $primary_registrant->reg_code()));
         $this->addField('amount_' . $item_num, $total_to_pay);
         $this->addField('on0_' . $item_num, __("Amount Owing:", 'event_espresso'));
         $this->addField('os0_' . $item_num, $description);
         $item_num++;
     }
     if ($paypal_settings['use_sandbox']) {
         $this->addField('item_name_' . $item_num, 'DEBUG INFO (this item only added in sandbox mode)');
         $this->addField('amount_' . $item_num, 0);
         $this->addField('on0_' . $item_num, 'NOTIFY URL');
         $this->addField('os0_' . $item_num, $this->_get_notify_url($primary_registrant));
     }
     $this->addField('business', $paypal_id);
     $this->addField('return', $this->_get_return_url($primary_registrant));
     $this->addField('cancel_return', $this->_get_cancel_url());
     $this->addField('notify_url', $this->_get_notify_url($primary_registrant));
     $this->addField('cmd', '_cart');
     $this->addField('upload', '1');
     $this->addField('currency_code', $paypal_cur);
     $this->addField('image_url', empty($paypal_settings['image_url']) ? '' : $paypal_settings['image_url']);
     $this->addField('no_shipping ', $no_shipping);
     do_action('AHEE_log', __FILE__, __FUNCTION__, serialize(get_object_vars($this)));
     $this->_EEM_Gateways->set_off_site_form($this->submitPayment());
     $this->redirect_after_reg_step_3($transaction, $paypal_settings['use_sandbox']);
 }
 /**
  * Adds the line item as a child to this line item
  * @param EE_Line_Item $line_item
  * @return void
  */
 function add_child_line_item(EE_Line_Item $line_item)
 {
     if ($this->ID()) {
         $line_item->set_parent_ID($this->ID());
         $line_item->save();
     } else {
         $this->_Line_Item[$line_item->code()] = $line_item;
     }
 }
 /**
  * _delete_line_item
  *
  * @access public
  * @param \EE_Line_Item $line_item
  * @return boolean
  */
 public static function _delete_line_item(EE_Line_Item $line_item)
 {
     if ($line_item->ID()) {
         return $line_item->delete();
     } else {
         return EE_Registry::instance()->CART->delete_items($line_item->code());
     }
 }
 /**
  *    _total_row
  *
  * @param EE_Line_Item $line_item
  * @param string $text
  * @param bool $tax_total
  * @return mixed
  */
 private function _total_row(EE_Line_Item $line_item, $text = '', $tax_total = false)
 {
     if ($tax_total && $this->_tax_count < 2) {
         return '';
     }
     //EE_Registry::instance()->load_helper('Money');
     //if ( )
     // start of row
     $html = EEH_HTML::tr('', 'event-cart-total-row', 'total_tr odd');
     // total td
     $html .= EEH_HTML::td(EEH_HTML::strong(EED_Multi_Event_Registration::$event_cart_name . ' ' . $line_item->desc() . ' ' . $text), '', 'total_currency total jst-rght', '', ' colspan="2"');
     // total qty
     $total_qty = $tax_total ? '' : EE_Registry::instance()->CART->all_ticket_quantity_count();
     $html .= EEH_HTML::td(EEH_HTML::strong($total_qty), '', 'mini-cart-tbl-qty-td total jst-cntr');
     // total td
     $html .= EEH_HTML::td(EEH_HTML::strong($line_item->total_no_code()), '', 'total jst-rght');
     // end of row
     $html .= EEH_HTML::trx();
     return $html;
 }
 /**
  * 	_total_row
  *
  * @param EE_Line_Item $line_item
  * @param string       $text
  * @param array        $options
  * @return mixed
  */
 private function _total_row(EE_Line_Item $line_item, $text = '', $options = array())
 {
     // colspan
     $colspan = $options['show_desc'] ? ' colspan="2"' : '';
     // start of row
     $html = EEH_HTML::tr('', '', 'total_tr odd');
     // empty td
     $html .= EEH_HTML::td(EEH_HTML::nbsp(), '', '', '', $colspan);
     // total td
     $html .= EEH_HTML::td($text, '', 'total_currency total', '', $colspan);
     // total td
     $html .= EEH_HTML::td($line_item->total_no_code(), '', 'total');
     // end of row
     $html .= EEH_HTML::trx();
     return $html;
 }
 /**
  * get_redeemable_scope_promos
  * searches the cart for any items that this promotion applies to
  *
  * @since   1.0.0
  *
  * @param EE_Line_Item $parent_line_item the line item to create the new promotion line item under
  * @param EE_Promotion $promotion        the promotion object that the line item is being created for
  * @param string       $promo_name
  * @param bool         $affects_tax
  * @return \EE_Line_Item
  * @throws \EE_Error
  */
 public function generate_promotion_line_item(EE_Line_Item $parent_line_item, EE_Promotion $promotion, $promo_name = '', $affects_tax = false)
 {
     // verify EE_Line_Item
     if (!$parent_line_item instanceof EE_Line_Item) {
         throw new EE_Error(__('A valid EE_Line_Item object is required to generate a promotion line item.', 'event_espresso'));
     }
     // verify EE_Promotion
     if (!$promotion instanceof EE_Promotion) {
         throw new EE_Error(__('A valid EE_Promotion object is required to generate a promotion line item.', 'event_espresso'));
     }
     $promo_name = !empty($promo_name) ? $promo_name : $promotion->name();
     $promo_desc = $promotion->price()->desc();
     $promo_desc .= $promotion->code() != '' ? ' ( ' . $promotion->code() . ' )' : '';
     // generate promotion line_item
     $line_item = EE_Line_Item::new_instance(array('LIN_code' => 'promotion-' . $promotion->ID(), 'TXN_ID' => $parent_line_item->TXN_ID(), 'LIN_name' => apply_filters('FHEE__EE_Promotion_Scope__generate_promotion_line_item__LIN_name', $promo_name, $promotion), 'LIN_desc' => $promo_desc, 'LIN_unit_price' => $promotion->is_percent() ? 0 : $promotion->amount(), 'LIN_percent' => $promotion->is_percent() ? $promotion->amount() : 0, 'LIN_is_taxable' => $affects_tax, 'LIN_order' => $promotion->price()->order() + EE_Promotion_Scope::$_counter, 'LIN_total' => $promotion->calculated_amount_on_value($parent_line_item->total()), 'LIN_quantity' => 1, 'LIN_parent' => $parent_line_item->ID(), 'LIN_type' => $this->get_promotion_line_item_type(), 'OBJ_ID' => $promotion->ID(), 'OBJ_type' => 'Promotion'));
     EE_Promotion_Scope::$_counter++;
     return $line_item;
 }
 /**
  * Adds the line item as a child to this line item. If there is another child line
  * item with the same LIN_code, it is overwritten by this new one
  * @param EE_Line_Item $line_item
  * @return boolean success
  */
 function add_child_line_item(EE_Line_Item $line_item)
 {
     if ($this->ID()) {
         //check for any duplicate line items (with the same code), if so, this replaces it
         $line_item_with_same_code = $this->get_child_line_item($line_item->code());
         if ($line_item_with_same_code instanceof EE_Line_Item && $line_item_with_same_code !== $line_item) {
             $this->delete_child_line_item($line_item_with_same_code->code());
         }
         $line_item->set_parent_ID($this->ID());
         if ($this->TXN_ID()) {
             $line_item->set_TXN_ID($this->TXN_ID());
         }
         return $line_item->save();
     } else {
         $this->_Line_Item[$line_item->code()] = $line_item;
         return TRUE;
     }
 }
 /**
  *    _total_row
  *
  * @param EE_Line_Item $line_item
  * @param string       $text
  * @param int          $total_items
  * @return mixed
  */
 private function _total_row(EE_Line_Item $line_item, $text = '', $total_items = 0)
 {
     //EE_Registry::instance()->load_helper('Money');
     // start of row
     $html = EEH_HTML::tr('', 'event-cart-total-row-' . $line_item->ID(), 'event-cart-total-row-' . $line_item->type() . ' event-cart-total-row total_tr');
     // total td
     $html .= EEH_HTML::td(EEH_HTML::strong($text), '', 'total_currency total jst-rght', '', ' colspan="2"');
     // total qty
     $total_items = $total_items ? $total_items : '';
     $html .= EEH_HTML::td(EEH_HTML::strong('<span class="total">' . $total_items . '</span>'), '', 'total jst-cntr');
     // total td
     $html .= EEH_HTML::td(EEH_HTML::strong($line_item->total_no_code()), '', 'total jst-rght');
     // end of row
     $html .= EEH_HTML::trx();
     return $html;
 }
/**
 * Recursive function for traversing all the sub-items of each line item
 * and displaying them in the table
 * @param EE_Line_Item $line_item
 * @param boolean $odd for indicating whether to style this line item as an 'odd' or 'even'
 */
function ee_invoice_display_line_item(EE_Line_Item $line_item, $show_line_item_description, $odd = false)
{
    switch ($line_item->type()) {
        case EEM_Line_Item::type_total:
            foreach ($line_item->children() as $child_line_item) {
                ee_invoice_display_line_item($child_line_item, $show_line_item_description);
            }
            ?>
							<tr><td colspan="<?php 
            echo $show_line_item_description ? 5 : 4;
            ?>
"><hr></td></tr>
							<tr class="total_tr odd">
								<td colspan="<?php 
            echo $show_line_item_description ? 2 : 1;
            ?>
">&nbsp;</td>
								<td colspan="2" class="total" id="total_currency"><?php 
            _e('Total', 'event_espresso');
            ?>
</td>
								<td class="total"><?php 
            echo $line_item->total_no_code();
            ?>
</td>
							</tr>
						<?php 
            break;
        case EEM_Line_Item::type_sub_total:
            foreach ($line_item->children() as $child_line_item) {
                //$odd = !$odd;
                ee_invoice_display_line_item($child_line_item, $show_line_item_description, $odd);
            }
            ?>
							<tr class="total_tr odd">
								<td colspan="<?php 
            echo $show_line_item_description ? 2 : 1;
            ?>
">&nbsp;</td>
								<td colspan="2" class="total" id="total_currency"><?php 
            _e('Sub-Total', 'event_espresso');
            ?>
</td>
								<td class="total"><?php 
            echo $line_item->total_no_code();
            ?>
</td>
							</tr>
						<?php 
            break;
        case EEM_Line_Item::type_tax_sub_total:
            foreach ($line_item->children() as $child_line_item) {
                $odd = !$odd;
                ee_invoice_display_line_item($child_line_item, $show_line_item_description, $odd);
            }
            ?>
							<tr class="total_tr odd">
								<td colspan="<?php 
            echo $show_line_item_description ? 2 : 1;
            ?>
">&nbsp;</td>
								<td colspan="2" class="total" id="total_currency"><?php 
            _e('Tax Total', 'event_espresso');
            ?>
</td>
								<td class="total"><?php 
            echo $line_item->total_no_code();
            ?>
</td>
							</tr>
						<?php 
            break;
        case EEM_Line_Item::type_line_item:
            $subitems = $line_item->children();
            $has_subitems = count($subitems) > 1;
            if ($has_subitems) {
                ?>
							<tr class="item <?php 
                echo $odd ? 'odd' : '';
                ?>
">
								<td class="item_l"><?php 
                echo $line_item->name();
                ?>
</td>
								<?php 
                if ($show_line_item_description) {
                    ?>
<td class="item_l"><?php 
                    echo $line_item->desc();
                    ?>
</td><?php 
                }
                ?>
								<td class="item_l"><?php 
                echo $line_item->quantity();
                ?>
</td>

								<td class="item_c"><?php 
                echo $line_item->unit_price_no_code();
                ?>
</td>

								<td class="item_r"> <?php 
                echo $line_item->total_no_code();
                echo $line_item->is_taxable() ? '*' : '';
                ?>
 </td>
								<?php 
                //<td class="item_l"><?php  $datetimes_strings = array(); foreach($datetimes as $datetime){ $datetimes_strings[]= $datetime->start_date_and_time();} echo implode(", ",$datetimes_strings);
                ?>
							</tr>
							<?php 
                if ($has_subitems) {
                    foreach ($line_item->children() as $child_line_item) {
                        ee_invoice_display_line_item($child_line_item, $show_line_item_description, $odd);
                    }
                }
            } else {
                //no subitems - just show this line item
                ?>
								<tr class="item <?php 
                echo $odd ? 'odd' : '';
                ?>
">
									<td class="item_l"><?php 
                echo $line_item->name();
                ?>
</td>
									<?php 
                if ($show_line_item_description) {
                    ?>
<td class="item_l"><?php 
                    echo $line_item->desc();
                    ?>
</td><?php 
                }
                ?>
									<td class="item_l"><?php 
                echo $line_item->quantity();
                ?>
</td>
									<td class="item_c"><?php 
                echo $line_item->unit_price_no_code();
                ?>
</td>
									<td class="item_r"> <?php 
                echo $line_item->total_no_code();
                echo $line_item->is_taxable() ? '*' : '';
                ?>
 </td>
									<?php 
                //<td class="item_l"><?php  $datetimes_strings = array(); foreach($datetimes as $datetime){ $datetimes_strings[]= $datetime->start_date_and_time();} echo implode(", ",$datetimes_strings);
                ?>
								</tr>
							<?php 
            }
            break;
        case EEM_Line_Item::type_sub_line_item:
            ?>
						<tr class="item subitem-row">
							<td class="item_l subitem"><?php 
            echo $line_item->name();
            ?>
</td>
							<?php 
            if ($show_line_item_description) {
                ?>
<td class="item_l"><?php 
                echo $line_item->desc();
                ?>
</td><?php 
            }
            ?>
							<?php 
            if ($line_item->is_percent()) {
                ?>
									<td></td>
									<td class="item_c"><?php 
                echo $line_item->percent();
                ?>
%</td>
							<?php 
            } else {
                //flat discount/surcharge
                ?>
									<td></td>
									<td class="item_c"><?php 
                echo $line_item->unit_price_no_code();
                ?>
</td>
							<?php 
            }
            ?>
							<td class="item_r"><?php 
            echo $line_item->total_no_code();
            ?>
</td>
						</tr>
						<?php 
            break;
        case EEM_Line_Item::type_tax:
            ?>
						<tr class="item sub-item tax-total">
							<td class="item_l"><?php 
            echo $line_item->name();
            ?>
</td>
							<?php 
            if ($show_line_item_description) {
                ?>
<td class="item_l"><?php 
                echo $line_item->desc();
                ?>
</td><?php 
            }
            ?>
							<td colspan="2" class="item_c"><?php 
            echo $line_item->percent();
            ?>
%</td>

							<td class="item_r"><?php 
            echo $line_item->total_no_code();
            ?>
</td>
						</tr><?php 
            break;
    }
}
 /**
  * 	_sub_item_row
  *
  * @param EE_Line_Item $line_item
  * @param array        $options
  * @return mixed
  */
 private function _sub_item_row(EE_Line_Item $line_item, $options = array())
 {
     // start of row
     $html = EEH_HTML::tr('', 'item sub-item-row');
     // name && desc
     $name_and_desc = $line_item->name();
     $name_and_desc .= $options['show_desc'] ? '<span class="line-sub-item-desc-spn smaller-text">: ' . $line_item->desc() . '</span>' : '';
     // name td
     $html .= EEH_HTML::td($name_and_desc, '', 'item_l sub-item');
     // discount/surcharge td
     if ($line_item->is_percent()) {
         $html .= EEH_HTML::td($line_item->percent() . '%', '', 'item_c');
     } else {
         $html .= EEH_HTML::td($line_item->unit_price_no_code(), '', 'item_c jst-rght');
     }
     // total td
     $html .= EEH_HTML::td(EEH_Template::format_currency($line_item->total(), false, false), '', 'item_r jst-rght');
     // end of row
     $html .= EEH_HTML::trx();
     return $html;
 }
 /**
  * Checks if this line item, or any of its children, actually has a description.
  * If none do, then the template can decide to not show any description column
  * @param EE_Line_Item $line_item
  * @return boolean
  */
 function check_if_any_line_items_have_a_description(EE_Line_Item $line_item)
 {
     if ($line_item->desc()) {
         return true;
     } else {
         foreach ($line_item->children() as $child_line_item) {
             if ($this->check_if_any_line_items_have_a_description($child_line_item)) {
                 return true;
             }
         }
         //well, if I and my children don't have descriptions, I guess not
         return false;
     }
 }
 /**
  *    _process_billable_total
  *
  * @param EE_Line_Item $line_item
  * @return mixed
  */
 private function _is_billable(EE_Line_Item $line_item)
 {
     $billable = 0;
     // is this a ticket ?
     if ($line_item->OBJ_type() == 'Ticket') {
         //echo '<br/><h5 style="color:#2EA2CC;">$line_item->name() : <span style="color:#E76700">' . $line_item->name() . '</span><br/><span style="font-size:9px;font-weight:normal;color:#666">' . __FILE__ . '</span>    <b style="font-size:10px;color:#333">  ' . __LINE__ . ' </b></h5>';
         //echo '<h5 style="color:#2EA2CC;">$line_item->OBJ_ID() : <span style="color:#E76700">' . $line_item->OBJ_ID() . '</span><br/><span style="font-size:9px;font-weight:normal;color:#666">' . __FILE__ . '</span>    <b style="font-size:10px;color:#333">  ' . __LINE__ . ' </b></h5>';
         // is it in the "do not bill" list?
         foreach ($this->_billable as $REG_ID => $TKT_ID) {
             if ($line_item->OBJ_ID() === $TKT_ID) {
                 //echo '<h5 style="color:#2EA2CC;">billable : <span style="color:#E76700">' . $line_item->unit_price() . '</span><br/><span style="font-size:9px;font-weight:normal;color:#666">' . __FILE__ . '</span>    <b style="font-size:10px;color:#333">  ' . __LINE__ . ' </b></h5>';
                 $this->_billable_total += $line_item->unit_price();
                 //$this->_total_items += $line_item->quantity();
                 if ($line_item->is_taxable()) {
                     $this->_billable_tax_total += $line_item->unit_price();
                 }
                 $this->_total_items++;
                 $billable++;
                 unset($this->_do_not_bill[$REG_ID]);
             }
         }
         foreach ($this->_do_not_bill as $REG_ID => $TKT_ID) {
             if ($line_item->OBJ_ID() === $TKT_ID) {
                 //echo '<h5 style="color:#2EA2CC;">non_billable : <span style="color:#E76700">' . $line_item->unit_price() . '</span><br/><span style="font-size:9px;font-weight:normal;color:#666">' . __FILE__ . '</span>    <b style="font-size:10px;color:#333">  ' . __LINE__ . ' </b></h5>';
                 $this->_non_billable_total += $line_item->unit_price();
                 if ($line_item->is_taxable()) {
                     $this->_non_billable_tax_total += $line_item->unit_price();
                 }
                 unset($this->_do_not_bill[$REG_ID]);
             }
         }
     }
     return $billable;
 }