diff --git a/include/class.dept.php b/include/class.dept.php
index d12216f5611f26a26ac2c22c814b1f6e82cfb029..fe217a9759c9e849fe776b0d2f0b1e112cd1f853 100644
--- a/include/class.dept.php
+++ b/include/class.dept.php
@@ -14,56 +14,40 @@
     vim: expandtab sw=4 ts=4 sts=4:
 **********************************************************************/
 
-class Dept implements Translatable {
+class Dept extends VerySimpleModel {
+
+    static $meta = array(
+        'table' => DEPT_TABLE,
+        'pk' => array('dept_id'),
+        'joins' => array(
+            'sla' => array(
+                'constraint' => array('sla_id' => 'SLA.sla_id'),
+                'null' => true,
+            ),
+            'manager' => array(
+                'constraint' => array('manager_id' => 'StaffModel.staff_id'),
+            ),
+            'groups' => array(
+                'reverse' => 'GroupDeptAccess.dept'
+            ),
+        ),
+    );
 
-    var $id;
-
-    var $email;
-    var $sla;
-    var $manager;
     var $members;
-    var $groups;
+    var $config;
 
-    var $ht;
+    var $template;
+    var $email;
+    var $autorespEmail;
 
     const ALERTS_DISABLED = 2;
     const ALERTS_DEPT_AND_GROUPS = 1;
     const ALERTS_DEPT_ONLY = 0;
 
-    function Dept($id) {
-        $this->id=0;
-        $this->load($id);
-    }
-
-    function load($id=0) {
-        global $cfg;
-
-        if(!$id && !($id=$this->getId()))
-            return false;
-
-        $sql='SELECT dept.*,dept.dept_id as id,dept.dept_name as name, dept.dept_signature as signature, count(staff.staff_id) as users '
-            .' FROM '.DEPT_TABLE.' dept '
-            .' LEFT JOIN '.STAFF_TABLE.' staff ON (dept.dept_id=staff.dept_id) '
-            .' WHERE dept.dept_id='.db_input($id)
-            .' GROUP BY dept.dept_id';
-
-        if(!($res=db_query($sql)) || !db_num_rows($res))
-            return false;
-
-
-
-        $this->ht=db_fetch_array($res);
-        $this->id=$this->ht['dept_id'];
-        $this->email=$this->sla=$this->manager=null;
-        $this->getEmail(); //Auto load email struct.
-        $this->config = new Config('dept.'.$this->id);
-        $this->members=$this->groups=array();
-
-        return true;
-    }
-
-    function reload() {
-        return $this->load();
+    function getConfig() {
+        if (!isset($this->config))
+            $this->config = new Config('dept.'. $this->getId());
+        return $this->config;
     }
 
     function asVar() {
@@ -71,27 +55,27 @@ class Dept implements Translatable {
     }
 
     function getId() {
-        return $this->id;
+        return $this->dept_id;
     }
 
     function getName() {
-        return $this->ht['name'];
+        return $this->dept_name;
     }
 
     function getLocalName($locale=false) {
-        return CustomDataTranslation::translate($this->getTranslationTag(), $locale);
+        $tag = $this->getTranslateTag();
+        $T = CustomDataTranslation::translate($tag);
+        return $T != $tag ? $T : $this->dept_name;
     }
-    function getTranslationTag() {
+    function getTranslateTag() {
         return _H('dept.name.' . $this->getId());
     }
 
     function getEmailId() {
-        return $this->ht['email_id'];
+        return $this->email_id;
     }
 
     function getEmail() {
-        global $cfg;
-
         if(!$this->email)
             if(!($this->email = Email::lookup($this->getEmailId())) && $cfg)
                 $this->email = $cfg->getDefaultEmail();
@@ -99,54 +83,36 @@ class Dept implements Translatable {
         return $this->email;
     }
 
-    function getNumStaff() {
-        return $this->ht['users'];
-    }
-
-
-    function getNumUsers() {
-        return $this->getNumStaff();
-    }
-
     function getNumMembers() {
         return count($this->getMembers());
     }
 
     function getMembers($criteria=null) {
-
-        if(!$this->members || $criteria) {
-            $members = array();
-            $sql='SELECT DISTINCT s.staff_id FROM '.STAFF_TABLE.' s '
-                .' LEFT JOIN '.GROUP_TABLE.' g ON (g.group_id=s.group_id) '
-                .' LEFT JOIN '.GROUP_DEPT_TABLE.' gd ON(s.group_id=gd.group_id) '
-                .' INNER JOIN '.DEPT_TABLE.' d
-                       ON ( d.dept_id=s.dept_id
-                            OR d.manager_id=s.staff_id
-                            OR (d.dept_id=gd.dept_id AND d.group_membership='.
-                                self::ALERTS_DEPT_AND_GROUPS.')
-                        ) '
-                .' WHERE d.dept_id='.db_input($this->getId());
+        if (!$this->members || $criteria) {
+            $members = StaffModel::objects()
+                ->filter(Q::any(array(
+                    'dept_id' => $this->getId(),
+                    new Q(array(
+                        'group__depts__dept_id' => $this->getId(),
+                        'group__depts__group_membership' => self::ALERTS_DEPT_AND_GROUPS,
+                    )),
+                    'staff_id' => $this->manager_id
+                )));
 
             if ($criteria && $criteria['available'])
-                $sql .= ' AND
-                        ( g.group_enabled=1
-                          AND s.isactive=1
-                          AND s.onvacation=0 ) ';
+                $members->filter(array(
+                    'group__group_enabled' => 1,
+                    'isactive' => 1,
+                    'onvacation' => 0,
+                ));
 
-            $sql.=' ORDER BY s.lastname, s.firstname';
-
-            if(($res=db_query($sql)) && db_num_rows($res)) {
-                while(list($id)=db_fetch_row($res))
-                    $members[$id] = Staff::lookup($id);
-            }
+            $qs->order_by('lastname', 'firstname');
 
             if ($criteria)
-                return $members;
-
-            $this->members = $members;
+                return $qs->all();
 
+            $this->members = $qs->all();
         }
-
         return $this->members;
     }
 
@@ -166,19 +132,15 @@ class Dept implements Translatable {
     }
 
     function getSLAId() {
-        return $this->ht['sla_id'];
+        return $this->sla_id;
     }
 
     function getSLA() {
-
-        if(!$this->sla && $this->getSLAId())
-            $this->sla=SLA::lookup($this->getSLAId());
-
         return $this->sla;
     }
 
     function getTemplateId() {
-         return $this->ht['tpl_id'];
+         return $this->tpl_id;
     }
 
     function getTemplate() {
@@ -195,8 +157,8 @@ class Dept implements Translatable {
     function getAutoRespEmail() {
 
         if (!$this->autorespEmail) {
-            if (!$this->ht['autoresp_email_id']
-                    || !($this->autorespEmail = Email::lookup($this->ht['autoresp_email_id'])))
+            if (!$this->autoresp_email_id
+                    || !($this->autorespEmail = Email::lookup($this->autoresp_email_id)))
                 $this->autorespEmail = $this->getEmail();
         }
 
@@ -209,7 +171,7 @@ class Dept implements Translatable {
     }
 
     function getSignature() {
-        return $this->ht['signature'];
+        return $this->dept_signature;
     }
 
     function canAppendSignature() {
@@ -217,14 +179,10 @@ class Dept implements Translatable {
     }
 
     function getManagerId() {
-        return $this->ht['manager_id'];
+        return $this->manager_id;
     }
 
     function getManager() {
-
-        if(!$this->manager && $this->getManagerId())
-            $this->manager=Staff::lookup($this->getManagerId());
-
         return $this->manager;
     }
 
@@ -237,27 +195,27 @@ class Dept implements Translatable {
 
 
     function isPublic() {
-         return ($this->ht['ispublic']);
+         return $this->ispublic;
     }
 
     function autoRespONNewTicket() {
-        return ($this->ht['ticket_auto_response']);
+        return $this->ticket_auto_response;
     }
 
     function autoRespONNewMessage() {
-        return ($this->ht['message_auto_response']);
+        return $this->message_auto_response;
     }
 
     function noreplyAutoResp() {
-         return ($this->ht['noreply_autoresp']);
+         return $this->noreply_autoresp;
     }
 
     function assignMembersOnly() {
-        return ($this->config->get('assign_members_only', 0));
+        return $this->getConfig()->get('assign_members_only', 0);
     }
 
     function isGroupMembershipEnabled() {
-        return ($this->ht['group_membership']);
+        return $this->group_membership;
     }
 
     function getHashtable() {
@@ -265,21 +223,21 @@ class Dept implements Translatable {
     }
 
     function getInfo() {
-        return $this->config->getInfo() + $this->getHashtable();
+        return $this->getConfig()->getInfo() + $this->getHashtable();
     }
 
     function getAllowedGroups() {
+        if ($this->groups)
+            return $this->groups;
 
-        if($this->groups) return $this->groups;
+        $groups = GroupDept::object()
+            ->filter(array('dept_id' => $this->getId()))
+            ->values_flat('group_id');
 
-        $sql='SELECT group_id FROM '.GROUP_DEPT_TABLE
-            .' WHERE dept_id='.db_input($this->getId());
-
-        if(($res=db_query($sql)) && db_num_rows($res)) {
-            while(list($id)=db_fetch_row($res))
-                $this->groups[] = $id;
+        foreach ($groups as $row) {
+            list($id) = $row;
+            $this->groups[] = $id;
         }
-
         return $this->groups;
     }
 
@@ -287,31 +245,23 @@ class Dept implements Translatable {
 
         // Groups allowes to access department
         if($vars['groups'] && is_array($vars['groups'])) {
-            foreach($vars['groups'] as $k=>$id) {
-                $sql='INSERT IGNORE INTO '.GROUP_DEPT_TABLE
-                    .' SET dept_id='.db_input($this->getId()).', group_id='.db_input($id);
-                db_query($sql);
+            $groups = GroupDept::object()
+                ->filter(array('dept_id' => $this->getId()));
+            foreach ($groups as $group) {
+                if ($idx = array_search($group->group_id, $vars['groups']))
+                    unset($vars['groups'][$idx]);
+                else
+                    $group->delete();
+            }
+            foreach ($vars['groups'] as $id) {
+                GroupDept::create(array(
+                    'dept_id'=>$this->getId(), 'group_id'=>$id
+                ))->save();
             }
         }
-        $sql='DELETE FROM '.GROUP_DEPT_TABLE.' WHERE dept_id='.db_input($this->getId());
-        if($vars['groups'] && is_array($vars['groups']))
-            $sql.=' AND group_id NOT IN ('.implode(',', db_input($vars['groups'])).')';
-
-        db_query($sql);
 
         // Misc. config settings
-        $this->config->set('assign_members_only', $vars['assign_members_only']);
-
-        return true;
-    }
-
-    function update($vars, &$errors) {
-
-        if(!$this->save($this->getId(), $vars, $errors))
-            return false;
-
-        $this->updateSettings($vars);
-        $this->reload();
+        $this->getConfig()->set('assign_members_only', $vars['assign_members_only']);
 
         return true;
     }
@@ -319,14 +269,19 @@ class Dept implements Translatable {
     function delete() {
         global $cfg;
 
-        if(!$cfg
-                // Default department cannot be deleted
-                || $this->getId()==$cfg->getDefaultDeptId()
-                // Department  with users cannot be deleted
-                || $this->getNumUsers())
+        if (!$cfg
+            // Default department cannot be deleted
+            || $this->getId()==$cfg->getDefaultDeptId()
+            // Department  with users cannot be deleted
+            || StaffModel::objects()
+                ->filter(array('dept_id'=>$this->getId()))
+                ->count()
+        ) {
             return 0;
+        }
 
-        $id=$this->getId();
+        parent::delete();
+        $id = $this->getId();
         $sql='DELETE FROM '.DEPT_TABLE.' WHERE dept_id='.db_input($id).' LIMIT 1';
         if(db_query($sql) && ($num=db_affected_rows())) {
             // DO SOME HOUSE CLEANING
@@ -344,7 +299,7 @@ class Dept implements Translatable {
             db_query('DELETE FROM '.GROUP_DEPT_TABLE.' WHERE dept_id='.db_input($id));
 
             // Destrory config settings
-            $this->config->destroy();
+            $this->getConfig()->destroy();
         }
 
         return $num;
@@ -355,22 +310,18 @@ class Dept implements Translatable {
     }
 
     /*----Static functions-------*/
-	function getIdByName($name) {
-        $id=0;
-        $sql ='SELECT dept_id FROM '.DEPT_TABLE.' WHERE dept_name='.db_input($name);
-        if(($res=db_query($sql)) && db_num_rows($res))
-            list($id)=db_fetch_row($res);
+	static function getIdByName($name) {
+        $row = static::objects()
+            ->filter(array('dept_name'=>$name))
+            ->values_flat('dept_id')
+            ->first();
 
-        return $id;
-    }
-
-    function lookup($id) {
-        return ($id && is_numeric($id) && ($dept = new Dept($id)) && $dept->getId()==$id)?$dept:null;
+        return $row ? $row[0] : 0;
     }
 
     function getNameById($id) {
 
-        if($id && ($dept=Dept::lookup($id)))
+        if($id && ($dept=static::lookup($id)))
             $name= $dept->getName();
 
         return $name;
@@ -381,106 +332,106 @@ class Dept implements Translatable {
         return ($cfg && $cfg->getDefaultDeptId() && ($name=Dept::getNameById($cfg->getDefaultDeptId())))?$name:null;
     }
 
-    function getDepartments( $criteria=null) {
+    static function getDepartments( $criteria=null) {
 
-        $depts=array();
-        $sql='SELECT dept_id, dept_name FROM '.DEPT_TABLE.' WHERE 1';
-        if($criteria['publiconly'])
-            $sql.=' AND  ispublic=1';
+        $depts = self::objects();
+        if ($criteria['publiconly'])
+            $depts->filter(array('public' => 1));
 
-        if(($manager=$criteria['manager']))
-            $sql.=' AND manager_id='.db_input(is_object($manager)?$manager->getId():$manager);
+        if ($manager=$criteria['manager'])
+            $depts->filter(array('manager_id' => is_object($manager)?$manager->getId():$manager));
 
-        $sql.=' ORDER BY dept_name';
+        $depts->order_by('dept_name')
+            ->values_flat('dept_id', 'dept_name');
 
-        if(($res=db_query($sql)) && db_num_rows($res)) {
-            while(list($id, $name)=db_fetch_row($res))
-                $depts[$id] = $name;
+        $names = array();
+        foreach ($depts as $row) {
+            list($id, $name) = $row;
+            $names[$id] = $name;
         }
 
         // Fetch local names
-        foreach (CustomDataTranslation::getDepartmentNames(array_keys($depts)) as $id=>$name) {
+        foreach (CustomDataTranslation::getDepartmentNames(array_keys($names)) as $id=>$name) {
             // Translate the department
-            $depts[$id] = $name;
+            $names[$id] = $name;
         }
-
-        return $depts;
+        return $names;
     }
 
     function getPublicDepartments() {
         return self::getDepartments(array('publiconly'=>true));
     }
 
-    function create($vars, &$errors) {
-
-        if(!($id=self::save(0, $vars, $errors)))
-            return null;
-
-        if (($dept=self::lookup($id)))
-            $dept->updateSettings($vars);
+    static function create($vars, &$errors) {
+        $dept = parent::create($vars);
+        $dept->create = SqlFunction::NOW();
+        return $dept;
+    }
 
-        return $id;
+    function save($refetch=false) {
+        if ($this->dirty)
+            $this->updated = SqlFunction::NOW();
+        return parent::save($refetch || $this->dirty);
     }
 
-    function save($id, $vars, &$errors) {
+    function update($vars, &$errors) {
         global $cfg;
 
-        if($id && $id!=$vars['id'])
+        if (isset($this->dept_id) && $this->getId() != $vars['id'])
             $errors['err']=__('Missing or invalid Dept ID (internal error).');
 
-        if(!$vars['name']) {
+        if (!$vars['name']) {
             $errors['name']=__('Name required');
-        } elseif(strlen($vars['name'])<4) {
+        } elseif (strlen($vars['name'])<4) {
             $errors['name']=__('Name is too short.');
-        } elseif(($did=Dept::getIdByName($vars['name'])) && $did!=$id) {
+        } elseif (($did=static::getIdByName($vars['name']))
+                && (!isset($this->dept_id) || $did!=$this->getId())) {
             $errors['name']=__('Department already exists');
         }
 
-        if(!$vars['ispublic'] && $cfg && ($vars['id']==$cfg->getDefaultDeptId()))
+        if (!$vars['ispublic'] && $cfg && ($vars['id']==$cfg->getDefaultDeptId()))
             $errors['ispublic']=__('System default department cannot be private');
 
-        if($errors) return false;
-
-
-        $sql='SET updated=NOW() '
-            .' ,ispublic='.db_input(isset($vars['ispublic'])?$vars['ispublic']:0)
-            .' ,email_id='.db_input(isset($vars['email_id'])?$vars['email_id']:0)
-            .' ,tpl_id='.db_input(isset($vars['tpl_id'])?$vars['tpl_id']:0)
-            .' ,sla_id='.db_input(isset($vars['sla_id'])?$vars['sla_id']:0)
-            .' ,autoresp_email_id='.db_input(isset($vars['autoresp_email_id'])?$vars['autoresp_email_id']:0)
-            .' ,manager_id='.db_input($vars['manager_id']?$vars['manager_id']:0)
-            .' ,dept_name='.db_input(Format::striptags($vars['name']))
-            .' ,dept_signature='.db_input(Format::sanitize($vars['signature']))
-            .' ,group_membership='.db_input($vars['group_membership'])
-            .' ,ticket_auto_response='.db_input(isset($vars['ticket_auto_response'])?$vars['ticket_auto_response']:1)
-            .' ,message_auto_response='.db_input(isset($vars['message_auto_response'])?$vars['message_auto_response']:1);
-
-
-        if($id) {
-            $sql='UPDATE '.DEPT_TABLE.' '.$sql.' WHERE dept_id='.db_input($id);
-            if(db_query($sql) && db_affected_rows())
-                return true;
+        if ($errors)
+            return false;
 
+        $this->updated = SqlFunction::NOW();
+        $this->ispublic = isset($vars['ispublic'])?$vars['ispublic']:0;
+        $this->email_id = isset($vars['email_id'])?$vars['email_id']:0;
+        $this->tpl_id = isset($vars['tpl_id'])?$vars['tpl_id']:0;
+        $this->sla_id = isset($vars['sla_id'])?$vars['sla_id']:0;
+        $this->autoresp_email_id = isset($vars['autoresp_email_id'])?$vars['autoresp_email_id']:0;
+        $this->manager_id = $vars['manager_id']?$vars['manager_id']:0;
+        $this->dept_name = Format::striptags($vars['name']);
+        $this->dept_signature = Format::sanitize($vars['signature']);
+        $this->group_membership = $vars['group_membership'];
+        $this->ticket_auto_response = isset($vars['ticket_auto_response'])?$vars['ticket_auto_response']:1;
+        $this->message_auto_response = isset($vars['message_auto_response'])?$vars['message_auto_response']:1;
+
+        if ($this->save())
+            return $this->updateSettings($vars);
+
+        if (isset($this->dept_id))
             $errors['err']=sprintf(__('Unable to update %s.'), __('this department'))
                .' '.__('Internal error occurred');
-
-        } else {
-            if (isset($vars['id']))
-                $sql .= ', dept_id='.db_input($vars['id']);
-
-            $sql='INSERT INTO '.DEPT_TABLE.' '.$sql.',created=NOW()';
-            if(db_query($sql) && ($id=db_insert_id()))
-                return $id;
-
-
+        else
             $errors['err']=sprintf(__('Unable to create %s.'), __('this department'))
                .' '.__('Internal error occurred');
 
-        }
-
-
         return false;
     }
 
 }
+
+class GroupDeptAccess extends VerySimpleModel {
+    static $meta = array(
+        'table' => GROUP_DEPT_TABLE,
+        'pk' => array('dept_id', 'group_id'),
+        'joins' => array(
+            'dept' => array(
+                'constraint' => array('dept_id' => 'Dept.dept_id'),
+            ),
+        ),
+    );
+}
 ?>
diff --git a/scp/departments.php b/scp/departments.php
index 999380219ca49a9293089fb51a6a7272d6af93d5..db9b259bf27539cd23f97da833dad5d926646a21 100644
--- a/scp/departments.php
+++ b/scp/departments.php
@@ -33,7 +33,8 @@ if($_POST){
             }
             break;
         case 'create':
-            if(($id=Dept::create($_POST,$errors))){
+            $dept = Dept::create();
+            if(($dept->update($_POST,$errors))){
                 $msg=sprintf(__('Successfully added "%s"'),Format::htmlchars($_POST['name']));
                 $_REQUEST['a']=null;
             }elseif(!$errors['err']){