/**
  * the singleton pattern
  *
  * @return Tinebase_Relations
  */
 public static function getInstance()
 {
     if (self::$instance === NULL) {
         self::$instance = new Tinebase_Relations();
     }
     return self::$instance;
 }
 /**
  * Returns all relatable models for this app
  * 
  * @return array
  */
 public function getRelatableModels()
 {
     if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
         Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' This method is deprecated and will be removed. Please use Tinebase_ModelFactory with Tinebase_ModelConfiguration!');
     }
     if (property_exists($this, '_relatableModels') && is_array($this->_relatableModels)) {
         return Tinebase_Relations::getConstraintsConfigs($this->_relatableModels);
     } else {
         return array();
     }
 }
Пример #3
0
 /**
  * appends sql to given select statement
  *
  * @param Zend_Db_Select                $_select
  * @param Tinebase_Backend_Sql_Abstract $_backend
  */
 public function appendFilterSql($_select, $_backend)
 {
     if (empty($this->_value)) {
         // nothing to filter
         return;
     }
     $filterData = array(array('field' => 'lead_name', 'operator' => 'contains', 'value' => $this->_value), array('field' => 'description', 'operator' => 'contains', 'value' => $this->_value), array('field' => 'showClosed', 'operator' => 'equals', 'value' => TRUE));
     $filter = new Crm_Model_LeadFilter($filterData, 'OR');
     /*** also filter for related contacts ***/
     $contactFilter = new Addressbook_Model_ContactFilter(array(array('field' => 'query', 'operator' => 'contains', 'value' => $this->_value)));
     $contactIds = Addressbook_Controller_Contact::getInstance()->search($contactFilter, NULL, FALSE, TRUE);
     $relationFilter = new Tinebase_Model_RelationFilter(array(array('field' => 'own_model', 'operator' => 'equals', 'value' => 'Crm_Model_Lead'), array('field' => 'related_model', 'operator' => 'equals', 'value' => 'Addressbook_Model_Contact'), array('field' => 'related_id', 'operator' => 'in', 'value' => $contactIds)));
     $leadIds = Tinebase_Relations::getInstance()->search($relationFilter, NULL)->own_id;
     $filter->addFilter(new Tinebase_Model_Filter_Id('id', 'in', $leadIds));
     Tinebase_Backend_Sql_Filter_FilterGroup::appendFilters($_select, $filter, $_backend);
 }
 /**
  * append relation filter
  * 
  * @param Crm_Model_LeadFilter $filter
  */
 protected function _appendRelationFilter($filter)
 {
     if (!Tinebase_Core::getPreference()->getValue(Tinebase_Preference::ADVANCED_SEARCH, false)) {
         return;
     }
     $relationsToSearchIn = array('Addressbook_Model_Contact', 'Sales_Model_Product', 'Tasks_Model_Task');
     $leadIds = array();
     foreach ($relationsToSearchIn as $relatedModel) {
         $filterModel = $relatedModel . 'Filter';
         $relatedFilter = new $filterModel(array(array('field' => 'query', 'operator' => 'contains', 'value' => $this->_value)));
         $relatedIds = Tinebase_Core::getApplicationInstance($relatedModel)->search($relatedFilter, NULL, FALSE, TRUE);
         $relationFilter = new Tinebase_Model_RelationFilter(array(array('field' => 'own_model', 'operator' => 'equals', 'value' => 'Crm_Model_Lead'), array('field' => 'related_model', 'operator' => 'equals', 'value' => $relatedModel), array('field' => 'related_id', 'operator' => 'in', 'value' => $relatedIds)));
         $leadIds = array_merge($leadIds, Tinebase_Relations::getInstance()->search($relationFilter, NULL)->own_id);
     }
     $filter->addFilter(new Tinebase_Model_Filter_Id('id', 'in', $leadIds));
 }
 /**
  * returns own ids defined by relation filter
  *
  * @param string $_modelName
  * @return array
  */
 protected function _getOwnIds($_modelName)
 {
     if (!$this->_options['own_filtergroup']) {
         throw new Tinebase_Exception_InvalidArgument('own filter group has to be defined!');
     }
     if (!$this->_options['own_controller']) {
         throw new Tinebase_Exception_InvalidArgument('own controller has to be defined!');
     }
     $idProperty = 'id';
     $filtergroup = $this->_options['own_filtergroup'];
     $controller = $this->_options['own_controller'];
     if (!$this->_value[0]['value']) {
         $relationFilter = new Tinebase_Model_RelationFilter(array(array('field' => 'own_model', 'operator' => 'equals', 'value' => $_modelName), array('field' => 'related_model', 'operator' => 'equals', 'value' => $this->_options['related_model'])));
         $notInIds = Tinebase_Relations::getInstance()->search($relationFilter, NULL)->own_id;
         $filter = new $filtergroup(array(), 'AND');
         $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => $idProperty, 'operator' => 'notin', 'value' => $notInIds)));
         return $controller::getInstance()->search($filter, null, false, true);
     }
     return parent::_getOwnIds($_modelName);
 }
 /**
  * get all relations of a given record
  *
  * @param  string       $_model         own model to get relations for
  * @param  string       $_id            own id to get relations for
  * @param  string       $_degree        only return relations of given degree
  * @param  array        $_type          only return relations of given type
  * @param  string       $_relatedModel  only return relations having this related model
  * @return array
  */
 public function getRelations($model, $id, $degree = NULL, $type = array(), $relatedModel = NULL)
 {
     $relations = Tinebase_Relations::getInstance()->getRelations($model, 'Sql', $id, $degree, $type, false, $relatedModel);
     // @TODO we still have no converter for relations :-(
     // -> related records returned here are different to the records returned by the apps itself!
     // -> this problem also applies to to generic json converter!
     if (count($relations) > 0) {
         $relations->setTimezone(Tinebase_Core::getUserTimezone());
         $relations->bypassFilters = true;
         $result = $relations->toArray();
     } else {
         $result = array();
     }
     return array('results' => array_values($result), 'totalcount' => count($result));
 }
 /**
  * @param Sales_Model_Contract $contractId
  */
 public function getTimeaccountsBySalesContract($contractId)
 {
     $contractId = is_string($contractId) ? $contractId : $contractId->getId();
     $filter = new Tinebase_Model_RelationFilter(array(array('field' => 'related_model', 'operator' => 'equals', 'value' => 'Sales_Model_Contract'), array('field' => 'related_id', 'operator' => 'equals', 'value' => $contractId), array('field' => 'own_model', 'operator' => 'equals', 'value' => 'Timetracker_Model_Timeaccount'), array('field' => 'type', 'operator' => 'equals', 'value' => 'TIME_ACCOUNT')), 'AND');
     return Sales_Controller_Contract::getInstance()->getMultiple(Tinebase_Relations::getInstance()->search($filter)->own_id);
 }
 /**
  * inspects delete action
  *
  * @param array $_ids
  * @return array of ids to actually delete
  */
 protected function _inspectDelete(array $_ids)
 {
     $records = $this->_backend->getMultiple($_ids);
     $records->setTimezone(Tinebase_Core::getUserTimezone());
     $invoicePositionController = Sales_Controller_InvoicePosition::getInstance();
     $contractController = Sales_Controller_Contract::getInstance();
     foreach ($records as $record) {
         if (!$record->is_auto) {
             continue;
         }
         if ($record->cleared == 'CLEARED') {
             // cleared invoices must not be deleted
             throw new Sales_Exception_InvoiceAlreadyClearedDelete();
         } else {
             // try to find a invoice after this one
             // there should be a contract
             $contractRelation = Tinebase_Relations::getInstance()->getRelations('Sales_Model_Invoice', 'Sql', $record->getId(), NULL, array(), TRUE, array('Sales_Model_Contract'))->getFirstRecord();
             if ($contractRelation) {
                 $contract = $contractRelation->related_record;
                 $contract->setTimezone(Tinebase_Core::getUserTimezone());
                 // get all invoices related to this contract. throw exception if a follwing invoice has been found
                 $invoiceRelations = Tinebase_Relations::getInstance()->getRelations('Sales_Model_Contract', 'Sql', $contract->getId(), NULL, array(), TRUE, array('Sales_Model_Invoice'));
                 foreach ($invoiceRelations as $invoiceRelation) {
                     $invoiceRelation->related_record->setTimezone(Tinebase_Core::getUserTimezone());
                     if ($record->getId() !== $invoiceRelation->related_record->getId() && $record->creation_time < $invoiceRelation->related_record->creation_time) {
                         throw new Sales_Exception_DeletePreviousInvoice();
                     }
                 }
                 $this->_currentBillingContract = $contract;
                 $productAggregates = $this->_findProductAggregates();
             } else {
                 if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) {
                     Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' Could not find contract relation -> skip contract handling');
                 }
                 $contract = null;
                 $productAggregates = array();
             }
             // remove invoice_id from billables
             $filter = new Sales_Model_InvoicePositionFilter(array());
             $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $record->getId())));
             $invoicePositions = $invoicePositionController->search($filter);
             $allModels = array_unique($invoicePositions->model);
             foreach ($allModels as $model) {
                 if ($model == 'Sales_Model_ProductAggregate') {
                     continue;
                 }
                 $filteredInvoicePositions = $invoicePositions->filter('model', $model);
                 $billableControllerName = $model::getBillableControllerName();
                 $billableFilterName = $model::getBillableFilterName();
                 $filterInstance = new $billableFilterName(array());
                 $filterInstance->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $record->getId())));
                 $billableControllerName::getInstance()->updateMultiple($filterInstance, array('invoice_id' => NULL));
                 // set invoice ids of the timeaccounts
                 if ($model == 'Timetracker_Model_Timeaccount') {
                     $filterInstance = new Timetracker_Model_TimeaccountFilter(array());
                     $filterInstance->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $record->getId())));
                     Timetracker_Controller_Timeaccount::getInstance()->updateMultiple($filterInstance, array('invoice_id' => NULL));
                 }
             }
             // delete invoice positions
             $invoicePositionController->delete($invoicePositions->getId());
             // set last_autobill a period back
             if ($contract) {
                 //find the month of each productAggregate we have to set it back to
                 $undoProductAggregates = array();
                 $paController = Sales_Controller_ProductAggregate::getInstance();
                 foreach ($invoicePositions as $inPos) {
                     if ($inPos->model != 'Sales_Model_ProductAggregate') {
                         continue;
                     }
                     //if we didnt find a month for the productAggreagte yet or if the month found is greater than the one we have at hands
                     if (!isset($undoProductAggregates[$inPos->accountable_id]) || strcmp($undoProductAggregates[$inPos->accountable_id], $inPos->month) > 0) {
                         $undoProductAggregates[$inPos->accountable_id] = $inPos->month;
                     }
                 }
                 foreach ($productAggregates as $productAggregate) {
                     if (!$productAggregate->last_autobill) {
                         continue;
                     }
                     if (!isset($undoProductAggregates[$productAggregate->id])) {
                         $product = $this->_cachedProducts->getById($productAggregate->product_id);
                         if (!$product) {
                             $product = Sales_Controller_Product::getInstance()->get($productAggregate->product_id);
                             $this->_cachedProducts->addRecord($product);
                         }
                         if ($product->accountable == 'Sales_Model_Product' || $record->date != null && $record->date->isLater($productAggregate->last_autobill)) {
                             continue;
                         }
                         $productAggregate->last_autobill->subMonth($productAggregate->interval);
                     } else {
                         $productAggregate->last_autobill = new Tinebase_DateTime($undoProductAggregates[$productAggregate->id] . '-01 00:00:00', Tinebase_Core::getUserTimezone());
                         if ($productAggregate->billing_point == 'begin') {
                             $productAggregate->last_autobill->subMonth($productAggregate->interval);
                         }
                         if ($productAggregate->start_date && $productAggregate->last_autobill < $productAggregate->start_date) {
                             $tmp = clone $productAggregate->start_date;
                             $tmp->setTimezone(Tinebase_Core::getUserTimezone());
                             $tmp->setDate($tmp->format('Y'), $tmp->format('m'), 1);
                             $tmp->setTime(0, 0, 0);
                             if ($productAggregate->last_autobill < $tmp || $productAggregate->billing_point == 'end' && $productAggregate->last_autobill == $tmp) {
                                 $productAggregate->last_autobill = NULL;
                             }
                         }
                     }
                     $productAggregate->setTimezone('UTC');
                     $paController->update($productAggregate);
                     $productAggregate->setTimezone(Tinebase_Core::getUserTimezone());
                 }
             }
         }
     }
     return $_ids;
 }
 /**
  * append relation filter
  *
  * @param string $ownModel
  * @param array $relationsToSearchIn
  * @return Tinebase_Model_Filter_Id
  */
 protected function _getAdvancedSearchFilter($ownModel = null, $relationsToSearchIn = null)
 {
     if (Tinebase_Core::get('ADVANCED_SEARCHING') || !Tinebase_Core::getPreference()->getValue(Tinebase_Preference::ADVANCED_SEARCH, false) || empty($relationsToSearchIn)) {
         return null;
     }
     if (0 === strpos($this->_operator, 'not')) {
         $not = true;
         $operator = substr($this->_operator, 3);
     } else {
         $not = false;
         $operator = $this->_operator;
     }
     $ownIds = array();
     foreach ((array) $relationsToSearchIn as $relatedModel) {
         $filterModel = $relatedModel . 'Filter';
         // prevent recursion here
         // TODO find a better way for this, maybe we could pass this an option to all filters in filter model
         Tinebase_Core::set('ADVANCED_SEARCHING', true);
         $relatedFilter = new $filterModel(array(array('field' => 'query', 'operator' => $operator, 'value' => $this->_value)));
         $relatedIds = Tinebase_Core::getApplicationInstance($relatedModel)->search($relatedFilter, NULL, FALSE, TRUE);
         Tinebase_Core::set('ADVANCED_SEARCHING', false);
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Found ' . count($relatedIds) . ' related ids');
         }
         $relationFilter = new Tinebase_Model_RelationFilter(array(array('field' => 'own_model', 'operator' => 'equals', 'value' => $ownModel), array('field' => 'related_model', 'operator' => 'equals', 'value' => $relatedModel), array('field' => 'related_id', 'operator' => 'in', 'value' => $relatedIds)));
         $ownIds = array_merge($ownIds, Tinebase_Relations::getInstance()->search($relationFilter, NULL)->own_id);
     }
     return new Tinebase_Model_Filter_Id('id', $not ? 'notin' : 'in', $ownIds);
 }
 /**
  * delete linked relations
  * 
  * @param Tinebase_Record_Interface $_record
  * 
  * TODO check if this needs to be done, as we might already deleting this "from the other side"
  */
 protected function _deleteLinkedRelations(Tinebase_Record_Interface $_record)
 {
     $relations = Tinebase_Relations::getInstance()->getRelations($this->_modelName, $this->_getBackendType(), $_record->getId());
     if (empty($relations)) {
         return;
     }
     // remove relations
     Tinebase_Relations::getInstance()->setRelations($this->_modelName, $this->_getBackendType(), $_record->getId(), array());
     if (empty($this->_relatedObjectsToDelete)) {
         return;
     }
     // remove related objects
     Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Deleting all ' . implode(',', $this->_relatedObjectsToDelete) . ' relations.');
     foreach ($relations as $relation) {
         if (in_array($relation->related_model, $this->_relatedObjectsToDelete)) {
             list($appName, $i, $itemName) = explode('_', $relation->related_model);
             $appController = Tinebase_Core::getApplicationInstance($appName, $itemName);
             try {
                 $appController->delete($relation->related_id);
             } catch (Exception $e) {
                 Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Error deleting: ' . $e->getMessage());
             }
         }
     }
 }
 /**
  * returns recipients for a lead notification
  *
  * @param  Crm_Model_Lead $_lead
  * @return Tinebase_Record_RecordSet of Addressbook_Model_Contact
  */
 protected function _getNotificationRecipients(Crm_Model_Lead $_lead)
 {
     if (!$_lead->relations instanceof Tinebase_Record_RecordSet) {
         $_lead->relations = Tinebase_Relations::getInstance()->getRelations('Crm_Model_Lead', 'Sql', $_lead->getId(), true);
     }
     $recipients = $_lead->getResponsibles();
     // if no responsibles are defined, send message to all readers of container
     if (count($recipients) === 0) {
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__CLASS__ . '::' . __METHOD__ . '::' . __LINE__ . ' no responsibles found for lead: ' . $_lead->getId() . ' sending notification to all people having read access to container ' . $_lead->container_id);
         }
         $containerGrants = Tinebase_Container::getInstance()->getGrantsOfContainer($_lead->container_id, TRUE);
         // NOTE: we just send notifications to users, not to groups or anyones!
         foreach ($containerGrants as $grant) {
             if ($grant['account_type'] == Tinebase_Acl_Rights::ACCOUNT_TYPE_USER && $grant[Tinebase_Model_Grants::GRANT_READ] == 1) {
                 try {
                     $contact = Addressbook_Controller_Contact::getInstance()->getContactByUserId($grant['account_id'], TRUE);
                     $recipients->addRecord($contact);
                 } catch (Addressbook_Exception_NotFound $aenf) {
                     if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) {
                         Tinebase_Core::getLogger()->notice(__CLASS__ . '::' . __METHOD__ . '::' . __LINE__ . ' Do not send notification to non-existant user: ' . $aenf->getMessage());
                     }
                 }
             }
         }
     }
     return $recipients;
 }
 /**
  * transfers all contracts starting with AB- to orderconfirmation
  */
 public function transferContractsToOrderConfirmation()
 {
     $contractController = Sales_Controller_Contract::getInstance();
     $ocController = Sales_Controller_OrderConfirmation::getInstance();
     $rel = Tinebase_Relations::getInstance();
     $filter = new Sales_Model_ContractFilter(array(array('field' => 'number', 'operator' => 'startswith', 'value' => 'AB-')), 'AND');
     $contracts = $contractController->search($filter);
     foreach ($contracts as $contract) {
         $oc = $ocController->create(new Sales_Model_OrderConfirmation(array('number' => $contract->number, 'title' => $contract->title, 'description' => '')));
         $rel->setRelations('Sales_Model_OrderConfirmation', 'Sql', $oc->getId(), array(array('own_degree' => 'sibling', 'related_degree' => 'sibling', 'related_model' => 'Sales_Model_Contract', 'related_backend' => 'Sql', 'related_id' => $contract->getId(), 'type' => 'CONTRACT')));
     }
 }
