public function checkForRecreation(array $ids, $contract) { //we should delete from recent to old //we should create from old to recent //then compare correctly... if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { $forTrace = $contract->id . ' ' . print_r($ids, true); Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' for: ' . $forTrace); } $this->_autoInvoiceIterationDetailResults = array(); $this->_autoInvoiceIterationResults = array(); $this->_autoInvoiceRecreationResults = array(); $oldInvoices = array(); $oldPositions = array(); $somethingChanged = false; $failed = false; $transactionId = Tinebase_TransactionManager::getInstance()->startTransaction(Tinebase_Core::getDb()); $invoicePositionController = Sales_Controller_InvoicePosition::getInstance(); foreach ($ids as $id) { $invoice = $this->get($id); if (!$invoice) { Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . ' can not ::get invoice with id: ' . $id); continue; } $invoice->setTimezone(Tinebase_Core::getUserTimezone()); $oldInvoices[] = $invoice; $filter = new Sales_Model_InvoicePositionFilter(array()); $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $invoice->getId()))); $oldPositions[$invoice->getId()] = $invoicePositionController->search($filter); try { $this->delete(array($invoice)); } catch (Sales_Exception_DeletePreviousInvoice $sedpi) { $failed = true; Tinebase_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . ' could not delete invoice with id: ' . $id); break; } //is $invoice still valid?!?!? } if (true === $failed) { Tinebase_TransactionManager::getInstance()->rollBack(); return; } // reload relations as they may have changed as we deleted the invoices above // TODO: could be made more efficient as we just need to reload releationsa actually and not the whole contract. $contract = Sales_Controller_Contract::getInstance()->get($contract->getId()); $this->_currentBillingContract = $contract; $this->_currentBillingContract->setTimezone(Tinebase_Core::getUserTimezone()); // the newest invoice! $date = clone $oldInvoices[0]->date; // date seems not to have a tz, so after the clone, the tz is UTC!! we need to reset it $date->setTimezone(Tinebase_Core::getUserTimezone()); $this->_createAutoInvoicesForContract($this->_currentBillingContract, $date); if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' deleted ' . count($oldInvoices) . ' and recreated ' . count($this->_autoInvoiceIterationDetailResults) . ' invoices for: ' . $forTrace); } if (count($oldInvoices) !== count($this->_autoInvoiceIterationDetailResults)) { // something changed for sure. fine, commit => done $somethingChanged = true; } else { // WE NEED TO DIFF POSITIONS TOO! diff on invoice does not do a diff on the positions! // if diff on invoice is negative, then check the positions foreach ($this->_autoInvoiceIterationDetailResults as $newInvoice) { $diff = null; foreach ($oldInvoices as $oldInvoice) { if ($newInvoice->date->equals($oldInvoice->date)) { $diff = $newInvoice->diff($oldInvoice, array('description', 'id', 'relations', 'contract', 'customer', 'created_by', 'creation_time', 'last_modified_by', 'last_modified_time')); //if nothing changed, check the invoice positions if ($diff->isEmpty()) { $filter = new Sales_Model_InvoicePositionFilter(array()); $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => $newInvoice->getId()))); $newPositions = $invoicePositionController->search($filter); $i = 0; foreach ($oldPositions[$invoice->getId()] as $oldPosition) { if ($i + 1 > $newPositions->count()) { $diff = null; break; } $newPosition = $newPositions->getByIndex($i++); $diff = $newPosition->diff($oldPosition, array('id', 'invoice_id')); if (!$diff->isEmpty()) { break; } } } break; } } // null === $diff means that we could not match the new Invoice to the old one, though the count of invoices seems not to have changed if (null === $diff || !$diff->isEmpty()) { if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) { Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' something changed with $diff = ' . (null === $diff ? 'null' : print_r($diff->toArray(), true)) . ' for: ' . $forTrace); } $somethingChanged = true; break; } } } if (true === $somethingChanged) { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' something changed for: ' . $forTrace); } Tinebase_TransactionManager::getInstance()->commitTransaction($transactionId); //create mapping of old to new invoices foreach ($this->_autoInvoiceIterationDetailResults as $newInvoice) { foreach ($oldInvoices as $oldInvoice) { if ($newInvoice->date->equals($oldInvoice->date)) { $this->_autoInvoiceRecreationResults[$oldInvoice->getId()] = $newInvoice->getId(); } } } } else { if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) { Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' nothing changed for: ' . $forTrace); } Tinebase_TransactionManager::getInstance()->rollBack(); } }
/** * 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; }