0011676: apply new config concept to CRM
authorCornelius Weiß <c.weiss@metaways.de>
Tue, 24 Nov 2015 15:54:20 +0000 (16:54 +0100)
committerPhilipp Schüle <p.schuele@metaways.de>
Fri, 11 Mar 2016 12:43:11 +0000 (13:43 +0100)
- add keyfield definitions to config
- migrate old keyfield data
- remove appdefaults/getConfigSettings/saveConfigSettings from Crm
- remove Crm_Model_Config
- refactor keyfield usage in filters/domainlogic
- refactor crm js (admin & grid/edit)
- support custom models in keyFieldConfig

https://forge.tine20.org/view.php?id=11676

Change-Id: I16842cacce5808229a35cd53215bf84851c719f4

36 files changed:
tests/tine20/Crm/JsonTest.php
tine20/Crm/Backend/Lead.php
tine20/Crm/Config.php
tine20/Crm/Controller.php
tine20/Crm/Controller/Lead.php
tine20/Crm/Crm.jsb2
tine20/Crm/Export/Csv.php
tine20/Crm/Export/Helper.php
tine20/Crm/Export/Pdf.php
tine20/Crm/Frontend/Json.php
tine20/Crm/Import/Csv.php
tine20/Crm/Model/Config.php [deleted file]
tine20/Crm/Model/LeadSource.php [new file with mode: 0644]
tine20/Crm/Model/LeadState.php [new file with mode: 0644]
tine20/Crm/Setup/Initialize.php
tine20/Crm/Setup/Update/Release8.php
tine20/Crm/Setup/Update/Release9.php [new file with mode: 0644]
tine20/Crm/Setup/setup.xml
tine20/Crm/js/AdminPanel.js
tine20/Crm/js/Crm.js
tine20/Crm/js/LeadEditDialog.js
tine20/Crm/js/LeadGridDetailsPanel.js
tine20/Crm/js/LeadGridPanel.js
tine20/Crm/js/LeadSource.js [deleted file]
tine20/Crm/js/LeadSourceFilterModel.js [deleted file]
tine20/Crm/js/LeadState.js [deleted file]
tine20/Crm/js/LeadStateFilterModel.js [deleted file]
tine20/Crm/js/LeadType.js [deleted file]
tine20/Crm/js/Model.js
tine20/Projects/js/Model.js
tine20/Tinebase/Config/Abstract.php
tine20/Tinebase/Config/KeyField.php
tine20/Tinebase/js/Models.js
tine20/Tinebase/js/extFixes.js
tine20/Tinebase/js/widgets/keyfield/ConfigGrid.js
tine20/Tinebase/js/widgets/keyfield/Store.js

index 5206bbb..48e27b3 100644 (file)
@@ -87,86 +87,7 @@ class Crm_JsonTest extends Crm_AbstractTest
         parent::tearDown();
         Crm_Controller_Lead::getInstance()->duplicateCheckFields(array('lead_name'));
     }
-     
-    /**
-     * test get crm registry
-     * 
-     * @return void
-     */
-    public function testGetRegistryData()
-    {
-        $registry = $this->_getUit()->getRegistryData();
-        
-        $types = array('leadtypes', 'leadstates', 'leadsources');
-        
-        // check data
-        foreach ($types as $type) {
-            $this->assertGreaterThan(0, $registry[$type]['totalcount']);
-            $this->assertGreaterThan(0, count($registry[$type]['results']));
-        }
-        
-        // check defaults
-        $this->assertEquals(array(
-            'leadstate_id'  => 1,
-            'leadtype_id'   => 1,
-            'leadsource_id' => 1,
-        ), array(
-            'leadstate_id' => $registry['defaults']['leadstate_id'],
-            'leadtype_id' => $registry['defaults']['leadtype_id'],
-            'leadsource_id' => $registry['defaults']['leadsource_id'],
-        ));
-        $this->assertEquals(
-            Tinebase_Container::getInstance()->getDefaultContainer('Crm')->getId(),
-            $registry['defaults']['container_id']['id']
-        );
-    }
-    
-    /**
-     * test get settings/config
-     * 
-     * @return void
-     */
-    public function testGetSettings()
-    {
-        $result = $this->_getUit()->getSettings();
-        
-        $this->assertArrayHasKey('leadstates',  $result);
-        $this->assertArrayHasKey('leadtypes',   $result);
-        $this->assertArrayHasKey('leadsources', $result);
-        $this->assertArrayHasKey('defaults',    $result);
-        $this->assertEquals(6, count($result[Crm_Model_Config::LEADSTATES]));
-        $this->assertEquals(3, count($result[Crm_Model_Config::LEADTYPES]));
-        $this->assertEquals(4, count($result[Crm_Model_Config::LEADSOURCES]));
-    }
-    
-    /**
-     * test get settings/config
-     * 
-     * @return void
-     */
-    public function testSaveSettings()
-    {
-        $oldSettings = $this->_getUit()->getSettings();
-        
-        // change some settings
-        $newSettings = $oldSettings;
-        $newSettings['defaults']['leadstate_id'] = 2;
-        $newSettings['leadsources'][] = array(
-            'id' => 5,
-            'leadsource' => 'Another Leadsource'
-        );
-        $anotherResult = $this->_getUit()->saveSettings($newSettings);
-        $this->assertEquals($newSettings, $anotherResult, 'new settings have not been saved');
-        
-        // reset original settings
-        $result = $this->_getUit()->saveSettings($oldSettings);
-        $this->assertEquals($result, $oldSettings, 'old settings have not been reset');
-        
-        // test Crm_Model_Config::getOptionById
-        $settings = Crm_Controller::getInstance()->getConfigSettings();
-        $this->assertEquals(array(), $settings->getOptionById(5, 'leadsources'), 'Crm_Model_Config::getOptionById failed');
-    }
-    
+
     /**
      * try to add/search/delete a lead with linked contact, task and product
      * 
index fdf5632..383186c 100644 (file)
@@ -116,20 +116,19 @@ class Crm_Backend_Lead extends Tinebase_Backend_Sql_Abstract
     protected function _appendForeignSort(Tinebase_Model_Pagination $pagination, Zend_Db_Select $select)
     {
         $virtualSortColumns = array(
-            'leadstate_id'  => Crm_Model_Config::LEADSTATES,
-            'leadsource_id' => Crm_Model_Config::LEADSOURCES,
-            'leadtype_id'   => Crm_Model_Config::LEADTYPES,
+            'leadstate_id'  => Crm_Config::LEAD_STATES,
+            'leadsource_id' => Crm_Config::LEAD_SOURCES,
+            'leadtype_id'   => Crm_Config::LEAD_TYPES,
         );
         
         $col = $pagination->sort;
         if (isset($virtualSortColumns[$col])) {
-            $settings = Crm_Controller::getInstance()->getConfigSettings();
-            $setting = $settings->{$virtualSortColumns[$col]};
-            
+            $config = Crm_Config::getInstance()->get($virtualSortColumns[$col]);
+
             // create cases (when => then) for sql switch (CASE) command
             $cases = array();
-            foreach ($setting as $settingRecord) {
-                $cases[$settingRecord['id']] = $settingRecord[str_replace('_id', '', $col)];
+            foreach ($config['records'] as $settingRecord) {
+                $cases[$settingRecord['id']] = $settingRecord['value'];
             }
             
             $foreignSortCase = $this->_dbCommand->getSwitch($col, $cases);
index cb62491..a44b8d0 100644 (file)
 class Crm_Config extends Tinebase_Config_Abstract
 {
     /**
+     * lead states available
+     *
+     * @var string
+     */
+    const LEAD_STATES = 'leadstates';
+
+    /**
+     * lead sources available
+     *
+     * @var string
+     */
+    const LEAD_SOURCES = 'leadsources';
+
+    /**
+     * lead types available
+     *
+     * @var string
+     */
+    const LEAD_TYPES = 'leadtypes';
+
+    /**
      * lead import feature
      *
      * @var string
@@ -48,6 +69,67 @@ class Crm_Config extends Tinebase_Config_Abstract
      * @see tine20/Tinebase/Config/Definition::$_properties
      */
     protected static $_properties = array(
+        self::LEAD_STATES => array(
+            //_('Lead States Available')
+            'label'                 => 'Lead States Available',
+            //_('Possible lead status, with their associated turnover probabilities. If a status is flagged, leads with this status are treated as closed.')
+            'description'           => 'Possible lead status, with their associated turnover probabilities. If a status is flagged, leads with this status are treated as closed.',
+            'type'                  => Tinebase_Config_Abstract::TYPE_KEYFIELD_CONFIG,
+            'options'               => array('recordModel' => 'Crm_Model_LeadState'),
+            'clientRegistryInclude' => TRUE,
+            'setByAdminModule'      => TRUE,
+            'default'               => array(
+                'records' => array(
+                    array('id' => 1, 'value' => 'open',                  'probability' => 0,     'endslead' => 0), //_('open')
+                    array('id' => 2, 'value' => 'contacted',             'probability' => 10,    'endslead' => 0), //_('contacted')
+                    array('id' => 3, 'value' => 'waiting for feedback',  'probability' => 30,    'endslead' => 0), //_('waiting for feedback')
+                    array('id' => 4, 'value' => 'quote sent',            'probability' => 50,    'endslead' => 0), //_('quote sent')
+                    array('id' => 5, 'value' => 'accepted',              'probability' => 100,   'endslead' => 1), //_('accepted')
+                    array('id' => 6, 'value' => 'lost',                  'probability' => 0,     'endslead' => 1), //_('lost')
+                ),
+                'default' => 1
+            )
+        ),
+
+        self::LEAD_SOURCES => array(
+            //_('Lead Sources Available')
+            'label'                 => 'Lead Sources Available',
+            //_('Possible lead sources. If a source is flagged as archived, leads of this source are treated as closed.')
+            'description'           => '\'Possible lead sources. If a source is flagged as archived, leads of this source are treated as closed.',
+            'type'                  => Tinebase_Config_Abstract::TYPE_KEYFIELD_CONFIG,
+            'options'               => array('recordModel' => 'Crm_Model_LeadSource'),
+            'clientRegistryInclude' => TRUE,
+            'setByAdminModule'      => TRUE,
+            'default'               => array (
+                'records' => array(
+                    array('id' => 1, 'value' => 'Market'),
+                    array('id' => 2, 'value' => 'Email'),
+                    array('id' => 3, 'value' => 'Telephone'),
+                    array('id' => 4, 'value' => 'Website'),
+                ),
+                'default' => 1
+            )
+        ),
+
+        self::LEAD_TYPES => array(
+            //_('Lead Types Available')
+            'label'                 => 'Lead Types Available',
+            //_('Possible lead types.')
+            'description'           => 'Possible lead types.',
+            'type'                  => Tinebase_Config_Abstract::TYPE_KEYFIELD_CONFIG,
+//            'options'               => array('recordModel' => 'Crm_Model_LeadType'),
+            'clientRegistryInclude' => TRUE,
+            'setByAdminModule'      => TRUE,
+            'default'               => array(
+                'records' => array(
+                    array('id' => 1, 'value' => 'Customer'),   //_('Customer')
+                    array('id' => 2, 'value' => 'Partner'),    //_('Partner')
+                    array('id' => 3, 'value' => 'Reseller'),   //_('Reseller')
+                ),
+                'default' => 1
+            )
+        ),
+
         /**
          * enabled Crm features
          */
index b848b7a..57eb9db 100644 (file)
@@ -122,93 +122,4 @@ class Crm_Controller extends Tinebase_Controller_Event implements Tinebase_Conta
 
         return $container;
     }