Пример #13
0
 public function testBreakRelations()
 {
     $this->_object->setRelations($this->_crmId['model'], $this->_crmId['backend'], $this->_crmId['id'], array());
     $relations = $this->_object->getRelations($this->_crmId['model'], $this->_crmId['backend'], $this->_crmId['id']);
     $this->assertEquals(0, count($relations));
 }
 /**
  * returns path of record
  *
  * @param Tinebase_Record_Interface     $record
  * @param boolean|int                   $depth
  * @return Tinebase_Record_RecordSet
  * @throws Tinebase_Exception_Record_NotAllowed
  * @throws Tinebase_Exception
  */
 protected function _getPathsOfRecord(Tinebase_Record_Interface $record, $depth = false)
 {
     if (false !== $depth && $depth > 8) {
         throw new Tinebase_Exception('too many recursions while calculating record path');
     }
     $result = new Tinebase_Record_RecordSet('Tinebase_Model_Path');
     $parentRelations = Tinebase_Relations::getInstance()->getRelationsOfRecordByDegree($record, Tinebase_Model_Relation::DEGREE_PARENT);
     foreach ($parentRelations as $parent) {
         if (!is_object($parent->related_record)) {
             $parent->related_record = Tinebase_Core::getApplicationInstance($parent->related_model)->get($parent->related_id);
         }
         if (false === $depth) {
             // we do not need to generate the parents paths, they should be in DB
             $parentPaths = Tinebase_Record_Path::getInstance()->getPathsForRecords($parent->related_record);
         } else {
             // we have to regenerate parents paths
             $parentPaths = $this->_getPathsOfRecord($parent->related_record, $depth === true ? 1 : $depth + 1);
         }
         if (count($parentPaths) === 0) {
             $path = new Tinebase_Model_Path(array('path' => $this->_getPathPart($parent->related_record) . $this->_getPathPart($record, $parent), 'shadow_path' => '/' . $parent->related_id . $this->_getShadowPathPart($record, $parent), 'record_id' => $record->getId(), 'creation_time' => Tinebase_DateTime::now()));
             $result->addRecord($path);
         } else {
             // merge paths
             foreach ($parentPaths as $path) {
                 $newPath = new Tinebase_Model_Path(array('path' => $path->path . $this->_getPathPart($record, $parent), 'shadow_path' => $path->shadow_path . $this->_getShadowPathPart($record, $parent), 'record_id' => $record->getId(), 'creation_time' => Tinebase_DateTime::now()));
                 $result->addRecord($newPath);
             }
         }
     }
     return $result;
 }
 /**
  * inspects delete action
  *
  * @param array $_ids
  * @return array of ids to actually delete
  */
 protected function _inspectDelete(array $_ids)
 {
     $records = $this->_backend->getMultiple($_ids);
     $records->setTimezone(Tinebase_Core::getUserTimezone());
     $invoicePositionController = Sales_Controller_InvoicePosition::getInstance();
     $contractController = Sales_Controller_Contract::getInstance();
     foreach ($records as $record) {
         if (!$record->is_auto) {
             continue;
         }
         if ($record->cleared == 'CLEARED') {
             // cleared invoices must not be deleted
             throw new Sales_Exception_InvoiceAlreadyClearedDelete();
         } else {
             // try to find a invoice after this one
             // there should be a contract
             $contractRelation = Tinebase_Relations::getInstance()->getRelations('Sales_Model_Invoice', 'Sql', $record->getId(), NULL, array(), TRUE, array('Sales_Model_Contract'))->getFirstRecord();
             if ($contractRelation) {
                 $contract = $contractRelation->related_record;
                 $contract->setTimezone(Tinebase_Core::getUserTimezone());
                 // get all invoices related to this contract. throw exception if a follwing invoice has been found
                 $invoiceRelations = Tinebase_Relations::getInstance()->getRelations('Sales_Model_Contract', 'Sql', $contract->getId(), NULL, array(), TRUE, array('Sales_Model_Invoice'));
                 foreach ($invoiceRelations as $invoiceRelation) {
                     $invoiceRelation->related_record->setTimezone(Tinebase_Core::getUserTimezone());
                     if ($record->getId() !== $invoiceRelation->related_record->getId() && $record->creation_time < $invoiceRelation->related_record->creation_time) {
                         throw new Sales_Exception_DeletePreviousInvoice();
                     }
                 }
             } else {
                 if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) {
                     Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' Could not find contract relation -> skip contract handling');
                 }
                 $contract = null;
             }
             // remove invoice_id from billables
             $filter = new Sales_Model_InvoicePositionFilter(array());
             $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $record->getId())));
             $invoicePositions = $invoicePositionController->search($filter);
             $allModels = array_unique($invoicePositions->model);
             foreach ($allModels as $model) {
                 if ($model == 'Sales_Model_ProductAggregate') {
                     continue;
                 }
                 $filteredInvoicePositions = $invoicePositions->filter('model', $model);
                 $billableControllerName = $model::getBillableControllerName();
                 $billableFilterName = $model::getBillableFilterName();
                 $filterInstance = new $billableFilterName(array());
                 $filterInstance->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $record->getId())));
                 $billableControllerName::getInstance()->updateMultiple($filterInstance, array('invoice_id' => NULL));
                 // set invoice ids of the timeaccounts
                 if ($model == 'Timetracker_Model_Timeaccount') {
                     $filterInstance = new Timetracker_Model_TimeaccountFilter(array());
                     $filterInstance->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $record->getId())));
                     Timetracker_Controller_Timeaccount::getInstance()->updateMultiple($filterInstance, array('invoice_id' => NULL));
                 }
             }
             // delete invoice positions
             $invoicePositionController->delete($invoicePositions->getId());
             // set last_autobill a period back
             if ($contract) {
                 // check product aggregates
                 $filter = new Sales_Model_ProductAggregateFilter(array());
                 $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'contract_id', 'operator' => 'equals', 'value' => $contract->getId())));
                 $paController = Sales_Controller_ProductAggregate::getInstance();
                 $productAggregates = $paController->search($filter);
                 $productAggregates->setTimezone(Tinebase_Core::getUserTimezone());
                 foreach ($productAggregates as $productAggregate) {
                     if ($productAggregate->last_autobill) {
                         $lab = clone $productAggregate->last_autobill;
                         $add = 0 - (int) $productAggregate->interval;
                         $productAggregate->last_autobill = $lab->addMonth($add);
                         $productAggregate->last_autobill->setTime(0, 0, 0);
                         // last_autobill may not be before aggregate starts (may run into this case if interval has been resized)
                         if (!$productAggregate->start_date || $productAggregate->last_autobill < $productAggregate->start_date) {
                             $productAggregate->last_autobill = NULL;
                         }
                     }
                     $productAggregate->setTimezone('UTC');
                     $paController->update($productAggregate);
                 }
             }
         }
     }
     return $_ids;
 }
 /**
  * rebills an invoice
  * 
  * @param string $id
  */
 public function rebillInvoice($id)
 {
     $invoice = Sales_Controller_Invoice::getInstance()->get($id);
     $relation = Tinebase_Relations::getInstance()->getRelations('Sales_Model_Invoice', 'Sql', $id, 'sibling', array('CONTRACT'), 'Sales_Model_Contract')->getFirstRecord();
     $contract = Sales_Controller_Contract::getInstance()->get($relation->related_id);
     $date = clone $invoice->creation_time;
     $date->setTimezone(Tinebase_Core::getUserTimezone());
     Sales_Controller_Invoice::getInstance()->delete(array($id));
     return Sales_Controller_Invoice::getInstance()->createAutoInvoices($date, $contract);
 }
