/**
  * Get a static reference to the storage object associated with this model object
  * 
  * @return rental_socontract_price_item the storage object
  */
 public static function get_instance()
 {
     if (self::$so == null) {
         self::$so = CreateObject('rental.socontract_price_item');
     }
     return self::$so;
 }
 /**
  * (non-PHPdoc)
  * @see rental/inc/model/rental_model#check_consistency()
  */
 public function check_consistency()
 {
     // Retrieve the start and end date
     $dates = $this->get_contract_date();
     if (isset($dates)) {
         $start_date = $this->get_contract_date()->get_start_date();
         $end_date = $this->get_contract_date()->get_end_date();
     }
     // Give warning if the contract lacks a start date
     if (!isset($start_date)) {
         $this->set_consistency_warning(lang('warning_lacking_start_date'));
     } else {
         // If set, the billing date must be between the contract's start date and end date
         $billing_start = $this->get_billing_start_date();
         if (isset($billing_start) && is_numeric($billing_start) && $billing_start > 0) {
             if ($billing_start < $start_date || isset($end_date) && $billing_start > $end_date) {
                 $this->set_consistency_warning(lang('warning_billing_date_between'));
             }
         }
         // If set, the billing date must be between the contract's start date and end date
         $billing_end = $this->get_billing_end_date();
         if (isset($billing_end) && is_numeric($billing_end) && $billing_end > 0) {
             if ($billing_end < $start_date || isset($end_date) && $billing_end > $end_date) {
                 $this->set_consistency_warning(lang('warning_billing_end_date_between'));
             }
         }
         // If set, the due date must be between the contract's start date and end date
         $due_date = $this->get_due_date();
         if (isset($due_date) && is_numeric($due_date) && $due_date > 0) {
             if ($due_date < $start_date || isset($end_date) && $due_date > $end_date) {
                 $this->set_consistency_warning(lang('warning_due_date_between'));
             }
         }
         $so_price_item = rental_socontract_price_item::get_instance();
         $price_items = $so_price_item->get(null, null, null, null, null, null, array('contract_id' => $this->get_id()));
         foreach ($price_items as $price_item) {
             //get price item dates
             $pi_date_start = $price_item->get_date_start();
             $pi_date_end = $price_item->get_date_end();
             if (isset($pi_date_start) && is_numeric($pi_date_start) && $pi_date_start > 0) {
                 if ($pi_date_start < $start_date || isset($pi_date_end) && $pi_date_end > $end_date) {
                     $this->set_consistency_warning($price_item->get_agresso_id() . ' - ' . lang('warning_price_item_date_between'));
                 }
             } else {
                 if (isset($pi_date_end) && is_numeric($pi_date_end) && $pi_date_end > 0) {
                     if ($pi_date_end > $end_date) {
                         $this->set_consistency_warning($price_item->get_agresso_id() . ' - ' . lang('warning_price_item_date_between'));
                     }
                 }
             }
         }
     }
 }
 protected function import_contract_price_items($contracts)
 {
     $start_time = time();
     $soprice_item = rental_soprice_item::get_instance();
     $socontract_price_item = rental_socontract_price_item::get_instance();
     $socontract = rental_socontract::get_instance();
     // Read priselementdetaljkontrakt list first so we can create our complete price items in the next loop
     // This is an array keyed by the main price item ID
     $detail_price_items = array();
     $datalines = $this->getcsvdata($this->path . "/u_PrisElementDetaljKontrakt.csv");
     $this->messages[] = "Read 'u_PrisElementDetaljKontrakt.csv' file in " . (time() - $start_time) . " seconds";
     $this->messages[] = "'u_PrisElementDetaljKontrakt.csv' contained " . count($datalines) . " lines";
     foreach ($datalines as $data) {
         //Felt fra 'PrisElementDetaljKontrakt'
         if (count($data) <= 10) {
             continue;
         }
         if (isset($detail_price_items[$data[1]])) {
             // Update existing detail only start date is later than existing start date detail
             if (!$this->is_null($data[4])) {
                 $detail_date = strtotime($this->decode($data[4]));
                 if ($detail_date > $detail_price_items[$data[1]]['date_start']) {
                     $detail_price_items[$data[1]]['date_start'] = $detail_date;
                     $detail_price_items[$data[1]]['amount'] = str_replace(',', '.', $data[3]);
                     $detail_price_items[$data[1]]['price'] = str_replace(',', '.', $data[2]);
                 }
             }
         } else {
             //Create a row in the array holding the details (price, amount, dates) for the price item
             $detail_price_items[$data[1]] = array('price' => str_replace(',', '.', $data[2]), 'amount' => str_replace(',', '.', $data[3]), 'date_start' => null, 'date_end' => null);
             if (!$this->is_null($data[4])) {
                 $detail_price_items[$data[1]]['date_start'] = strtotime($this->decode($data[4]));
             }
             if (!$this->is_null($data[5])) {
                 $detail_price_items[$data[1]]['date_end'] = strtotime($this->decode($data[5]));
             }
         }
     }
     $datalines = $this->getcsvdata($this->path . "/u_PrisElementKontrakt.csv");
     $this->messages[] = "Read 'u_PrisElementKontrakt.csv' file in " . (time() - $start_time) . " seconds";
     $this->messages[] = "'u_PrisElementKontrakt.csv' contained " . count($datalines) . " lines";
     //Retrieve the title for the responsibility area we are importing (to hande the respoonsibility areas differently)
     $title = $socontract->get_responsibility_title($this->location_id);
     //If we are importing price items for 'Innleie', we have a default price item in the 'Prisbok' with agresso-id 'INNLEIE'
     if ($title == 'contract_type_innleie') {
         $admin_price_item = $soprice_item->get_single_with_id('INNLEIE');
     }
     foreach ($datalines as $data) {
         if (count($data) <= 24) {
             continue;
         }
         /* If we are importing contract price items for external or internal:
          * - see if a pricebook element exist
          */
         if ($title != 'contract_type_innleie') {
             // The Agresso-ID is unique for price items
             $id = $this->decode($data[12]);
             //cVarenr
             $admin_price_item = null;
             if (isset($id) && $id != '') {
                 $admin_price_item = $soprice_item->get_single_with_id($id);
             } else {
                 $admin_price_item = $soprice_item->get_single_with_id('UNKNOWN');
             }
         }
         // Get the facilit price item id so that we can retrieve the price item details
         $facilit_id = $this->decode($data[0]);
         //nPrisElementId
         /* Create a new pricebook price item if one does not exist in the pricebook; store it if it has a new unique agresso-id. 
          * Note: First price item with unique agresso-id determines title, area or "nr of items", and the price (from the price item details) */
         if ($admin_price_item == null) {
             $admin_price_item = new rental_price_item();
             $admin_price_item->set_title($this->decode($data[3]));
             //cPrisElementNavn
             $admin_price_item->set_agresso_id($id);
             //cVareNr
             // This assumes 1 for AREA, and anything else for count, even blanks
             $admin_price_item->set_is_area($this->decode($data[4]) == '1' ? true : false);
             //nMengdeTypeId
             // This assumes -1 for adjustable, and anything else for not adjustable, even blanks
             $admin_price_item->set_is_adjustable($this->decode($data[17]) == '-1' ? true : false);
             //bRegulerbar
             // Get the price for this price item
             $admin_price_item->set_price($detail_price_items[$facilit_id]['price']);
             $admin_price_item->set_responsibility_id($this->location_id);
             if (isset($id)) {
                 $soprice_item->store($admin_price_item);
                 $this->messages[] = "Stored price item ({$id}) with title " . $admin_price_item->get_title() . " in 'Prisbok'";
             }
         } else {
             //check type on price item (not is_area and data[4]=1, or is_area and data[4] != 1)
             if ($admin_price_item->is_area() && $this->decode($data[4] != '1')) {
                 $this->warnings[] = "Price item ({$admin_price_item->get_agresso_id()}) - " . $admin_price_item->get_title() . " - on contract {$contracts[$this->decode($data[1])]} is stored as area price item, but has record indicating it is not an area price item!";
             } else {
                 if (!$admin_price_item->is_area() && $this->decode($data[4] == '1')) {
                     $this->warnings[] = "Price item ({$admin_price_item->get_agresso_id()}) - " . $admin_price_item->get_title() . " - on contract {$contracts[$this->decode($data[1])]} is stored as non-area price item, but has record indicating it is an area price item!";
                 }
             }
         }
         $contract_id = $contracts[$this->decode($data[1])];
         //nKontraktId
         if ($contract_id) {
             // Create a new contract price item that we can tie to our contract
             $price_item = new rental_contract_price_item();
             // Retrieve the contract
             $contract = $socontract->get_single($contract_id);
             // Set cLonnsArt for price item as contract reference
             $contract->set_reference($this->decode($data[13]));
             // The contract price item title should be the same as in the price book for internal
             if ($title == 'contract_type_internleie') {
                 $price_item->set_title($admin_price_item->get_title());
             } else {
                 // ... and overridden by the price item for innleie and external
                 $price_item->set_title($data[3]);
             }
             // Set the price book element's agresso-id and type (area/piece)
             $price_item->set_agresso_id($admin_price_item->get_agresso_id());
             // If the price item is unknown do not use the 'is_area' from the price book
             if ($admin_price_item->get_agresso_id() != 'UNKNOWN') {
                 $price_item->set_is_area($admin_price_item->is_area());
             } else {
                 $price_item->set_is_area($this->decode($data[4]) == '1' ? true : false);
             }
             // Get the price for the price item details
             $price_item->set_price($detail_price_items[$facilit_id]['price']);
             // Give a warning if a contract has a price element of type area with are like 1
             if ($price_item->is_area() && $detail_price_items[$facilit_id]['amount'] == '1') {
                 $this->warnings[] = "Contract " . $contract->get_old_contract_id() . " has a price item of type area with amount like 1";
             }
             // Tie this price item to its parent admin price item
             $price_item->set_price_item_id($admin_price_item->get_id());
             if ($admin_price_item->is_area()) {
                 $rented_area = $contract->get_rented_area();
                 if (isset($rented_area)) {
                     if ($detail_price_items[$facilit_id]['amount'] != $rented_area) {
                         if ($rented_area == 0) {
                             $contract->set_rented_area($detail_price_items[$facilit_id]['amount']);
                             $this->warnings[] = "Price item {$id} - (Facilit ID {$facilit_id}) has area " . $detail_price_items[$facilit_id]['amount'] . " while contract {$contract_id} already has rented area set to 0. Using rented area from price item.";
                         } else {
                             $this->warnings[] = "Price item {$id} - (Facilit ID {$facilit_id}) has area " . $detail_price_items[$facilit_id]['amount'] . " while contract {$contract_id} already has rented area {$rented_area}. Using rented area on contract.";
                         }
                     }
                 } else {
                     //Store price item area on contract if the contract has no area (not from contract)
                     $contract->set_rented_area($detail_price_items[$facilit_id]['amount']);
                     $this->message[] = "Price item {$id} - (Facilit ID {$facilit_id}) has area " . $detail_price_items[$facilit_id]['amount'] . " while contract {$contract_id} already no area {$rented_area}. Using rented area on price item.";
                     //Store the contract
                     $socontract->store($contract);
                 }
                 // Set the the contract area on the price item
                 $price_item->set_area($contract->get_rented_area());
                 //Calculate the total price for the price item
                 $item_area = $price_item->get_area();
                 $item_price = $price_item->get_price();
                 $price_item->set_total_price($item_area * $item_price);
             } else {
                 $price_item->set_count($detail_price_items[$facilit_id]['amount']);
                 $item_count = $price_item->get_count();
                 $item_price = $price_item->get_price();
                 $price_item->set_total_price($item_count * $item_price);
             }
             $price_item->set_date_start($detail_price_items[$facilit_id]['date_start']);
             $price_item->set_date_end($detail_price_items[$facilit_id]['date_end']);
             // Tie the price item to the contract it belongs to
             $price_item->set_contract_id($contract_id);
             // Tie this price item to its parent admin price item
             $price_item->set_price_item_id($admin_price_item->get_id());
             //update contract with adjustment share
             $adjustment_share = $this->decode($data[18]);
             //nReguleringsandel
             if ($adjustment_share != null && $adjustment_share > 0) {
                 $socontract->update_adjustment_share($contract_id, $adjustment_share);
             }
             // .. and save
             if ($socontract_price_item->import($price_item)) {
                 $this->messages[] = "Successfully imported price item ({$id}) for contract {$contract_id}";
             } else {
                 $this->warnings[] = "Could not store price item ({$id}) - " . $price_item->get_title();
             }
         } else {
             $this->warnings[] = "Skipped price item with no contract attached: " . join(", ", $data);
         }
     }
     $this->messages[] = "Imported contract price items. (" . (time() - $start_time) . " seconds)";
     return true;
 }
 /**
  * (non-PHPdoc)
  * @see rental/inc/rental_uicommon#query()
  */
 public function query()
 {
     if ($GLOBALS['phpgw_info']['user']['preferences']['common']['maxmatchs'] > 0) {
         $user_rows_per_page = $GLOBALS['phpgw_info']['user']['preferences']['common']['maxmatchs'];
     } else {
         $user_rows_per_page = 10;
     }
     // YUI variables for paging and sorting
     $start_index = phpgw::get_var('startIndex', 'int');
     $num_of_objects = phpgw::get_var('results', 'int', 'GET', $user_rows_per_page);
     $sort_field = phpgw::get_var('sort');
     if ($sort_field == null) {
         $sort_field = 'agresso_id';
     }
     $sort_ascending = phpgw::get_var('dir') == 'desc' ? false : true;
     //Create an empty result set
     $records = array();
     //Retrieve a contract identifier and load corresponding contract
     $contract_id = phpgw::get_var('contract_id');
     if (isset($contract_id)) {
         $contract = rental_socontract::get_instance()->get_single($contract_id);
     }
     //Retrieve the type of query and perform type specific logic
     $type = phpgw::get_var('type');
     switch ($type) {
         case 'included_price_items':
             if (isset($contract)) {
                 $filters = array('contract_id' => $contract->get_id());
                 $result_objects = rental_socontract_price_item::get_instance()->get($start_index, $num_of_objects, $sort_field, $sort_ascending, $search_for, $search_type, $filters);
                 $object_count = rental_socontract_price_item::get_instance()->get_count($search_for, $search_type, $filters);
             }
             break;
         case 'not_included_price_items':
             // We want to show price items in the source list even after they've been added to a contract
             $filters = array('price_item_status' => 'active', 'responsibility_id' => phpgw::get_var('responsibility_id'));
             $result_objects = rental_soprice_item::get_instance()->get($start_index, $num_of_objects, $sort_field, $sort_ascending, $search_for, $search_type, $filters);
             $object_count = rental_soprice_item::get_instance()->get_count($search_for, $search_type, $filters);
             break;
         case 'manual_adjustment':
             $filters = array('price_item_status' => 'active', 'is_adjustable' => 'false');
             $result_objects = rental_soprice_item::get_instance()->get($start_index, $num_of_objects, $sort_field, $sort_ascending, $search_for, $search_type, $filters);
             $object_count = rental_soprice_item::get_instance()->get_count($search_for, $search_type, $filters);
             break;
         default:
             //$filters = array('price_item_status' => 'active','responsibility_id' => phpgw::get_var('responsibility_id'));
             $result_objects = rental_soprice_item::get_instance()->get($start_index, $num_of_objects, $sort_field, $sort_ascending, $search_for, $search_type, $filters);
             $object_count = rental_soprice_item::get_instance()->get_count($search_for, $search_type, $filters);
             break;
     }
     // Create an empty row set
     $rows = array();
     foreach ($result_objects as $record) {
         if (isset($record)) {
             // ... add a serialized record
             $rows[] = $record->serialize();
         }
     }
     $data = array('results' => $rows, 'total_records' => $object_count);
     $editable = phpgw::get_var('editable') == 'true' ? true : false;
     //Add action column to each row in result table
     array_walk($data['results'], array($this, 'add_actions'), array($contract_id, $type, $editable));
     return $this->yui_results($data, 'total_records', 'results');
 }
 /**
  * Deletes an uncommited billing job.
  */
 public function delete()
 {
     if (!$this->isExecutiveOfficer()) {
         $this->render('permission_denied.php');
         return;
     }
     $billing_job = rental_sobilling::get_instance()->get_single((int) phpgw::get_var('id'));
     $billing_job->set_deleted(true);
     rental_sobilling::get_instance()->store($billing_job);
     //set deleted=true on billing_info
     $billing_infos = rental_sobilling_info::get_instance()->get(null, null, null, null, null, null, array('billing_id' => phpgw::get_var('id')));
     foreach ($billing_infos as $billing_info) {
         $billing_info->set_deleted(true);
         rental_sobilling_info::get_instance()->store($billing_info);
     }
     //set is_billed on invoice price items to false
     $billing_job_invoices = rental_soinvoice::get_instance()->get(null, null, null, null, null, null, array('billing_id' => phpgw::get_var('id')));
     foreach ($billing_job_invoices as $invoice) {
         $price_items = rental_socontract_price_item::get_instance()->get(null, null, null, null, null, null, array('contract_id' => $invoice->get_contract_id(), 'one_time' => true, 'include_billed' => true));
         foreach ($price_items as $price_item) {
             if ($price_item->get_date_start() >= $invoice->get_timestamp_start() && $price_item->get_date_start() <= $invoice->get_timestamp_end()) {
                 $price_item->set_is_billed(false);
                 rental_socontract_price_item::get_instance()->store($price_item);
             }
         }
         $invoice->set_serial_number(null);
         rental_soinvoice::get_instance()->store($invoice);
     }
 }
 private function get_contracts_per_location()
 {
     $org_unit = $this->header_state['selected_org_unit'];
     if ($org_unit == 'all' || $org_unit == 'none') {
         phpgwapi_cache::message_set('Velg organisasjon', 'error');
         return array();
     }
     $values = phpgwapi_cache::session_get('frontend', $this->contracts_per_location_identifier);
     if (isset($values[$org_unit])) {
         return $values[$org_unit];
     }
     $parties = rental_soparty::get_instance()->get(null, null, null, null, null, null, array('org_unit_id' => $org_unit));
     $types = rental_socontract::get_instance()->get_fields_of_responsibility();
     $location_id_internal = array_search('contract_type_internleie', $types);
     $location_id_in = array_search('contract_type_innleie', $types);
     $location_id_ex = array_search('contract_type_eksternleie', $types);
     $contracts_per_location = array();
     $contracts_in_per_location = array();
     $contracts_ex_per_location = array();
     //For all parties connected to the internal organization unit
     foreach ($parties as $party) {
         //... get the contracts
         $contracts = rental_socontract::get_instance()->get(null, null, null, null, null, null, array('party_id' => $party->get_id()));
         //... and for each contract connected to this contract part
         foreach ($contracts as $id => $contract) {
             //... get the composites
             $composites = rental_socomposite::get_instance()->get(null, null, null, null, null, null, array('contract_id' => $contracts[$id]->get_id()));
             //...and for each composite in the contract in which this contract part is connected
             foreach ($composites as $composite) {
                 //... get the units
                 $units = $composite->get_units();
                 //... and for each unit retrieve the property locations we are after
                 foreach ($units as $unit) {
                     $property_location = $unit->get_location();
                     $property_locations[$property_location->get_location_code()] = $property_location;
                     // Contract holders: contracts_per_location (internal) and contracts_in_per_location (in)
                     // Internal contract should have impact on total price
                     if ($contract->get_location_id() == $location_id_internal) {
                         $total_price = rental_socontract_price_item::get_instance()->get_total_price($contract->get_id());
                         $contract->set_total_price($total_price);
                         if (!is_array($contracts_per_location[$org_unit][$property_location->get_location_code()])) {
                             $contracts_per_location[$org_unit][$property_location->get_location_code()] = array();
                         }
                         array_push($contracts_per_location[$org_unit][$property_location->get_location_code()], $contract);
                     } else {
                         if ($contract->get_location_id() == $location_id_in) {
                             $total_price = rental_socontract_price_item::get_instance()->get_total_price($contract->get_id());
                             $contract->set_total_price($total_price);
                             if (!is_array($contracts_in_per_location[$org_unit][$property_location->get_location_code()])) {
                                 $contracts_in_per_location[$org_unit][$property_location->get_location_code()] = array();
                             }
                             array_push($contracts_in_per_location[$org_unit][$property_location->get_location_code()], $contract);
                         } else {
                             if ($contract->get_location_id() == $location_id_ex) {
                                 $total_price = rental_socontract_price_item::get_instance()->get_total_price($contract->get_id());
                                 $contract->set_total_price($total_price);
                                 if (!is_array($contracts_ex_per_location[$org_unit][$property_location->get_location_code()])) {
                                     $contracts_ex_per_location[$org_unit][$property_location->get_location_code()] = array();
                                 }
                                 array_push($contracts_ex_per_location[$org_unit][$property_location->get_location_code()], $contract);
                             }
                         }
                     }
                 }
             }
         }
     }
     phpgwapi_cache::session_set('frontend', 'contracts_per_location', $contracts_per_location);
     phpgwapi_cache::session_set('frontend', 'contracts_in_per_location', $contracts_in_per_location);
     phpgwapi_cache::session_set('frontend', 'contracts_ex_per_location', $contracts_ex_per_location);
     return ${$this}->contracts_per_location_identifier[$org_unit];
 }
 public function get_missing_billing_info($contract)
 {
     //FIXME: Might have to check for this one...
     /*
     	static $responsibility_arr = array();
     	static $responsibility_check = array();
     	if(!$responsibility_arr)
     	{
     		$responsibility_arr = execMethod('property.bogeneric.get_list',array('type' => 'responsibility_unit'));
     		foreach ($responsibility_arr as $responsibility_entry)
     		{
     			$responsibility_check[$responsibility_entry['id']] = true;
     		}
     	}
     */
     $missing_billing_info = array();
     $payer_id = $contract->get_payer_id();
     if ($payer_id == null || ($payer_id = 0)) {
         $missing_billing_info[] = 'Missing payer id.';
     }
     $contract_parties = $contract->get_parties();
     if ($contract_parties == null || count($contract_parties) < 1) {
         $missing_billing_info[] = 'Missing contract party.';
     }
     $account_in = $contract->get_account_in();
     if ($account_in == null || $account_in == '') {
         $missing_billing_info[] = 'Missing account in.';
     }
     $account_out = $contract->get_account_out();
     if ($account_out == null || $account_out == '') {
         $missing_billing_info[] = 'Missing account out.';
     }
     /*$responsibility_id_in = $GLOBALS['phpgw_info']['user']['preferences']['rental']['responsibility']; 
     		if($responsibility_id_in == null || $responsibility_id_in == '')
     		{
     			$missing_billing_info[] = 'Missing system setting for responsibility id for the current user.';
     		}
     		else if(strlen($responsibility_id_in) != 6)
     		{
     			$missing_billing_info[] = 'System setting for responsibility id for the current user must be 6 characters.';
     		}*/
     $responsibility_id_out = $contract->get_responsibility_id();
     if ($responsibility_id_out == null || $responsibility_id_out == '') {
         $missing_billing_info[] = 'Missing responsibility id.';
     } else {
         if (strlen($responsibility_id_out) != 6) {
             $missing_billing_info[] = 'Responsibility id must be 6 characters.';
         }
     }
     $service_id = $contract->get_service_id();
     if ($service_id == null || $service_id == '') {
         $missing_billing_info[] = 'Missing service id.';
     } else {
         if (strlen($service_id) != 5) {
             $missing_billing_info[] = 'Service id must be 5 characters.';
         }
     }
     // HACK to get the needed location code for the building
     $building_location_code = rental_socomposite::get_instance()->get_building_location_code($contract->get_id());
     if ($building_location_code == null || $building_location_code == '') {
         $missing_billing_info[] = 'Unable to get a location code for the building.';
     } else {
         if (strlen($building_location_code) != 6) {
             $missing_billing_info[] = 'Invalid location code for the building.';
         }
     }
     /*$project_id_in = $GLOBALS['phpgw_info']['user']['preferences']['rental']['project_id'];
     		if($project_id_in == null || $project_id_in == '')
     		{
     			$missing_billing_info[] = 'Missing system setting for project id.';
     		}
     		else if(strlen($project_id_in) > 6)
     		{
     			$missing_billing_info[] = 'System setting for project id can not be more than 6 characters.';
     		}*/
     $project_id_out = $contract->get_project_id();
     if ($project_id_out == null || $project_id_out == '') {
         $missing_billing_info[] = 'Missing project id.';
     } else {
         if (strlen($project_id_out) > 6) {
             $missing_billing_info[] = 'Project id can not be more than 6 characters.';
         }
     }
     $price_items = rental_socontract_price_item::get_instance()->get(null, null, null, null, null, null, array('contract_id' => $contract->get_id()));
     foreach ($price_items as $price_item) {
         $agresso_id = $price_item->get_agresso_id();
         if ($agresso_id == null || $agresso_id == '') {
             $missing_billing_info[] = 'One or more price items are missing Agresso ids.';
             break;
             // We only need one error message
         } else {
             if (!preg_match("([A-Z]{1}[0-9]{3})", $agresso_id)) {
                 $missing_billing_info[] = 'One or more price items have an invalid Agresso id. Id must consist of one capital letter and three digits.';
                 break;
                 // We only need one error message
             }
         }
     }
     return $missing_billing_info;
 }
 /**
  * Create invoice
  * 
  * @param int $decimals	the number of decimals on the total sum of the onvoice
  * @param int $billing_id	the billing this invoice is part of
  * @param int $contract_id	the contract
  * @param bool $override	flag to indicate if the invoice start period should be overridden with the billing start date of contract
  * @param int $timestamp_invoice_start	the startdate of the invoice period
  * @param int $timestamp_invoice_end	the enddate of the invoice period
  * @param bool $bill_only_one_time	flag to indicate if the the invoice should only bil one time price elements
  * @return rental_invoice	the newly created invoice
  */
 public static function create_invoice(int $decimals, int $billing_id, int $contract_id, bool $override, int $timestamp_invoice_start, int $timestamp_invoice_end, $bill_only_one_time, $dry_run = false, $billing_term = 0)
 {
     $contract = rental_socontract::get_instance()->get_single($contract_id);
     // If the invoice period should be overriden with the biling start date
     if ($override) {
         $timestamp_invoice_start = $contract->get_billing_start_date();
     }
     // If no account out is specified: check if the contract type defines any data to be used in this field (AGRESSO specific logic)
     $account_out = $contract->get_account_out();
     if (!isset($account_out) || $account_out == '') {
         //If no account out - check the contract type for default
         $account_tmp = rental_socontract::get_instance()->get_contract_type_account($contract->get_contract_type_id());
         if (isset($account_tmp) && $account_tmp != '') {
             $account_out = $account_tmp;
         } else {
             $account_out = rental_socontract::get_instance()->get_default_account($contract->get_location_id(), false);
         }
     }
     // Create invoice ...
     $invoice = new rental_invoice(-1, $billing_id, $contract_id, time(), $timestamp_invoice_start, $timestamp_invoice_end, 0, $contract->get_rented_area(), $contract->get_invoice_header(), $contract->get_account_in(), $account_out, $contract->get_service_id(), $contract->get_responsibility_id());
     // ... and add party identifier, project number and the old contract identifier
     $invoice->set_party_id($contract->get_payer_id());
     $invoice->set_project_id($contract->get_project_id());
     $invoice->set_old_contract_id($contract->get_old_contract_id());
     if (!$dry_run) {
         rental_soinvoice::get_instance()->store($invoice);
         // We must store the invoice at this point to have an id to give to the price item
     }
     // Retrieve the contract price items: only one-time or all
     if ($bill_only_one_time) {
         $filters2 = array('contract_id' => $contract->get_id(), 'contract_ids_one_time' => true, 'billing_term_id' => $billing_term, 'year' => date('Y', $timestamp_invoice_start), 'month' => date('m', $timestamp_invoice_start));
         //$contract_price_items = $socontract_price_item->get($start_index, $num_of_objects, $sort_field, $sort_ascending, $search_for, $search_type, $filters2);
         $contract_price_items = rental_socontract_price_item::get_instance()->get(null, null, null, null, null, null, $filters2);
         //$contract_price_items = rental_socontract_price_item::get_instance()->get(null, null, null, null, null, null, array('contract_id' => $contract->get_id(), 'one_time' => true));
     } else {
         $contract_price_items = rental_socontract_price_item::get_instance()->get(null, null, null, null, null, null, array('contract_id' => $contract->get_id()));
     }
     $total_sum = 0;
     // Holding the total price of the invoice
     $contract_dates = $contract->get_contract_date();
     if (isset($contract_dates)) {
         $contract_start = $contract->get_contract_date()->get_start_date();
         $contract_end = $contract->get_contract_date()->get_end_date();
     }
     // Run through the contract price items
     foreach ($contract_price_items as $contract_price_item) {
         // ---- Period calculation ---
         // Determine start date for price item
         $contract_price_item_start = $contract_price_item->get_date_start();
         if ($contract_price_item_start == null || $contract_price_item_start == '') {
             // We just use the invoice date for our calculations
             $contract_price_item_start = $timestamp_invoice_start;
         }
         // Determine end date for price item
         $contract_price_item_end = $contract_price_item->get_date_end();
         if ($contract_price_item_end == null || $contract_price_item_end == '') {
             // We just use the invoice date for our calculations
             $contract_price_item_end = $timestamp_invoice_end;
         }
         // Sanity check - end date should never be before start date
         if ($contract_price_item_end < $contract_price_item_start) {
             continue;
             // We don't add this price item - continue to next
         }
         // Checking the start date against the invoice dates
         if ($contract_price_item_start < $timestamp_invoice_start) {
             $invoice_price_item_start = $timestamp_invoice_start;
             // We use the invoice start
         } else {
             if ($contract_price_item_start > $timestamp_invoice_end) {
                 continue;
                 // We don't add this price item - continue to next
             } else {
                 $invoice_price_item_start = $contract_price_item_start;
                 // We use the price item start
             }
         }
         // Checking the end date against invoice dates
         if ($contract_price_item_end < $timestamp_invoice_start) {
             continue;
             // We don't add this price item - continue to next
         } else {
             if ($contract_price_item_end < $timestamp_invoice_end) {
                 $invoice_price_item_end = $contract_price_item_end;
                 // We use the price item end
             } else {
                 $invoice_price_item_end = $timestamp_invoice_end;
                 // We use the invoice end
             }
         }
         // Checking the contract dates against the temporary price item dates
         if (isset($contract_start) && !$contract_price_item->is_one_time()) {
             if ($contract_start > $timestamp_invoice_end) {
                 continue;
                 //No price items for this contract will be billed
             }
             if ($contract_start > $invoice_price_item_start) {
                 $invoice_price_item_start = $contract_start;
             }
         }
         if (isset($contract_end) && !$contract_price_item->is_one_time()) {
             if ($contract_end < $timestamp_invoice_start) {
                 continue;
                 //No price items for this contract will be billed
             }
             if ($contract_end < $invoice_price_item_end) {
                 $invoice_price_item_end = $contract_end;
             }
         }
         // --- End of period calculation ---
         // Create a new invoice price item
         $invoice_price_item = new rental_invoice_price_item($decimals, -1, $invoice->get_id(), $contract_price_item->get_title(), $contract_price_item->get_agresso_id(), $contract_price_item->is_area(), $contract_price_item->get_price(), $contract_price_item->get_area(), $contract_price_item->get_count(), $invoice_price_item_start, $invoice_price_item_end);
         // If the contract price item is of type one-time and it's dates are within the invoice period ...
         if ($contract_price_item->is_one_time()) {
             if ($contract_price_item_start >= $timestamp_invoice_start && $contract_price_item_start <= $timestamp_invoice_end) {
                 // ... set the total price of the invoice price item to the total price of the contract price item
                 $invoice_price_item->set_total_price($contract_price_item->get_total_price());
                 // ... and set the contract price item as billed
                 $contract_price_item->set_is_billed(true);
                 if (!$dry_run) {
                     rental_socontract_price_item::get_instance()->store($contract_price_item);
                 }
             }
         }
         if (!$dry_run) {
             // Store the invoice price item
             rental_soinvoice_price_item::get_instance()->store($invoice_price_item);
         }
         // Add the price item to the invoice
         $invoice->add_invoice_price_item($invoice_price_item);
         // Add this price item's total sum to the tota sum of the invoice
         $total_sum += $invoice_price_item->get_total_price();
     }
     // end of looping through the contract price items
     // Set the total sum of the invoice rounded to the specified number of decimals
     $invoice->set_total_sum(round($total_sum, $decimals));
     if (!$dry_run) {
         // ... and store the invoice
         rental_soinvoice::get_instance()->store($invoice);
     }
     return $invoice;
 }
 public function adjust_contracts($adjustments)
 {
     /*
      * gather all adjustable contracts with 
      * 		interval = adjustment interval and this year = last adjusted + interval
      * 		or
      * 		last adjusted is null / 0 (use contract start year)
      * adjust each contract's price items according to adjustment info (percent, adjustment_percent)
      * Run as transaction
      * update adjustment -> set is_executed to true
      * update price book elements according to type if interval=1
      */
     $current_year = (int) date('Y');
     //var_dump("innicontr");
     foreach ($adjustments as $adjustment) {
         //gather all adjustable contracts
         $adjustable_contracts = "SELECT id, adjustment_share, date_start, adjustment_year FROM rental_contract ";
         $adjustable_contracts .= "WHERE location_id = '{$adjustment->get_responsibility_id()}' AND adjustable ";
         $adjustable_contracts .= "AND adjustment_interval = {$adjustment->get_interval()} ";
         $adjustable_contracts .= "AND (((adjustment_year + {$adjustment->get_interval()}) <= {$adjustment->get_year()})";
         $adjustable_contracts .= " OR ";
         $adjustable_contracts .= "(";
         if ($adjustment->is_extra_adjustment()) {
             $adjustable_contracts .= "adjustment_year = {$adjustment->get_year()}";
             $adjustable_contracts .= " OR ";
         }
         $adjustable_contracts .= "(adjustment_year IS NULL OR adjustment_year = 0)";
         $adjustable_contracts .= "))";
         //var_dump($adjustable_contracts);
         //die();
         $result = $this->db->query($adjustable_contracts);
         while ($this->db->next_record()) {
             $contract_id = $this->unmarshal($this->db->f('id', true), 'int');
             $adjustment_share = $this->unmarshal($this->db->f('adjustment_share', true), 'int');
             $date_start = $this->unmarshal($this->db->f('date_start', true), 'int');
             $adj_year = $this->unmarshal($this->db->f('adjustment_year', true), 'int');
             $start_year = date('Y', $date_start);
             $contract = rental_socontract::get_instance()->get_single($contract_id);
             $firstJanAdjYear = mktime(0, 0, 0, 1, 1, $adjustment->get_year());
             if ($contract->is_active($firstJanAdjYear) && ($adj_year != null && $adj_year > 0 || ($adj_year == null || $adj_year == 0) && $start_year + $adjustment->get_interval() <= $adjustment->get_year())) {
                 //update adjustment_year on contract
                 rental_socontract::get_instance()->update_adjustment_year($contract_id, $adjustment->get_year());
                 //gather price items to be adjusted
                 $contract_price_items = rental_socontract_price_item::get_instance()->get(null, null, null, null, null, null, array('contract_id' => $contract_id));
                 foreach ($contract_price_items as $cpi) {
                     //update price according to adjustment info
                     $cpi_old_price = $cpi->get_price();
                     $cpi_adjustment = $cpi_old_price * ($adjustment->get_percent() / 100) * ($adjustment_share / 100);
                     $cpi_new_price = $cpi_old_price + $cpi_adjustment;
                     $cpi->set_price($cpi_new_price);
                     rental_socontract_price_item::get_instance()->store($cpi);
                 }
             }
         }
         //TODO: update price book
         if ($adjustment->get_interval() == 1) {
             $adjustable_price_items = "SELECT * FROM rental_price_item WHERE responsibility_id = {$adjustment->get_responsibility_id()} AND is_adjustable";
             $result = $this->db->query($adjustable_price_items);
             $price_items = array();
             while ($this->db->next_record()) {
                 $price_item = new rental_price_item($this->unmarshal($this->db->f('id'), 'int'));
                 $price_item->set_title($this->unmarshal($this->db->f('title'), 'string'));
                 $price_item->set_agresso_id($this->unmarshal($this->db->f('agresso_id'), 'string'));
                 $price_item->set_is_area($this->unmarshal($this->db->f('is_area'), 'bool'));
                 $price_item->set_is_inactive($this->unmarshal($this->db->f('is_inactive'), 'bool'));
                 $price_item->set_is_adjustable($this->unmarshal($this->db->f('is_adjustable'), 'bool'));
                 $price_item->set_price($this->unmarshal($this->db->f('price'), 'float'));
                 $price_item->set_responsibility_id($this->unmarshal($this->db->f('responsibility_id', true), 'int'));
                 $price_item->set_responsibility_title($this->unmarshal($this->db->f('resp_title', true), 'string'));
                 $price_items[] = $price_item;
             }
             foreach ($price_items as $pi) {
                 $pi_old_price = $pi->get_price();
                 $pi_adjustment = $pi_old_price * ($adjustment->get_percent() / 100);
                 $pi_new_price = $pi_old_price + $pi_adjustment;
                 $pi->set_price($pi_new_price);
                 rental_soprice_item::get_instance()->store($pi);
             }
         }
         $adjustment->set_is_executed(true);
         $this->update($adjustment);
         //notify all users with write access on the field of responsibility
         $location_id = $adjustment->get_responsibility_id();
         if ($location_id) {
             $location_names = $GLOBALS['phpgw']->locations->get_name($location_id);
             if ($location_names['appname'] == $GLOBALS['phpgw_info']['flags']['currentapp']) {
                 $responsible_accounts = $GLOBALS['phpgw']->acl->get_user_list_right(PHPGW_ACL_EDIT, $location_names['location']);
                 foreach ($responsible_accounts as $ra) {
                     $account_ids[] = $ra['account_id'];
                 }
             }
         }
         $location_label = rental_socontract::get_instance()->get_responsibility_title($location_id);
         $adj_interval = $adjustment->get_interval();
         $day = date("Y-m-d", strtotime('now'));
         $ts_today = strtotime($day);
         //notify each unique account
         foreach ($account_ids as $account_id) {
             if ($account_id && $account_id > 0) {
                 $notification = new rental_notification(0, $account_id, 0, null, $ts_today, $location_label . '_' . $adj_interval, null, null, null, null);
                 rental_soworkbench_notification::get_instance()->store($notification);
             }
         }
     }
     return true;
 }
 public function get_max_area()
 {
     $contract_id = (int) phpgw::get_var('contract_id');
     $total_price = rental_socontract_price_item::get_instance()->get_max_area($contract_id);
     $result_array = array('max_area' => $max_area);
     $result_data = array('results' => $result_array, 'total_records' => 1);
     return $this->yui_results($result_data, 'total_records', 'results');
 }