-
-    /**
-     * Returns settings for crm app
-     * - result is cached
-     *
-     * @param boolean $_resolve if some values should be resolved (here yet unused)
-     * @return  Crm_Model_Config
-     * 
-     * @todo check 'endslead' values
-     * @todo use keyfield configs here
-     */
-    public function getConfigSettings($_resolve = FALSE)
-    {
-        $cache = Tinebase_Core::get('cache');
-        $cacheId = Tinebase_Helper::convertCacheId('getCrmSettings');
-        $result = $cache->load($cacheId);
-        
-        if (! $result) {
-            
-            if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ 
-                . ' Fetching Crm Settings ...');
-            
-            $translate = Tinebase_Translation::getTranslation('Crm');
-            
-            $result = new Crm_Model_Config(array(
-                'defaults' => parent::getConfigSettings()
-            ));
-            
-            $others = array(
-                Crm_Model_Config::LEADTYPES => array(
-                    array('id' => 1, 'leadtype' => $translate->_('Customer')),
-                    array('id' => 2, 'leadtype' => $translate->_('Partner')),
-                    array('id' => 3, 'leadtype' => $translate->_('Reseller')),
-                ), 
-                Crm_Model_Config::LEADSTATES => array(
-                    array('id' => 1, 'leadstate' => $translate->_('open'),                  'probability' => 0,     'endslead' => 0),
-                    array('id' => 2, 'leadstate' => $translate->_('contacted'),             'probability' => 10,    'endslead' => 0),
-                    array('id' => 3, 'leadstate' => $translate->_('waiting for feedback'),  'probability' => 30,    'endslead' => 0),
-                    array('id' => 4, 'leadstate' => $translate->_('quote sent'),            'probability' => 50,    'endslead' => 0),
-                    array('id' => 5, 'leadstate' => $translate->_('accepted'),              'probability' => 100,   'endslead' => 1),
-                    array('id' => 6, 'leadstate' => $translate->_('lost'),                  'probability' => 0,     'endslead' => 1),
-                ), 
-                Crm_Model_Config::LEADSOURCES => array(
-                    array('id' => 1, 'leadsource' => $translate->_('Market')),
-                    array('id' => 2, 'leadsource' => $translate->_('Email')),
-                    array('id' => 3, 'leadsource' => $translate->_('Telephone')),
-                    array('id' => 4, 'leadsource' => $translate->_('Website')),
-                )
-            );
-            foreach ($others as $setting => $defaults) {
-                $result->$setting = Crm_Config::getInstance()->get($setting, new Tinebase_Config_Struct($defaults))->toArray();
-            }
-            
-            // save result and tag it with 'settings'
-            $cache->save($result, $cacheId, array('settings'));
-        }
-        
-        return $result;
-    }
-    
-    /**
-     * save crm settings
-     * 
-     * @param Crm_Model_Config $_settings
-     * @return Crm_Model_Config
-     * 
-     * @todo generalize this
-     */
-    public function saveConfigSettings($_settings)
-    {
-        if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ 
-            . ' Updating Crm Settings: ' . print_r($_settings->toArray(), TRUE));
-        
-        foreach ($_settings->toArray() as $field => $value) {
-            if ($field == 'id') {
-                continue;
-            } else if ($field == 'defaults') {
-                parent::saveConfigSettings($value);
-            } else {
-                Crm_Config::getInstance()->set($field, $value);
-            }
-        }
-        
-        // invalidate cache
-        Tinebase_Core::getCache()->remove('getCrmSettings');
-        Crm_Config::getInstance()->clearCache();
-        
-        return $this->getConfigSettings();
-    }
 }
index 7d53155..94bfa06 100644 (file)
@@ -166,10 +166,9 @@ class Crm_Controller_Lead extends Tinebase_Controller_Record_Abstract
         
         $view->updater = $_updater;
         $view->lead = $_lead;
-        $settings = Crm_Controller::getInstance()->getConfigSettings();
-        $view->leadState = $settings->getOptionById($_lead->leadstate_id, 'leadstates');
-        $view->leadType = $settings->getOptionById($_lead->leadtype_id, 'leadtypes');
-        $view->leadSource = $settings->getOptionById($_lead->leadsource_id, 'leadsources');
+        $view->leadState = Crm_Config::getInstance()->get(Crm_Config::LEAD_STATES)->getTranslatedValue($_lead->leadstate_id);
+        $view->leadType = Crm_Config::getInstance()->get(Crm_Config::LEAD_TYPES)->getTranslatedValue($_lead->leadtype_id);
+        $view->leadSource = Crm_Config::getInstance()->get(Crm_Config::LEAD_SOURCES)->getTranslatedValue($_lead->leadsource_id);
         $view->container = Tinebase_Container::getInstance()->getContainerById($_lead->container_id);
         
         if (isset($_lead->relations)) {
index f6da865..b55624f 100644 (file)
           "path": "js/"
         },
         {
-          "text": "LeadState.js",
-          "path": "js/"
-        },
-        {
-          "text": "LeadStateFilterModel.js",
-          "path": "js/"
-        },
-          {
-              "text": "LeadSourceFilterModel.js",
-              "path": "js/"
-          },
-        {
-          "text": "LeadSource.js",
-          "path": "js/"
-        },
-        {
-          "text": "LeadType.js",
-          "path": "js/"
-        },
-        {
           "text": "Contact.js",
           "path": "js/"
         },
index c1e33fa..80a4dcd 100644 (file)
@@ -99,6 +99,7 @@ class Crm_Export_Csv extends Tinebase_Export_Csv
      */
     protected function _addSpecialValue(Tinebase_Record_Abstract $_record, $_fieldName)
     {
-        return Tinebase_Config::getOptionString($_record, preg_replace('/_id/', '', $_fieldName));
+        $keyFieldName = preg_replace('/_id/', 's', $_fieldName);
+        return Crm_Config::getInstance()->get($keyFieldName)->getTranslatedValue($_record->$_fieldName);
     }
 }
index c32e4ca..8d70f84 100644 (file)
@@ -57,16 +57,23 @@ class Crm_Export_Helper
         if (is_null($_key)) {
             throw new Tinebase_Exception_InvalidArgument('Missing required parameter $key');
         }
-        
+
         switch($_param['type']) {
             case 'status':
+                // TODO what about status? there is something missing here ... the code should be generalized for status/source/type
             case 'source':
+                $source = Crm_Config::getInstance()->get(Crm_Config::LEAD_SOURCES)->getTranslatedValue($_record->leadsource_id);
+                if (isset($source)) {
+                    $value = $source;
+                } else {
+                    Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' Leadsource id not found:' . $_record->leadsource_id);
+                    $value = '';
+                }
+                break;
             case 'type':