Пример #17
0
 /**
  * delete linked objects (notes, relations, ...) of record
  *
  * @param Tinebase_Record_Interface $_record
  */
 protected function _deleteLinkedObjects(Tinebase_Record_Interface $_record)
 {
     // delete notes & relations
     if ($_record->has('notes')) {
         Tinebase_Notes::getInstance()->deleteNotesOfRecord($this->_modelName, $this->_backend->getType(), $_record->getId());
     }
     if ($_record->has('relations')) {
         $relations = Tinebase_Relations::getInstance()->getRelations($this->_modelName, $this->_backend->getType(), $_record->getId());
         if (!empty($relations)) {
             // remove relations
             Tinebase_Relations::getInstance()->setRelations($this->_modelName, $this->_backend->getType(), $_record->getId(), array());
             // remove related objects
             if (!empty($this->_relatedObjectsToDelete)) {
                 foreach ($relations as $relation) {
                     if (in_array($relation->related_model, $this->_relatedObjectsToDelete)) {
                         list($appName, $i, $itemName) = explode('_', $relation->related_model);
                         $appController = Tinebase_Core::getApplicationInstance($appName, $itemName);
                         $appController->delete($relation->related_id);
                     }
                 }
             }
         }
     }
 }
 /**
  * test if a user, who has no manage_invoices - right, is able tosave a timeaccount having an invoice linked
  */
 public function testUpdateInvoiceLinkedTimeaccount()
 {
     $this->markTestSkipped('0010492: fix failing invoices and timetracker tests');
     $ta = $this->_getTimeaccount(array('title' => 'to find'), true);
     $cc = Sales_Controller_CostCenter::getInstance()->create(new Sales_Model_CostCenter(array('number' => 1, 'title' => 'test')));
     $customer = Sales_Controller_Customer::getInstance()->create(new Sales_Model_Customer(array('number' => 100, 'name' => 'test', 'description' => 'unittest', 'credit_term' => 1)));
     $address = Sales_Controller_Address::getInstance()->create(new Sales_Model_Address(array('street' => 'teststreet', 'locality' => 'testcity', 'customer_id' => $customer->id, 'postalcode' => 12345)));
     $invoice = Sales_Controller_Invoice::getInstance()->create(new Sales_Model_Invoice(array('description' => 'test', 'address_id' => $address->id, 'date' => Tinebase_DateTime::now(), 'credit_term' => 1, 'type' => 'INVOICE', 'start_date' => Tinebase_DateTime::now(), 'end_date' => Tinebase_DateTime::now()->addMonth(1), 'costcenter_id' => $cc->id)));
     Tinebase_Relations::getInstance()->setRelations('Sales_Model_Invoice', 'Sql', $invoice->id, array(array('related_id' => $ta->id, 'related_model' => 'Timetracker_Model_Timeaccount', 'related_record' => $ta, 'own_degree' => 'sibling', 'type' => 'INVOICE')));
     // fetch user group
     $group = Tinebase_Group::getInstance()->getGroupByName('Users');
     $groupId = $group->getId();
     // create new user
     $user = new Tinebase_Model_FullUser(array('accountLoginName' => 'testuser', 'accountPrimaryGroup' => $groupId, 'accountDisplayName' => 'Test User', 'accountLastName' => 'User', 'accountFirstName' => 'Test', 'accountFullName' => 'Test User', 'accountEmailAddress' => '*****@*****.**'));
     $user = Admin_Controller_User::getInstance()->create($user, 'pw', 'pw');
     // add tt-ta admin right to user role to allow user to update (manage) timeaccounts
     // user has no right to see sales contracts
     $fe = new Admin_Frontend_Json();
     $userRoles = $fe->getRoles('user', array(), array(), 0, 1);
     $userRole = $fe->getRole($userRoles['results'][0]['id']);
     $roleRights = $fe->getRoleRights($userRole['id']);
     $roleMembers = $fe->getRoleMembers($userRole['id']);
     $roleMembers['results'][] = array('name' => 'testuser', 'type' => 'user', 'id' => $user->accountId);
     $app = Tinebase_Application::getInstance()->getApplicationByName('Timetracker');
     $roleRights['results'][] = array('application_id' => $app->getId(), 'right' => Timetracker_Acl_Rights::MANAGE_TIMEACCOUNTS);
     $roleRights['results'][] = array('application_id' => $app->getId(), 'right' => Tinebase_Acl_Rights::ADMIN);
     $fe->saveRole($userRole, $roleMembers['results'], $roleRights['results']);
     // switch to other user
     $this->_testUser = Tinebase_Core::getUser();
     Tinebase_Core::set(Tinebase_Core::USER, $user);
     $ta = $this->_json->getTimeaccount($ta->id);
     $this->assertTrue(empty($ta['relations']), 'relations are not empty: ' . print_r($ta['relations'], true));
     // this must be possible
     $ta = $this->_json->saveTimeaccount($ta);
     Tinebase_Core::set(Tinebase_Core::USER, $this->_testUser);
     $ta = $this->_json->getTimeaccount($ta['id']);
     $this->assertTrue(count($ta['relations']) == 1);
 }
 /**
  * uninstall app
  *
  * @param Tinebase_Model_Application $_application
  * @throws Setup_Exception
  */
 protected function _uninstallApplication(Tinebase_Model_Application $_application, $uninstallAll = false)
 {
     if ($this->_backend === null) {
         throw new Setup_Exception('No setup backend available');
     }
     Setup_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Uninstall ' . $_application);
     try {
         $applicationTables = Tinebase_Application::getInstance()->getApplicationTables($_application);
     } catch (Zend_Db_Statement_Exception $zdse) {
         Setup_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . " " . $zdse);
         throw new Setup_Exception('Could not uninstall ' . $_application . ' (you might need to remove the tables by yourself): ' . $zdse->getMessage());
     }
     $disabledFK = FALSE;
     $db = Tinebase_Core::getDb();
     do {
         $oldCount = count($applicationTables);
         if ($_application->name == 'Tinebase') {
             $installedApplications = Tinebase_Application::getInstance()->getApplications(NULL, 'id');
             if (count($installedApplications) !== 1) {
                 throw new Setup_Exception_Dependency('Failed to uninstall application "Tinebase" because of dependencies to other installed applications.');
             }
         }
         foreach ($applicationTables as $key => $table) {
             Setup_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " Remove table: {$table}");
             try {
                 // drop foreign keys which point to current table first
                 $foreignKeys = $this->_backend->getExistingForeignKeys($table);
                 foreach ($foreignKeys as $foreignKey) {
                     Setup_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " Drop index: " . $foreignKey['table_name'] . ' => ' . $foreignKey['constraint_name']);
                     $this->_backend->dropForeignKey($foreignKey['table_name'], $foreignKey['constraint_name']);
                 }
                 // drop table
                 $this->_backend->dropTable($table);
                 if ($_application->name != 'Tinebase') {
                     Tinebase_Application::getInstance()->removeApplicationTable($_application, $table);
                 }
                 unset($applicationTables[$key]);
             } catch (Zend_Db_Statement_Exception $e) {
                 // we need to catch exceptions here, as we don't want to break here, as a table
                 // might still have some foreign keys
                 // this works with mysql only
                 $message = $e->getMessage();
                 Setup_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . " Could not drop table {$table} - " . $message);
                 // remove app table if table not found in db
                 if (preg_match('/SQLSTATE\\[42S02\\]: Base table or view not found/', $message) && $_application->name != 'Tinebase') {
                     Tinebase_Application::getInstance()->removeApplicationTable($_application, $table);
                     unset($applicationTables[$key]);
                 } else {
                     Setup_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . " Disabling foreign key checks ... ");
                     if ($db instanceof Zend_Db_Adapter_Pdo_Mysql) {
                         $db->query("SET FOREIGN_KEY_CHECKS=0");
                     }
                     $disabledFK = TRUE;
                 }
             }
         }
         if ($oldCount > 0 && count($applicationTables) == $oldCount) {
             throw new Setup_Exception('dead lock detected oldCount: ' . $oldCount);
         }
     } while (count($applicationTables) > 0);
     if ($disabledFK) {
         if ($db instanceof Zend_Db_Adapter_Pdo_Mysql) {
             Setup_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . " Enabling foreign key checks again... ");
             $db->query("SET FOREIGN_KEY_CHECKS=1");
         }
     }
     if ($_application->name != 'Tinebase') {
         if (!$uninstallAll) {
             Tinebase_Relations::getInstance()->removeApplication($_application->name);
             Tinebase_Timemachine_ModificationLog::getInstance()->removeApplication($_application);
             // delete containers, config options and other data for app
             Tinebase_Application::getInstance()->removeApplicationData($_application);
         }
         // remove application from table of installed applications
         Tinebase_Application::getInstance()->deleteApplication($_application);
     }
     Setup_Uninitialize::uninitialize($_application);
     Setup_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " Removed app: " . $_application->name);
 }
 /**
  * resolve multiple record fields (Tinebase_ModelConfiguration._recordsFields)
  * 
  * @param Tinebase_Record_RecordSet $_records
  * @param Tinebase_ModelConfiguration $modelConfiguration
  * @param boolean $multiple
  * @throws Tinebase_Exception_UnexpectedValue
  */
 protected function _resolveMultipleRecordFields(Tinebase_Record_RecordSet $_records, $modelConfiguration = NULL, $multiple = false)
 {
     if (!$modelConfiguration || !$_records->count()) {
         return;
     }
     if (!($resolveFields = $modelConfiguration->recordsFields)) {
         return;
     }
     $ownIds = $_records->{$modelConfiguration->idProperty};
     // iterate fields to resolve
     foreach ($resolveFields as $fieldKey => $c) {
         $config = $c['config'];
         // resolve records, if omitOnSearch is definitively set to FALSE (by default they won't be resolved on search)
         if ($multiple && !(isset($config['omitOnSearch']) && $config['omitOnSearch'] === FALSE)) {
             continue;
         }
         if (!isset($config['controllerClassName'])) {
             throw new Tinebase_Exception_UnexpectedValue('Controller class name needed');
         }
         // fetch the fields by the refIfField
         /** @var Tinebase_Controller_Record_Interface|Tinebase_Controller_SearchInterface $controller */
         /** @noinspection PhpUndefinedMethodInspection */
         $controller = $config['controllerClassName']::getInstance();
         $filterName = $config['filterClassName'];
         $filterArray = array();
         // addFilters can be added and must be added if the same model resides in more than one records fields
         if (isset($config['addFilters']) && is_array($config['addFilters'])) {
             $filterArray = $config['addFilters'];
         }
         /** @var Tinebase_Model_Filter_FilterGroup $filter */
         $filter = new $filterName($filterArray);
         $filter->addFilter(new Tinebase_Model_Filter_Id(array('field' => $config['refIdField'], 'operator' => 'in', 'value' => $ownIds)));
         $paging = NULL;
         if (isset($config['paging']) && is_array($config['paging'])) {
             $paging = new Tinebase_Model_Pagination($config['paging']);
         }
         $foreignRecords = $controller->search($filter, $paging);
         /** @var Tinebase_Record_Interface $foreignRecordClass */
         $foreignRecordClass = $foreignRecords->getRecordClassName();
         $foreignRecordModelConfiguration = $foreignRecordClass::getConfiguration();
         $foreignRecords->setTimezone(Tinebase_Core::getUserTimezone());
         $foreignRecords->convertDates = true;
         $fr = $foreignRecords->getFirstRecord();
         // @todo: resolve alarms?
         // @todo: use parts parameter?
         if ($foreignRecordModelConfiguration->resolveRelated && $fr) {
             if ($fr->has('notes')) {
                 Tinebase_Notes::getInstance()->getMultipleNotesOfRecords($foreignRecords);
             }
             if ($fr->has('tags')) {
                 Tinebase_Tags::getInstance()->getMultipleTagsOfRecords($foreignRecords);
             }
             if ($fr->has('relations')) {
                 $relations = Tinebase_Relations::getInstance()->getMultipleRelations($foreignRecordClass, 'Sql', $foreignRecords->{$fr->getIdProperty()});
                 $foreignRecords->setByIndices('relations', $relations);
             }
             if ($fr->has('customfields')) {
                 Tinebase_CustomField::getInstance()->resolveMultipleCustomfields($foreignRecords);
             }
             if ($fr->has('attachments') && Tinebase_Core::isFilesystemAvailable()) {
                 Tinebase_FileSystem_RecordAttachments::getInstance()->getMultipleAttachmentsOfRecords($foreignRecords);
             }
         }
         if ($foreignRecords->count() > 0) {
             /** @var Tinebase_Record_Interface $record */
             foreach ($_records as $record) {
                 $filtered = $foreignRecords->filter($config['refIdField'], $record->getId())->toArray();
                 $filtered = $this->_resolveAfterToArray($filtered, $foreignRecordModelConfiguration, TRUE);
                 $record->{$fieldKey} = $filtered;
             }
         } else {
             $_records->{$fieldKey} = NULL;
         }
     }
 }
 /**
  * merges source contracts into the target contract (relations and products)
  * 
  * @param Sales_Model_Contract $targetContract
  * @param Tinebase_Record_RecordSet $sourceContracts
  */
 public function mergeContracts(Sales_Model_Contract $targetContract, Tinebase_Record_RecordSet $sourceContracts)
 {
     // handle relations (duplicates get skipped)
     foreach ($sourceContracts as $sourceContract) {
         Tinebase_Relations::getInstance()->transferRelations($sourceContract->getId(), $targetContract->getId(), 'Sales_Model_Contract');
     }
     // handle products
     $filter = new Sales_Model_ProductAggregateFilter(array());
     $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'contract_id', 'operator' => 'in', 'value' => $sourceContracts->getId())));
     $products = Sales_Controller_ProductAggregate::getInstance()->search($filter);
     foreach ($products as $product) {
         $product->contract_id = $targetContract->getId();
         Sales_Controller_ProductAggregate::getInstance()->update($product);
     }
     return true;
 }
 /**
  * set relations for contract
  * 
  * @param array|Sales_Model_Contract $contract
  * @param array $contacts
  * @param string $type
  */
 protected function _setContractRelations($contract, $contacts, $type = 'PARTNER')
 {
     $relationData = array();
     foreach ($contacts as $contact) {
         $relationData[] = array('own_degree' => 'sibling', 'related_degree' => 'sibling', 'related_model' => 'Addressbook_Model_Contact', 'related_backend' => 'Sql', 'related_id' => $contact->getId(), 'type' => $type);
     }
     $contractId = $contract instanceof Sales_Model_Contract ? $contract->getId() : $contract['id'];
     Tinebase_Relations::getInstance()->setRelations('Sales_Model_Contract', 'Sql', $contractId, $relationData);
 }
 /**
  * tests if constraints config is called properly
  * 
  * @see #8840: relations config - constraints from the other side
  *      - validate in backend
  *      
  *      https://forge.tine20.org/mantisbt/view.php?id=8840
  */
 public function testGetConstraintsConfigs()
 {
     $result = Tinebase_Relations::getConstraintsConfigs('Sales_Model_Contract');
     $this->assertEquals(12, count($result));
     foreach ($result as $item) {
         if ($item['ownRecordClassName'] == 'Sales_Model_Contract' && $item['relatedRecordClassName'] == 'Timetracker_Model_Timeaccount') {
             $this->assertEquals('Contract', $item['ownModel']);
             $this->assertEquals('Timeaccount', $item['relatedModel']);
             $this->assertEquals('', $item['defaultType']);
             $this->assertEquals('TIME_ACCOUNT', $item['config'][0]['type']);
             $this->assertSame(0, $item['config'][0]['max']);
         } elseif ($item['ownRecordClassName'] == 'Timetracker_Model_Timeaccount' && $item['relatedRecordClassName'] == 'Sales_Model_Contract') {
             $this->assertEquals('Contract', $item['relatedModel']);
             $this->assertEquals('Timeaccount', $item['ownModel']);
             $this->assertEquals('TIME_ACCOUNT', $item['config'][0]['type']);
             $this->assertEquals(TRUE, $item['reverted']);
             $this->assertSame(1, $item['config'][0]['max']);
         }
     }
 }
 /**
  * returns recipients for a resource notification
  *
  *  users who are allowed to edit a resource, should receive a notification
  *
  * @param  Calendar_Model_Resource $_lead
  * @return array          array of int|Addressbook_Model_Contact
  */
 public function getNotificationRecipients(Calendar_Model_Resource $resource)
 {
     $recipients = array();
     $relations = Tinebase_Relations::getInstance()->getRelations('Calendar_Model_Resource', 'Sql', $resource->getId(), true);
     foreach ($relations as $relation) {
         if ($relation->related_model == 'Addressbook_Model_Contact' && $relation->type == 'RESPONSIBLE') {
             $recipients[] = $relation->related_record;
         }
     }
     if (empty($recipients)) {
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__CLASS__ . '::' . __METHOD__ . '::' . __LINE__ . ' no responsibles found for calendar resource: ' . $resource->getId() . ' sending notification to all people having edit access to container ' . $resource->container_id);
         }
         $containerGrants = Tinebase_Container::getInstance()->getGrantsOfContainer($resource->container_id, TRUE);
         foreach ($containerGrants as $grant) {
             if ($grant['account_type'] == Tinebase_Acl_Rights::ACCOUNT_TYPE_USER && $grant[Tinebase_Model_Grants::GRANT_EDIT] == 1) {
                 try {
                     $recipient = Addressbook_Controller_Contact::getInstance()->getContactByUserId($grant['account_id'], TRUE);
                     $recipients[] = $recipient;
                 } catch (Addressbook_Exception_NotFound $aenf) {
                     if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) {
                         Tinebase_Core::getLogger()->notice(__CLASS__ . '::' . __METHOD__ . '::' . __LINE__ . ' Do not send notification to non-existant user: ' . $aenf->getMessage());
                     }
                 }
             }
         }
     }
     return $recipients;
 }
 /**
  * tests auto invoice creation
  */
 public function testFullAutoInvoice()
 {
     $this->markTestSkipped('0010492: fix failing invoices and timetracker tests');
     $this->_createFullFixtures();
     $this->_createFailingContracts();
     $this->assertEquals(7, $this->_contractRecords->count());
     $date = clone $this->_referenceDate;
     $i = 0;
     // the whole year, 12 months
     while ($i < 12) {
         $result = $this->_invoiceController->createAutoInvoices($date);
         $date->addMonth(1);
         $i++;
     }
     $this->assertEquals(6, count($result['failures']));
     $failures = '';
     foreach ($result['failures'] as $failure) {
         $failures .= $failure;
     }
     $this->assertTrue(strstr($failures, 'no customer') !== FALSE);
     $this->assertTrue(strstr($failures, 'no billing') !== FALSE);
     $this->assertTrue(strstr($failures, 'no costcenter') !== FALSE);
     // also add an hour to get the last end
     $date->addHour(1);
     $this->_invoiceController->createAutoInvoices($date);
     $date->addHour(1);
     $this->_invoiceController->createAutoInvoices($date);
     $all = $this->_invoiceController->getAll();
     $cc1 = $this->_costcenterRecords->filter('remark', 'unittest1')->getFirstRecord();
     $cc2 = $this->_costcenterRecords->filter('remark', 'unittest2')->getFirstRecord();
     $cc3 = $this->_costcenterRecords->filter('remark', 'unittest3')->getFirstRecord();
     $cc4 = $this->_costcenterRecords->filter('remark', 'unittest4')->getFirstRecord();
     $all->setTimezone(Tinebase_Core::getUserTimezone());
     $customer1Invoices = $all->filter('costcenter_id', $cc1->getId())->sort('start_date');
     $customer2Invoices = $all->filter('costcenter_id', $cc2->getId())->sort('start_date');
     $customer3Invoices = $all->filter('costcenter_id', $cc3->getId())->sort('start_date');
     $customer4Invoices = $all->filter('costcenter_id', $cc4->getId())->sort('start_date');
     // customer 1 must have one invoice (timeaccount with budget has been billed the first month)
     $this->assertEquals(1, $customer1Invoices->count(), 'Customer 1 must have 1 invoice!');
     // customer 2 must have one invoice (timeaccount with budget has been billed the first time)
     $this->assertEquals(1, $customer2Invoices->count(), 'Customer 2 must have 1 invoice!');
     // there are timesheets in 2 intervals, so no empty invoice should be generated
     $this->assertEquals(2, $customer3Invoices->count(), 'Customer 3 must have 2 invoices!');
     // there are 2 products, interval 3,6 -> so every quarter in this year and the first of next year must be found
     $this->assertEquals(5, $customer4Invoices->count(), 'Customer 4 must have 5 invoices!');
     // test invoice positions
     $allInvoicePositions = Sales_Controller_InvoicePosition::getInstance()->getAll();
     $this->assertEquals(1, $allInvoicePositions->filter('invoice_id', $customer1Invoices->getFirstRecord()->getId())->count());
     $this->assertEquals(1, $allInvoicePositions->filter('invoice_id', $customer2Invoices->getFirstRecord()->getId())->count());
     // each invoice should contain 1 timeaccount
     foreach ($customer3Invoices as $ci) {
         $this->assertEquals(1, $allInvoicePositions->filter('invoice_id', $ci->getId())->count());
     }
     // we need 9,3,9,3,9 invoice positions
     $i = 1;
     foreach ($customer4Invoices as $ci) {
         $ip = $allInvoicePositions->filter('invoice_id', $ci->getId());
         $this->assertEquals($i % 2 == 1 ? 9 : 3, $ip->count());
         $i++;
     }
     // contract 1 gets billed at the begin of the period
     $c1IArray = $customer1Invoices->start_date;
     $this->assertEquals($this->_referenceYear . '-01-01 00:00:00', $c1IArray[0]->toString());
     $c1IArray = $customer1Invoices->end_date;
     $this->assertEquals($this->_referenceYear . '-01-31 23:59:59', $c1IArray[0]->toString());
     // contract 2 gets billed at the end of the period, and the second period ends at 1.8.20xx
     $c2IsArray = $customer2Invoices->start_date;
     $c2IeArray = $customer2Invoices->end_date;
     $this->assertEquals($this->_referenceYear . '-05-01 00:00:00', $c2IsArray[0]->toString());
     $this->assertEquals($this->_referenceYear . '-05-31 23:59:59', $c2IeArray[0]->toString());
     // test correct timesheet handling of customer 3
     $c3IsArray = $customer3Invoices->start_date;
     $c3IeArray = $customer3Invoices->end_date;
     $this->assertEquals($this->_referenceYear . '-05-01 00:00:00', $c3IsArray[0]->toString());
     $this->assertEquals($this->_referenceYear . '-05-31 23:59:59', $c3IeArray[0]->toString());
     $this->assertEquals($this->_referenceYear . '-09-01 00:00:00', $c3IsArray[1]->toString());
     $this->assertEquals($this->_referenceYear . '-09-30 23:59:59', $c3IeArray[1]->toString());
     // test customer 4 having products only
     $c4IsArray = $customer4Invoices->start_date;
     $c4IeArray = $customer4Invoices->end_date;
     // should contain billeachquarter & billhalfyearly
     $this->assertEquals($this->_referenceYear . '-01-01 00:00:00', $c4IsArray[0]->toString());
     $this->assertEquals($this->_referenceYear . '-06-30 23:59:59', $c4IeArray[0]->toString());
     // should contain billeachquarter
     $this->assertEquals($this->_referenceYear . '-04-01 00:00:00', $c4IsArray[1]->toString());
     $this->assertEquals($this->_referenceYear . '-06-30 23:59:59', $c4IeArray[1]->toString());
     // should contain billeachquarter & billhalfyearly
     $this->assertEquals($this->_referenceYear . '-07-01 00:00:00', $c4IsArray[2]->toString());
     $this->assertEquals($this->_referenceYear . '-12-31 23:59:59', $c4IeArray[2]->toString());
     // should contain billeachquarter
     $this->assertEquals($this->_referenceYear . '-10-01 00:00:00', $c4IsArray[3]->toString());
     $this->assertEquals($this->_referenceYear . '-12-31 23:59:59', $c4IeArray[3]->toString());
     // look if hours of timesheets gets calculated properly
     $c3Invoice = $customer3Invoices->getFirstRecord();
     $filter = new Sales_Model_InvoicePositionFilter(array());
     $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $c3Invoice->getId())));
     $c3InvoicePositions = Sales_Controller_InvoicePosition::getInstance()->search($filter);
     $this->assertEquals(1, $c3InvoicePositions->count());
     $this->assertEquals(3.5, $c3InvoicePositions->getFirstRecord()->quantity);
     $invoice = $customer1Invoices->getFirstRecord();
     $invoice->relations = Tinebase_Relations::getInstance()->getRelations('Sales_Model_Invoice', 'Sql', $invoice->getId())->toArray();
     $filter = new Sales_Model_InvoicePositionFilter(array());
     $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $invoice['id'])));
     $invoice->positions = Sales_Controller_InvoicePosition::getInstance()->search($filter);
     $invoice->cleared = 'CLEARED';
     $invoice = $this->_invoiceController->update($invoice);
     // check correct number generation
     $this->assertEquals("R-00001", $invoice->number);
     $invoice = $customer2Invoices->getFirstRecord();
     $invoice->relations = Tinebase_Relations::getInstance()->getRelations('Sales_Model_Invoice', 'Sql', $invoice->getId())->toArray();
     $filter = new Sales_Model_InvoicePositionFilter(array());
     $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $invoice['id'])));
     $invoice->positions = Sales_Controller_InvoicePosition::getInstance()->search($filter);
     $invoice->cleared = 'CLEARED';
     $invoice = $this->_invoiceController->update($invoice);
     $this->assertEquals("R-00002", $invoice->number);
     // check disallow editing invoice after clearing
     $invoice->credit_term = 20;
     $this->setExpectedException('Sales_Exception_InvoiceAlreadyClearedEdit');
     $this->_invoiceController->update($invoice);
 }
