/**
  * Sets up the fixture.
  * This method is called before a test is executed.
  *
  * @access protected
  */
 protected function setUp()
 {
     Sales_Config::getInstance()->set(Sales_Config::CONTRACT_NUMBER_VALIDATION, 'text');
     $this->_backend = Sales_Controller_Contract::getInstance();
     $this->_backend->setNumberPrefix();
     $this->_backend->setNumberZerofill();
 }
 /**
  * Sets up the fixture.
  * This method is called before a test is executed.
  *
  * @access protected
  */
 protected function setUp()
 {
     if ($this->_dbIsPgsql() || !Sales_Config::getInstance()->featureEnabled(Sales_Config::FEATURE_INVOICES_MODULE)) {
         $this->markTestSkipped('0011670: fix Sales_Invoices Tests with postgresql backend');
     }
     parent::setUp();
 }
 /**
  * the constructor
  */
 public function __construct()
 {
     if (Sales_Config::getInstance()->featureEnabled(Sales_Config::FEATURE_INVOICES_MODULE)) {
         $this->_relatableModels[] = 'Sales_Model_Invoice';
         $this->_configuredModels[] = 'InvoicePosition';
         $this->_configuredModels[] = 'Invoice';
     } else {
         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
             Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Invoices module disabled');
         }
     }
     if (Sales_Config::getInstance()->featureEnabled(Sales_Config::FEATURE_OFFERS_MODULE)) {
         $this->_relatableModels[] = 'Sales_Model_Offer';
         $this->_configuredModels[] = 'Offer';
     }
     if (Sales_Config::getInstance()->featureEnabled(Sales_Config::FEATURE_SUPPLIERS_MODULE)) {
         $this->_relatableModels[] = 'Sales_Model_Supplier';
         $this->_configuredModels[] = 'Supplier';
     }
     if (Sales_Config::getInstance()->featureEnabled(Sales_Config::FEATURE_PURCHASE_INVOICES_MODULE)) {
         $this->_relatableModels[] = 'Sales_Model_PurchaseInvoice';
         $this->_configuredModels[] = 'PurchaseInvoice';
     }
     if (Sales_Config::getInstance()->featureEnabled(Sales_Config::FEATURE_ORDERCONFIRMATIONS_MODULE)) {
         $this->_relatableModels[] = 'Sales_Model_OrderConfirmation';
         $this->_configuredModels[] = 'OrderConfirmation';
     }
 }
 /**
  * update from 5.0 -> 5.1
  * - save shared contracts container id in config
  * 
  * @return void
  */
 public function update_0()
 {
     $appId = Tinebase_Application::getInstance()->getApplicationByName('Sales')->getId();
     try {
         $sharedContractsId = Sales_Config::getInstance()->get(Sales_Model_Config::SHAREDCONTRACTSID);
         $sharedContracts = Tinebase_Container::getInstance()->get($sharedContractsId ? $sharedContractsId : 1);
     } catch (Tinebase_Exception_NotFound $tenf) {
         // try to fetch default shared container
         $filter = new Tinebase_Model_ContainerFilter(array(array('field' => 'application_id', 'operator' => 'equals', 'value' => $appId), array('field' => 'name', 'operator' => 'equals', 'value' => 'Shared Contracts'), array('field' => 'type', 'operator' => 'equals', 'value' => Tinebase_Model_Container::TYPE_SHARED)));
         $sharedContracts = Tinebase_Container::getInstance()->search($filter)->getFirstRecord();
         if ($sharedContracts) {
             Sales_Config::getInstance()->set(Sales_Model_Config::SHAREDCONTRACTSID, $sharedContracts->getId());
         }
     }
     $this->setApplicationVersion('Sales', '5.1');
 }
 /**
  * testFeatureEnabled
  *
  * @see 0010756: add feature switches for easy enabling/disabling of features
  */
 public function testFeatureEnabled()
 {
     $customConfigFilename = $this->_getSalesCustomDefaultConfig();
     if (file_exists($customConfigFilename)) {
         $this->markTestSkipped('do not test with existing custom config');
     }
     $invoicesFeatureEnabled = Sales_Config::getInstance()->featureEnabled(Sales_Config::FEATURE_INVOICES_MODULE);
     $this->assertTrue($invoicesFeatureEnabled);
 }
 /**
  * Sets up the fixture.
  * This method is called before a test is executed.
  *
  * @access protected
  */
 protected function setUp()
 {
     Sales_Controller_Contract::getInstance()->deleteByFilter(new Sales_Model_ContractFilter(array()));
     $cfg = Sales_Config::getInstance();
     $cfg->set(Sales_Config::AUTO_INVOICE_CONTRACT_INTERVAL, 12);
     $this->_invoiceController = Sales_Controller_Invoice::getInstance();
     $this->_invoiceController->deleteByFilter(new Sales_Model_InvoiceFilter(array()));
     parent::setUp();
     Sales_Controller_Contract::getInstance()->setNumberPrefix();
     Sales_Controller_Contract::getInstance()->setNumberZerofill();
     $this->_setReferenceDate();
 }
 /**
  * get (create if it does not exist) container for shared contracts
  * 
  * @return Tinebase_Model_Container|NULL
  * 
  * @todo use Tinebase_Container::createSystemContainer()
  */
 public static function getSharedContractsContainer()
 {
     $sharedContracts = NULL;
     $appId = Tinebase_Application::getInstance()->getApplicationByName('Sales')->getId();
     try {
         $sharedContractsId = Sales_Config::getInstance()->get(Sales_Model_Config::SHAREDCONTRACTSID);
         $sharedContracts = Tinebase_Container::getInstance()->get($sharedContractsId);
     } catch (Tinebase_Exception_NotFound $tenf) {
         $newContainer = new Tinebase_Model_Container(array('name' => 'Shared Contracts', 'type' => Tinebase_Model_Container::TYPE_SHARED, 'backend' => 'Sql', 'application_id' => $appId, 'model' => 'Sales_Model_Contract'));
         $sharedContracts = Tinebase_Container::getInstance()->addContainer($newContainer, NULL, TRUE);
         Sales_Config::getInstance()->set(Sales_Model_Config::SHAREDCONTRACTSID, $sharedContracts->getId());
         // add grants for groups
         $groupsBackend = Tinebase_Group::factory(Tinebase_Group::SQL);
         $adminGroup = $groupsBackend->getDefaultAdminGroup();
         $userGroup = $groupsBackend->getDefaultGroup();
         Tinebase_Container::getInstance()->addGrants($sharedContracts, Tinebase_Acl_Rights::ACCOUNT_TYPE_GROUP, $userGroup, array(Tinebase_Model_Grants::GRANT_READ, Tinebase_Model_Grants::GRANT_EDIT), TRUE);
         Tinebase_Container::getInstance()->addGrants($sharedContracts, Tinebase_Acl_Rights::ACCOUNT_TYPE_GROUP, $adminGroup, array(Tinebase_Model_Grants::GRANT_ADD, Tinebase_Model_Grants::GRANT_READ, Tinebase_Model_Grants::GRANT_EDIT, Tinebase_Model_Grants::GRANT_DELETE, Tinebase_Model_Grants::GRANT_ADMIN), TRUE);
     }
     return $sharedContracts;
 }
 /**
  * test get all registry data
  *
  * @return void
  *
  * @see 0007934: change pw button active even if it is not allowed
  * @see 0008310: apps should be sorted the other way round in menu
  * @see 0009130: Can't open login page on Ubuntu "due to a temporary overloading"
  * @see 0012188: add copyOmitFields to modelconfig
  */
 public function testGetAllRegistryData()
 {
     $registryData = $this->_instance->getAllRegistryData();
     $currentUser = Tinebase_Core::getUser();
     $this->assertEquals($currentUser->toArray(), $registryData['Tinebase']['currentAccount']);
     $this->assertEquals(Addressbook_Controller_Contact::getInstance()->getContactByUserId($currentUser->getId())->toArray(), $registryData['Tinebase']['userContact']);
     $this->assertEquals(TRUE, $registryData['Tinebase']['config']['changepw']['value'], 'changepw should be TRUE');
     Tinebase_Config::getInstance()->set('changepw', 0);
     $registryData = $this->_instance->getAllRegistryData();
     $changepwValue = $registryData['Tinebase']['config']['changepw']['value'];
     $this->assertEquals(FALSE, $changepwValue, 'changepw should be (bool) false');
     $this->assertTrue(is_bool($changepwValue), 'changepw should be (bool) false: ' . var_export($changepwValue, TRUE));
     $userApps = $registryData['Tinebase']['userApplications'];
     $this->assertEquals('Admin', $userApps[0]['name'], 'first app should be Admin: ' . print_r($userApps, TRUE));
     $locale = Tinebase_Core::getLocale();
     $symbols = Zend_Locale::getTranslationList('symbols', $locale);
     $this->assertEquals($symbols['decimal'], $registryData['Tinebase']['decimalSeparator']);
     if (Sales_Config::getInstance()->featureEnabled(Sales_Config::FEATURE_INVOICES_MODULE)) {
         $configuredSalesModels = array_keys($registryData['Sales']['models']);
         $this->assertTrue(in_array('Invoice', $configuredSalesModels), 'Invoices is missing from configured models: ' . print_r($configuredSalesModels, true));
     }
     $this->assertTrue(isset($registryData['Timetracker']['models']['Timeaccount']['copyOmitFields']), 'Timeaccount copyOmitFields empty/missing');
     $this->assertEquals(array('billed_in', 'invoice_id', 'status', 'cleared_at'), $registryData['Timetracker']['models']['Timeaccount']['copyOmitFields']);
 }
 /**
  * Checks if number is unique if manual generated
  *
  * @param Tinebase_Record_Interface $r
  * @throws Tinebase_Exception_Record_Validation
  */
 protected function _checkNumberType($record)
 {
     $number = $record->number;
     if (empty($number)) {
         throw new Tinebase_Exception_Record_Validation('Please use a product number!');
     }
     if (Sales_Config::getInstance()->get(Sales_Config::PRODUCT_NUMBER_VALIDATION) == 'integer' && !is_numeric($number)) {
         throw new Tinebase_Exception_Record_Validation('Please use a decimal number as product number!');
     }
 }
 /**
  * returns the timesheet filter 
  * 
  * @param Tinebase_DateTime $date
  * @param Sales_Model_Contract
  * @return Timetracker_Model_TimesheetFilter
  */
 protected function _getBillableTimesheetsFilter(Tinebase_DateTime $date, Sales_Model_Contract $contract = NULL)
 {
     $endDate = clone $date;
     $endDate->setDate($endDate->format('Y'), $endDate->format('n'), 1);
     $endDate->setTime(0, 0, 0);
     $endDate->subSecond(1);
     if (!$contract) {
         $contract = $this->_referenceContract;
     }
     $csdt = clone $contract->start_date;
     $csdt->setTimezone('UTC');
     $endDate->setTimezone('UTC');
     $border = new Tinebase_DateTime(Sales_Config::getInstance()->get(Sales_Config::IGNORE_BILLABLES_BEFORE));
     // if this is not budgeted, show for timesheets in this period
     $filter = new Timetracker_Model_TimesheetFilter(array(array('field' => 'start_date', 'operator' => 'before_or_equals', 'value' => $endDate), array('field' => 'start_date', 'operator' => 'after_or_equals', 'value' => $csdt), array('field' => 'start_date', 'operator' => 'after_or_equals', 'value' => $border), array('field' => 'is_cleared', 'operator' => 'equals', 'value' => FALSE), array('field' => 'is_billable', 'operator' => 'equals', 'value' => TRUE)), 'AND');
     if (!is_null($contract->end_date)) {
         $ced = clone $contract->end_date;
         $ced->setTimezone('UTC');
         $filter->addFilter(new Tinebase_Model_Filter_Date(array('field' => 'start_date', 'operator' => 'before_or_equals', 'value' => $ced)));
     }
     $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'invoice_id', 'operator' => 'equals', 'value' => '')));
     $filter->addFilter(new Tinebase_Model_Filter_Text(array('field' => 'timeaccount_id', 'operator' => 'equals', 'value' => $this->getId())));
     return $filter;
 }
 /**
  * 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();
 }
 /**
  * Returns instance of Tinebase_Config
  *
  * @return Tinebase_Config
  */
 public static function getInstance()
 {
     if (self::$_instance === NULL) {
         self::$_instance = new self();
     }
     return self::$_instance;
 }
 /**
  * adds "start_date", "end_date" to contract and removes "status", "cleared", "cleared_in"
  */
 protected function _updateContractsFields()
 {
     $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);
         // cleared, cleared_in, status gets deleted, if the update is not called on cli
         $controller = Sales_Controller_Contract::getInstance();
         $table = new Zend_Db_Table(SQL_TABLE_PREFIX . 'sales_contracts', new Zend_Db_Table_Definition(array('id' => array('name' => 'id'), 'status' => array('name' => 'status'), 'cleared' => array('name' => 'cleared'), 'cleared_in' => array('name' => 'cleared_in'), 'description' => array('name' => 'description'), 'last_modified_time' => array('name' => 'last_modified_time'))));
         $count = 50;
         $offset = 0;
         $more = true;
         $updateDescription = $statusConfig = $clearedConfig = $setEndDate = array();
         $appId = Tinebase_Application::getInstance()->getApplicationByName('Tinebase')->getId();
         $pref = Tinebase_Core::getPreference('Tinebase');
         Tinebase_Core::setupUserLocale($pref->locale);
         $t = Tinebase_Translation::getTranslation('Sales', Tinebase_Core::getLocale());
         $config = Sales_Config::getInstance()->get('contractStatus');
         foreach ($config['records'] as $cfg) {
             $statusConfig[$cfg['id']] = $cfg['value'];
         }
         $config = Sales_Config::getInstance()->get('contractCleared');
         foreach ($config['records'] as $cfg) {
             $clearedConfig[$cfg['id']] = $cfg['value'];
         }
         while ($more) {
             $results = $table->fetchAll(NULL, NULL, $count, $offset)->toArray();
             foreach ($results as $row) {
                 if ($row['status'] == 'CLOSED') {
                     $setEndDate[$row['id']] = $row['last_modified_time'];
                 }
                 $desc = $row['description'];
                 $desc .= PHP_EOL . '---' . PHP_EOL . PHP_EOL;
                 $contents = FALSE;
                 if (!empty($row['status'])) {
                     $desc .= $t->_('Status') . ': ';
                     $desc .= isset($statusConfig[$row['status']]) ? $t->_($statusConfig[$row['status']]) : $row['status'];
                     $desc .= PHP_EOL;
                     $contents = TRUE;
                 }
                 if (!empty($row['cleared'])) {
                     $desc .= $t->_('Cleared') . ': ';
                     $desc .= isset($clearedConfig[$row['cleared']]) ? $t->_($clearedConfig[$row['cleared']]) : $row['cleared'];
                     $desc .= PHP_EOL;
                     $contents = TRUE;
                 }
                 if (!empty($row['cleared_in'])) {
                     $desc .= $t->_('Cleared In') . ': ';
                     $desc .= $row['cleared_in'];
                     $desc .= PHP_EOL;
                     $contents = TRUE;
                 }
                 if ($contents) {
                     $updateDescription[$row['id']] = $desc . PHP_EOL;
                 }
             }
             if (count($updateDescription) > 50) {
                 foreach ($controller->getMultiple(array_keys($updateDescription)) as $contr) {
                     $contr->description = $updateDescription[$contr->getId()];
                     $controller->update($contr, FALSE);
                 }
                 $updateDescription = array();
             }
             if (count($results) < $count) {
                 $more = FALSE;
             } else {
                 $offset = $offset + $count;
             }
         }
         try {
             foreach ($controller->getMultiple(array_keys($updateDescription)) as $contr) {
                 $contr->description = $updateDescription[$contr->getId()];
                 $controller->update($contr, FALSE);
             }
         } catch (Tinebase_Exception_AccessDenied $tead) {
             // could not update contracts ...
             Tinebase_Exception::log($tead);
         }
     }
     // remove deprecated sales contract fields
     foreach (array('status', 'cleared_in', 'cleared') as $colToDrop) {
         try {
             $this->_backend->dropCol('sales_contracts', $colToDrop);
         } catch (Zend_Db_Statement_Exception $zdse) {
             Tinebase_Exception::log($zdse);
         }
     }
     // add new sales contract fields
     $fields = array('<field>
         <name>start_date</name>
         <type>datetime</type>
     </field>', '
     <field>
         <name>end_date</name>
         <type>datetime</type>
     </field>');
     foreach ($fields as $field) {
         try {
             $declaration = new Setup_Backend_Schema_Field_Xml($field);
             $this->_backend->addCol('sales_contracts', $declaration);
         } catch (Zend_Db_Statement_Exception $zdse) {
             Tinebase_Exception::log($zdse);
         }
     }
     $table = new Zend_Db_Table(SQL_TABLE_PREFIX . 'sales_contracts', new Zend_Db_Table_Definition(array('id' => array('name' => 'id'), 'last_modified_time' => array('name' => 'last_modified_time'), 'end_date' => array('name' => 'end_date'), 'start_date' => array('name' => 'start_date'))));
     $db = $table->getAdapter();
     $values = array_keys($setEndDate);
     if (!empty($values)) {
         $sql = 'UPDATE ' . $db->quoteIdentifier(SQL_TABLE_PREFIX . 'sales_contracts') . ' SET ' . $db->quoteIdentifier('start_date') . ' = ' . $db->quoteIdentifier('last_modified_time') . ', ' . $db->quoteIdentifier('end_date') . ' = ' . $db->quoteIdentifier('last_modified_time') . ' WHERE ' . $db->quoteIdentifier('id') . $db->quoteInto(' IN (?)', $values);
         $db->query($sql);
     }
     if ($this->getTableVersion('sales_contracts') == 5) {
         $this->setTableVersion('sales_contracts', 6);
     } else {
         $this->setTableVersion('sales_contracts', 7);
     }
 }
 /**
  * get all possible application rights
  *
  * @return  array   all application rights
  */
 public function getAllApplicationRights()
 {
     $allRights = parent::getAllApplicationRights();
     $addRights = array(Tinebase_Acl_Rights::USE_PERSONAL_TAGS, self::MANAGE_PRODUCTS, self::MANAGE_CONTRACTS, self::MANAGE_COSTCENTERS, self::MANAGE_CUSTOMERS, self::MANAGE_DIVISIONS);
     // add rights dependent on feature switches
     if (Sales_Config::getInstance()->featureEnabled(Sales_Config::FEATURE_INVOICES_MODULE)) {
         $addRights[] = self::MANAGE_INVOICES;
         $addRights[] = self::SET_INVOICE_NUMBER;
     }
     if (Sales_Config::getInstance()->featureEnabled(Sales_Config::FEATURE_SUPPLIERS_MODULE)) {
         $addRights[] = self::MANAGE_SUPPLIERS;
     }
     if (Sales_Config::getInstance()->featureEnabled(Sales_Config::FEATURE_PURCHASE_INVOICES_MODULE)) {
         $addRights[] = self::MANAGE_PURCHASE_INVOICES;
     }
     if (Sales_Config::getInstance()->featureEnabled(Sales_Config::FEATURE_OFFERS_MODULE)) {
         $addRights[] = self::MANAGE_OFFERS;
     }
     if (Sales_Config::getInstance()->featureEnabled(Sales_Config::FEATURE_ORDERCONFIRMATIONS_MODULE)) {
         $addRights[] = self::MANAGE_ORDERCONFIRMATIONS;
         $addRights[] = self::CHANGE_OC_NUMBER;
     }
     $allRights = array_merge($allRights, $addRights);
     return $allRights;
 }
 /**
  * save Sales settings
  *
  * @param array config
  * @return array
  */
 public function setConfig($config)
 {
     if (!Tinebase_Core::getUser()->hasRight('Sales', 'admin')) {
         throw new Tinebase_Exception_AccessDenied(_('You do not have admin rights on Sales'));
     }
     Sales_Controller_Customer::validateCurrencyCode($config['ownCurrency']);
     $properties = Sales_Config::getProperties();
     foreach ($config as $configName => $configValue) {
         if (!isset($properties[$configName])) {
             continue;
         }
         if (!isset($properties[$configName]['setByAdminModule'])) {
             continue;
         }
         Sales_Config::getInstance()->set($configName, $configValue);
     }
     return $this->getConfig();
 }
 protected function _updateContractsWithUser($user)
 {
     Tinebase_Core::set(Tinebase_Core::USER, $user);
     // cleared, cleared_in, status gets deleted, if the update is not called on cli
     $controller = Sales_Controller_Contract::getInstance();
     $table = new Zend_Db_Table(SQL_TABLE_PREFIX . 'sales_contracts', new Zend_Db_Table_Definition(array('id' => array('name' => 'id'), 'status' => array('name' => 'status'), 'cleared' => array('name' => 'cleared'), 'cleared_in' => array('name' => 'cleared_in'), 'description' => array('name' => 'description'), 'last_modified_time' => array('name' => 'last_modified_time'))));
     $count = 50;
     $offset = 0;
     $more = true;
     $updateDescription = $statusConfig = $clearedConfig = $setEndDate = array();
     $pref = Tinebase_Core::getPreference('Tinebase');
     Tinebase_Core::setupUserLocale($pref->locale);
     $t = Tinebase_Translation::getTranslation('Sales', Tinebase_Core::getLocale());
     $config = Sales_Config::getInstance()->get('contractStatus');
     foreach ($config['records'] as $cfg) {
         $statusConfig[$cfg['id']] = $cfg['value'];
     }
     $config = Sales_Config::getInstance()->get('contractCleared');
     foreach ($config['records'] as $cfg) {
         $clearedConfig[$cfg['id']] = $cfg['value'];
     }
     while ($more) {
         $results = $table->fetchAll(NULL, NULL, $count, $offset)->toArray();
         foreach ($results as $row) {
             if ($row['status'] == 'CLOSED') {
                 $setEndDate[$row['id']] = $row['last_modified_time'];
             }
             $desc = $row['description'];
             $desc .= PHP_EOL . '---' . PHP_EOL . PHP_EOL;
             $contents = FALSE;
             if (!empty($row['status'])) {
                 $desc .= $t->_('Status') . ': ';
                 $desc .= isset($statusConfig[$row['status']]) ? $t->_($statusConfig[$row['status']]) : $row['status'];
                 $desc .= PHP_EOL;
                 $contents = TRUE;
             }
             if (!empty($row['cleared'])) {
                 $desc .= $t->_('Cleared') . ': ';
                 $desc .= isset($clearedConfig[$row['cleared']]) ? $t->_($clearedConfig[$row['cleared']]) : $row['cleared'];
                 $desc .= PHP_EOL;
                 $contents = TRUE;
             }
             if (!empty($row['cleared_in'])) {
                 $desc .= $t->_('Cleared In') . ': ';
                 $desc .= $row['cleared_in'];
                 $desc .= PHP_EOL;
                 $contents = TRUE;
             }
             if ($contents) {
                 $updateDescription[$row['id']] = $desc . PHP_EOL;
             }
         }
         if (count($updateDescription) > 50) {
             foreach ($controller->getMultiple(array_keys($updateDescription)) as $contr) {
                 $contr->description = $updateDescription[$contr->getId()];
                 $controller->update($contr, FALSE);
             }
             $updateDescription = array();
         }
         if (count($results) < $count) {
             $more = FALSE;
         } else {
             $offset = $offset + $count;
         }
     }
     try {
         foreach ($controller->getMultiple(array_keys($updateDescription)) as $contr) {
             $contr->description = $updateDescription[$contr->getId()];
             $controller->update($contr, FALSE);
         }
     } catch (Tinebase_Exception_AccessDenied $tead) {
         // could not update contracts ...
         Tinebase_Exception::log($tead);
     }
 }