-                $leadIdType = $_param['type'] == 'status' ? 'leadstate' : 'lead' . $_param['type'];
-                $settings = Crm_Controller::getInstance()->getConfigSettings();
-                $source = $settings->getOptionById($_record->{$leadIdType . '_id'}, $leadIdType . 's');
-                if (isset($source[$leadIdType])) {
-                    $value = $source[$leadIdType];
+                $type = Crm_Config::getInstance()->get(Crm_Config::LEAD_TYPES)->getTranslatedValue($_record->leadtype_id);
+                if (isset($type['leadtype'])) {
+                    $value = $type;
                 } else {
                     Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . $leadIdType . ' id not found:' . $_record->{$leadIdType . '_id'});
                     $value = '';
index cfdfe62..f152714 100644 (file)
@@ -69,8 +69,6 @@ class Crm_Export_Pdf extends Tinebase_Export_Pdf
      */
     protected function getRecord(Crm_Model_Lead $_lead, Zend_Locale $_locale, Zend_Translate $_translate)
     {
-        $settings = Crm_Controller::getInstance()->getConfigSettings();
-        
         $leadFields = array (
             array(  'label' => /* $_translate->_('Lead Data') */ "", 
                     'type' => 'separator' 
@@ -128,14 +126,11 @@ class Crm_Export_Pdf extends Tinebase_Export_Pdf
                             } elseif ( $key === 'probability' ) {
                                 $content[] = $_lead->$key . " %";
                             } elseif ( $key === 'leadstate_id' ) {
-                                $state = $settings->getOptionById($_lead->leadstate_id, 'leadstates');
-                                $content[] = $state['leadstate'];
+                                $content[] = Crm_Config::getInstance()->get(Crm_Config::LEAD_STATES)->getTranslatedValue($_lead->leadstate_id);
                             } elseif ( $key === 'leadtype_id' ) {
-                                $type = $settings->getOptionById($_lead->leadtype_id, 'leadtypes');
-                                $content[] = $type['leadtype'];
+                                $content[] = Crm_Config::getInstance()->get(Crm_Config::LEAD_TYPES)->getTranslatedValue($_lead->leadtype_id);
                             } elseif ( $key === 'leadsource_id' ) {
-                                $source = $settings->getOptionById($_lead->leadsource_id, 'leadsources');
-                                $content[] = $source['leadsource'];
+                                $content[] = Crm_Config::getInstance()->get(Crm_Config::LEAD_SOURCES)->getTranslatedValue($_lead->leadsource_id);
                             } else {
                                 $content[] = $_lead->$key;
                             }
index 4dd11e8..8b897bf 100644 (file)
@@ -123,24 +123,8 @@ class Crm_Frontend_Json extends Tinebase_Frontend_Json_Abstract
      */
     public function getRegistryData()
     {
-        $settings = $this->getSettings();
-        $defaults = $settings['defaults'];
-        $defaults['container_id'] = $this->getDefaultContainer();
-        
         $registryData = array(
-            'leadtypes'     => array(
-                'results' => $settings[Crm_Model_Config::LEADTYPES],
-                'totalcount' => count($settings[Crm_Model_Config::LEADTYPES])
-            ),
-            'leadstates'    => array(
-                'results' => $settings[Crm_Model_Config::LEADSTATES],
-                'totalcount' => count($settings[Crm_Model_Config::LEADSTATES])
-            ),
-            'leadsources'   => array(
-                'results' => $settings[Crm_Model_Config::LEADSOURCES],
-                'totalcount' => count($settings[Crm_Model_Config::LEADSOURCES])
-            ),
-            'defaults'      => $defaults,
+            'defaultContainer' => $this->getDefaultContainer(),
         );
 
         $registryData = array_merge($registryData, $this->_getImportDefinitionRegistryData());
@@ -163,20 +147,6 @@ class Crm_Frontend_Json extends Tinebase_Frontend_Json_Abstract
         
         return $defaultContainerArray;
     }
-    
-    /**
-     * Returns settings for crm app
-     *
-     * @return  array record data
-     *
-     * @todo    return json store style with totalcount/result?
-     */
-    public function getSettings()
-    {
-        $result = Crm_Controller::getInstance()->getConfigSettings()->toArray();
-        
-        return $result;
-    }
 
     /**
      * creates/updates settings
@@ -187,7 +157,7 @@ class Crm_Frontend_Json extends Tinebase_Frontend_Json_Abstract
     {
         $settings = new Crm_Model_Config($recordData);
         $result = Crm_Controller::getInstance()->saveConfigSettings($settings)->toArray();
-        
+
         return $result;
     }
 
index 9053f3e..cf9ae3f 100644 (file)
@@ -79,7 +79,6 @@ class Crm_Import_Csv extends Tinebase_Import_Csv_Abstract
      * @return array
      *
      * TODO think about moving this to import definition
-     * TODO simplify crm/lead config handling for leadstate/source/type
      */
     protected function _doConversions($_data)
     {
@@ -89,36 +88,19 @@ class Crm_Import_Csv extends Tinebase_Import_Csv_Abstract
             . ' ' . print_r($data, true));
 
         // adjust lead_name/leadstate/source/types if missing
-        $configSettings = Crm_Controller::getInstance()->getConfigSettings()->toArray();
-
-        $requiredFields = array(
-            'leadstate_id' => 'leadstates',
-            'leadtype_id' => 'leadtypes',
-            'leadsource_id' => 'leadsources'
+        $keyFields = array(
+            Crm_Config::LEAD_STATES  => 'leadstate_id',
+            Crm_Config::LEAD_TYPES   => 'leadtype_id',
+            Crm_Config::LEAD_SOURCES => 'leadsource_id',
         );
-        foreach ($requiredFields as $requiredField => $configKey) {
-            if (! empty($data[$requiredField])) {
-                continue;
-            }
-
-            switch ($requiredField) {
-                default:
-                    // get default leadstate/source/type OR try to find it by name if given
-                    if (! isset($configSettings[$configKey])) {
-                        continue;
-                    }
-                    $settingField = preg_replace('/s$/', '', $configKey);
 
-                    if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__
-                        . ' config settings' . print_r($configSettings[$configKey], true));
+        foreach ($keyFields as $keyFieldName => $fieldName) {
+            $keyField = Crm_Config::getInstance()->get($keyFieldName);
 
-                    // init with default
-                    $data[$requiredField] = isset($configSettings[$configKey][0]['id']) ? $configSettings[$configKey][0]['id'] : 1;
-                    foreach ($configSettings[$configKey] as $setting) {
-                        if (isset($setting[$settingField]) && isset($_data[$settingField]) && strtolower($setting[$settingField]) === strtolower($_data[$settingField])) {
-                            $data[$requiredField] = $setting['id'];
-                        }
-                    }
+            if (isset($data[$fieldName])) {
+                $data[$fieldName] = $keyField->getIdByTranslatedValue($data[$fieldName]);
+            } else {
+                $data[$fieldName] = $keyField->getKeyfieldDefault()->getId();
             }
         }
 
diff --git a/tine20/Crm/Model/Config.php b/tine20/Crm/Model/Config.php
deleted file mode 100644 (file)
index 796f0c5..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-<?php
-/**
- * Tine 2.0
- * 
- * @package     Crm
- * @subpackage  Record
- * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
- * @copyright   Copyright (c) 2009 Metaways Infosystems GmbH (http://www.metaways.de)
- * @author      Philipp Schuele <p.schuele@metaways.de>
- * 
- * TODO         generalize this (by adding more generic fields)
- */
-
-/**
- * class Crm_Model_Config
- * 
- * @package     Crm
- * @subpackage  Record
- */
-class Crm_Model_Config extends Tinebase_Record_Abstract 
-{
-    /**
-     * lead states config
-     * 
-     * @var string
-     */
-    const LEADSTATES = 'leadstates';
-    
-    /**
-     * lead types config
-     * 
-     * @var string
-     */
-    const LEADTYPES = 'leadtypes';
-    
-    /**
-     * lead sources config
-     * 
-     * @var string
-     */
-    const LEADSOURCES = 'leadsources';
-    
-    /**
-     * identifier
-     * 
-     * @var string
-     */ 
-    protected $_identifier = 'id';
-    
-    /**
-     * application the record belongs to
-     *
-     * @var string
-     */
-    protected $_application = 'Crm';
-    
-    /**
-     * record validators
-     *
-     * @var array
-     */
-    protected $_validators = array(
-        'id'                => array('allowEmpty' => true ),
-        'leadstates'        => array('allowEmpty' => true ),
-        'leadtypes'         => array('allowEmpty' => true ),
-        'leadsources'       => array('allowEmpty' => true ),        
-        'defaults'          => array('allowEmpty' => true ),
-    );
-    
-    /**
-     * get an array in a multidimensional array by its property
-     * 
-     * @param array $_id
-     * @param string $_property
-     * @return array
-     * 
-     * @todo add to generic config/settings model
-     */
-    public function getOptionById($_id, $_property, $_idProperty = 'id')
-    {
-        if ($this->has($_property) && isset($this->$_property) && is_array($this->$_property)) {
-            foreach ($this->$_property as $sub) {
-                if ((isset($sub[$_idProperty]) || array_key_exists($_idProperty, $sub)) && $sub[$_idProperty] == $_id) {
-                    return $sub;
-                }
-            }
-        }
-        
-        return array();
-    }
-    
-    /**
-     * get an array of leadstates with property endslead set to 1
-     * 
-     * @param bool $_onlyIds
-     * @return array
-     */
-    public function getEndedLeadstates($_onlyIds = FALSE)
-    {
-        $result = array();
-        foreach($this->leadstates as $leadstate) {
-            if ($leadstate['endslead']) {
-                $result[] = $_onlyIds ? $leadstate['id'] : $leadstate;
-            }
-        }
-        
-        return $result;
-    }
-}
diff --git a/tine20/Crm/Model/LeadSource.php b/tine20/Crm/Model/LeadSource.php
new file mode 100644 (file)
index 0000000..2cb9085
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+/**
+ * @package     Crm
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Cornelius Weiss <c.weiss@metaways.de>
+ * @copyright   Copyright (c) 2015 Metaways Infosystems GmbH (http://www.metaways.de)
+ */
+
+/**
+ * lead source record
+ * 
+ * @package     Crm
+ */
+class Crm_Model_LeadSource extends Tinebase_Config_KeyFieldRecord
+{
+    protected $_additionalValidators = array(
+        'archived'                => array('allowEmpty' => true         ),
+    );
+}
\ No newline at end of file
diff --git a/tine20/Crm/Model/LeadState.php b/tine20/Crm/Model/LeadState.php
new file mode 100644 (file)
index 0000000..07c5425
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+/**
+ * @package     Crm
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
+ * @author      Cornelius Weiss <c.weiss@metaways.de>
+ * @copyright   Copyright (c) 2015 Metaways Infosystems GmbH (http://www.metaways.de)
+ */
+
+/**
+ * lead state record
+ * 
+ * @package     Crm
+ */
+class Crm_Model_LeadState extends Tinebase_Config_KeyFieldRecord
+{
+    protected $_additionalValidators = array(
+        'probability'             => array('allowEmpty' => true         ),
+        'endslead'                => array('allowEmpty' => true         ),
+    );
+}
\ No newline at end of file
index ccfb930..e3b64e7 100644 (file)
@@ -28,9 +28,9 @@ class Crm_Setup_Initialize extends Setup_Initialize
             'application_id'    => Tinebase_Application::getInstance()->getApplicationByName('Crm')->getId(),
             'model'             => 'Crm_Model_LeadFilter',
         );
-        
-        $closedStatus = Crm_Controller::getInstance()->getConfigSettings()->getEndedLeadstates(TRUE);
-        
+
+        $closedStatus = Crm_Config::getInstance()->get(Crm_Config::LEAD_STATES)->records->filter('endslead', true)->id;
+
         $pfe->createDuringSetup(new Tinebase_Model_PersistentFilter(array_merge($commonValues, array(
             'name'              => Crm_Preference::DEFAULTPERSISTENTFILTER_NAME,
             'description'       => "All leads I have read grants for", // _("All leads I have read grants for")
index 1e01450..3a488ae 100644 (file)
@@ -58,7 +58,7 @@ class Crm_Setup_Update_Release8 extends Setup_Update_Abstract
         Setup_Controller::getInstance()->createImportExportDefinitions(Tinebase_Application::getInstance()->getApplicationByName('Crm'));
         $this->setApplicationVersion('Crm', '8.3');
     }
-    
+
     /**
      * update to 9.0
      *
diff --git a/tine20/Crm/Setup/Update/Release9.php b/tine20/Crm/Setup/Update/Release9.php
new file mode 100644 (file)
index 0000000..8d35e06
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+/**
+ * Tine 2.0
+ *
+ * @package     Crm
+ * @subpackage  Setup
+ * @license     http://www.gnu.org/licenses/agpl.html AGPL3
+ * @copyright   Copyright (c) 2015 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author      Philipp Schüle <p.schuele@metaways.de>
+ */
+class Crm_Setup_Update_Release9 extends Setup_Update_Abstract
+{
+    /**
+     * update to 9.1
+     * - 0011676: apply new config concept to CRM
+     */
+    public function update_0()
+    {
+        // get all configs for crm from DB
+        $crmApp = Tinebase_Application::getInstance()->getApplicationByName('Crm');
+
+        // either put default to DB or delete form DB
+        $cb = new Tinebase_Backend_Sql(array(
+            'modelName' => 'Tinebase_Model_Config',
+            'tableName' => 'config',
+        ));
+        $configRecords = $cb->search(new Tinebase_Model_ConfigFilter(array(array(
+            'field' => 'application_id', 'operator'=> 'equals', 'value' => $crmApp->getId()
+        ))));
+
+        $appDefaults = $configRecords->filter('name', 'appdefaults')->getFirstRecord();
+
+        foreach(array('leadstate', 'leadtype', 'leadsource') as $oldValueName) {
+            $keyFieldName = $oldValueName + 's';
+            $DBconfig = $configRecords->filter('name', $keyFieldName)->getFirstRecord();
+            if ($DBconfig) {
+                $decodedConfig = json_decode($DBconfig->value, true);
+                foreach($decodedConfig as $oldRecord) {
+                    $oldRecord['value'] = $oldRecord[$oldValueName];
+                    unset($oldRecord[$oldValueName]);
+                }
+                $default = isset($appDefaults[$keyFieldName]) ? $appDefaults[$keyFieldName] : 1;
+                $DBconfig->value = json_encode(array(
+                    'records' => $decodedConfig,
+                    'default' => $default,
+                ));
+                $cb->update($DBconfig);
+            }
+
+        }
+
+        if ($appDefaults) {
+            $cb->delete($appDefaults->getId());
+        }
+
+        $this->setApplicationVersion('Crm', '9.1');
+    }
+}
index 47605cf..c693818 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <application>
     <name>Crm</name>
-    <version>9.0</version>
+    <version>9.1</version>
     <order>20</order>
     <depends>
         <application>Admin</application>
index 414420a..573f0bb 100644 (file)
@@ -4,7 +4,7 @@
  * @package     Crm
  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
  * @author      Philipp Schuele <p.schuele@metaways.de>
- * @copyright   Copyright (c) 2009-2010 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2009-2015 Metaways Infosystems GmbH (http://www.metaways.de)
  *
  */
 
@@ -25,174 +25,34 @@ Ext.namespace('Tine.Crm');
  * 
  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
  * @author      Philipp Schuele <p.schuele@metaways.de>
- * @copyright   Copyright (c) 2009-2010 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @copyright   Copyright (c) 2009-2015 Metaways Infosystems GmbH (http://www.metaways.de)
  * 
  * @param       {Object} config
  * @constructor
  * Create a new Tine.Crm.AdminPanel
  */
-Tine.Crm.AdminPanel = Ext.extend(Tine.widgets.dialog.EditDialog, {
-    /**
-     * @private
-     */
-    //windowNamePrefix: 'LeadEditWindow_',
-    appName: 'Crm',
-    recordClass: Tine.Crm.Model.Settings,
-    recordProxy: Tine.Crm.settingsBackend,
-    evalGrants: false,
-    
-    /**
-     * overwrite update toolbars function (we don't have record grants yet)
-     * @private
-     */
-    updateToolbars: function() {
-    },
-    
-    /**
-     * executed after record got updated from proxy
-     * 
-     * @private
-     */
-    onRecordLoad: function() {
-        if (! this.record.get('default_leadstate_id') ) {
-            this.record.set('default_leadstate_id', this.record.data.defaults.leadstate_id);
-            this.record.set('default_leadsource_id', this.record.data.defaults.leadsource_id);
-            this.record.set('default_leadtype_id', this.record.data.defaults.leadtype_id);
-        }
-        
-        if (this.fireEvent('load', this) !== false) {
-            this.getForm().loadRecord(this.record);
-            this.updateToolbars(this.record, this.recordClass.getMeta('containerProperty'));
-            
-            this.loadMask.hide();
-        }
-    },
-    
-    /**
-     * executed when record gets updated from form
-     * - add attachments to record here
-     * 
-     * @private
-     * 
-     */
-    onRecordUpdate: function() {
-        Tine.Crm.AdminPanel.superclass.onRecordUpdate.call(this);
-        
-        var defaults = {
-            leadstate_id: this.record.get('default_leadstate_id'), 
-            leadsource_id: this.record.get('default_leadsource_id'), 
-            leadtype_id: this.record.get('default_leadtype_id')
-        };
-        
-        this.record.set('defaults', defaults);
-        
-        // save leadstate / commit store
-        this.record.set('leadstates', this.getFromStore(this.leadstatePanel.store));
-        this.record.set('leadtypes', this.getFromStore(this.leadtypePanel.store));
-        this.record.set('leadsources', this.getFromStore(this.leadsourcePanel.store));
-    },
-    
-    /**
-     * get values from store (as array)
-     * 
-     * @param {Ext.data.JsonStore} store
-     * @return {Array}
-     */
-    getFromStore: function(store) {
-        var result = [];
-        store.each(function(record) {
-            result.push(record.data);
-        }, this);
-        store.commitChanges();
-        
-        return result;
-    },
-    
+Tine.Crm.AdminPanel = Ext.extend(Ext.TabPanel, {
+
+    border: false,
+    activeTab: 0,
+
     /**
-     * returns dialog
-     * 
-     * NOTE: when this method gets called, all initalisation is done.
-     * 
-     * @return {Object}
      * @private
      */
-    getFormItems: function() {
-        
-        this.leadstatePanel = new Tine.Crm.LeadState.GridPanel({
-            title: this.app.i18n._('Leadstates')
-        });
-        
-        this.leadtypePanel = new Tine.Crm.LeadType.GridPanel({
-            title: this.app.i18n._('Leadtypes')
-        });
-        
-        this.leadsourcePanel = new Tine.Crm.LeadSource.GridPanel({
-            title: this.app.i18n._('Leadsources')
-        });
-        
-        return {
-            xtype: 'tabpanel',
-            activeTab: 0,
-            border: true,
-            items: [{
-                title: this.app.i18n._('Defaults'),
-                autoScroll: true,
-                border: false,
-                frame: true,
-                xtype: 'columnform',
-                formDefaults: {
-                    xtype:'combo',
-                    anchor: '90%',
-                    labelSeparator: '',
-                    columnWidth: 1,
-                    valueField:'id',
-                    typeAhead: true,
-                    mode: 'local',
-                    triggerAction: 'all',
-                    editable: false,
-                    allowBlank: false,
-                    forceSelection: true
-                },
-                items: [[{
-                    fieldLabel: this.app.i18n._('Leadstate'), 
-                    name:'default_leadstate_id',
-                    store: Tine.Crm.LeadState.getStore(),
-                    displayField:'leadstate',
-                    lazyInit: false,
-                    value: (Tine.Crm.LeadState.getStore().getCount() > 0) ? Tine.Crm.LeadState.getStore().getAt(0).id : null
-                }, {
-                    fieldLabel: this.app.i18n._('Leadsource'), 
-                    name:'default_leadsource_id',
-                    store: Tine.Crm.LeadSource.getStore(),
-                    displayField:'leadsource',
-                    lazyInit: false,
-                    value: (Tine.Crm.LeadSource.getStore().getCount() > 0) ? Tine.Crm.LeadSource.getStore().getAt(0).id : null
-                }, {
-                    fieldLabel: this.app.i18n._('Leadtype'), 
-                    name:'default_leadtype_id',
-                    store: Tine.Crm.LeadType.getStore(),
-                    displayField:'leadtype',
-                    lazyInit: false,
-                    value: (Tine.Crm.LeadType.getStore().getCount() > 0) ? Tine.Crm.LeadType.getStore().getAt(0).id : null
-                }]]
-            }, 
-                this.leadstatePanel,
-                this.leadtypePanel,
-                this.leadsourcePanel
-            ]            
-        };
-    } // end of getFormItems
-});
+    initComponent: function() {
 
-/**
- * admin panel on update function
- * 
- * TODO         update registry without reloading the mainscreen
- */
-Tine.Crm.AdminPanel.onUpdate = function() {
-    // reload mainscreen to make sure registry gets updated
-    Tine.Tinebase.common.reload();
-}
+        this.app = Tine.Tinebase.appMgr.get('Crm');
+
+        this.items = [
+            new Tine.Admin.config.GridPanel({
+                configApp: this.app
+            })
+
+        ];
+
+        this.supr().initComponent.call(this);
+    }
+});
 
 /**
  * Crm admin settings popup
@@ -204,31 +64,10 @@ Tine.Crm.AdminPanel.openWindow = function (config) {
     var id = (config.record && config.record.id) ? config.record.id : 0;
     var window = Tine.WindowFactory.getWindow({
         width: 600,
-        height: 400,
+        height: 470,
         name: Tine.Crm.AdminPanel.prototype.windowNamePrefix + id,
         contentPanelConstructor: 'Tine.Crm.AdminPanel',
         contentPanelConstructorConfig: config
     });
     return window;
 };
-
-Ext.namespace('Tine.Crm.Admin');
-
-/**
- * @namespace   Tine.Crm.Admin
- * @class       Tine.Crm.Admin.QuickaddGridPanel
- * @extends     Tine.widgets.grid.QuickaddGridPanel
- * 
- * admin config option quickadd grid panel
- */
-Tine.Crm.Admin.QuickaddGridPanel = Ext.extend(Tine.widgets.grid.QuickaddGridPanel, {
-
-    /**
-     * @private
-     */
-    initComponent: function() {
-        this.app = this.app ? this.app : Tine.Tinebase.appMgr.get('Crm');
-
-        Tine.Crm.Admin.QuickaddGridPanel.superclass.initComponent.call(this);
-    }
-});
index d9019e7..c75a755 100644 (file)
@@ -111,31 +111,16 @@ Tine.Crm.leadBackend = new Tine.Tinebase.data.RecordProxy({
 });
 
 /**
- * @namespace Tine.Crm
- * @class Tine.Crm.settingBackend
- * @extends Tine.Tinebase.data.RecordProxy
- * 
- * Settings Backend
- * 
- * TODO generalize this
- */ 
-Tine.Crm.settingsBackend = new Tine.Tinebase.data.RecordProxy({
-    appName: 'Crm',
-    modelName: 'Settings',
-    recordClass: Tine.Crm.Model.Settings
-});
-
-/**
  * returns ids of ended lead states
  */
 Tine.Crm.getEndedLeadStateIds = function() {
-    var leadstates = Tine.Crm.registry.get('leadstates')['results'];
+    var leadstates = Tine.Tinebase.widgets.keyfield.StoreMgr.get('Crm', 'leadstates');
     var ids = [];
-    for (var index = 0; index < leadstates.length; index++) {
-        if (leadstates[index].endslead == 1) {
-            ids.push(leadstates[index].id);
+    leadstates.each(function(leadstate) {
+        if (leadstate.json.endslead == 1) {
+            ids.push(leadstate.id);
         }
-    }
+    }, this);
     
     return ids;
 }
index 9f06236..f594abe 100644 (file)
@@ -260,7 +260,7 @@ Tine.Crm.LeadEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
         }
 
         // Don't show item if it's a archived source!
-        var sourceStore = Tine.Crm.LeadSource.getStore();
+        var sourceStore = Tine.Tinebase.widgets.keyfield.StoreMgr.get('Crm', 'leadsources');
 
         var preserveRecords = [];
 
@@ -275,7 +275,7 @@ Tine.Crm.LeadEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
         copiedStore.add(preserveRecords);
 
         sourceStore.each(function(item) {
-            if (item.get('archived') == true) {
+            if (item.json.archived == true) {
                 sourceStore.remove(item);
             }
         });
@@ -284,7 +284,7 @@ Tine.Crm.LeadEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
             var rawValue = parseInt(combo.getRawValue());
 
             if (Ext.isNumber(rawValue)) {
-                combo.setRawValue(copiedStore.getById(combo.getValue()).get('leadsource'));
+                combo.setRawValue(copiedStore.getById(combo.getValue()).get('value'));
             }
         };
 
@@ -369,39 +369,32 @@ Tine.Crm.LeadEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
                                         anchor:'95%',
                                         xtype: 'combo'
                                     },
-                                    items: [{
-                                        fieldLabel: this.app.i18n._('Leadstate'), 
-                                        id:'leadstatus',
-                                        name:'leadstate_id',
-                                        store: Tine.Crm.LeadState.getStore(),
-                                        displayField:'leadstate',
-                                        lazyInit: false,
-                                        value: (Tine.Crm.LeadState.getStore().getCount() > 0) ? Tine.Crm.LeadState.getStore().getAt(0).id : null,
+                                    items: [new Tine.Tinebase.widgets.keyfield.ComboBox({
+                                        app: 'Crm',
+                                        keyFieldName: 'leadstates',
+                                        fieldLabel: this.app.i18n._('Leadstate'),
+                                        name: 'leadstate_id',
                                         listeners: {
                                             'select': function(combo, record, index) {
-                                                if (this.record.data.probability !== null) {
+                                                if (this.record.json.probability !== null) {
                                                     this.combo_probability.setValue(record.data.probability);
                                                 }
-                                                if (record.data.endslead == '1') {
+                                                if (record.json.endslead == '1') {
                                                     this.date_end.setValue(new Date());
                                                 }
                                             },
                                             scope: this
                                         }
-                                    }, {
-                                        fieldLabel: this.app.i18n._('Leadtype'), 
-                                        id:'leadtype',
-                                        name:'leadtype_id',
-                                        store: Tine.Crm.LeadType.getStore(),
-                                        value: (Tine.Crm.LeadType.getStore().getCount() > 0) ? Tine.Crm.LeadType.getStore().getAt(0).id : null,
-                                        displayField:'leadtype'
-                                    }, {
-                                        fieldLabel: this.app.i18n._('Leadsource'), 
-                                        id:'leadsource',
-                                        name:'leadsource_id',
-                                        store: sourceStore,
-                                        displayField:'leadsource',
-                                        value: (sourceStore.getCount() > 0) ? sourceStore.getAt(0).id : null,
+                                    }), new Tine.Tinebase.widgets.keyfield.ComboBox({
+                                        app: 'Crm',
+                                        keyFieldName: 'leadtypes',
+                                        fieldLabel: this.app.i18n._('Leadtype'),
+                                        name: 'leadtype_id'
+                                    }), new Tine.Tinebase.widgets.keyfield.ComboBox({
+                                        app: 'Crm',
+                                        keyFieldName: 'leadsources',
+                                        fieldLabel: this.app.i18n._('Leadsource'),
+                                        name: 'leadsource_id',
                                         listeners: {
                                             scope: this,
                                             // When loading
@@ -413,7 +406,7 @@ Tine.Crm.LeadEditDialog = Ext.extend(Tine.widgets.dialog.EditDialog, {
                                                 setdeffered.defer(5, this, [combo]);
                                             }
                                         }
-                                    }]
+                                    })]
                                 }]
                             }, {
                                 columnWidth: 0.33,
index 683963a..7f6bdb0 100644 (file)
@@ -94,24 +94,7 @@ Tine.Crm.LeadGridDetailsPanel = Ext.extend(Tine.widgets.grid.DetailsPanel, {
         
         return a.join("\n");
     },
-    
-    /**
-     * lead state renderer
-     * 
-     * @param   {Number} id
-     * @param   {Store} store
-     * @return  {String} label
-     * @return  {String} label
-     */
-    sourceTypeRenderer: function(id, store, definitionsLabel) {
-        record = store.getById(id);
-        if (record) {
-            return record.data[definitionsLabel];
-        } else {
-            return this.app.i18n._('undefined');
-        }
-    },
-    
+
     /**
      * inits this component
      */
@@ -237,12 +220,12 @@ Tine.Crm.LeadGridDetailsPanel = Ext.extend(Tine.widgets.grid.DetailsPanel, {
                                 xtype: 'ux.displayfield',
                                 name: 'leadtype_id',
                                 fieldLabel: this.app.i18n._('Leadtype'),
-                                renderer: this.sourceTypeRenderer.createDelegate(this, [Tine.Crm.LeadType.getStore(), 'leadtype'], true)
+                                renderer: Tine.Tinebase.widgets.keyfield.Renderer.get('Crm', 'leadtypes')
                             }, {
                                 xtype: 'ux.displayfield',
                                 name: 'leadsource_id',
                                 fieldLabel: this.app.i18n._('Leadsource'),
-                                renderer: this.sourceTypeRenderer.createDelegate(this, [Tine.Crm.LeadSource.getStore(), 'leadsource'], true)
+                                renderer: Tine.Tinebase.widgets.keyfield.Renderer.get('Crm', 'leadsources')
                             }]
                         }, {
                             flex: 1,
index 7377338..0869869 100644 (file)
@@ -84,7 +84,7 @@ Tine.Crm.LeadGridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
 
         this.gridConfig.cm = this.getColumnModel();
 
-        this.defaultFilters = [{field: 'leadstate_id', operator: 'notin', value: Tine.Crm.LeadState.getClosedStatus()}];
+        this.defaultFilters = [{field: 'leadstate_id', operator: 'notin', value: Tine.Crm.getEndedLeadStateIds()}];
 
         this.detailsPanel = new Tine.Crm.LeadGridDetailsPanel({
             grid: this
@@ -151,8 +151,8 @@ Tine.Crm.LeadGridPanel = Ext.extend(Tine.widgets.grid.GridPanel, {
                 {header: this.app.i18n._('Responsible'), id: 'lead_responsible', dataIndex: 'relations', width: 175, sortable: false, hidden: true, renderer: this.responsibleRenderer},
                 {header: this.app.i18n._('Partner'), id: 'lead_partner', dataIndex: 'relations', width: 175, sortable: false, renderer: this.partnerRenderer},
                 {header: this.app.i18n._('Customer'), id: 'lead_customer', dataIndex: 'relations', width: 175, sortable: false, renderer: this.customerRenderer},
-                {header: this.app.i18n._('Leadstate'), id: 'leadstate_id', dataIndex: 'leadstate_id', width: 100, renderer: Tine.Crm.LeadState.Renderer},
-                {header: this.app.i18n._('Leadsource'), id: 'leadsource_id', dataIndex: 'leadsource_id', width: 100, renderer: Tine.Crm.LeadSource.Renderer},
+                {header: this.app.i18n._('Leadstate'), id: 'leadstate_id', dataIndex: 'leadstate_id', width: 100, renderer: Tine.Tinebase.widgets.keyfield.Renderer.get('Crm', 'leadstates')},
+                {header: this.app.i18n._('Leadsource'), id: 'leadsource_id', dataIndex: 'leadsource_id', width: 100, renderer: Tine.Tinebase.widgets.keyfield.Renderer.get('Crm', 'leadsources')},
                 {header: this.app.i18n._('Probability'), id: 'probability', dataIndex: 'probability', width: 50, renderer: Ext.ux.PercentRenderer },
                 {header: this.app.i18n._('Turnover'), id: 'turnover', dataIndex: 'turnover', width: 100, renderer: Ext.util.Format.euMoney },
 
diff --git a/tine20/Crm/js/LeadSource.js b/tine20/Crm/js/LeadSource.js
deleted file mode 100644 (file)
index 8623b0f..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Tine 2.0
- * lead source edit dialog and model
- * 
- * @package     Crm
- * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
- * @author      Philipp Schuele <p.schuele@metaways.de>
- * @copyright   Copyright (c) 2007-2010 Metaways Infosystems GmbH (http://www.metaways.de)
- *
- */
-
-Ext.namespace('Tine.Crm', 'Tine.Crm.LeadSource');
-
-/**
- * @namespace Tine.Crm.LeadSource
- * @class Tine.Crm.LeadSource.Model
- * @extends Ext.data.Record
- * 
- * lead source model
- */ 
-Tine.Crm.LeadSource.Model = Tine.Tinebase.data.Record.create([
-    {name: 'id', type: 'int'},
-    {name: 'leadsource'},
-    {name: 'archived'}
-], {
-    appName: 'Crm',
-    modelName: 'LeadState',
-    idProperty: 'id',
-    titleProperty: 'leadsource',
-    // ngettext('Lead Source', 'Lead Sources', n);
-    recordName: 'Lead Source',
-    recordsName: 'Lead Sources'
-});
-
-/**
- * @namespace Tine.Crm.LeadSource
- * 
- * get default data for a new leadsource
- *  
- * @return {Object} default data
- * @static
- */ 
-Tine.Crm.LeadSource.Model.getDefaultData = function() {
-    
-    var data = {
-        id: Tine.Crm.Model.getRandomUnusedId(Ext.StoreMgr.get('CrmLeadSourceStore'))
-    };
-    
-    return data;
-};
-
-/**
- * lead source renderer
- *
- * @param   {Number} _leadsourceId
- * @return  {String} leadsource
- */
-Tine.Crm.LeadSource.Renderer = function(_leadsourceId) {
-    var leadsourceStore = Tine.Crm.LeadSource.getStore();
-    var record = leadsourceStore.getById(_leadsourceId);
-
-    if (record) {
-        return record.data.leadsource;
-    } else {
-        return Tine.Tinebase.appMgr.get('Crm').i18n._('undefined');
-    }
-};
-
-/**
- * get lead source store
- * if available, load data from LeadSources
- * 
- * @return {Ext.data.JsonStore}
- */
-Tine.Crm.LeadSource.getStore = function() {
-    
-    var store = Ext.StoreMgr.get('CrmLeadSourceStore');
-    if (!store) {
-
-        store = new Ext.data.JsonStore({
-            fields: Tine.Crm.LeadSource.Model,
-            baseParams: {
-                method: 'Crm.getLeadsources',
-                sort: 'LeadSource',
-                dir: 'ASC'
-            },
-            root: 'results',
-            totalProperty: 'totalcount',
-            id: 'id',
-            remoteSort: false
-        });
-        
-        if (Tine.Crm.registry.get('leadsources')) {
-            store.loadData(Tine.Crm.registry.get('leadsources'));
-        }
-
-        Ext.StoreMgr.add('CrmLeadSourceStore', store);
-    }
-    return store;
-};
-
-
-/**
- * @namespace   Tine.Crm.LeadSource
- * @class       Tine.Crm.LeadSource.GridPanel
- * @extends     Tine.Crm.Admin.QuickaddGridPanel
- * 
- * lead sources grid panel
- * 
- * <p>
- * </p>
- * 
- * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
- * @author      Philipp Schuele <p.schuele@metaways.de>
- * @copyright   Copyright (c) 2009 Metaways Infosystems GmbH (http://www.metaways.de)
- */
-Tine.Crm.LeadSource.GridPanel = Ext.extend(Tine.Crm.Admin.QuickaddGridPanel, {
-    
-    /**
-     * @private
-     */
-    autoExpandColumn:'leadsource',
-    quickaddMandatory: 'leadsource',
-
-    /**
-     * @private
-     */
-    initComponent: function() {
-        this.app = this.app ? this.app : Tine.Tinebase.appMgr.get('Crm');
-        
-        this.store = Tine.Crm.LeadSource.getStore();
-        this.recordClass = Tine.Crm.LeadSource.Model;
-        
-        Tine.Crm.LeadSource.GridPanel.superclass.initComponent.call(this);
-    },
-    
-    getColumnModel: function() {
-        return new Ext.grid.ColumnModel([
-        {
-            id:'leadsource_id', 
-            header: "id", 
-            dataIndex: 'id', 
-            width: 25, 
-            hidden: true 
-        }, {
-            id:'leadsource', 
-            header: 'entries', 
-            dataIndex: 'leadsource', 
-            width: 170, 
-            hideable: false, 
-            sortable: false, 
-            editor: new Ext.form.TextField({allowBlank: false}),
-            quickaddField: new Ext.form.TextField({
-                emptyText: this.app.i18n._('Add a Leadsource...')
-            })
-        }, {
-            header: this.app.i18n._('archived'),
-            id:'archived',
-            dataIndex: 'archived',
-            width: 70,
-            editor: new Ext.form.Checkbox({}),
-            quickaddField: new Ext.form.Checkbox({
-                name: 'archived'
-            }),
-            renderer: Tine.Tinebase.common.booleanRenderer
-        }]);
-    }
-});
diff --git a/tine20/Crm/js/LeadSourceFilterModel.js b/tine20/Crm/js/LeadSourceFilterModel.js
deleted file mode 100644 (file)
index c62b9e4..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Tine 2.0
- * 
- * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
- * @author      Michael Spahn <m.spahn@metaways.de>
- * @copyright   Copyright (c) 2014 Metaways Infosystems GmbH (http://www.metaways.de)
- */
-Ext.ns('Tine.Crm');
-
-/**
- * @namespace   Tine.Crm
- * @class       Tine.Crm.LeadSourceFilterModel
- * @extends     Tine.widgets.grid.FilterModel
- */
-Tine.Crm.LeadSourceFilterModel = Ext.extend(Tine.widgets.grid.FilterModel, {
-    /**
-     * @property Tine.Tinebase.Application app
-     */
-    app: null,
-    
-    field: 'leadsource_id',
-    defaultOperator: 'in',
-    
-    /**
-     * @private
-     */
-    initComponent: function() {
-        this.label = this.app.i18n._('Leadsource');
-        this.operators = ['in', 'notin'];
-
-        this.supr().initComponent.call(this);
-    },
-    
-    /**
-     * value renderer
-     * 
-     * @param {Ext.data.Record} filter line
-     * @param {Ext.Element} element to render to 
-     */
-    valueRenderer: function(filter, el) {
-        var value = new Tine.Crm.LeadSourceFilterModelValueField({
-            app: this.app,
-            filter: filter,
-            width: 350,
-            id: 'tw-ftb-frow-valuefield-' + filter.id,
-            value: filter.data.value ? filter.data.value : this.defaultValue,
-            renderTo: el
-        });
-        value.on('specialkey', function(field, e){
-             if(e.getKey() == e.ENTER){
-                 this.onFiltertrigger();
-             }
-        }, this);
-        value.on('select', this.onFiltertrigger, this);
-        
-        return value;
-    }
-});
-
-Tine.widgets.grid.FilterToolbar.FILTERS['crm.leadsource'] = Tine.Crm.LeadSourceFilterModel;
-
-/**
- * @namespace   Tine.Crm
- * @class       Tine.Crm.LeadSourceFilterModelValueField
- * @extends     Ext.ux.form.LayerCombo
- * 
- * @author      Cornelius Weiss <c.weiss@metaways.de>
- * @author      Michael Spahn <m.spahn@metaways.de>
- */
-Tine.Crm.LeadSourceFilterModelValueField = Ext.extend(Ext.ux.form.LayerCombo, {
-    hideButtons: false,
-    formConfig: {
-        labelAlign: 'left',
-        labelWidth: 30
-    },
-    
-    getFormValue: function() {
-        var ids = [];
-        var statusStore = Tine.Crm.LeadSource.getStore();
-        
-        var formValues = this.getInnerForm().getForm().getValues();
-        for (var id in formValues) {
-            if (formValues[id] === 'on' && statusStore.getById(id)) {
-                ids.push(id);
-            }
-        }
-        
-        return ids;
-    },
-
-    getItems: function() {
-        var items = [];
-        
-        Tine.Crm.LeadSource.getStore().each(function(status) {
-            items.push({
-                xtype: 'checkbox',
-                boxLabel: status.get('leadsource'),
-                icon: status.get('status_icon'),
-                name: status.get('id')
-            });
-        }, this);
-        
-        return items;
-    },
-    
-    /**
-     * @param {String} value
-     * @return {Ext.form.Field} this
-     */
-    setValue: function(value) {
-        value = Ext.isArray(value) ? value : [value];
-        
-        var statusStore = Tine.Crm.LeadSource.getStore();
-        var statusText = [];
-        this.currentValue = [];
-        
-        Tine.Crm.LeadSource.getStore().each(function(status) {
-            var id = status.get('id');
-            var name = status.get('leadsource');
-            Ext.each(value, function(valueId) {
-                // NOTE: no type match id's might be int or string and should match anyway!
-                if (valueId == id) {
-                    statusText.push(name);
-                    this.currentValue.push(id);
-                }
-            }, this);
-        }, this);
-        
-        this.setRawValue(statusText.join(', '));
-        
-        return this;
-    },
-    
-    /**
-     * sets values to innerForm
-     */
-    setFormValue: function(value) {
-        this.getInnerForm().getForm().items.each(function(item) {
-            item.setValue(value.indexOf(item.name) >= 0 ? 'on' : 'off');
-        }, this);
-    }
-});
diff --git a/tine20/Crm/js/LeadState.js b/tine20/Crm/js/LeadState.js
deleted file mode 100644 (file)
index 1b9993c..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Tine 2.0
- * lead state edit dialog and model
- * 
- * @package     Crm
- * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
- * @author      Cornelius Weiss <c.weiss@metaways.de>
- * @copyright   Copyright (c) 2007-2010 Metaways Infosystems GmbH (http://www.metaways.de)
- *
- * TODO         don't use json store anymore?
- */
-
-Ext.namespace('Tine.Crm', 'Tine.Crm.LeadState');
-
-/**
- * @namespace Tine.Crm.LeadState
- * @class Tine.Crm.LeadState.Model
- * @extends Ext.data.Record
- * 
- * lead state model
- */ 
-Tine.Crm.LeadState.Model = Tine.Tinebase.data.Record.create([
-    {name: 'id', type: 'int'},
-    {name: 'leadstate'},
-    {name: 'probability', type: 'int'},
-    {name: 'endslead', type: 'boolean'}
-], {
-    appName: 'Crm',
-    modelName: 'LeadState',
-    idProperty: 'id',
-    titleProperty: 'leadstate',
-    // ngettext('Lead State', 'Lead States', n);
-    recordName: 'Lead State',
-    recordsName: 'Lead States'
-});
-
-/**
- * @namespace Tine.Crm.LeadState
- * 
- * get default data for a new leadstate
- *  
- * @return {Object} default data
- * @static
- */ 
-Tine.Crm.LeadState.Model.getDefaultData = function() {
-    
-    var data = {
-        id: Tine.Crm.Model.getRandomUnusedId(Ext.StoreMgr.get('CrmLeadstateStore'))
-    };
-    
-    return data;
-};
-
-/**
- * get lead state store
- * if available, load data from Tine.Crm.registry.get('leadstates')
- *
- * @return {Ext.data.JsonStore}
- */
-Tine.Crm.LeadState.getStore = function() {
-    var store = Ext.StoreMgr.get('CrmLeadstateStore');
-    if (!store) {
-        // create store
-        store = new Ext.data.JsonStore({
-            fields: Tine.Crm.LeadState.Model,
-            baseParams: {
-                method: 'Crm.getLeadstates',
-                sort: 'leadstate',
-                dir: 'ASC'
-            },
-            root: 'results',
-            totalProperty: 'totalcount',
-            id: 'id',
-            remoteSort: false
-        });
-        
-        // check if initital data available
-        if (Tine.Crm.registry.get('leadstates')) {
-            store.loadData(Tine.Crm.registry.get('leadstates'));
-        }
-        
-        Ext.StoreMgr.add('CrmLeadstateStore', store);
-    }
-    return store;
-};
-
-Tine.Crm.LeadState.getClosedStatus = function() {
-    var reqStatus = [];
-        
-    Tine.Crm.LeadState.getStore().each(function(status) {
-        if (status.get('endslead')) {
-            reqStatus.push(status.get('id'));
-        }
-    }, this);
-    
-    return reqStatus;
-};
-/**
- * lead state renderer
- * 
- * @param   {Number} _leadstateId
- * @return  {String} leadstate
- */
-Tine.Crm.LeadState.Renderer = function(_leadstateId) {
-    leadstateStore = Tine.Crm.LeadState.getStore();
-    record = leadstateStore.getById(_leadstateId);
-    
-    if (record) {
-       return record.data.leadstate;
-    } else {
-        return Tine.Tinebase.appMgr.get('Crm').i18n._('undefined');
-    }
-};
-
-/**
- * @namespace   Tine.Crm.LeadState
- * @class       Tine.Crm.LeadState.GridPanel
- * @extends     Tine.Crm.Admin.QuickaddGridPanel
- * 
- * lead states grid panel
- * 
- * <p>
- * </p>
- * 
- * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
- * @author      Philipp Schuele <p.schuele@metaways.de>
- * @copyright   Copyright (c) 2009 Metaways Infosystems GmbH (http://www.metaways.de)
- */
-Tine.Crm.LeadState.GridPanel = Ext.extend(Tine.Crm.Admin.QuickaddGridPanel, {
-    
-    /**
-     * @private
-     */
-    autoExpandColumn:'leadstate',
-    quickaddMandatory: 'leadstate',
-
-    /**
-     * @private
-     */
-    initComponent: function() {
-        this.app = this.app ? this.app : Tine.Tinebase.appMgr.get('Crm');
-        
-        this.store = Tine.Crm.LeadState.getStore();
-        this.recordClass = Tine.Crm.LeadState.Model;
-        this.cm = this.getColumnModel();
-        
-        Tine.Crm.LeadState.GridPanel.superclass.initComponent.call(this);
-    },
-    
-    getColumnModel: function() {
-        return new Ext.grid.ColumnModel([
-        {
-            id:'leadstate_id', 
-            header: 'id', 
-            dataIndex: 'id', 
-            width: 25, 
-            hidden: true 
-        }, {
-            id:'leadstate', 
-            header: 'entries', 
-            dataIndex: 'leadstate', 
-            width: 170, 
-            hideable: false, 
-            sortable: false,
-            quickaddField: new Ext.form.TextField({
-                emptyText: this.app.i18n._('Add a Leadstate...')
-            }),
-            editor: new Ext.form.TextField({allowBlank: false}) 
-        }, {
-            id:'probability', 
-            header: 'probability', 
-            dataIndex: 'probability', 
-            width: 100, 
-            hideable: false, 
-            sortable: false, 
-            renderer: Ext.util.Format.percentage,
-            editor: new Ext.ux.PercentCombo({
-                name: 'probability',
-                id: 'probability'
-            }),
-            quickaddField: new Ext.ux.PercentCombo({
-                autoExpand: true
-            })
-        }, {
-            header: "X Lead?",
-            id:'endslead',
-            dataIndex: 'endslead',
-            width: 50,
-            editor: new Ext.form.Checkbox({}),
-            quickaddField: new Ext.form.Checkbox({
-                name: 'endslead'
-            }),
-            renderer: Tine.Tinebase.common.booleanRenderer
-        }]);
-    }
-});
diff --git a/tine20/Crm/js/LeadStateFilterModel.js b/tine20/Crm/js/LeadStateFilterModel.js
deleted file mode 100644 (file)
index 479220f..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Tine 2.0
- * 
- * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
- * @author      Cornelius Weiss <c.weiss@metaways.de>
- * @copyright   Copyright (c) 2010 Metaways Infosystems GmbH (http://www.metaways.de)
- */
-Ext.ns('Tine.Crm');
-
-/**
- * @namespace   Tine.Crm
- * @class       Tine.Crm.LeadStateFilterModel
- * @extends     Tine.widgets.grid.FilterModel
- * 
- * @author      Cornelius Weiss <c.weiss@metaways.de>
- * 
- * TODO         use keyfield filter when lead state is a keyfield config
- */
-Tine.Crm.LeadStateFilterModel = Ext.extend(Tine.widgets.grid.FilterModel, {
-    /**
-     * @property Tine.Tinebase.Application app
-     */
-    app: null,
-    
-    field: 'leadstate_id',
-    defaultOperator: 'notin',
-    
-    /**
-     * @private
-     */
-    initComponent: function() {
-        this.label = this.app.i18n._('Leadstate');
-        this.operators = [/*'showClosed',*/ 'in', 'notin'];
-        
-        /*
-        this.customOperators = [
-            {operator: 'showClosed',   label: this.app.i18n._('Show closed')}
-        ];
-        */
-        
-        this.defaultValue = Tine.Crm.LeadState.getClosedStatus();
-        
-        this.supr().initComponent.call(this);
-    },
-    
-    /**
-     * value renderer
-     * 
-     * @param {Ext.data.Record} filter line
-     * @param {Ext.Element} element to render to 
-     */
-    valueRenderer: function(filter, el) {
-        var value = new Tine.Crm.LeadStateFilterModelValueField({
-            app: this.app,
-            filter: filter,
-            width: 350,
-            id: 'tw-ftb-frow-valuefield-' + filter.id,
-            value: filter.data.value ? filter.data.value : this.defaultValue,
-            renderTo: el
-        });
-        value.on('specialkey', function(field, e){
-             if(e.getKey() == e.ENTER){
-                 this.onFiltertrigger();
-             }
-        }, this);
-        value.on('select', this.onFiltertrigger, this);
-        
-        return value;
-    }
-});
-
-Tine.widgets.grid.FilterToolbar.FILTERS['crm.leadstate'] = Tine.Crm.LeadStateFilterModel;
-
-/**
- * @namespace   Tine.Crm
- * @class       Tine.Crm.LeadStateFilterModelValueField
- * @extends     Ext.ux.form.LayerCombo
- * 
- * @author      Cornelius Weiss <c.weiss@metaways.de>
- */
-Tine.Crm.LeadStateFilterModelValueField = Ext.extend(Ext.ux.form.LayerCombo, {
-    hideButtons: false,
-    formConfig: {
-        labelAlign: 'left',
-        labelWidth: 30
-    },
-    
-    getFormValue: function() {
-        var ids = [];
-        var statusStore = Tine.Crm.LeadState.getStore();
-        
-        var formValues = this.getInnerForm().getForm().getValues();
-        for (var id in formValues) {
-            if (formValues[id] === 'on' && statusStore.getById(id)) {
-                ids.push(id);
-            }
-        }
-        
-        return ids;
-    },
-    
-    getItems: function() {
-        var items = [];
-        
-        Tine.Crm.LeadState.getStore().each(function(status) {
-            items.push({
-                xtype: 'checkbox',
-                boxLabel: status.get('leadstate'),
-                icon: status.get('status_icon'),
-                name: status.get('id')
-            });
-        }, this);
-        
-        return items;
-    },
-    
-    /**
-     * @param {String} value
-     * @return {Ext.form.Field} this
-     */
-    setValue: function(value) {
-        value = Ext.isArray(value) ? value : [value];
-        
-        var statusStore = Tine.Crm.LeadState.getStore();
-        var statusText = [];
-        this.currentValue = [];
-        
-        Tine.Crm.LeadState.getStore().each(function(status) {
-            var id = status.get('id');
-            var name = status.get('leadstate');
-            Ext.each(value, function(valueId) {
-                // NOTE: no type match id's might be int or string and should match anyway!
-                if (valueId == id) {
-                    statusText.push(name);
-                    this.currentValue.push(id);
-                }
-            }, this);
-        }, this);
-        
-        this.setRawValue(statusText.join(', '));
-        
-        return this;
-    },
-    
-    /**
-     * sets values to innerForm
-     */
-    setFormValue: function(value) {
-        this.getInnerForm().getForm().items.each(function(item) {
-            item.setValue(value.indexOf(item.name) >= 0 ? 'on' : 'off');
-        }, this);
-    }
-});
diff --git a/tine20/Crm/js/LeadType.js b/tine20/Crm/js/LeadType.js
deleted file mode 100644 (file)
index c205847..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Tine 2.0
- * lead type edit dialog and model
- * 
- * @package     Crm
- * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
- * @author      Philipp Schuele <p.schuele@metaways.de>
- * @copyright   Copyright (c) 2007-2010 Metaways Infosystems GmbH (http://www.metaways.de)
- *
- */
-
-Ext.namespace('Tine.Crm', 'Tine.Crm.LeadType');
-
-/**
- * @namespace Tine.Crm.LeadType
- * @class Tine.Crm.LeadType.Model
- * @extends Ext.data.Record
- * 
- * lead type model
- */ 
-Tine.Crm.LeadType.Model = Tine.Tinebase.data.Record.create([
-   {name: 'id', type: 'int'},
-   {name: 'leadtype'}
-], {
-    appName: 'Crm',
-    modelName: 'LeadType',
-    idProperty: 'id',
-    titleProperty: 'leadtype',
-    // ngettext('Lead Type', 'Lead Types', n);
-    recordName: 'Lead Type',
-    recordsName: 'Lead Types'
-});
-
-/**
- * @namespace Tine.Crm.LeadType
- * 
- * get default data for a new leadtype
- *  
- * @return {Object} default data
- * @static
- */ 
-Tine.Crm.LeadType.Model.getDefaultData = function() {
-    
-    var data = {
-        id: Tine.Crm.Model.getRandomUnusedId(Ext.StoreMgr.get('CrmLeadTypeStore'))
-    };
-    
-    return data;
-};
-
-/**
- * get lead type store
- * 
- * @return  {Ext.data.JsonStore}
- */
-Tine.Crm.LeadType.getStore = function() {
-    
-    var store = Ext.StoreMgr.get('CrmLeadTypeStore');
-    if (!store) {
-
-        store = new Ext.data.JsonStore({
-            fields: Tine.Crm.LeadType.Model,
-            baseParams: {
-                method: 'Crm.getLeadtypes',
-                sort: 'LeadType',
-                dir: 'ASC'
-            },
-            root: 'results',
-            totalProperty: 'totalcount',
-            id: 'id',
-            remoteSort: false
-        });
-        
-        if ( Tine.Crm.registry.get('leadtypes') ) {
-            store.loadData(Tine.Crm.registry.get('leadtypes'));
-        }
-            
-        Ext.StoreMgr.add('CrmLeadTypeStore', store);
-    }
-    return store;
-};
-
-/**
- * @namespace   Tine.Crm.LeadType
- * @class       Tine.Crm.LeadType.GridPanel
- * @extends     Tine.Crm.Admin.QuickaddGridPanel
- * 
- * lead types grid panel
- * 
- * <p>
- * </p>
- * 
- * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
- * @author      Philipp Schuele <p.schuele@metaways.de>
- * @copyright   Copyright (c) 2009 Metaways Infosystems GmbH (http://www.metaways.de)
- */
-Tine.Crm.LeadType.GridPanel = Ext.extend(Tine.Crm.Admin.QuickaddGridPanel, {
-    
-    /**
-     * @private
-     */
-    autoExpandColumn:'leadtype',
-    quickaddMandatory: 'leadtype',
-
-    /**
-     * @private
-     */
-    initComponent: function() {
-        this.app = this.app ? this.app : Tine.Tinebase.appMgr.get('Crm');
-        
-        this.store = Tine.Crm.LeadType.getStore();
-        this.recordClass = Tine.Crm.LeadType.Model;
-        
-        Tine.Crm.LeadType.GridPanel.superclass.initComponent.call(this);
-    },
-    
-    getColumnModel: function() {
-        return new Ext.grid.ColumnModel([
-        {
-            id:'leadtype_id', 
-            header: "id", 
-            dataIndex: 'id', 
-            width: 25, 
-            hidden: true 
-        }, {
-            id:'leadtype', 
-            header: 'entries', 
-            dataIndex: 'leadtype', 
-            width: 170, 
-            hideable: false, 
-            sortable: false, 
-            editor: new Ext.form.TextField({allowBlank: false}),
-            quickaddField: new Ext.form.TextField({
-                emptyText: this.app.i18n._('Add a Leadtype...')
-            })
-        }]);
-    }
-});
index 3a4bacc..fb9f627 100644 (file)
@@ -68,19 +68,14 @@ Tine.Crm.Model.Lead = Tine.Tinebase.data.Record.create(Tine.Tinebase.Model.gener
  *  
  * @return {Object} default data
  * @static
- * 
- * TODO generalize default container id handling?
- */ 
+ */
 Tine.Crm.Model.Lead.getDefaultData = function() {
     
-    var defaults = Tine.Crm.registry.get('defaults');
     var app = Tine.Tinebase.appMgr.get('Crm');
     
     var data = {
         start: new Date().clearTime(),
-        leadstate_id: defaults.leadstate_id,
-        leadtype_id: defaults.leadtype_id,
-        container_id: app.getMainScreen().getWestPanel().getContainerTreePanel().getSelectedContainer('addGrant', defaults.container_id),
+        container_id: app.getMainScreen().getWestPanel().getContainerTreePanel().getDefaultContainer(),
         probability: 0,
         turnover: 0,
         relations: [{
@@ -105,9 +100,21 @@ Tine.Crm.Model.Lead.getFilterModel = function() {
             {label: _('Quick Search'),  field: 'query',    operators: ['contains']},
             {filtertype: 'tine.widget.container.filtermodel', app: app, recordClass: Tine.Crm.Model.Lead},
             {label: app.i18n._('Lead name'),   field: 'lead_name' },
-            {filtertype: 'crm.leadstate', app: app},
+            {
+                label: app.i18n._('Leadstate'),
+                field: 'leadstate_id',
+                filtertype: 'tine.widget.keyfield.filter',
+                app: app,
+                keyfieldName: 'leadstates'
+            },
             {label: app.i18n._('Probability'), field: 'probability', valueType: 'percentage'},
-            {filtertype: 'crm.leadsource', app: app},
+            {
+                label: app.i18n._('Leadsource'),
+                field: 'leadsource_id',
+                filtertype: 'tine.widget.keyfield.filter',
+                app: app,
+                keyfieldName: 'leadsources'
+            },
             {label: app.i18n._('Turnover'),    field: 'turnover', valueType: 'number', defaultOperator: 'greater'},
             {filtertype: 'tinebase.tag', app: app},
             {label: _('Last Modified Time'),                                                field: 'last_modified_time', valueType: 'date'},
@@ -133,37 +140,31 @@ Tine.Crm.Model.Lead.getFilterModel = function() {
     return filters;
 }
 
-/**
- * @namespace Tine.Crm.Model
- * @class Tine.Crm.Model.Settings
- * @extends Tine.Tinebase.data.Record
- * 
- * Settings Record Definition
- * 
- * TODO         generalize this
- */ 
-Tine.Crm.Model.Settings = Tine.Tinebase.data.Record.create([
-        {name: 'id'},
-        {name: 'defaults'},
-        {name: 'leadstates'},
-        {name: 'leadtypes'},
-        {name: 'leadsources'},
-        {name: 'default_leadstate_id',  type: 'int'},
-        {name: 'default_leadtype_id',   type: 'int'},
-    ], {
+// custom keyFieldRecord
+Tine.Crm.Model.LeadState = Tine.Tinebase.data.Record.create([
+    { name: 'id' },
+    { name: 'value' },
+    { name: 'system' },
+    { name: 'probability', label: 'Probability', type: 'percentage' }, // _('Probability')
+    { name: 'endslead', label: 'X Lead', type: 'bool'} // _('X Lead')
+], {
     appName: 'Crm',
-    modelName: 'Settings',
+    modelName: 'LeadState',
     idProperty: 'id',
-    titleProperty: 'title',
-    // ngettext('Settings', 'Settings', n);
-    recordName: 'Settings',
-    recordsName: 'Settingss',
-    // ngettext('record list', 'record lists', n);
-    containerName: 'Settings',
-    containersName: 'Settings',
-    getTitle: function() {
-        return this.recordName;
-    }
+    titleProperty: 'value'
+});
+
+// custom keyFieldRecord
+Tine.Crm.Model.LeadSource = Tine.Tinebase.data.Record.create([
+    { name: 'id' },
+    { name: 'value' },
+    { name: 'system' },
+    { name: 'archived', label: 'Archived', type: 'bool' } // _('Archived')
+], {
+    appName: 'Crm',
+    modelName: 'LeadSource',
+    idProperty: 'id',
+    titleProperty: 'value'
 });
 
 Tine.Crm.Model.getRandomUnusedId = function(store) {
index a7576d0..834e065 100644 (file)
@@ -52,8 +52,7 @@ Tine.Projects.Model.Project = Tine.Tinebase.data.Record.create(Tine.Tinebase.Mod
  */ 
 Tine.Projects.Model.Project.getDefaultData = function() {
     var app = Tine.Tinebase.appMgr.get('Projects');
-    var defaultsContainer = Tine.Projects.registry.get('defaultContainer');
-    
+
     return {
         container_id: app.getMainScreen().getWestPanel().getContainerTreePanel().getDefaultContainer(),
         status: 'IN-PROCESS'
index 3c8051a..e80f7e2 100644 (file)
@@ -652,10 +652,11 @@ abstract class Tinebase_Config_Abstract
             case self::TYPE_FLOAT:      return (float) $_rawData;
             case self::TYPE_ARRAY:      return (array) $_rawData;
             case self::TYPE_DATETIME:   return new DateTime($_rawData);
-            case self::TYPE_KEYFIELD_CONFIG:   return Tinebase_Config_KeyField::create(
-                $_rawData,
-                (isset($definition['options']) || array_key_exists('options', $definition)) ? (array) $definition['options'] : array()
-            );
+            case self::TYPE_KEYFIELD_CONFIG:
+                $options = (isset($definition['options']) || array_key_exists('options', $definition)) ? (array) $definition['options'] : array();
+                $options['appName'] = $this->_appName;
+                return Tinebase_Config_KeyField::create($_rawData, $options);
+
             default:                    return is_array($_rawData) ? new Tinebase_Config_Struct($_rawData) : $_rawData;
         }
     }
index 901f0be..d53c068 100644 (file)
 class Tinebase_Config_KeyField extends Tinebase_Record_Abstract
 {
     /**
+     * appname this keyfield belongs to
+     *
+     * @var string
+     */
+    protected $_appName = null;
+
+    /**
      * classname of the key fields record model
      * 
      * @var string
      */
     protected $_keyFieldRecordModel = 'Tinebase_Config_KeyFieldRecord';
-    
+
     /**
      * (non-PHPdoc)
      * @see tine20/Tinebase/Record/Abstract::$_identifier
@@ -49,10 +56,13 @@ class Tinebase_Config_KeyField extends Tinebase_Record_Abstract
     public static function create($_data, array $_options = array())
     {
         $record = new self();
+        if (isset($_options['appName'])) {
+            $record->setAppName($_options['appName']);
+        }
         if (isset($_options['recordModel'])) {
             $record->setKeyFieldRecordModel($_options['recordModel']);
         }
-        
+
         $record->setFromArray($_data);
         return $record;
     }
@@ -78,6 +88,20 @@ class Tinebase_Config_KeyField extends Tinebase_Record_Abstract
      */
     public function setKeyFieldRecordModel($_keyFieldRecordModel) {
         $this->_keyFieldRecordModel = $_keyFieldRecordModel;
+
+        return $this;
+    }
+
+    /**
+     * set appName
+     *
+     * @param  string $_appName
+     * @return Tinebase_Config_KeyField $this
+     */
+    public function setAppName($_appName) {
+        $this->_appName = $_appName;
+
+        return $this;
     }
     
     /**
@@ -104,4 +128,61 @@ class Tinebase_Config_KeyField extends Tinebase_Record_Abstract
         }
         return '';
     }
+
+    /**
+     * get value of given id
+     *
+     * @param $id
+     * @return string
+     */
+    public function getValue($id)
+    {
+        $record = $this->records->filter('id', $id)->getFirstRecord();
+        if (! $record) {
+            $record = $this->getKeyfieldDefault();
+        }
+
+        return $record ? $record->value : '';
+    }
+
+    /**
+     * get translated value of given id
+     *
+     * @param $id
+     * @return string
+     */
+    public function getTranslatedValue($id)
+    {
+        $value = $this->getValue($id);
+        if ($value) {
+            $translate = Tinebase_Translation::getTranslation($this->_appName);
+            return $translate->_($value);
+        }
+
+        return '';
+    }
+
+    /**
+     * get keyfield record id for given translated value
+     *
+     * @TODO try all locales
+     *
+     * @param $translatedValue
+     * @return string|null
+     */
+    public function getIdByTranslatedValue($translatedValue)
+    {
+        $translate = Tinebase_Translation::getTranslation($this->_appName);
+        $originRecord = null;
+
+        foreach ($this->records as $record) {
+            // check id & translated value
+            if (in_array($translatedValue, array($translate->_($record->value), $record->getId()))) {
+                $originRecord = $record;
+                break;
+            }
+        }
+
+        return $originRecord ? $originRecord->getId() : null;
+    }
 }
\ No newline at end of file
index f5e143e..18addca 100644 (file)
@@ -506,3 +506,17 @@ Tine.Tinebase.Model.Node = Tine.Tinebase.data.Record.create(Tine.Tinebase.Model.
     recordName: 'File',
     recordsName: 'Files'
 });
+
+Tine.Tinebase.Model.KeyFieldRecord = Tine.Tinebase.data.Record.create([
+    { name: 'id' },
+    { name: 'value' },
+    { name: 'i18nValue' },
+    { name: 'icon' },
+    { name: 'color' },
+    { name: 'system' }
+], {
+    appName: 'Tinebase',
+    modelName: 'KeyFieldRecord',
+    idProperty: 'id',
+    titleProperty: 'value'
+});
index 1b98a74..90d349e 100644 (file)
@@ -503,6 +503,8 @@ Ext.form.TriggerField.prototype.taskForFocusFix.delay(1000);
 // Ext.Layer.prototype.showAction = Ext.Layer.prototype.showAction.createSequence(function() {
 // Ext.Layer.prototype.hideAction = Ext.Layer.prototype.hideAction.createSequence(function() {
 Ext.form.ComboBox.prototype.expand = Ext.form.ComboBox.prototype.expand.createSequence(function() {
+    // fix z-index problem when used in editorGrids
+    // manage z-index by windowMgr
     this.list.setActive = Ext.emptyFn;
     this.list.setZIndex = Ext.emptyFn;
     Ext.WindowMgr.register(this.list);
index fc1031c..85ffaad 100644 (file)
@@ -9,6 +9,8 @@ Ext.ns('Tine.Tinebase.widgets.keyfield');
 
 /**
  * quickadd grid panel
+ *
+ * @TODO: add extra options hasColor, hasIcon, hasStandard?
  * 
  * @namespace   Tine.Tinebase.widgets.keyfield
  * @class       Tine.Tinebase.widgets.keyfield.ConfigGrid
@@ -44,14 +46,17 @@ Tine.Tinebase.widgets.keyfield.ConfigGrid = Ext.extend(Tine.widgets.grid.Quickad
         if (this.configRecord) {
             // used withing config system
             this.keyFieldOptions = this.configRecord.get('options') || {};
+            this.configApp = Tine.Tinebase.appMgr.getById(this.configRecord.get('application_Id'));
         } else {
             // defaults
             this.keyFieldOptions = {
-                recordModel : 'Tinebase_Config_KeyFieldRecord'
+                recordModel : 'Tinebase_Model_KeyFieldRecord'
             }
         }
 
         this.keyFieldConfig = {};
+        this.configGettext = this.configApp ? this.configApp.i18n._ : _;
+        this.initStore();
 
         this.defaultCheck = new Ext.ux.grid.CheckColumn({
             id: 'default',
@@ -63,8 +68,6 @@ Tine.Tinebase.widgets.keyfield.ConfigGrid = Ext.extend(Tine.widgets.grid.Quickad
         });
         this.plugins = [this.defaultCheck];
 
-        this.initStore();
-
         Tine.Tinebase.widgets.keyfield.ConfigGrid.superclass.initComponent.call(this);
 
         this.getSelectionModel().on('selectionchange', function(sm) {
@@ -82,17 +85,23 @@ Tine.Tinebase.widgets.keyfield.ConfigGrid = Ext.extend(Tine.widgets.grid.Quickad
 
     /**
      * init keyfield store
+     *
+     * for "normal" keyFields we could work on the default store (client side)
+     * this way the client dosn't need a client reload
+     *
+     *
      */
     initStore: function() {
-        var storeEntry = Ext.data.Record.create([
-            {name: 'default'},
-            {name: 'id'},
-            {name: 'value'},
-            {name: 'color'}
-        ]);
-        this.recordClass = storeEntry;
+        var recordClass = Tine.Tinebase.data.RecordMgr.get(this.keyFieldOptions.recordModel) || Tine.Tinebase.Model.KeyFieldRecord,
+            fields = [].concat(recordClass.getFieldDefinitions());
+
+        // add default field
+        fields.unshift({name: 'default'});
+
+        this.recordClass = Tine.Tinebase.data.Record.create(fields, {});
+
         this.store = new Ext.data.Store({
-            reader: new Ext.data.ArrayReader({idIndex: 0}, storeEntry),
+            reader: new Ext.data.ArrayReader({idIndex: 0}, this.recordClass),
             listeners: {
                 scope: this,
                 'update': function (store, rec, operation) {
@@ -126,39 +135,96 @@ Tine.Tinebase.widgets.keyfield.ConfigGrid = Ext.extend(Tine.widgets.grid.Quickad
      * @returns {Ext.grid.ColumnModel}
      */
     getColumnModel: function () {
-        return new Ext.grid.ColumnModel([
-            this.defaultCheck,
-            {
-                id: 'id',
-                header: _('ID'),
-                dataIndex: 'id',
-                hideable: false,
-                sortable: false,
-                editor: new Ext.form.TextField({}),
-                quickaddField: new Ext.form.TextField({
-                    emptyText: _('Add a New ID...')
-                })
-            }, {
-                id: 'value',
-                header: _('Value'),
-                dataIndex: 'value',
-                hideable: false,
-                sortable: false,
-                editor: new Ext.form.TextField({}),
-                quickaddField: new Ext.form.TextField({
-                    emptyText: _('Add a New Value...')
-                })
-
-            }, {
-                id: 'color',
-                header: _('Color'),
-                dataIndex: 'color',
-                sortable: false,
-                width: 50,
-                editor: new Ext.ux.form.ColorField({}),
-                renderer: Tine.Tinebase.common.colorRenderer
+        var fields = this.recordClass.getFieldDefinitions(),
+            cols = [
+                this.defaultCheck,
+                {
+                    id: 'id',
+                    header: _('ID'),
+                    dataIndex: 'id',
+                    hideable: false,
+                    sortable: false,
+                    editor: new Ext.form.TextField({}),
+                    quickaddField: new Ext.form.TextField({
+                        emptyText: _('Add a New ID...')
+                    })
+                }, {
+                    id: 'value',
+                    header: _('Value'),
+                    dataIndex: 'value',
+                    hideable: false,
+                    sortable: false,
+                    editor: new Ext.form.TextField({}),
+                    quickaddField: new Ext.form.TextField({
+                        emptyText: _('Add a New Value...')
+                    })
+
+                }
+            ];
+
+        Ext.each(fields, function(field) {
+            if (['default', 'id', 'value', 'i18nValue', 'system'].indexOf(field.name) == -1) {
+                switch (field.name) {
+                    case 'color':
+                        cols.push({
+                            id: 'color',
+                            header: _('Color'),
+                            dataIndex: 'color',
+                            sortable: false,
+                            width: 50,
+                            editor: new Ext.ux.form.ColorField({}),
+                            renderer: Tine.Tinebase.common.colorRenderer
+                        });
+                        break;
+                    case 'icon':
+                        // not supported yet
+                        break;
+                    default:
+                        cols.push(this.getColumn(field));
+                        break;
+                }
             }
-        ]);
+        }, this);
+
+        return new Ext.grid.ColumnModel(cols);
+    },
+
+    getColumn: function(field) {
+        var col = {
+            id: field.name,
+            header: field.label ? this.configGettext(field.label) : field.name,
+            dataIndex: field.name,
+            sortable: false,
+            width: field.uiConfig && field.uiConfig.width ? field.uiConfig.width : 50
+        };
+
+        switch (field.type) {
+            case 'bool':
+                Ext.applyIf(col, {
+                    align: 'center',
+                    width: 55
+                });
+                col = new Ext.ux.grid.CheckColumn(col);
+                this.plugins.push(col);
+                break;
+            case 'percentage':
+                Ext.applyIf(col, {
+                    renderer: Ext.ux.PercentRenderer,
+                    editor: new Ext.ux.PercentCombo({
+                        autoExpand: true,
+                        blurOnSelect: true
+                    }),
+                    quickaddField: new Ext.ux.PercentCombo({
+                        autoExpand: true
+                    })
+                });
+                break;
+            default:
+                col.editor = new Ext.form.TextField({});
+                break;
+        }
+
+        return col;
     },
 
     onBeforeValueEdit: function(o) {
index 07cc9a3..13de35d 100644 (file)
@@ -41,12 +41,16 @@ Tine.Tinebase.widgets.keyfield.Store = function(config) {
                     && config.keyFieldConfig.definition.options
                     && config.keyFieldConfig.definition.options.recordModel ?
                         config.keyFieldConfig.definition.options.recordModel :
-                        "Tinebase_Config_KeyFieldRecord",
-        modelParts = modelName.split('_Model_'),
-        recordClass = Tine[modelParts[0]] && Tine[modelParts[0]]['Model'] && Tine[modelParts[0]]['Model'][modelParts[1]] ? Tine[modelParts[0]]['Model'][modelParts[1]] : null;
-    
-    config.fields = recordClass ? recordClass : ['id', 'value', 'icon', 'system', 'i18nValue'];
-    
+                        "Tinebase_Model_KeyFieldRecord",
+        recordClass = Tine.Tinebase.data.RecordMgr.get(modelName) || Tine.Tinebase.Model.KeyFieldRecord,
+        fields = [].concat(recordClass.getFieldDefinitions());
+
+    // add 'virtual' field
+    fields.push({name: 'i18nValue'});
+    this.recordClass = Ext.data.Record.create(fields);
+
+    config.fields = this.recordClass;
+
     Tine.Tinebase.widgets.keyfield.Store.superclass.constructor.call(this, config);
 };