Пример #26
0
 /**
  * create notification message for task alarm
  *
  * @return string
  * 
  * @todo should we get the locale pref for each single user here instead of the default?
  * @todo move lead stuff to Crm(_Model_Lead)?
  * @todo add getSummary to Addressbook_Model_Contact for linked contacts?
  */
 public function getNotificationMessage()
 {
     // get locale from prefs
     $localePref = Tinebase_Core::getPreference()->getValue(Tinebase_Preference::LOCALE);
     $locale = Tinebase_Translation::getLocale($localePref);
     $translate = Tinebase_Translation::getTranslation($this->_application, $locale);
     // get date strings
     $timezone = $this->originator_tz ? $this->originator_tz : Tinebase_Core::get(Tinebase_Core::USERTIMEZONE);
     $dueDateString = Tinebase_Translation::dateToStringInTzAndLocaleFormat($this->due, $timezone, $locale);
     // resolve values
     Tinebase_User::getInstance()->resolveUsers($this, 'organizer', true);
     $status = Tasks_Config::getInstance()->get(Tasks_Config::TASK_STATUS)->records->getById($this->status);
     $organizerName = $this->organizer ? $this->organizer->accountDisplayName : '';
     //if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . print_r($this->toArray(), TRUE));
     $text = $this->summary . "\n\n" . $translate->_('Due') . ': ' . $dueDateString . "\n" . $translate->_('Organizer') . ': ' . $organizerName . "\n" . $translate->_('Description') . ': ' . $this->description . "\n" . $translate->_('Priority') . ': ' . $this->priority . "\n" . $translate->_('Status') . ': ' . $translate->_($status['value']) . "\n" . $translate->_('Percent') . ': ' . $this->percent . "%\n\n";
     // add relations (get with ignore acl)
     $relations = Tinebase_Relations::getInstance()->getRelations(get_class($this), 'Sql', $this->getId(), NULL, array('TASK'), TRUE);
     foreach ($relations as $relation) {
         if ($relation->related_model == 'Crm_Model_Lead') {
             $lead = $relation->related_record;
             $text .= $translate->_('Lead') . ': ' . $lead->lead_name . "\n";
             $leadRelations = Tinebase_Relations::getInstance()->getRelations(get_class($lead), 'Sql', $lead->getId());
             foreach ($leadRelations as $leadRelation) {
                 if ($leadRelation->related_model == 'Addressbook_Model_Contact') {
                     $contact = $leadRelation->related_record;
                     $text .= $leadRelation->type . ': ' . $contact->n_fn . ' (' . $contact->org_name . ')' . "\n" . (!empty($contact->tel_work) ? "\t" . $translate->_('Telephone') . ': ' . $contact->tel_work . "\n" : '') . (!empty($contact->email) ? "\t" . $translate->_('Email') . ': ' . $contact->email . "\n" : '');
                 }
             }
         }
     }
     //if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . $text);
     return $text;
 }
 /**
  * transfer relations
  * 
  * @param Zend_Console_Getopt $opts
  */
 public function transferRelations($opts)
 {
     if (!$this->_checkAdminRight()) {
         return FALSE;
     }
     $this->_addOutputLogWriter();
     try {
         $args = $this->_parseArgs($opts, array('oldId', 'newId', 'model'));
     } catch (Tinebase_Exception_InvalidArgument $e) {
         if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) {
             Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' Parameters "oldId", "newId" and "model" are required!');
         }
         exit(1);
     }
     $skippedEntries = Tinebase_Relations::getInstance()->transferRelations($args['oldId'], $args['newId'], $args['model']);
     if (!empty($skippedEntries) && Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) {
         Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' ' . count($skippedEntries) . ' entries has been skipped:');
     }
     if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
         Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' The operation has been terminated successfully.');
     }
     return 0;
 }
