/** * test timeaccount - sales contract filter * also tests Tinebase_Model_Filter_ExplicitRelatedRecord */ public function testTimeaccountContractFilter() { $this->_getTimeaccount(array('title' => 'TA1', 'number' => 12345, 'description' => 'UnitTest'), true); $ta1 = $this->_timeaccountController->get($this->_lastCreatedRecord['id']); $this->_getTimeaccount(array('title' => 'TA2', 'number' => 12346, 'description' => 'UnitTest'), true); $ta2 = $this->_timeaccountController->get($this->_lastCreatedRecord['id']); $cId = Tinebase_Container::getInstance()->getDefaultContainer('Sales_Model_Contract')->getId(); $contract = Sales_Controller_Contract::getInstance()->create(new Sales_Model_Contract(array('title' => 'testRelateTimeaccount', 'number' => Tinebase_Record_Abstract::generateUID(), 'container_id' => $cId))); $ta1->relations = array($this->_getRelation($contract, $ta1)); $this->_timeaccountController->update($ta1); // search by contract $f = new Timetracker_Model_TimeaccountFilter(array(array('field' => 'contract', 'operator' => 'AND', 'value' => array(array('field' => ':id', 'operator' => 'equals', 'value' => $contract->getId()))))); $filterArray = $f->toArray(); $this->assertEquals($contract->getId(), $filterArray[0]['value'][0]['value']['id']); $result = $this->_timeaccountController->search($f); $this->assertEquals(1, $result->count()); $this->assertEquals('TA1', $result->getFirstRecord()->title); // test empty filter (without contract) $f = new Timetracker_Model_TimeaccountFilter(array(array('field' => 'contract', 'operator' => 'AND', 'value' => array(array('field' => ':id', 'operator' => 'equals', 'value' => null))), array('field' => 'description', 'operator' => 'equals', 'value' => 'UnitTest'))); $result = $this->_timeaccountController->search($f); $this->assertEquals(1, $result->count(), 'Only one record should have been found!'); $this->assertEquals('TA2', $result->getFirstRecord()->title); // test generic relation filter $f = new Timetracker_Model_TimeaccountFilter(array(array('field' => 'foreignRecord', 'operator' => 'AND', 'value' => array('appName' => 'Sales', 'linkType' => 'relation', 'modelName' => 'Contract', 'filters' => array('field' => 'query', 'operator' => 'contains', 'value' => 'TA1'))))); $result = $this->_timeaccountController->search($f); $this->assertEquals(1, $result->count()); $this->assertEquals('TA1', $result->getFirstRecord()->title); // test "not" operator $f = new Timetracker_Model_TimeaccountFilter(array(array('field' => 'contract', 'operator' => 'AND', 'value' => array(array('field' => ':id', 'operator' => 'not', 'value' => $contract->getId()))), array('field' => 'description', 'operator' => 'equals', 'value' => 'UnitTest'))); $result = $this->_timeaccountController->search($f); // TODO is this correct? do we expect the timaccount without contract to be missing from results? $this->assertEquals(0, $result->count(), 'No record should be found'); }
/** * the singleton pattern * * @return Sales_Controller_Contract */ public static function getInstance() { if (self::$_instance === NULL) { self::$_instance = new Sales_Controller_Contract(); } return self::$_instance; }
/** * tests adding and removing of products to a contract */ public function testAddDeleteProducts() { $prodTest = new Sales_ProductControllerTest(); $productOne = $prodTest->testCreateProduct(); $productTwo = $prodTest->testCreateProduct(); $contractData = $this->_getContract(); $contractData->products = array(array('product_id' => $productOne->getId(), 'quantity' => 1, 'interval' => 1, 'billing_point' => 1), array('product_id' => $productTwo->getId(), 'quantity' => 1, 'interval' => 1, 'billing_point' => 1)); $this->_backend->create($contractData); $contract = $this->_backend->get($contractData->getId()); // checks $this->assertEquals($contractData->getId(), $contract->getId()); $this->assertGreaterThan(0, $contract->number); $this->assertEquals(Tinebase_Core::getUser()->getId(), $contract->created_by); // check count of product aggregates $filter = new Sales_Model_ProductAggregateFilter(array()); $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'contract_id', 'operator' => 'equals', 'value' => $contract->getId()))); $productAggregates = Sales_Controller_ProductAggregate::getInstance()->search($filter); $this->assertEquals(2, count($productAggregates)); $contractData->products = array(array('product_id' => $productOne->getId(), 'quantity' => 1, 'interval' => 1, 'billing_point' => 1)); $this->_backend->update($contractData); $contract = $this->_backend->get($contractData->getId()); // check count of product aggregates $filter = new Sales_Model_ProductAggregateFilter(array()); $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'contract_id', 'operator' => 'equals', 'value' => $contract->getId()))); $productAggregates = Sales_Controller_ProductAggregate::getInstance()->search($filter); $this->assertEquals(1, count($productAggregates)); // cleanup $this->_backend->delete($contract->getId()); $this->_decreaseNumber(); $prodTest->getUit()->delete(array($productOne->getId(), $productTwo->getId())); }
/** * Sets up the fixture. * This method is called before a test is executed. * * @access protected */ protected function setUp() { Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb()); $this->_contactController = Addressbook_Controller_Contact::getInstance(); $this->_contractController = Sales_Controller_Contract::getInstance(); $this->_json = new Sales_Frontend_Json(); }
/** * Sets up the fixture. * This method is called before a test is executed. * * @access protected */ protected function setUp() { $this->_transactionId = Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb()); $this->_instance = Tinebase_CustomField::getInstance(); Sales_Controller_Contract::getInstance()->setNumberPrefix(); Sales_Controller_Contract::getInstance()->setNumberZerofill(); }
/** * Sets up the fixture. * This method is called before a test is executed. * * @access protected */ protected function setUp() { Tinebase_Acl_Roles::getInstance()->resetClassCache(); Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb()); $this->_json = new Timetracker_Frontend_Json(); Sales_Controller_Contract::getInstance()->setNumberPrefix(); Sales_Controller_Contract::getInstance()->setNumberZerofill(); }
/** * create new contract * */ public function testCreateContract() { $contract = $this->_getContract(); $created = $this->_backend->create($contract); $this->assertEquals($created->title, $contract->title); $this->assertGreaterThan(0, $created->number); $this->assertEquals($created->container_id, Sales_Controller_Contract::getSharedContractsContainer()->getId()); $this->_backend->delete($contract); $this->_decreaseNumber(); }
/** * get contract * * @return Sales_Model_Contract */ protected function _getContract() { $contract = new Sales_Model_Contract(array('title' => 'phpunit contract', 'description' => 'blabla'), TRUE); // add container $contract->container_id = Sales_Controller_Contract::getSharedContractsContainer(); // add number $numberBackend = new Sales_Backend_Number(); $number = $numberBackend->getNext('Sales_Model_Contract', Tinebase_Core::getUser()->getId()); $contract->number = $number->number; return $contract; }
/** * try to get a contract * */ public function testGetContract() { $contractData = $this->_getContract(); $this->_backend->create($contractData); $contract = $this->_backend->get($contractData->getId()); // checks $this->assertEquals($contractData->getId(), $contract->getId()); $this->assertGreaterThan(0, $contract->number); $this->assertEquals(Tinebase_Core::getUser()->getId(), $contract->created_by); // cleanup $this->_backend->delete($contract->getId()); $this->_decreaseNumber(); }
/** * testTransfer * * @see 0009210: Allow to change relations * https://forge.tine20.org/mantisbt/view.php?id=9210 */ public function testTransfer() { $sclever = Addressbook_Controller_Contact::getInstance()->get($this->_personas['sclever']->contact_id, null, false); $pwulf = Addressbook_Controller_Contact::getInstance()->get($this->_personas['pwulf']->contact_id, null, false); $container = Tinebase_Container::getInstance()->create(new Tinebase_Model_Container(array('application_id' => Tinebase_Application::getInstance()->getApplicationByName('Sales')->getId(), 'type' => Tinebase_Model_Container::TYPE_SHARED, 'backend' => 'sql', 'name' => 'testsdf'))); $contract = new Sales_Model_Contract(array('number' => '23547', 'title' => 'test', 'container_id' => $container->getId())); $contract = Sales_Controller_Contract::getInstance()->create($contract); $contract2 = new Sales_Model_Contract(array('number' => '23347', 'title' => 'test', 'container_id' => $container->getId())); $contract2 = Sales_Controller_Contract::getInstance()->create($contract2); $json = new Sales_Frontend_Json(); $contractJson = $contract->toArray(); $contractJson['relations'][] = array('own_degree' => Tinebase_Model_Relation::DEGREE_SIBLING, 'related_model' => 'Addressbook_Model_Contact', 'related_record' => $sclever->toArray(), 'type' => 'CUSTOMER'); $contractJson = $json->saveContract($contractJson); $contract2Json = $contract2->toArray(); $contract2Json['relations'][] = array('own_degree' => Tinebase_Model_Relation::DEGREE_SIBLING, 'related_model' => 'Addressbook_Model_Contact', 'related_record' => $sclever->toArray(), 'type' => 'PARTNER'); $contract2Json['relations'][] = array('own_degree' => Tinebase_Model_Relation::DEGREE_SIBLING, 'related_model' => 'Addressbook_Model_Contact', 'related_record' => $pwulf->toArray(), 'type' => 'PARTNER'); $contract2Json = $json->saveContract($contract2Json); $this->assertEquals($sclever->getId(), $contractJson['relations'][0]['related_id']); $skipped = Tinebase_Relations::getInstance()->transferRelations($sclever->getId(), $pwulf->getId(), 'Addressbook_Model_Contact'); $this->assertEquals(1, count($skipped)); $skipped = array_pop($skipped); $this->assertEquals($sclever->getId(), $skipped['own_id']); $contractJson = $json->getContract($contract->getId()); $this->assertEquals($pwulf->getId(), $contractJson['relations'][0]['related_id']); $this->setExpectedException('Tinebase_Exception_NotFound'); Tinebase_Relations::getInstance()->transferRelations($sclever->getId(), $pwulf->getId(), 'Addressbook_Model_Contract'); }
/** * creates some order confirmations */ protected function _createSharedOrderconfirmations() { $i = 1; $this->_setReferenceDate(); $contracts = Sales_Controller_Contract::getInstance()->getAll('number'); // create for each contract a order confirmation foreach ($contracts as $contract) { $relations = array(array('own_model' => 'Sales_Model_OrderConfirmation', 'own_backend' => Tasks_Backend_Factory::SQL, 'own_id' => NULL, 'own_degree' => Tinebase_Model_Relation::DEGREE_SIBLING, 'related_model' => 'Sales_Model_Contract', 'related_backend' => Tasks_Backend_Factory::SQL, 'related_id' => $contract->getId(), 'type' => 'CONTRACT')); $oc = Sales_Controller_OrderConfirmation::getInstance()->create(new Sales_Model_OrderConfirmation(array('number' => $i, 'title' => self::$_de ? 'Auftragsbestätigung für Vertrag ' . $contract->title : 'Order Confirmation for Contract' . $contract->title, 'description' => 'Created by Tine 2.0 DemoData', 'relations' => $relations))); $i++; } }
/** * 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; }
/** * inspects delete action * * @param array $_ids * @return array of ids to actually delete */ protected function _inspectDelete(array $_ids) { $cc = Sales_Controller_Contract::getInstance(); $filter = new Sales_Model_ContractFilter(array()); $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'billing_address_id', 'operator' => 'in', 'value' => $_ids))); $contracts = $cc->search($filter); if ($contracts->count()) { $e = new Sales_Exception_DeleteUsedBillingAddress(); $e->setContracts($contracts); throw $e; } return $_ids; }
/** * @see https://forge.tine20.org/mantisbt/view.php?id=8840 */ public function testRelationConstraintsOtherSide() { $contract = Sales_Controller_Contract::getInstance()->create($this->_getContract()); list($contact1, $contact2, $contact3, $contact4) = $this->_createContacts(4); $this->_setContractRelations($contract, array($contact1), 'RESPONSIBLE'); Addressbook_Controller_Contact::getInstance()->update($contact1); $contact1 = Addressbook_Controller_Contact::getInstance()->get($contact1->getId(), NULL, TRUE); $this->assertEquals(1, count($contact1->relations)); // a partner may be added $relation = new Tinebase_Model_Relation(array('own_degree' => 'sibling', 'own_model' => 'Addressbook_Model_Contact', 'own_backend' => 'Sql', 'own_id' => $contact2->getId(), 'related_degree' => 'sibling', 'related_model' => 'Sales_Model_Contract', 'related_backend' => 'Sql', 'related_id' => $contract->getId(), 'type' => 'PARTNER')); $contact2->relations = array($relation); $contact2 = Addressbook_Controller_Contact::getInstance()->update($contact2); $contact2 = Addressbook_Controller_Contact::getInstance()->get($contact2->getId(), NULL, TRUE); $this->assertEquals(1, count($contact2->relations)); // a second partner may be added also $relation = new Tinebase_Model_Relation(array('own_degree' => 'sibling', 'own_model' => 'Addressbook_Model_Contact', 'own_backend' => 'Sql', 'own_id' => $contact3->getId(), 'related_degree' => 'sibling', 'related_model' => 'Sales_Model_Contract', 'related_backend' => 'Sql', 'related_id' => $contract->getId(), 'type' => 'PARTNER')); $contact3->relations = array($relation); Addressbook_Controller_Contact::getInstance()->update($contact3); $contact3 = Addressbook_Controller_Contact::getInstance()->get($contact3->getId(), NULL, TRUE); $this->assertEquals(1, count($contact3->relations)); $contract = Sales_Controller_Contract::getInstance()->get($contract->getId(), NULL, TRUE); $this->assertEquals(3, count($contract->relations)); // but a second responsible must not be added $relation = new Tinebase_Model_Relation(array('own_degree' => 'sibling', 'own_model' => 'Addressbook_Model_Contact', 'own_backend' => 'Sql', 'own_id' => $contact4->getId(), 'related_degree' => 'sibling', 'related_model' => 'Sales_Model_Contract', 'related_backend' => 'Sql', 'related_id' => $contract->getId(), 'type' => 'RESPONSIBLE')); $contact4->relations = array($relation); $this->setExpectedException('Tinebase_Exception_InvalidRelationConstraints'); $contact4 = Addressbook_Controller_Contact::getInstance()->update($contact4); }
/** * test searching records by record as a customfield type * https://forge.tine20.org/mantisbt/view.php?id=6730 */ public function testSearchByRecord() { $cf = self::getCustomField(array('application_id' => Tinebase_Application::getInstance()->getApplicationByName('Addressbook')->getId(), 'model' => 'Addressbook_Model_Contact', 'definition' => array('type' => 'record', "recordConfig" => array("value" => array("records" => "Tine.Sales.Model.Contract"))))); $this->_instance->addCustomField($cf); $contract = Sales_Controller_Contract::getInstance()->create(new Sales_Model_Contract(array('number' => Tinebase_Record_Abstract::generateUID(10), 'title' => Tinebase_Record_Abstract::generateUID(10), 'container_id' => Tinebase_Container::getInstance()->getDefaultContainer('Sales_Model_Contract')->getId()))); // contact1 with customfield record = contract $contact1 = new Addressbook_Model_Contact(array('n_given' => 'Rita', 'n_family' => 'Blütenrein')); $contact1->customfields = array($cf->name => $contract->getId()); $contact1 = Addressbook_Controller_Contact::getInstance()->create($contact1, false); // contact2 with customfield record is not set -> should act like without this record $contact2 = new Addressbook_Model_Contact(array('n_given' => 'Rainer', 'n_family' => 'Blütenrein')); $contact2 = Addressbook_Controller_Contact::getInstance()->create($contact2, false); $json = new Addressbook_Frontend_Json(); $result = $json->searchContacts(array(array("condition" => "OR", "filters" => array(array("condition" => "AND", "filters" => array(array("field" => "customfield", "operator" => "equals", "value" => array("cfId" => $cf->getId(), "value" => $contract->getId()))))))), array()); $this->assertEquals(1, $result['totalcount'], 'One Record should have been found where cf-record = contract (Rita Blütenrein)'); $this->assertEquals('Rita', $result['results'][0]['n_given'], 'The Record should be Rita Blütenrein'); $result = $json->searchContacts(array(array("condition" => "OR", "filters" => array(array("condition" => "AND", "filters" => array(array("field" => "customfield", "operator" => "not", "value" => array("cfId" => $cf->getId(), "value" => $contract->getId())), array('field' => 'n_family', 'operator' => 'equals', 'value' => 'Blütenrein')))))), array()); $this->assertEquals(1, $result['totalcount'], 'One Record should have been found where cf-record is not set (Rainer Blütenrein)'); $this->assertEquals('Rainer', $result['results'][0]['n_given'], 'The Record should be Rainer Blütenrein'); // search using the same cf filter in an or - filter $contract2 = Sales_Controller_Contract::getInstance()->create(new Sales_Model_Contract(array('number' => Tinebase_Record_Abstract::generateUID(10), 'title' => Tinebase_Record_Abstract::generateUID(10), 'container_id' => Tinebase_Container::getInstance()->getDefaultContainer('Sales_Model_Contract')->getId()))); $contact2->customfields = array($cf->name => $contract2->getId()); $contact2 = Addressbook_Controller_Contact::getInstance()->update($contact2, false); $result = $json->searchContacts(array(array("condition" => "OR", "filters" => array(array("condition" => "AND", "filters" => array(array("field" => "customfield", "operator" => "equals", "value" => array("cfId" => $cf->getId(), "value" => $contract->getId())))), array("condition" => "AND", "filters" => array(array("field" => "customfield", "operator" => "equals", "value" => array("cfId" => $cf->getId(), "value" => $contract2->getId()))))))), array()); $this->assertEquals(2, $result['totalcount'], 'Rainer and Rita should have been found.'); $this->assertEquals('Blütenrein', $result['results'][0]['n_family'], 'Rainer and Rita should have been found.'); $this->assertEquals('Blütenrein', $result['results'][1]['n_family'], 'Rainer and Rita should have been found.'); }
protected function _transferBillingInformation() { $adminGroup = Tinebase_Group::getInstance()->getDefaultAdminGroup(); $groupMembers = Tinebase_Group::getInstance()->getGroupMembers($adminGroup->getId()); if (count($groupMembers) > 0) { $user = Tinebase_User::getInstance()->getUserById($groupMembers[0]); Tinebase_Core::set(Tinebase_Core::USER, $user); Sales_Controller_Contract::getInstance()->transferBillingInformation(); } }
/** * 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; }
/** * @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); }
/** * sets start date and last_auobill by existing invoice positions / normalizes last_autobill */ public function updateLastAutobillOfProductAggregates() { Sales_Controller_Contract::getInstance()->updateLastAutobillOfProductAggregates(); }
/** * @see 0011494: activate advanced search for contracts (customers, ...) */ public function testAdvancedContractsSearch() { Tinebase_Core::getPreference()->setValue(Tinebase_Preference::ADVANCED_SEARCH, true); $contract = Sales_Controller_Contract::getInstance()->create($this->_getContract()); list($contact1) = $this->_createContacts(1); $this->_setContractRelations($contract, array($contact1), 'RESPONSIBLE'); $result = $this->_instance->searchContracts($this->_getFilter('wolf'), array()); $this->assertEquals(1, $result['totalcount'], 'should find contract of customer person Peter Wolf'); // test notcontains $contract2 = Sales_Controller_Contract::getInstance()->create($this->_getContract('test2')); $result = $this->_instance->searchContracts($this->_getFilter(), array()); $this->assertEquals(2, $result['totalcount'], 'should find 2 contracts'); // search with notcontains $search = $this->_instance->searchContracts(array(array('field' => 'query', 'operator' => 'notcontains', 'value' => 'wolf')), $this->_getPaging()); $this->assertEquals($contract2->title, $search['results'][0]['title']); $this->assertEquals(1, $search['totalcount']); }
/** * creates/updates a record * * @param array $recordData * @param boolean $duplicateCheck * * @return array created/updated record */ public function saveInvoice($recordData, $duplicateCheck = TRUE) { // validate customer $foundCustomer = FALSE; $customerCalculated = FALSE; if (is_array($recordData['relations'])) { foreach ($recordData['relations'] as $relation) { if ($relation['related_model'] == 'Sales_Model_Customer') { $foundCustomer = $relation['related_record']; break; } } } // if no customer is set, try to find by contract if (is_array($recordData['relations']) && !$foundCustomer) { foreach ($recordData['relations'] as $relation) { if ($relation['related_model'] == 'Sales_Model_Contract') { $foundContractRecord = Sales_Controller_Contract::getInstance()->get($relation['related_record']['id']); foreach ($foundContractRecord->relations as $relation) { if ($relation['related_model'] == 'Sales_Model_Customer') { $foundCustomer = $relation['related_record']; $customerCalculated = TRUE; break 2; } } } } } if ($customerCalculated) { $recordData['relations'] = array_merge($recordData['relations'], array(array("own_model" => "Sales_Model_Invoice", "own_backend" => Tasks_Backend_Factory::SQL, 'own_degree' => Tinebase_Model_Relation::DEGREE_SIBLING, 'related_model' => 'Sales_Model_Customer', 'related_backend' => Tasks_Backend_Factory::SQL, 'related_id' => $foundCustomer['id'], 'related_record' => $foundCustomer, 'type' => 'CUSTOMER'))); } if (!$foundCustomer) { throw new Tinebase_Exception_Data('You have to set a customer!'); } if (is_array($recordData["address_id"])) { $recordData["address_id"] = $recordData["address_id"]['id']; } if (is_array($recordData["costcenter_id"])) { $recordData["costcenter_id"] = $recordData["costcenter_id"]['id']; } // sanitize product_id if (isset($recordData['positions']) && is_array($recordData['positions'])) { for ($i = 0; $i < count($recordData['positions']); $i++) { if (isset($recordData['positions'][$i]['product_id']) && is_array($recordData['positions'][$i]['product_id'])) { $recordData['positions'][$i]['product_id'] = $recordData['positions'][$i]['product_id']['id']; } } } if (is_array($recordData['relations'])) { for ($i = 0; $i < count($recordData['relations']); $i++) { if (isset($recordData['relations'][$i]['related_record']['product_id'])) { if (is_array($recordData['relations'][$i]['related_record']['product_id'])) { $recordData['relations'][$i]['related_record']['product_id'] = $recordData['relations'][$i]['related_record']['product_id']['id']; } } elseif ($recordData['relations'][$i]['related_model'] == 'Sales_Model_Invoice') { if (is_array($recordData['relations'][$i]['related_record']['address_id'])) { $recordData['relations'][$i]['related_record']['address_id'] = $recordData['relations'][$i]['related_record']['address_id']['id']; } } } } return $this->_save($recordData, Sales_Controller_Invoice::getInstance(), 'Invoice', 'id', array($duplicateCheck)); }
/** * sets start date and last_auobill by existing invoice positions / normalizes last_autobill */ public function updateLastAutobillOfProductAggregates() { if (!Sales_Config::getInstance()->featureEnabled(Sales_Config::FEATURE_INVOICES_MODULE)) { Tinebase_Core::getLogger()->crit(__METHOD__ . '::' . __LINE__ . ' updateLastAutobillOfProductAggregates ran allthoug feature ' . Sales_Config::FEATURE_INVOICES_MODULE . ' is disabled'); return false; } Sales_Controller_Contract::getInstance()->updateLastAutobillOfProductAggregates(); }
/** * @see Tinebase_Setup_DemoData_Abstract * */ protected function _beforeCreate() { $this->_ccController = Sales_Controller_CostCenter::getInstance(); $this->_taController = Timetracker_Controller_Timeaccount::getInstance(); $this->_taController->sendNotifications(FALSE); $this->_tsController = Timetracker_Controller_Timesheet::getInstance(); $this->_tsController->sendNotifications(FALSE); $this->_tsController->doContainerACLChecks(false); $this->_contractController = Sales_Controller_Contract::getInstance(); $contracts = $this->_contractController->getAll(); $developmentString = self::$_de ? 'Entwicklung' : 'Development'; $this->_contractsDevelopment = $contracts->filter('title', '/.' . $developmentString . '/', TRUE); $this->_contractsMarketing = $contracts->filter('title', '/.Marketing/', TRUE); $this->_loadCostCentersAndDivisions(); if (Tinebase_Application::getInstance()->isInstalled('HumanResources')) { $this->_empController = HumanResources_Controller_Employee::getInstance(); $filter = new HumanResources_Model_EmployeeFilter(array()); $this->_employees = $this->_empController->search($filter); } // set start date to start date of june 1st before last year $date = Tinebase_DateTime::now(); $this->_startDate = $date->subMonth(3)->setTime(8, 0, 0); // set clearedDate almost a month after $this->_clearedDate = clone $this->_startDate; $this->_clearedDate->addMonth(1)->subDay(2); }
/** * updates last autobill of product aggregates * * @param boolen $update */ public function updateLastAutobillOfProductAggregates() { $filter = new Sales_Model_ContractFilter(array()); $iterator = new Tinebase_Record_Iterator(array('iteratable' => $this, 'controller' => Sales_Controller_Contract::getInstance(), 'filter' => $filter, 'options' => array('getRelations' => TRUE, 'limit' => 20), 'function' => 'processUpdateLastAutobillOfProductAggregates')); $iterator->iterate(); }
protected function _createInvoiceUpdateRecreationFixtures($createTimesheet = true) { $this->_createFullFixtures(); // we dont want this contract 1 to be part of the runs below, move it out of the way $this->_contractRecords->getByIndex(0)->start_date->addMonth(12); Sales_Controller_Contract::getInstance()->update($this->_contractRecords->getByIndex(0)); $date = clone $this->_referenceDate; $customer4Timeaccount = $this->_timeaccountRecords->filter('title', 'TA-for-Customer4')->getFirstRecord(); $customer4Timeaccount->status = 'to bill'; $customer4Timeaccount->budget = NULL; if (null === $this->_timesheetController) { $this->_timesheetController = Timetracker_Controller_Timesheet::getInstance(); } if (null === $this->_timeaccountController) { $this->_timeaccountController = Timetracker_Controller_Timeaccount::getInstance(); } $this->_timeaccountController->update($customer4Timeaccount); // this is a ts on 20xx-03-18 $this->sharedTimesheet = new Timetracker_Model_Timesheet(array('account_id' => Tinebase_Core::getUser()->getId(), 'timeaccount_id' => $customer4Timeaccount->getId(), 'start_date' => $date->addMonth(2)->addDay(17), 'duration' => 120, 'description' => 'ts from ' . (string) $date)); if (true === $createTimesheet) { $this->_timesheetController->create($this->sharedTimesheet); } //run autoinvoicing with 20xx-04-01 $date = clone $this->_referenceDate; $date->addMonth(3); $result = $this->_invoiceController->createAutoInvoices($date); $this->assertEquals(2, count($result['created'])); return $result; }
/** * create contracts, auto add timeaccounts if there are any * * @param array $contractData * @return Tinebase_Record_RecordSet */ protected function _createContracts($contractData = NULL) { // 1.1.20xx $startDate = clone $this->_referenceDate; $endDate = clone $startDate; // 1.8.20xx $endDate->addMonth(7); $this->_contractController = Sales_Controller_Contract::getInstance(); $container = $this->_contractController->getSharedContractsContainer(); $this->_sharedContractsContainerId = $container->getId(); if (!$contractData) { if (!$this->_costcenterRecords) { $this->_createCostCenters(); } if (!$this->_productRecords) { $this->_createProducts(); } if (!$this->_customerRecords) { $this->_createCustomers(); } if (!$this->_timesheetRecords) { $this->_createTimesheets(); } $contractData = array(array('number' => 1, 'title' => Tinebase_Record_Abstract::generateUID(), 'description' => '1 unittest begin', 'container_id' => $this->_sharedContractsContainerId, 'billing_address_id' => $this->_addressRecords->filter('customer_id', $this->_customerRecords->filter('name', 'Customer1')->getFirstRecord()->getId())->filter('type', 'billing')->getFirstRecord()->getId(), 'start_date' => clone $startDate, 'end_date' => NULL, 'products' => array(array('start_date' => $startDate, 'end_date' => NULL, 'quantity' => 1, 'interval' => 1, 'billing_point' => 'begin', 'product_id' => $this->_productRecords->filter('name', 'Hours')->getFirstRecord()->getId()))), array('number' => 2, 'title' => Tinebase_Record_Abstract::generateUID(), 'description' => '2 unittest end', 'container_id' => $this->_sharedContractsContainerId, 'billing_address_id' => $this->_addressRecords->filter('customer_id', $this->_customerRecords->filter('name', 'Customer2')->getFirstRecord()->getId())->filter('type', 'billing')->getFirstRecord()->getId(), 'start_date' => clone $startDate, 'end_date' => clone $endDate, 'products' => array(array('start_date' => clone $startDate, 'end_date' => clone $endDate, 'quantity' => 1, 'interval' => 4, 'billing_point' => 'end', 'product_id' => $this->_productRecords->filter('name', 'Hours')->getFirstRecord()->getId()))), array('number' => 3, 'title' => Tinebase_Record_Abstract::generateUID(), 'description' => '3 unittest end', 'container_id' => $this->_sharedContractsContainerId, 'billing_address_id' => $this->_addressRecords->filter('customer_id', $this->_customerRecords->filter('name', 'Customer3')->getFirstRecord()->getId())->filter('type', 'billing')->getFirstRecord()->getId(), 'start_date' => clone $startDate, 'end_date' => NULL, 'products' => array(array('start_date' => clone $startDate, 'end_date' => NULL, 'quantity' => 1, 'interval' => 3, 'billing_point' => 'end', 'product_id' => $this->_productRecords->filter('name', 'Hours')->getFirstRecord()->getId()))), array('number' => 4, 'title' => Tinebase_Record_Abstract::generateUID(), 'description' => '4 unittest products', 'container_id' => $this->_sharedContractsContainerId, 'billing_address_id' => $this->_addressRecords->filter('customer_id', $this->_customerRecords->filter('name', 'Customer4')->getFirstRecord()->getId())->filter('type', 'billing')->getFirstRecord()->getId(), 'start_date' => clone $startDate, 'end_date' => NULL, 'products' => array(array('start_date' => clone $startDate, 'end_date' => NULL, 'quantity' => 1, 'interval' => 6, 'billing_point' => 'begin', 'product_id' => $this->_productRecords->filter('name', 'billhalfyearly')->getFirstRecord()->getId()), array('start_date' => clone $startDate, 'end_date' => NULL, 'quantity' => 1, 'interval' => 3, 'billing_point' => 'begin', 'product_id' => $this->_productRecords->filter('name', 'billeachquarter')->getFirstRecord()->getId())))); } $this->_contractRecords = new Tinebase_Record_RecordSet('Sales_Model_Contract'); $i = 0; foreach ($contractData as $cd) { $costcenter = $this->_costcenterRecords->getByIndex($i); $customer = $this->_customerRecords->getByIndex($i); if ($this->_timeaccountRecords) { $timeaccount = $this->_timeaccountRecords->getByIndex($i); } $i++; $contract = new Sales_Model_Contract($cd); $contract->setTimezone('UTC'); $contract->relations = array(array('own_model' => 'Sales_Model_Contract', 'own_backend' => Tasks_Backend_Factory::SQL, 'own_id' => NULL, 'related_degree' => Tinebase_Model_Relation::DEGREE_SIBLING, 'related_model' => 'Sales_Model_CostCenter', 'related_backend' => Tasks_Backend_Factory::SQL, 'related_id' => $costcenter->getId(), 'type' => 'LEAD_COST_CENTER'), array('own_model' => 'Sales_Model_Contract', 'own_backend' => Tasks_Backend_Factory::SQL, 'own_id' => NULL, 'related_degree' => Tinebase_Model_Relation::DEGREE_SIBLING, 'related_model' => 'Sales_Model_Customer', 'related_backend' => Tasks_Backend_Factory::SQL, 'related_id' => $customer->getId(), 'type' => 'CUSTOMER')); if ($this->_timeaccountRecords) { $contract->relations = array_merge($contract->relations, array(array('own_model' => 'Sales_Model_Contract', 'own_backend' => Tasks_Backend_Factory::SQL, 'own_id' => NULL, 'related_degree' => Tinebase_Model_Relation::DEGREE_SIBLING, 'related_model' => 'Timetracker_Model_Timeaccount', 'related_backend' => Tasks_Backend_Factory::SQL, 'related_id' => $timeaccount->getId(), 'type' => 'TIME_ACCOUNT'))); } $this->_contractRecords->addRecord($this->_contractController->create($contract)); } return $this->_contractRecords; }
/** * tests if nested transactions will be rolled back, if the outer fails */ public function testNestedTransactions() { $c1 = Sales_Controller_Contract::getInstance(); $c2 = Sales_Controller_CostCenter::getInstance(); $tm = Tinebase_TransactionManager::getInstance(); $tm->startTransaction(Tinebase_Core::getDb()); try { // create cost center $costCenter = $c2->create(new Sales_Model_CostCenter(array('number' => 123, 'remark' => 'unittest123'))); // exception should be thrown (title needed) $c1->create(new Sales_Model_Contract(array())); } catch (Exception $e) { $tm->rollBack(); } $this->setExpectedException('Tinebase_Exception_NotFound'); // try to get the created cost center $c2->get($costCenter->getId()); }
/** * here we search for all timeaccounts, which are related to an contract with a special * internal contact assigned * * @see: 0009752: create contract - internal/external contact person filter */ public function testTimeaccountContractInternalContactFilter() { $this->markTestSkipped('0010492: fix failing invoices and timetracker tests'); $this->_getTimeaccount(array('title' => 'to find'), true); $taController = Timetracker_Controller_Timeaccount::getInstance(); $taToFind = $taController->get($this->_lastCreatedRecord['id']); $this->_getTimeaccount(array('title' => 'not to find'), true); $contact = Addressbook_Controller_Contact::getInstance()->create(new Addressbook_Model_Contact(array('n_family' => 'Green'))); $contractController = Sales_Controller_Contract::getInstance(); $contract = new Sales_Model_Contract(array('title' => 'xtestunit', 'description' => 'nothing')); $contract = $contractController->create($contract); $contract->relations = array(new Tinebase_Model_Relation(array('own_backend' => 'Sql', 'own_id' => $contract->getId(), 'own_model' => 'Sales_Model_Contract', 'own_degree' => 'sibling', 'remark' => 'PHP UNITTEST', 'related_model' => 'Addressbook_Model_Contact', 'related_backend' => 'Sql', 'related_id' => $contact->getId(), 'type' => 'RESPONSIBLE'))); $contract = $contractController->update($contract); $taToFind->relations = array(new Tinebase_Model_Relation(array('own_backend' => 'Sql', 'own_degree' => 'sibling', 'own_id' => $taToFind->getId(), 'own_model' => 'Timetracker_Model_Timeaccount', 'remark' => 'PHP UNITTEST', 'related_model' => 'Sales_Model_Contract', 'related_backend' => 'Sql', 'related_id' => $contract->getId(), 'type' => 'CONTRACT'))); $taToFind = $taController->update($taToFind); // build request with direct id $req = Zend_Json::decode('{"params":{"filter":[{"condition":"OR","filters":[{"condition":"AND","filters": [{"field":"contract","operator":"AND","value":[{"field":"contact_external","operator":"AND","value": [{"field":":id","operator":"equals","value":"' . $contact->getId() . '"}],"id":"ext-record-266"}, {"field":":id","operator":"AND"}],"id":"ext-record-181"}],"id":"ext-comp-1350","label":"Zeitkonten"}]}], "paging":{"sort":"creation_time","dir":"DESC","start":0,"limit":50}}}'); $filter = $req['params']['filter']; $paging = $req['params']['paging']; $result = $this->_json->searchTimeaccounts($filter, $paging); $this->assertEquals(1, $result['totalcount']); $this->assertEquals($taToFind->getId(), $result['results'][0]['id']); // build request with query=Green $req = Zend_Json::decode('{"jsonrpc":"2.0","method":"Timetracker.searchTimeaccounts","params":{"filter":[{"condition":"OR","filters":[{"condition":"AND","filters":[{"field":"contract","operator":"AND","value":[{"field":"foreignRecord","operator":"AND","value":{"appName":"Addressbook","modelName":"Contact","linkType":"relation","filters":[{"field":"query","operator":"contains","value":"Green","id":"ext-record-546"}]},"id":"ext-record-480"},{"field":":id","operator":"AND"}],"id":"ext-record-181"}],"id":"ext-comp-1350","label":"Zeitkonten"}]}],"paging":{"sort":"creation_time","dir":"DESC","start":0,"limit":50}},"id":62}'); $filter = $req['params']['filter']; $paging = $req['params']['paging']; $result = $this->_json->searchTimeaccounts($filter, $paging); $this->assertEquals(1, $result['totalcount']); $this->assertEquals($taToFind->getId(), $result['results'][0]['id']); }
/** * create tine contract * * @param array $_data with egw project data * @return Sales_Model_Contract * * @todo add more fields? */ protected function _createContract($_data) { $contract = new Sales_Model_Contract(array('title' => $_data['pm_title'], 'description' => $this->_convertDescription($_data['pm_description'])), TRUE); $this->_counters['contracts']++; return Sales_Controller_Contract::getInstance()->create($contract); }
/** * Returns registry data of the application. * * Each application has its own registry to supply static data to the client. * Registry data is queried only once per session from the client. * * This registry must not be used for rights or ACL purposes. Use the generic * rights and ACL mechanisms instead! * * @return mixed array 'variable name' => 'data' */ public function getRegistryData() { $sharedContainer = Sales_Controller_Contract::getSharedContractsContainer(); $sharedContainer->resolveGrantsAndPath(); return array('defaultContainer' => $sharedContainer->toArray()); }