Пример #28
0
 /**
  * returns own ids defined by relation filter
  * 
  * @param string $_modelName
  * @return array
  */
 protected function _getOwnIds($_modelName)
 {
     $relationFilter = new Tinebase_Model_RelationFilter(array(array('field' => 'own_model', 'operator' => 'equals', 'value' => $_modelName), array('field' => 'related_model', 'operator' => 'equals', 'value' => $this->_options['related_model']), array('field' => 'related_id', 'operator' => 'in', 'value' => $this->_foreignIds)));
     if ($this->_relationTypeFilter) {
         $typeValue = $this->_relationTypeFilter['value'];
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . 'Adding Relation type filter: ' . (is_array($typeValue) ? implode(',', $typeValue) : $typeValue));
         }
         $relationFilter->addFilter($relationFilter->createFilter('type', $this->_relationTypeFilter['operator'], $typeValue));
     }
     $ownIds = Tinebase_Relations::getInstance()->search($relationFilter, NULL)->own_id;
     if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
         Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' own ids: ' . print_r($ownIds, TRUE));
     }
     return $ownIds;
 }
 /**
  * transfers all contracts starting with AB- to orderconfirmation
  */
 public function transferContractsToOrderConfirmation()
 {
     if (!Sales_Config::getInstance()->featureEnabled(Sales_Config::FEATURE_ORDERCONFIRMATIONS_MODULE)) {
         Tinebase_Core::getLogger()->crit(__METHOD__ . '::' . __LINE__ . ' transferContractsToOrderConfirmation ran allthoug feature ' . Sales_Config::FEATURE_ORDERCONFIRMATIONS_MODULE . ' is disabled');
         return false;
     }
     $contractController = Sales_Controller_Contract::getInstance();
     $ocController = Sales_Controller_OrderConfirmation::getInstance();
     $rel = Tinebase_Relations::getInstance();
     $filter = new Sales_Model_ContractFilter(array(array('field' => 'number', 'operator' => 'startswith', 'value' => 'AB-')), 'AND');
     $contracts = $contractController->search($filter);
     foreach ($contracts as $contract) {
         $oc = $ocController->create(new Sales_Model_OrderConfirmation(array('number' => $contract->number, 'title' => $contract->title, 'description' => '')));
         $rel->setRelations('Sales_Model_OrderConfirmation', 'Sql', $oc->getId(), array(array('related_degree' => 'sibling', 'related_degree' => 'sibling', 'related_model' => 'Sales_Model_Contract', 'related_backend' => 'Sql', 'related_id' => $contract->getId(), 'type' => 'CONTRACT')));
     }
 }
 public function getRelationsOfRecordByDegree($record, $degree)
 {
     // get relations if not yet present OR use relation search here
     if (empty($record->relations)) {
         $backendType = 'Sql';
         $modelName = get_class($record);
         $record->relations = Tinebase_Relations::getInstance()->getRelations($modelName, $backendType, $record->getId());
     }
     $result = new Tinebase_Record_RecordSet('Tinebase_Model_Relation');
     foreach ($record->relations as $relation) {
         if ($relation->related_degree === $degree) {
             $result->addRecord($relation);
         }
     }
     return $result;
 }